@@ -427,6 +427,57 @@ void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze)
427427 mutex_unlock (& p -> mib .cnt_mutex );
428428}
429429
430+ int ksz9477_errata_monitor (struct ksz_device * dev , int port ,
431+ u64 tx_late_col )
432+ {
433+ u32 pmavbc ;
434+ u8 status ;
435+ u16 pqm ;
436+ int ret ;
437+
438+ ret = ksz_pread8 (dev , port , REG_PORT_STATUS_0 , & status );
439+ if (ret )
440+ return ret ;
441+ if (!(FIELD_GET (PORT_INTF_SPEED_MASK , status ) == PORT_INTF_SPEED_NONE ) &&
442+ !(status & PORT_INTF_FULL_DUPLEX )) {
443+ /* Errata DS80000754 recommends monitoring potential faults in
444+ * half-duplex mode. The switch might not be able to communicate anymore
445+ * in these states.
446+ * If you see this message, please read the errata-sheet for more information:
447+ * https://ww1.microchip.com/downloads/aemDocuments/documents/UNG/ProductDocuments/Errata/KSZ9477S-Errata-DS80000754.pdf
448+ * To workaround this issue, half-duplex mode should be avoided.
449+ * A software reset could be implemented to recover from this state.
450+ */
451+ dev_warn_once (dev -> dev ,
452+ "Half-duplex detected on port %d, transmission halt may occur\n" ,
453+ port );
454+ if (tx_late_col != 0 ) {
455+ /* Transmission halt with late collisions */
456+ dev_crit_once (dev -> dev ,
457+ "TX late collisions detected, transmission may be halted on port %d\n" ,
458+ port );
459+ }
460+ ret = ksz_read8 (dev , REG_SW_LUE_CTRL_0 , & status );
461+ if (ret )
462+ return ret ;
463+ if (status & SW_VLAN_ENABLE ) {
464+ ret = ksz_pread16 (dev , port , REG_PORT_QM_TX_CNT_0__4 , & pqm );
465+ if (ret )
466+ return ret ;
467+ ret = ksz_read32 (dev , REG_PMAVBC , & pmavbc );
468+ if (ret )
469+ return ret ;
470+ if ((FIELD_GET (PMAVBC_MASK , pmavbc ) <= PMAVBC_MIN ) ||
471+ (FIELD_GET (PORT_QM_TX_CNT_M , pqm ) >= PORT_QM_TX_CNT_MAX )) {
472+ /* Transmission halt with Half-Duplex and VLAN */
473+ dev_crit_once (dev -> dev ,
474+ "resources out of limits, transmission may be halted\n" );
475+ }
476+ }
477+ }
478+ return ret ;
479+ }
480+
430481void ksz9477_port_init_cnt (struct ksz_device * dev , int port )
431482{
432483 struct ksz_port_mib * mib = & dev -> ports [port ].mib ;
@@ -1297,6 +1348,10 @@ int ksz9477_setup(struct dsa_switch *ds)
12971348 /* Enable REG_SW_MTU__2 reg by setting SW_JUMBO_PACKET */
12981349 ksz_cfg (dev , REG_SW_MAC_CTRL_1 , SW_JUMBO_PACKET , true);
12991350
1351+ /* Use collision based back pressure mode. */
1352+ ksz_cfg (dev , REG_SW_MAC_CTRL_1 , SW_BACK_PRESSURE ,
1353+ SW_BACK_PRESSURE_COLLISION );
1354+
13001355 /* Now we can configure default MTU value */
13011356 ret = regmap_update_bits (ksz_regmap_16 (dev ), REG_SW_MTU__2 , REG_SW_MTU_MASK ,
13021357 VLAN_ETH_FRAME_LEN + ETH_FCS_LEN );
0 commit comments