Skip to content

Commit ed8fe20

Browse files
hkallweitdavem330
authored andcommitted
net: dsa: mv88e6xxx: prevent interrupt storm caused by mv88e6390x_port_set_cmode
When debugging another issue I faced an interrupt storm in this driver (88E6390, port 9 in SGMII mode), consisting of alternating link-up / link-down interrupts. Analysis showed that the driver wanted to set a cmode that was set already. But so far mv88e6390x_port_set_cmode() doesn't check this and powers down SERDES, what causes the link to break, and eventually results in the described interrupt storm. Fix this by checking whether the cmode actually changes. We want that the very first call to mv88e6390x_port_set_cmode() always configures the registers, therefore initialize port.cmode with a value that is different from any supported cmode value. We have to take care that we only init the ports cmode once chip->info->num_ports is set. v2: - add small helper and init the number of actual ports only Fixes: 364e9d7 ("net: dsa: mv88e6xxx: Power on/off SERDES on cmode change") Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 5e1a99e commit ed8fe20

File tree

3 files changed

+15
-0
lines changed

3 files changed

+15
-0
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4595,6 +4595,14 @@ static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
45954595
return 0;
45964596
}
45974597

4598+
static void mv88e6xxx_ports_cmode_init(struct mv88e6xxx_chip *chip)
4599+
{
4600+
int i;
4601+
4602+
for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
4603+
chip->ports[i].cmode = MV88E6XXX_PORT_STS_CMODE_INVALID;
4604+
}
4605+
45984606
static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
45994607
int port)
46004608
{
@@ -4631,6 +4639,8 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
46314639
if (err)
46324640
goto free;
46334641

4642+
mv88e6xxx_ports_cmode_init(chip);
4643+
46344644
mutex_lock(&chip->reg_lock);
46354645
err = mv88e6xxx_switch_reset(chip);
46364646
mutex_unlock(&chip->reg_lock);

drivers/net/dsa/mv88e6xxx/port.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,10 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
398398
cmode = 0;
399399
}
400400

401+
/* cmode doesn't change, nothing to do for us */
402+
if (cmode == chip->ports[port].cmode)
403+
return 0;
404+
401405
lane = mv88e6390x_serdes_get_lane(chip, port);
402406
if (lane < 0)
403407
return lane;

drivers/net/dsa/mv88e6xxx/port.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#define MV88E6185_PORT_STS_CMODE_1000BASE_X 0x0005
5353
#define MV88E6185_PORT_STS_CMODE_PHY 0x0006
5454
#define MV88E6185_PORT_STS_CMODE_DISABLED 0x0007
55+
#define MV88E6XXX_PORT_STS_CMODE_INVALID 0xff
5556

5657
/* Offset 0x01: MAC (or PCS or Physical) Control Register */
5758
#define MV88E6XXX_PORT_MAC_CTL 0x01

0 commit comments

Comments
 (0)