2222#define VSC9959_NUM_PORTS 6
2323
2424#define VSC9959_TAS_GCL_ENTRY_MAX 63
25+ #define VSC9959_TAS_MIN_GATE_LEN_NS 33
2526#define VSC9959_VCAP_POLICER_BASE 63
2627#define VSC9959_VCAP_POLICER_MAX 383
2728#define VSC9959_SWITCH_PCI_BAR 4
@@ -1478,6 +1479,23 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
14781479 mdiobus_free (felix -> imdio );
14791480}
14801481
1482+ /* The switch considers any frame (regardless of size) as eligible for
1483+ * transmission if the traffic class gate is open for at least 33 ns.
1484+ * Overruns are prevented by cropping an interval at the end of the gate time
1485+ * slot for which egress scheduling is blocked, but we need to still keep 33 ns
1486+ * available for one packet to be transmitted, otherwise the port tc will hang.
1487+ * This function returns the size of a gate interval that remains available for
1488+ * setting the guard band, after reserving the space for one egress frame.
1489+ */
1490+ static u64 vsc9959_tas_remaining_gate_len_ps (u64 gate_len_ns )
1491+ {
1492+ /* Gate always open */
1493+ if (gate_len_ns == U64_MAX )
1494+ return U64_MAX ;
1495+
1496+ return (gate_len_ns - VSC9959_TAS_MIN_GATE_LEN_NS ) * PSEC_PER_NSEC ;
1497+ }
1498+
14811499/* Extract shortest continuous gate open intervals in ns for each traffic class
14821500 * of a cyclic tc-taprio schedule. If a gate is always open, the duration is
14831501 * considered U64_MAX. If the gate is always closed, it is considered 0.
@@ -1539,6 +1557,65 @@ static void vsc9959_tas_min_gate_lengths(struct tc_taprio_qopt_offload *taprio,
15391557 min_gate_len [tc ] = 0 ;
15401558}
15411559
1560+ /* ocelot_write_rix is a macro that concatenates QSYS_MAXSDU_CFG_* with _RSZ,
1561+ * so we need to spell out the register access to each traffic class in helper
1562+ * functions, to simplify callers
1563+ */
1564+ static void vsc9959_port_qmaxsdu_set (struct ocelot * ocelot , int port , int tc ,
1565+ u32 max_sdu )
1566+ {
1567+ switch (tc ) {
1568+ case 0 :
1569+ ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_0 ,
1570+ port );
1571+ break ;
1572+ case 1 :
1573+ ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_1 ,
1574+ port );
1575+ break ;
1576+ case 2 :
1577+ ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_2 ,
1578+ port );
1579+ break ;
1580+ case 3 :
1581+ ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_3 ,
1582+ port );
1583+ break ;
1584+ case 4 :
1585+ ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_4 ,
1586+ port );
1587+ break ;
1588+ case 5 :
1589+ ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_5 ,
1590+ port );
1591+ break ;
1592+ case 6 :
1593+ ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_6 ,
1594+ port );
1595+ break ;
1596+ case 7 :
1597+ ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_7 ,
1598+ port );
1599+ break ;
1600+ }
1601+ }
1602+
1603+ static u32 vsc9959_port_qmaxsdu_get (struct ocelot * ocelot , int port , int tc )
1604+ {
1605+ switch (tc ) {
1606+ case 0 : return ocelot_read_rix (ocelot , QSYS_QMAXSDU_CFG_0 , port );
1607+ case 1 : return ocelot_read_rix (ocelot , QSYS_QMAXSDU_CFG_1 , port );
1608+ case 2 : return ocelot_read_rix (ocelot , QSYS_QMAXSDU_CFG_2 , port );
1609+ case 3 : return ocelot_read_rix (ocelot , QSYS_QMAXSDU_CFG_3 , port );
1610+ case 4 : return ocelot_read_rix (ocelot , QSYS_QMAXSDU_CFG_4 , port );
1611+ case 5 : return ocelot_read_rix (ocelot , QSYS_QMAXSDU_CFG_5 , port );
1612+ case 6 : return ocelot_read_rix (ocelot , QSYS_QMAXSDU_CFG_6 , port );
1613+ case 7 : return ocelot_read_rix (ocelot , QSYS_QMAXSDU_CFG_7 , port );
1614+ default :
1615+ return 0 ;
1616+ }
1617+ }
1618+
15421619/* Update QSYS_PORT_MAX_SDU to make sure the static guard bands added by the
15431620 * switch (see the ALWAYS_GUARD_BAND_SCH_Q comment) are correct at all MTU
15441621 * values (the default value is 1518). Also, for traffic class windows smaller
@@ -1595,11 +1672,16 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
15951672
15961673 vsc9959_tas_min_gate_lengths (ocelot_port -> taprio , min_gate_len );
15971674
1675+ mutex_lock (& ocelot -> fwd_domain_lock );
1676+
15981677 for (tc = 0 ; tc < OCELOT_NUM_TC ; tc ++ ) {
1678+ u64 remaining_gate_len_ps ;
15991679 u32 max_sdu ;
16001680
1601- if (min_gate_len [tc ] == U64_MAX /* Gate always open */ ||
1602- min_gate_len [tc ] * PSEC_PER_NSEC > needed_bit_time_ps ) {
1681+ remaining_gate_len_ps =
1682+ vsc9959_tas_remaining_gate_len_ps (min_gate_len [tc ]);
1683+
1684+ if (remaining_gate_len_ps > needed_bit_time_ps ) {
16031685 /* Setting QMAXSDU_CFG to 0 disables oversized frame
16041686 * dropping.
16051687 */
@@ -1612,9 +1694,15 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
16121694 /* If traffic class doesn't support a full MTU sized
16131695 * frame, make sure to enable oversize frame dropping
16141696 * for frames larger than the smallest that would fit.
1697+ *
1698+ * However, the exact same register, QSYS_QMAXSDU_CFG_*,
1699+ * controls not only oversized frame dropping, but also
1700+ * per-tc static guard band lengths, so it reduces the
1701+ * useful gate interval length. Therefore, be careful
1702+ * to calculate a guard band (and therefore max_sdu)
1703+ * that still leaves 33 ns available in the time slot.
16151704 */
1616- max_sdu = div_u64 (min_gate_len [tc ] * PSEC_PER_NSEC ,
1617- picos_per_byte );
1705+ max_sdu = div_u64 (remaining_gate_len_ps , picos_per_byte );
16181706 /* A TC gate may be completely closed, which is a
16191707 * special case where all packets are oversized.
16201708 * Any limit smaller than 64 octets accomplishes this
@@ -1637,47 +1725,14 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
16371725 max_sdu );
16381726 }
16391727
1640- /* ocelot_write_rix is a macro that concatenates
1641- * QSYS_MAXSDU_CFG_* with _RSZ, so we need to spell out
1642- * the writes to each traffic class
1643- */
1644- switch (tc ) {
1645- case 0 :
1646- ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_0 ,
1647- port );
1648- break ;
1649- case 1 :
1650- ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_1 ,
1651- port );
1652- break ;
1653- case 2 :
1654- ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_2 ,
1655- port );
1656- break ;
1657- case 3 :
1658- ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_3 ,
1659- port );
1660- break ;
1661- case 4 :
1662- ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_4 ,
1663- port );
1664- break ;
1665- case 5 :
1666- ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_5 ,
1667- port );
1668- break ;
1669- case 6 :
1670- ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_6 ,
1671- port );
1672- break ;
1673- case 7 :
1674- ocelot_write_rix (ocelot , max_sdu , QSYS_QMAXSDU_CFG_7 ,
1675- port );
1676- break ;
1677- }
1728+ vsc9959_port_qmaxsdu_set (ocelot , port , tc , max_sdu );
16781729 }
16791730
16801731 ocelot_write_rix (ocelot , maxlen , QSYS_PORT_MAX_SDU , port );
1732+
1733+ ocelot -> ops -> cut_through_fwd (ocelot );
1734+
1735+ mutex_unlock (& ocelot -> fwd_domain_lock );
16811736}
16821737
16831738static void vsc9959_sched_speed_set (struct ocelot * ocelot , int port ,
@@ -1704,13 +1759,13 @@ static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
17041759 break ;
17051760 }
17061761
1762+ mutex_lock (& ocelot -> tas_lock );
1763+
17071764 ocelot_rmw_rix (ocelot ,
17081765 QSYS_TAG_CONFIG_LINK_SPEED (tas_speed ),
17091766 QSYS_TAG_CONFIG_LINK_SPEED_M ,
17101767 QSYS_TAG_CONFIG , port );
17111768
1712- mutex_lock (& ocelot -> tas_lock );
1713-
17141769 if (ocelot_port -> taprio )
17151770 vsc9959_tas_guard_bands_update (ocelot , port );
17161771
@@ -2770,7 +2825,7 @@ static void vsc9959_cut_through_fwd(struct ocelot *ocelot)
27702825{
27712826 struct felix * felix = ocelot_to_felix (ocelot );
27722827 struct dsa_switch * ds = felix -> ds ;
2773- int port , other_port ;
2828+ int tc , port , other_port ;
27742829
27752830 lockdep_assert_held (& ocelot -> fwd_domain_lock );
27762831
@@ -2814,19 +2869,27 @@ static void vsc9959_cut_through_fwd(struct ocelot *ocelot)
28142869 min_speed = other_ocelot_port -> speed ;
28152870 }
28162871
2817- /* Enable cut-through forwarding for all traffic classes. */
2818- if (ocelot_port -> speed == min_speed )
2872+ /* Enable cut-through forwarding for all traffic classes that
2873+ * don't have oversized dropping enabled, since this check is
2874+ * bypassed in cut-through mode.
2875+ */
2876+ if (ocelot_port -> speed == min_speed ) {
28192877 val = GENMASK (7 , 0 );
28202878
2879+ for (tc = 0 ; tc < OCELOT_NUM_TC ; tc ++ )
2880+ if (vsc9959_port_qmaxsdu_get (ocelot , port , tc ))
2881+ val &= ~BIT (tc );
2882+ }
2883+
28212884set :
28222885 tmp = ocelot_read_rix (ocelot , ANA_CUT_THRU_CFG , port );
28232886 if (tmp == val )
28242887 continue ;
28252888
28262889 dev_dbg (ocelot -> dev ,
2827- "port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding\n" ,
2890+ "port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding on TC mask 0x%x \n" ,
28282891 port , mask , ocelot_port -> speed , min_speed ,
2829- val ? "enabling" : "disabling" );
2892+ val ? "enabling" : "disabling" , val );
28302893
28312894 ocelot_write_rix (ocelot , val , ANA_CUT_THRU_CFG , port );
28322895 }
0 commit comments