Skip to content

Commit bf1bff1

Browse files
deribaucourtdavem330
authored andcommitted
net: dsa: microchip: monitor potential faults in half-duplex mode
The errata DS80000754 recommends monitoring potential faults in half-duplex mode for the KSZ9477 family. half-duplex is not very common so I just added a critical message when the fault conditions are detected. The switch can be expected to be unable to communicate anymore in these states and a software reset of the switch would be required which I did not implement. Fixes: b987e98 ("dsa: add DSA switch driver for Microchip KSZ9477") Signed-off-by: Enguerrand de Ribaucourt <enguerrand.de-ribaucourt@savoirfairelinux.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent d963c95 commit bf1bff1

5 files changed

Lines changed: 73 additions & 2 deletions

File tree

drivers/net/dsa/microchip/ksz9477.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
430481
void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
431482
{
432483
struct ksz_port_mib *mib = &dev->ports[port].mib;

drivers/net/dsa/microchip/ksz9477.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
3636
bool ingress, struct netlink_ext_ack *extack);
3737
void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
3838
struct dsa_mall_mirror_tc_entry *mirror);
39+
int ksz9477_errata_monitor(struct ksz_device *dev, int port,
40+
u64 tx_late_col);
3941
void ksz9477_get_caps(struct ksz_device *dev, int port,
4042
struct phylink_config *config);
4143
int ksz9477_fdb_dump(struct ksz_device *dev, int port,

drivers/net/dsa/microchip/ksz9477_reg.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -843,8 +843,8 @@
843843

844844
#define REG_PORT_STATUS_0 0x0030
845845

846-
#define PORT_INTF_SPEED_M 0x3
847-
#define PORT_INTF_SPEED_S 3
846+
#define PORT_INTF_SPEED_MASK GENMASK(4, 3)
847+
#define PORT_INTF_SPEED_NONE GENMASK(1, 0)
848848
#define PORT_INTF_FULL_DUPLEX BIT(2)
849849
#define PORT_TX_FLOW_CTRL BIT(1)
850850
#define PORT_RX_FLOW_CTRL BIT(0)
@@ -1168,6 +1168,11 @@
11681168
#define PORT_RMII_CLK_SEL BIT(7)
11691169
#define PORT_MII_SEL_EDGE BIT(5)
11701170

1171+
#define REG_PMAVBC 0x03AC
1172+
1173+
#define PMAVBC_MASK GENMASK(26, 16)
1174+
#define PMAVBC_MIN 0x580
1175+
11711176
/* 4 - MAC */
11721177
#define REG_PORT_MAC_CTRL_0 0x0400
11731178

@@ -1495,6 +1500,7 @@
14951500

14961501
#define PORT_QM_TX_CNT_USED_S 0
14971502
#define PORT_QM_TX_CNT_M (BIT(11) - 1)
1503+
#define PORT_QM_TX_CNT_MAX 0x200
14981504

14991505
#define REG_PORT_QM_TX_CNT_1__4 0x0A14
15001506

drivers/net/dsa/microchip/ksz_common.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
13821382
.tc_cbs_supported = true,
13831383
.ops = &ksz9477_dev_ops,
13841384
.phylink_mac_ops = &ksz9477_phylink_mac_ops,
1385+
.phy_errata_9477 = true,
13851386
.mib_names = ksz9477_mib_names,
13861387
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
13871388
.reg_mib_cnt = MIB_COUNTER_NUM,
@@ -1416,6 +1417,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
14161417
.num_ipms = 8,
14171418
.ops = &ksz9477_dev_ops,
14181419
.phylink_mac_ops = &ksz9477_phylink_mac_ops,
1420+
.phy_errata_9477 = true,
14191421
.mib_names = ksz9477_mib_names,
14201422
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
14211423
.reg_mib_cnt = MIB_COUNTER_NUM,
@@ -1450,6 +1452,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
14501452
.num_ipms = 8,
14511453
.ops = &ksz9477_dev_ops,
14521454
.phylink_mac_ops = &ksz9477_phylink_mac_ops,
1455+
.phy_errata_9477 = true,
14531456
.mib_names = ksz9477_mib_names,
14541457
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
14551458
.reg_mib_cnt = MIB_COUNTER_NUM,
@@ -1540,6 +1543,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
15401543
.tc_cbs_supported = true,
15411544
.ops = &ksz9477_dev_ops,
15421545
.phylink_mac_ops = &ksz9477_phylink_mac_ops,
1546+
.phy_errata_9477 = true,
15431547
.mib_names = ksz9477_mib_names,
15441548
.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
15451549
.reg_mib_cnt = MIB_COUNTER_NUM,
@@ -1820,6 +1824,7 @@ void ksz_r_mib_stats64(struct ksz_device *dev, int port)
18201824
struct rtnl_link_stats64 *stats;
18211825
struct ksz_stats_raw *raw;
18221826
struct ksz_port_mib *mib;
1827+
int ret;
18231828

18241829
mib = &dev->ports[port].mib;
18251830
stats = &mib->stats64;
@@ -1861,6 +1866,12 @@ void ksz_r_mib_stats64(struct ksz_device *dev, int port)
18611866
pstats->rx_pause_frames = raw->rx_pause;
18621867

18631868
spin_unlock(&mib->stats64_lock);
1869+
1870+
if (dev->info->phy_errata_9477) {
1871+
ret = ksz9477_errata_monitor(dev, port, raw->tx_late_col);
1872+
if (ret)
1873+
dev_err(dev->dev, "Failed to monitor transmission halt\n");
1874+
}
18641875
}
18651876

18661877
void ksz88xx_r_mib_stats64(struct ksz_device *dev, int port)

drivers/net/dsa/microchip/ksz_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ struct ksz_chip_data {
6666
bool tc_cbs_supported;
6767
const struct ksz_dev_ops *ops;
6868
const struct phylink_mac_ops *phylink_mac_ops;
69+
bool phy_errata_9477;
6970
bool ksz87xx_eee_link_erratum;
7071
const struct ksz_mib_names *mib_names;
7172
int mib_cnt;

0 commit comments

Comments
 (0)