diff options
Diffstat (limited to 'drivers/net/dsa')
| -rw-r--r-- | drivers/net/dsa/b53/b53_common.c | 90 | ||||
| -rw-r--r-- | drivers/net/dsa/b53/b53_priv.h | 3 | ||||
| -rw-r--r-- | drivers/net/dsa/b53/b53_srab.c | 3 | ||||
| -rw-r--r-- | drivers/net/dsa/bcm_sf2.c | 12 | ||||
| -rw-r--r-- | drivers/net/dsa/microchip/ksz_common.c | 2 | ||||
| -rw-r--r-- | drivers/net/dsa/mt7530.c | 1 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 141 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.h | 5 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/global1_atu.c | 21 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/port.h | 10 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/serdes.c | 2 | ||||
| -rw-r--r-- | drivers/net/dsa/realtek-smi.c | 18 |
12 files changed, 257 insertions, 51 deletions
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 0e4bbdcc614f..c76892ac4e69 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c | |||
| @@ -344,7 +344,8 @@ static void b53_set_forwarding(struct b53_device *dev, int enable) | |||
| 344 | b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt); | 344 | b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt); |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | static void b53_enable_vlan(struct b53_device *dev, bool enable) | 347 | static void b53_enable_vlan(struct b53_device *dev, bool enable, |
| 348 | bool enable_filtering) | ||
| 348 | { | 349 | { |
| 349 | u8 mgmt, vc0, vc1, vc4 = 0, vc5; | 350 | u8 mgmt, vc0, vc1, vc4 = 0, vc5; |
| 350 | 351 | ||
| @@ -369,8 +370,13 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable) | |||
| 369 | vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; | 370 | vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; |
| 370 | vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; | 371 | vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; |
| 371 | vc4 &= ~VC4_ING_VID_CHECK_MASK; | 372 | vc4 &= ~VC4_ING_VID_CHECK_MASK; |
| 372 | vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; | 373 | if (enable_filtering) { |
| 373 | vc5 |= VC5_DROP_VTABLE_MISS; | 374 | vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; |
| 375 | vc5 |= VC5_DROP_VTABLE_MISS; | ||
| 376 | } else { | ||
| 377 | vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; | ||
| 378 | vc5 &= ~VC5_DROP_VTABLE_MISS; | ||
| 379 | } | ||
| 374 | 380 | ||
| 375 | if (is5325(dev)) | 381 | if (is5325(dev)) |
| 376 | vc0 &= ~VC0_RESERVED_1; | 382 | vc0 &= ~VC0_RESERVED_1; |
| @@ -420,6 +426,9 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable) | |||
| 420 | } | 426 | } |
| 421 | 427 | ||
| 422 | b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); | 428 | b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); |
| 429 | |||
| 430 | dev->vlan_enabled = enable; | ||
| 431 | dev->vlan_filtering_enabled = enable_filtering; | ||
| 423 | } | 432 | } |
| 424 | 433 | ||
| 425 | static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100) | 434 | static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100) |
| @@ -632,25 +641,35 @@ static void b53_enable_mib(struct b53_device *dev) | |||
| 632 | b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); | 641 | b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); |
| 633 | } | 642 | } |
| 634 | 643 | ||
| 644 | static u16 b53_default_pvid(struct b53_device *dev) | ||
| 645 | { | ||
| 646 | if (is5325(dev) || is5365(dev)) | ||
| 647 | return 1; | ||
| 648 | else | ||
| 649 | return 0; | ||
| 650 | } | ||
| 651 | |||
| 635 | int b53_configure_vlan(struct dsa_switch *ds) | 652 | int b53_configure_vlan(struct dsa_switch *ds) |
| 636 | { | 653 | { |
| 637 | struct b53_device *dev = ds->priv; | 654 | struct b53_device *dev = ds->priv; |
| 638 | struct b53_vlan vl = { 0 }; | 655 | struct b53_vlan vl = { 0 }; |
| 639 | int i; | 656 | int i, def_vid; |
| 657 | |||
| 658 | def_vid = b53_default_pvid(dev); | ||
| 640 | 659 | ||
| 641 | /* clear all vlan entries */ | 660 | /* clear all vlan entries */ |
| 642 | if (is5325(dev) || is5365(dev)) { | 661 | if (is5325(dev) || is5365(dev)) { |
| 643 | for (i = 1; i < dev->num_vlans; i++) | 662 | for (i = def_vid; i < dev->num_vlans; i++) |
| 644 | b53_set_vlan_entry(dev, i, &vl); | 663 | b53_set_vlan_entry(dev, i, &vl); |
| 645 | } else { | 664 | } else { |
| 646 | b53_do_vlan_op(dev, VTA_CMD_CLEAR); | 665 | b53_do_vlan_op(dev, VTA_CMD_CLEAR); |
| 647 | } | 666 | } |
| 648 | 667 | ||
| 649 | b53_enable_vlan(dev, false); | 668 | b53_enable_vlan(dev, false, dev->vlan_filtering_enabled); |
| 650 | 669 | ||
| 651 | b53_for_each_port(dev, i) | 670 | b53_for_each_port(dev, i) |
| 652 | b53_write16(dev, B53_VLAN_PAGE, | 671 | b53_write16(dev, B53_VLAN_PAGE, |
| 653 | B53_VLAN_PORT_DEF_TAG(i), 1); | 672 | B53_VLAN_PORT_DEF_TAG(i), def_vid); |
| 654 | 673 | ||
| 655 | if (!is5325(dev) && !is5365(dev)) | 674 | if (!is5325(dev) && !is5365(dev)) |
| 656 | b53_set_jumbo(dev, dev->enable_jumbo, false); | 675 | b53_set_jumbo(dev, dev->enable_jumbo, false); |
| @@ -1255,6 +1274,46 @@ EXPORT_SYMBOL(b53_phylink_mac_link_up); | |||
| 1255 | 1274 | ||
| 1256 | int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) | 1275 | int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) |
| 1257 | { | 1276 | { |
| 1277 | struct b53_device *dev = ds->priv; | ||
| 1278 | struct net_device *bridge_dev; | ||
| 1279 | unsigned int i; | ||
| 1280 | u16 pvid, new_pvid; | ||
| 1281 | |||
| 1282 | /* Handle the case were multiple bridges span the same switch device | ||
| 1283 | * and one of them has a different setting than what is being requested | ||
| 1284 | * which would be breaking filtering semantics for any of the other | ||
| 1285 | * bridge devices. | ||
| 1286 | */ | ||
| 1287 | b53_for_each_port(dev, i) { | ||
| 1288 | bridge_dev = dsa_to_port(ds, i)->bridge_dev; | ||
| 1289 | if (bridge_dev && | ||
| 1290 | bridge_dev != dsa_to_port(ds, port)->bridge_dev && | ||
| 1291 | br_vlan_enabled(bridge_dev) != vlan_filtering) { | ||
| 1292 | netdev_err(bridge_dev, | ||
| 1293 | "VLAN filtering is global to the switch!\n"); | ||
| 1294 | return -EINVAL; | ||
| 1295 | } | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &pvid); | ||
| 1299 | new_pvid = pvid; | ||
| 1300 | if (dev->vlan_filtering_enabled && !vlan_filtering) { | ||
| 1301 | /* Filtering is currently enabled, use the default PVID since | ||
| 1302 | * the bridge does not expect tagging anymore | ||
| 1303 | */ | ||
| 1304 | dev->ports[port].pvid = pvid; | ||
| 1305 | new_pvid = b53_default_pvid(dev); | ||
| 1306 | } else if (!dev->vlan_filtering_enabled && vlan_filtering) { | ||
| 1307 | /* Filtering is currently disabled, restore the previous PVID */ | ||
| 1308 | new_pvid = dev->ports[port].pvid; | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | if (pvid != new_pvid) | ||
| 1312 | b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), | ||
| 1313 | new_pvid); | ||
| 1314 | |||
| 1315 | b53_enable_vlan(dev, dev->vlan_enabled, vlan_filtering); | ||
| 1316 | |||
| 1258 | return 0; | 1317 | return 0; |
| 1259 | } | 1318 | } |
| 1260 | EXPORT_SYMBOL(b53_vlan_filtering); | 1319 | EXPORT_SYMBOL(b53_vlan_filtering); |
| @@ -1270,7 +1329,7 @@ int b53_vlan_prepare(struct dsa_switch *ds, int port, | |||
| 1270 | if (vlan->vid_end > dev->num_vlans) | 1329 | if (vlan->vid_end > dev->num_vlans) |
| 1271 | return -ERANGE; | 1330 | return -ERANGE; |
| 1272 | 1331 | ||
| 1273 | b53_enable_vlan(dev, true); | 1332 | b53_enable_vlan(dev, true, dev->vlan_filtering_enabled); |
| 1274 | 1333 | ||
| 1275 | return 0; | 1334 | return 0; |
| 1276 | } | 1335 | } |
| @@ -1300,7 +1359,7 @@ void b53_vlan_add(struct dsa_switch *ds, int port, | |||
| 1300 | b53_fast_age_vlan(dev, vid); | 1359 | b53_fast_age_vlan(dev, vid); |
| 1301 | } | 1360 | } |
| 1302 | 1361 | ||
| 1303 | if (pvid) { | 1362 | if (pvid && !dsa_is_cpu_port(ds, port)) { |
| 1304 | b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), | 1363 | b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), |
| 1305 | vlan->vid_end); | 1364 | vlan->vid_end); |
| 1306 | b53_fast_age_vlan(dev, vid); | 1365 | b53_fast_age_vlan(dev, vid); |
| @@ -1326,12 +1385,8 @@ int b53_vlan_del(struct dsa_switch *ds, int port, | |||
| 1326 | 1385 | ||
| 1327 | vl->members &= ~BIT(port); | 1386 | vl->members &= ~BIT(port); |
| 1328 | 1387 | ||
| 1329 | if (pvid == vid) { | 1388 | if (pvid == vid) |
| 1330 | if (is5325(dev) || is5365(dev)) | 1389 | pvid = b53_default_pvid(dev); |
| 1331 | pvid = 1; | ||
| 1332 | else | ||
| 1333 | pvid = 0; | ||
| 1334 | } | ||
| 1335 | 1390 | ||
| 1336 | if (untagged && !dsa_is_cpu_port(ds, port)) | 1391 | if (untagged && !dsa_is_cpu_port(ds, port)) |
| 1337 | vl->untag &= ~(BIT(port)); | 1392 | vl->untag &= ~(BIT(port)); |
| @@ -1644,10 +1699,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *br) | |||
| 1644 | b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan); | 1699 | b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan); |
| 1645 | dev->ports[port].vlan_ctl_mask = pvlan; | 1700 | dev->ports[port].vlan_ctl_mask = pvlan; |
| 1646 | 1701 | ||
| 1647 | if (is5325(dev) || is5365(dev)) | 1702 | pvid = b53_default_pvid(dev); |
| 1648 | pvid = 1; | ||
| 1649 | else | ||
| 1650 | pvid = 0; | ||
| 1651 | 1703 | ||
| 1652 | /* Make this port join all VLANs without VLAN entries */ | 1704 | /* Make this port join all VLANs without VLAN entries */ |
| 1653 | if (is58xx(dev)) { | 1705 | if (is58xx(dev)) { |
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index ec796482792d..4dc7ee38b258 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h | |||
| @@ -91,6 +91,7 @@ enum { | |||
| 91 | struct b53_port { | 91 | struct b53_port { |
| 92 | u16 vlan_ctl_mask; | 92 | u16 vlan_ctl_mask; |
| 93 | struct ethtool_eee eee; | 93 | struct ethtool_eee eee; |
| 94 | u16 pvid; | ||
| 94 | }; | 95 | }; |
| 95 | 96 | ||
| 96 | struct b53_vlan { | 97 | struct b53_vlan { |
| @@ -137,6 +138,8 @@ struct b53_device { | |||
| 137 | 138 | ||
| 138 | unsigned int num_vlans; | 139 | unsigned int num_vlans; |
| 139 | struct b53_vlan *vlans; | 140 | struct b53_vlan *vlans; |
| 141 | bool vlan_enabled; | ||
| 142 | bool vlan_filtering_enabled; | ||
| 140 | unsigned int num_ports; | 143 | unsigned int num_ports; |
| 141 | struct b53_port *ports; | 144 | struct b53_port *ports; |
| 142 | }; | 145 | }; |
diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index 90f514252987..d9c56a779c08 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c | |||
| @@ -511,9 +511,6 @@ static void b53_srab_prepare_irq(struct platform_device *pdev) | |||
| 511 | /* Clear all pending interrupts */ | 511 | /* Clear all pending interrupts */ |
| 512 | writel(0xffffffff, priv->regs + B53_SRAB_INTR); | 512 | writel(0xffffffff, priv->regs + B53_SRAB_INTR); |
| 513 | 513 | ||
| 514 | if (dev->pdata && dev->pdata->chip_id != BCM58XX_DEVICE_ID) | ||
| 515 | return; | ||
| 516 | |||
| 517 | for (i = 0; i < B53_N_PORTS; i++) { | 514 | for (i = 0; i < B53_N_PORTS; i++) { |
| 518 | port = &priv->port_intrs[i]; | 515 | port = &priv->port_intrs[i]; |
| 519 | 516 | ||
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 361fbde76654..14138d423cf1 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c | |||
| @@ -690,7 +690,7 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds) | |||
| 690 | * port, the other ones have already been disabled during | 690 | * port, the other ones have already been disabled during |
| 691 | * bcm_sf2_sw_setup | 691 | * bcm_sf2_sw_setup |
| 692 | */ | 692 | */ |
| 693 | for (port = 0; port < DSA_MAX_PORTS; port++) { | 693 | for (port = 0; port < ds->num_ports; port++) { |
| 694 | if (dsa_is_user_port(ds, port) || dsa_is_cpu_port(ds, port)) | 694 | if (dsa_is_user_port(ds, port) || dsa_is_cpu_port(ds, port)) |
| 695 | bcm_sf2_port_disable(ds, port, NULL); | 695 | bcm_sf2_port_disable(ds, port, NULL); |
| 696 | } | 696 | } |
| @@ -726,10 +726,11 @@ static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, | |||
| 726 | { | 726 | { |
| 727 | struct net_device *p = ds->ports[port].cpu_dp->master; | 727 | struct net_device *p = ds->ports[port].cpu_dp->master; |
| 728 | struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); | 728 | struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); |
| 729 | struct ethtool_wolinfo pwol; | 729 | struct ethtool_wolinfo pwol = { }; |
| 730 | 730 | ||
| 731 | /* Get the parent device WoL settings */ | 731 | /* Get the parent device WoL settings */ |
| 732 | p->ethtool_ops->get_wol(p, &pwol); | 732 | if (p->ethtool_ops->get_wol) |
| 733 | p->ethtool_ops->get_wol(p, &pwol); | ||
| 733 | 734 | ||
| 734 | /* Advertise the parent device supported settings */ | 735 | /* Advertise the parent device supported settings */ |
| 735 | wol->supported = pwol.supported; | 736 | wol->supported = pwol.supported; |
| @@ -750,9 +751,10 @@ static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, | |||
| 750 | struct net_device *p = ds->ports[port].cpu_dp->master; | 751 | struct net_device *p = ds->ports[port].cpu_dp->master; |
| 751 | struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); | 752 | struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); |
| 752 | s8 cpu_port = ds->ports[port].cpu_dp->index; | 753 | s8 cpu_port = ds->ports[port].cpu_dp->index; |
| 753 | struct ethtool_wolinfo pwol; | 754 | struct ethtool_wolinfo pwol = { }; |
| 754 | 755 | ||
| 755 | p->ethtool_ops->get_wol(p, &pwol); | 756 | if (p->ethtool_ops->get_wol) |
| 757 | p->ethtool_ops->get_wol(p, &pwol); | ||
| 756 | if (wol->wolopts & ~pwol.supported) | 758 | if (wol->wolopts & ~pwol.supported) |
| 757 | return -EINVAL; | 759 | return -EINVAL; |
| 758 | 760 | ||
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 3b12e2dcff31..8a5111f9414c 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | 7 | ||
| 8 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
| 9 | #include <linux/export.h> | 9 | #include <linux/export.h> |
| 10 | #include <linux/gpio.h> | ||
| 11 | #include <linux/gpio/consumer.h> | 10 | #include <linux/gpio/consumer.h> |
| 12 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 13 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| @@ -15,7 +14,6 @@ | |||
| 15 | #include <linux/phy.h> | 14 | #include <linux/phy.h> |
| 16 | #include <linux/etherdevice.h> | 15 | #include <linux/etherdevice.h> |
| 17 | #include <linux/if_bridge.h> | 16 | #include <linux/if_bridge.h> |
| 18 | #include <linux/of_gpio.h> | ||
| 19 | #include <linux/of_net.h> | 17 | #include <linux/of_net.h> |
| 20 | #include <net/dsa.h> | 18 | #include <net/dsa.h> |
| 21 | #include <net/switchdev.h> | 19 | #include <net/switchdev.h> |
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 74547f43b938..a8a2c728afba 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | #include <linux/mfd/syscon.h> | 18 | #include <linux/mfd/syscon.h> |
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
| 21 | #include <linux/of_gpio.h> | ||
| 22 | #include <linux/of_mdio.h> | 21 | #include <linux/of_mdio.h> |
| 23 | #include <linux/of_net.h> | 22 | #include <linux/of_net.h> |
| 24 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 8a517d8fb9d1..12fd7ce3f1ff 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c | |||
| @@ -261,6 +261,7 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) | |||
| 261 | unsigned int sub_irq; | 261 | unsigned int sub_irq; |
| 262 | unsigned int n; | 262 | unsigned int n; |
| 263 | u16 reg; | 263 | u16 reg; |
| 264 | u16 ctl1; | ||
| 264 | int err; | 265 | int err; |
| 265 | 266 | ||
| 266 | mutex_lock(&chip->reg_lock); | 267 | mutex_lock(&chip->reg_lock); |
| @@ -270,13 +271,28 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip) | |||
| 270 | if (err) | 271 | if (err) |
| 271 | goto out; | 272 | goto out; |
| 272 | 273 | ||
| 273 | for (n = 0; n < chip->g1_irq.nirqs; ++n) { | 274 | do { |
| 274 | if (reg & (1 << n)) { | 275 | for (n = 0; n < chip->g1_irq.nirqs; ++n) { |
| 275 | sub_irq = irq_find_mapping(chip->g1_irq.domain, n); | 276 | if (reg & (1 << n)) { |
| 276 | handle_nested_irq(sub_irq); | 277 | sub_irq = irq_find_mapping(chip->g1_irq.domain, |
| 277 | ++nhandled; | 278 | n); |
| 279 | handle_nested_irq(sub_irq); | ||
| 280 | ++nhandled; | ||
| 281 | } | ||
| 278 | } | 282 | } |
| 279 | } | 283 | |
| 284 | mutex_lock(&chip->reg_lock); | ||
| 285 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1); | ||
| 286 | if (err) | ||
| 287 | goto unlock; | ||
| 288 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); | ||
| 289 | unlock: | ||
| 290 | mutex_unlock(&chip->reg_lock); | ||
| 291 | if (err) | ||
| 292 | goto out; | ||
| 293 | ctl1 &= GENMASK(chip->g1_irq.nirqs, 0); | ||
| 294 | } while (reg & ctl1); | ||
| 295 | |||
| 280 | out: | 296 | out: |
| 281 | return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); | 297 | return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); |
| 282 | } | 298 | } |
| @@ -2403,6 +2419,107 @@ static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) | |||
| 2403 | return mv88e6xxx_g1_stats_clear(chip); | 2419 | return mv88e6xxx_g1_stats_clear(chip); |
| 2404 | } | 2420 | } |
| 2405 | 2421 | ||
| 2422 | /* The mv88e6390 has some hidden registers used for debug and | ||
| 2423 | * development. The errata also makes use of them. | ||
| 2424 | */ | ||
| 2425 | static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port, | ||
| 2426 | int reg, u16 val) | ||
| 2427 | { | ||
| 2428 | u16 ctrl; | ||
| 2429 | int err; | ||
| 2430 | |||
| 2431 | err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_DATA_PORT, | ||
| 2432 | PORT_RESERVED_1A, val); | ||
| 2433 | if (err) | ||
| 2434 | return err; | ||
| 2435 | |||
| 2436 | ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_WRITE | | ||
| 2437 | PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | | ||
| 2438 | reg; | ||
| 2439 | |||
| 2440 | return mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, | ||
| 2441 | PORT_RESERVED_1A, ctrl); | ||
| 2442 | } | ||
| 2443 | |||
| 2444 | static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip) | ||
| 2445 | { | ||
| 2446 | return mv88e6xxx_wait(chip, PORT_RESERVED_1A_CTRL_PORT, | ||
| 2447 | PORT_RESERVED_1A, PORT_RESERVED_1A_BUSY); | ||
| 2448 | } | ||
| 2449 | |||
| 2450 | |||
| 2451 | static int mv88e6390_hidden_read(struct mv88e6xxx_chip *chip, int port, | ||
| 2452 | int reg, u16 *val) | ||
| 2453 | { | ||
| 2454 | u16 ctrl; | ||
| 2455 | int err; | ||
| 2456 | |||
| 2457 | ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_READ | | ||
| 2458 | PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | | ||
| 2459 | reg; | ||
| 2460 | |||
| 2461 | err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, | ||
| 2462 | PORT_RESERVED_1A, ctrl); | ||
| 2463 | if (err) | ||
| 2464 | return err; | ||
| 2465 | |||
| 2466 | err = mv88e6390_hidden_wait(chip); | ||
| 2467 | if (err) | ||
| 2468 | return err; | ||
| 2469 | |||
| 2470 | return mv88e6xxx_port_read(chip, PORT_RESERVED_1A_DATA_PORT, | ||
| 2471 | PORT_RESERVED_1A, val); | ||
| 2472 | } | ||
| 2473 | |||
| 2474 | /* Check if the errata has already been applied. */ | ||
| 2475 | static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) | ||
| 2476 | { | ||
| 2477 | int port; | ||
| 2478 | int err; | ||
| 2479 | u16 val; | ||
| 2480 | |||
| 2481 | for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { | ||
| 2482 | err = mv88e6390_hidden_read(chip, port, 0, &val); | ||
| 2483 | if (err) { | ||
| 2484 | dev_err(chip->dev, | ||
| 2485 | "Error reading hidden register: %d\n", err); | ||
| 2486 | return false; | ||
| 2487 | } | ||
| 2488 | if (val != 0x01c0) | ||
| 2489 | return false; | ||
| 2490 | } | ||
| 2491 | |||
| 2492 | return true; | ||
| 2493 | } | ||
| 2494 | |||
| 2495 | /* The 6390 copper ports have an errata which require poking magic | ||
| 2496 | * values into undocumented hidden registers and then performing a | ||
| 2497 | * software reset. | ||
| 2498 | */ | ||
| 2499 | static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) | ||
| 2500 | { | ||
| 2501 | int port; | ||
| 2502 | int err; | ||
| 2503 | |||
| 2504 | if (mv88e6390_setup_errata_applied(chip)) | ||
| 2505 | return 0; | ||
| 2506 | |||
| 2507 | /* Set the ports into blocking mode */ | ||
| 2508 | for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { | ||
| 2509 | err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); | ||
| 2510 | if (err) | ||
| 2511 | return err; | ||
| 2512 | } | ||
| 2513 | |||
| 2514 | for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { | ||
| 2515 | err = mv88e6390_hidden_write(chip, port, 0, 0x01c0); | ||
| 2516 | if (err) | ||
| 2517 | return err; | ||
| 2518 | } | ||
| 2519 | |||
| 2520 | return mv88e6xxx_software_reset(chip); | ||
| 2521 | } | ||
| 2522 | |||
| 2406 | static int mv88e6xxx_setup(struct dsa_switch *ds) | 2523 | static int mv88e6xxx_setup(struct dsa_switch *ds) |
| 2407 | { | 2524 | { |
| 2408 | struct mv88e6xxx_chip *chip = ds->priv; | 2525 | struct mv88e6xxx_chip *chip = ds->priv; |
| @@ -2415,6 +2532,12 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) | |||
| 2415 | 2532 | ||
| 2416 | mutex_lock(&chip->reg_lock); | 2533 | mutex_lock(&chip->reg_lock); |
| 2417 | 2534 | ||
| 2535 | if (chip->info->ops->setup_errata) { | ||
| 2536 | err = chip->info->ops->setup_errata(chip); | ||
| 2537 | if (err) | ||
| 2538 | goto unlock; | ||
| 2539 | } | ||
| 2540 | |||
| 2418 | /* Cache the cmode of each port. */ | 2541 | /* Cache the cmode of each port. */ |
| 2419 | for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { | 2542 | for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { |
| 2420 | if (chip->info->ops->port_get_cmode) { | 2543 | if (chip->info->ops->port_get_cmode) { |
| @@ -3226,6 +3349,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { | |||
| 3226 | 3349 | ||
| 3227 | static const struct mv88e6xxx_ops mv88e6190_ops = { | 3350 | static const struct mv88e6xxx_ops mv88e6190_ops = { |
| 3228 | /* MV88E6XXX_FAMILY_6390 */ | 3351 | /* MV88E6XXX_FAMILY_6390 */ |
| 3352 | .setup_errata = mv88e6390_setup_errata, | ||
| 3229 | .irl_init_all = mv88e6390_g2_irl_init_all, | 3353 | .irl_init_all = mv88e6390_g2_irl_init_all, |
| 3230 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, | 3354 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, |
| 3231 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, | 3355 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, |
| @@ -3269,6 +3393,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { | |||
| 3269 | 3393 | ||
| 3270 | static const struct mv88e6xxx_ops mv88e6190x_ops = { | 3394 | static const struct mv88e6xxx_ops mv88e6190x_ops = { |
| 3271 | /* MV88E6XXX_FAMILY_6390 */ | 3395 | /* MV88E6XXX_FAMILY_6390 */ |
| 3396 | .setup_errata = mv88e6390_setup_errata, | ||
| 3272 | .irl_init_all = mv88e6390_g2_irl_init_all, | 3397 | .irl_init_all = mv88e6390_g2_irl_init_all, |
| 3273 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, | 3398 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, |
| 3274 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, | 3399 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, |
| @@ -3312,6 +3437,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { | |||
| 3312 | 3437 | ||
| 3313 | static const struct mv88e6xxx_ops mv88e6191_ops = { | 3438 | static const struct mv88e6xxx_ops mv88e6191_ops = { |
| 3314 | /* MV88E6XXX_FAMILY_6390 */ | 3439 | /* MV88E6XXX_FAMILY_6390 */ |
| 3440 | .setup_errata = mv88e6390_setup_errata, | ||
| 3315 | .irl_init_all = mv88e6390_g2_irl_init_all, | 3441 | .irl_init_all = mv88e6390_g2_irl_init_all, |
| 3316 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, | 3442 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, |
| 3317 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, | 3443 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, |
| @@ -3404,6 +3530,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { | |||
| 3404 | 3530 | ||
| 3405 | static const struct mv88e6xxx_ops mv88e6290_ops = { | 3531 | static const struct mv88e6xxx_ops mv88e6290_ops = { |
| 3406 | /* MV88E6XXX_FAMILY_6390 */ | 3532 | /* MV88E6XXX_FAMILY_6390 */ |
| 3533 | .setup_errata = mv88e6390_setup_errata, | ||
| 3407 | .irl_init_all = mv88e6390_g2_irl_init_all, | 3534 | .irl_init_all = mv88e6390_g2_irl_init_all, |
| 3408 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, | 3535 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, |
| 3409 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, | 3536 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, |
| @@ -3709,6 +3836,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { | |||
| 3709 | 3836 | ||
| 3710 | static const struct mv88e6xxx_ops mv88e6390_ops = { | 3837 | static const struct mv88e6xxx_ops mv88e6390_ops = { |
| 3711 | /* MV88E6XXX_FAMILY_6390 */ | 3838 | /* MV88E6XXX_FAMILY_6390 */ |
| 3839 | .setup_errata = mv88e6390_setup_errata, | ||
| 3712 | .irl_init_all = mv88e6390_g2_irl_init_all, | 3840 | .irl_init_all = mv88e6390_g2_irl_init_all, |
| 3713 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, | 3841 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, |
| 3714 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, | 3842 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, |
| @@ -3756,6 +3884,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { | |||
| 3756 | 3884 | ||
| 3757 | static const struct mv88e6xxx_ops mv88e6390x_ops = { | 3885 | static const struct mv88e6xxx_ops mv88e6390x_ops = { |
| 3758 | /* MV88E6XXX_FAMILY_6390 */ | 3886 | /* MV88E6XXX_FAMILY_6390 */ |
| 3887 | .setup_errata = mv88e6390_setup_errata, | ||
| 3759 | .irl_init_all = mv88e6390_g2_irl_init_all, | 3888 | .irl_init_all = mv88e6390_g2_irl_init_all, |
| 3760 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, | 3889 | .get_eeprom = mv88e6xxx_g2_get_eeprom8, |
| 3761 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, | 3890 | .set_eeprom = mv88e6xxx_g2_set_eeprom8, |
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index f9ecb7872d32..546651d8c3e1 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h | |||
| @@ -300,6 +300,11 @@ struct mv88e6xxx_mdio_bus { | |||
| 300 | }; | 300 | }; |
| 301 | 301 | ||
| 302 | struct mv88e6xxx_ops { | 302 | struct mv88e6xxx_ops { |
| 303 | /* Switch Setup Errata, called early in the switch setup to | ||
| 304 | * allow any errata actions to be performed | ||
| 305 | */ | ||
| 306 | int (*setup_errata)(struct mv88e6xxx_chip *chip); | ||
| 307 | |||
| 303 | int (*ieee_pri_map)(struct mv88e6xxx_chip *chip); | 308 | int (*ieee_pri_map)(struct mv88e6xxx_chip *chip); |
| 304 | int (*ip_pri_map)(struct mv88e6xxx_chip *chip); | 309 | int (*ip_pri_map)(struct mv88e6xxx_chip *chip); |
| 305 | 310 | ||
diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index 5200e4bdce93..ea243840ee0f 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c | |||
| @@ -314,6 +314,7 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) | |||
| 314 | { | 314 | { |
| 315 | struct mv88e6xxx_chip *chip = dev_id; | 315 | struct mv88e6xxx_chip *chip = dev_id; |
| 316 | struct mv88e6xxx_atu_entry entry; | 316 | struct mv88e6xxx_atu_entry entry; |
| 317 | int spid; | ||
| 317 | int err; | 318 | int err; |
| 318 | u16 val; | 319 | u16 val; |
| 319 | 320 | ||
| @@ -336,6 +337,8 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) | |||
| 336 | if (err) | 337 | if (err) |
| 337 | goto out; | 338 | goto out; |
| 338 | 339 | ||
| 340 | spid = entry.state; | ||
| 341 | |||
| 339 | if (val & MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION) { | 342 | if (val & MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION) { |
| 340 | dev_err_ratelimited(chip->dev, | 343 | dev_err_ratelimited(chip->dev, |
| 341 | "ATU age out violation for %pM\n", | 344 | "ATU age out violation for %pM\n", |
| @@ -344,23 +347,23 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) | |||
| 344 | 347 | ||
| 345 | if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) { | 348 | if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) { |
| 346 | dev_err_ratelimited(chip->dev, | 349 | dev_err_ratelimited(chip->dev, |
| 347 | "ATU member violation for %pM portvec %x\n", | 350 | "ATU member violation for %pM portvec %x spid %d\n", |
| 348 | entry.mac, entry.portvec); | 351 | entry.mac, entry.portvec, spid); |
| 349 | chip->ports[entry.portvec].atu_member_violation++; | 352 | chip->ports[spid].atu_member_violation++; |
| 350 | } | 353 | } |
| 351 | 354 | ||
| 352 | if (val & MV88E6XXX_G1_ATU_OP_MISS_VIOLATION) { | 355 | if (val & MV88E6XXX_G1_ATU_OP_MISS_VIOLATION) { |
| 353 | dev_err_ratelimited(chip->dev, | 356 | dev_err_ratelimited(chip->dev, |
| 354 | "ATU miss violation for %pM portvec %x\n", | 357 | "ATU miss violation for %pM portvec %x spid %d\n", |
| 355 | entry.mac, entry.portvec); | 358 | entry.mac, entry.portvec, spid); |
| 356 | chip->ports[entry.portvec].atu_miss_violation++; | 359 | chip->ports[spid].atu_miss_violation++; |
| 357 | } | 360 | } |
| 358 | 361 | ||
| 359 | if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) { | 362 | if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) { |
| 360 | dev_err_ratelimited(chip->dev, | 363 | dev_err_ratelimited(chip->dev, |
| 361 | "ATU full violation for %pM portvec %x\n", | 364 | "ATU full violation for %pM portvec %x spid %d\n", |
| 362 | entry.mac, entry.portvec); | 365 | entry.mac, entry.portvec, spid); |
| 363 | chip->ports[entry.portvec].atu_full_violation++; | 366 | chip->ports[spid].atu_full_violation++; |
| 364 | } | 367 | } |
| 365 | mutex_unlock(&chip->reg_lock); | 368 | mutex_unlock(&chip->reg_lock); |
| 366 | 369 | ||
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 0d81866d0e4a..e583641de758 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h | |||
| @@ -251,6 +251,16 @@ | |||
| 251 | /* Offset 0x19: Port IEEE Priority Remapping Registers (4-7) */ | 251 | /* Offset 0x19: Port IEEE Priority Remapping Registers (4-7) */ |
| 252 | #define MV88E6095_PORT_IEEE_PRIO_REMAP_4567 0x19 | 252 | #define MV88E6095_PORT_IEEE_PRIO_REMAP_4567 0x19 |
| 253 | 253 | ||
| 254 | /* Offset 0x1a: Magic undocumented errata register */ | ||
| 255 | #define PORT_RESERVED_1A 0x1a | ||
| 256 | #define PORT_RESERVED_1A_BUSY BIT(15) | ||
| 257 | #define PORT_RESERVED_1A_WRITE BIT(14) | ||
| 258 | #define PORT_RESERVED_1A_READ 0 | ||
| 259 | #define PORT_RESERVED_1A_PORT_SHIFT 5 | ||
| 260 | #define PORT_RESERVED_1A_BLOCK (0xf << 10) | ||
| 261 | #define PORT_RESERVED_1A_CTRL_PORT 4 | ||
| 262 | #define PORT_RESERVED_1A_DATA_PORT 5 | ||
| 263 | |||
| 254 | int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, | 264 | int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, |
| 255 | u16 *val); | 265 | u16 *val); |
| 256 | int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, | 266 | int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, |
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 2caa8c8b4b55..1bfc5ff8d81d 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c | |||
| @@ -664,7 +664,7 @@ int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port) | |||
| 664 | if (port < 9) | 664 | if (port < 9) |
| 665 | return 0; | 665 | return 0; |
| 666 | 666 | ||
| 667 | return mv88e6390_serdes_irq_setup(chip, port); | 667 | return mv88e6390x_serdes_irq_setup(chip, port); |
| 668 | } | 668 | } |
| 669 | 669 | ||
| 670 | void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port) | 670 | void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port) |
diff --git a/drivers/net/dsa/realtek-smi.c b/drivers/net/dsa/realtek-smi.c index b4b839a1d095..ad41ec63cc9f 100644 --- a/drivers/net/dsa/realtek-smi.c +++ b/drivers/net/dsa/realtek-smi.c | |||
| @@ -347,16 +347,17 @@ int realtek_smi_setup_mdio(struct realtek_smi *smi) | |||
| 347 | struct device_node *mdio_np; | 347 | struct device_node *mdio_np; |
| 348 | int ret; | 348 | int ret; |
| 349 | 349 | ||
| 350 | mdio_np = of_find_compatible_node(smi->dev->of_node, NULL, | 350 | mdio_np = of_get_compatible_child(smi->dev->of_node, "realtek,smi-mdio"); |
| 351 | "realtek,smi-mdio"); | ||
| 352 | if (!mdio_np) { | 351 | if (!mdio_np) { |
| 353 | dev_err(smi->dev, "no MDIO bus node\n"); | 352 | dev_err(smi->dev, "no MDIO bus node\n"); |
| 354 | return -ENODEV; | 353 | return -ENODEV; |
| 355 | } | 354 | } |
| 356 | 355 | ||
| 357 | smi->slave_mii_bus = devm_mdiobus_alloc(smi->dev); | 356 | smi->slave_mii_bus = devm_mdiobus_alloc(smi->dev); |
| 358 | if (!smi->slave_mii_bus) | 357 | if (!smi->slave_mii_bus) { |
| 359 | return -ENOMEM; | 358 | ret = -ENOMEM; |
| 359 | goto err_put_node; | ||
| 360 | } | ||
| 360 | smi->slave_mii_bus->priv = smi; | 361 | smi->slave_mii_bus->priv = smi; |
| 361 | smi->slave_mii_bus->name = "SMI slave MII"; | 362 | smi->slave_mii_bus->name = "SMI slave MII"; |
| 362 | smi->slave_mii_bus->read = realtek_smi_mdio_read; | 363 | smi->slave_mii_bus->read = realtek_smi_mdio_read; |
| @@ -371,10 +372,15 @@ int realtek_smi_setup_mdio(struct realtek_smi *smi) | |||
| 371 | if (ret) { | 372 | if (ret) { |
| 372 | dev_err(smi->dev, "unable to register MDIO bus %s\n", | 373 | dev_err(smi->dev, "unable to register MDIO bus %s\n", |
| 373 | smi->slave_mii_bus->id); | 374 | smi->slave_mii_bus->id); |
| 374 | of_node_put(mdio_np); | 375 | goto err_put_node; |
| 375 | } | 376 | } |
| 376 | 377 | ||
| 377 | return 0; | 378 | return 0; |
| 379 | |||
| 380 | err_put_node: | ||
| 381 | of_node_put(mdio_np); | ||
| 382 | |||
| 383 | return ret; | ||
| 378 | } | 384 | } |
| 379 | 385 | ||
| 380 | static int realtek_smi_probe(struct platform_device *pdev) | 386 | static int realtek_smi_probe(struct platform_device *pdev) |
| @@ -457,6 +463,8 @@ static int realtek_smi_remove(struct platform_device *pdev) | |||
| 457 | struct realtek_smi *smi = dev_get_drvdata(&pdev->dev); | 463 | struct realtek_smi *smi = dev_get_drvdata(&pdev->dev); |
| 458 | 464 | ||
| 459 | dsa_unregister_switch(smi->ds); | 465 | dsa_unregister_switch(smi->ds); |
| 466 | if (smi->slave_mii_bus) | ||
| 467 | of_node_put(smi->slave_mii_bus->dev.of_node); | ||
| 460 | gpiod_set_value(smi->reset, 1); | 468 | gpiod_set_value(smi->reset, 1); |
| 461 | 469 | ||
| 462 | return 0; | 470 | return 0; |
