b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From 7fa63fdde703aaabaa7199ae879219737a98a3f3 Mon Sep 17 00:00:00 2001 |
| 2 | From: Jonas Gorski <jonas.gorski@gmail.com> |
| 3 | Date: Fri, 6 Jan 2012 12:24:18 +0100 |
| 4 | Subject: [PATCH] NET: bcm63xx_enet: move phy_(dis)connect into probe/remove |
| 5 | |
| 6 | Only connect/disconnect the phy during probe and remove, not during any |
| 7 | open/close. The phy seldom changes during the runtime, and disconnecting |
| 8 | the phy during close will prevent it from keeping any configuration over |
| 9 | a down/up cycle. |
| 10 | |
| 11 | Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com> |
| 12 | --- |
| 13 | drivers/net/ethernet/broadcom/bcm63xx_enet.c | 158 +++++++++++++-------------- |
| 14 | 1 file changed, 78 insertions(+), 80 deletions(-) |
| 15 | |
| 16 | --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c |
| 17 | +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c |
| 18 | @@ -893,10 +893,8 @@ static int bcm_enet_open(struct net_devi |
| 19 | struct bcm_enet_priv *priv; |
| 20 | struct sockaddr addr; |
| 21 | struct device *kdev; |
| 22 | - struct phy_device *phydev; |
| 23 | int i, ret; |
| 24 | unsigned int size; |
| 25 | - char phy_id[MII_BUS_ID_SIZE + 3]; |
| 26 | void *p; |
| 27 | u32 val; |
| 28 | |
| 29 | @@ -904,31 +902,10 @@ static int bcm_enet_open(struct net_devi |
| 30 | kdev = &priv->pdev->dev; |
| 31 | |
| 32 | if (priv->has_phy) { |
| 33 | - /* connect to PHY */ |
| 34 | - snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, |
| 35 | - priv->mii_bus->id, priv->phy_id); |
| 36 | - |
| 37 | - phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link, |
| 38 | - PHY_INTERFACE_MODE_MII); |
| 39 | - |
| 40 | - if (IS_ERR(phydev)) { |
| 41 | - dev_err(kdev, "could not attach to PHY\n"); |
| 42 | - return PTR_ERR(phydev); |
| 43 | - } |
| 44 | - |
| 45 | - /* mask with MAC supported features */ |
| 46 | - phy_support_sym_pause(phydev); |
| 47 | - phy_set_max_speed(phydev, SPEED_100); |
| 48 | - phy_set_sym_pause(phydev, priv->pause_rx, priv->pause_rx, |
| 49 | - priv->pause_auto); |
| 50 | - |
| 51 | - phy_attached_info(phydev); |
| 52 | - |
| 53 | + /* Reset state */ |
| 54 | priv->old_link = 0; |
| 55 | priv->old_duplex = -1; |
| 56 | priv->old_pause = -1; |
| 57 | - } else { |
| 58 | - phydev = NULL; |
| 59 | } |
| 60 | |
| 61 | /* mask all interrupts and request them */ |
| 62 | @@ -938,7 +915,7 @@ static int bcm_enet_open(struct net_devi |
| 63 | |
| 64 | ret = request_irq(dev->irq, bcm_enet_isr_mac, 0, dev->name, dev); |
| 65 | if (ret) |
| 66 | - goto out_phy_disconnect; |
| 67 | + return ret; |
| 68 | |
| 69 | ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, 0, |
| 70 | dev->name, dev); |
| 71 | @@ -1100,8 +1077,8 @@ static int bcm_enet_open(struct net_devi |
| 72 | enet_dmac_writel(priv, priv->dma_chan_int_mask, |
| 73 | ENETDMAC_IRMASK, priv->tx_chan); |
| 74 | |
| 75 | - if (phydev) |
| 76 | - phy_start(phydev); |
| 77 | + if (priv->has_phy) |
| 78 | + phy_start(dev->phydev); |
| 79 | else |
| 80 | bcm_enet_adjust_link(dev); |
| 81 | |
| 82 | @@ -1131,10 +1108,6 @@ out_freeirq_rx: |
| 83 | out_freeirq: |
| 84 | free_irq(dev->irq, dev); |
| 85 | |
| 86 | -out_phy_disconnect: |
| 87 | - if (phydev) |
| 88 | - phy_disconnect(phydev); |
| 89 | - |
| 90 | return ret; |
| 91 | } |
| 92 | |
| 93 | @@ -1227,10 +1200,6 @@ static int bcm_enet_stop(struct net_devi |
| 94 | free_irq(priv->irq_rx, dev); |
| 95 | free_irq(dev->irq, dev); |
| 96 | |
| 97 | - /* release phy */ |
| 98 | - if (priv->has_phy) |
| 99 | - phy_disconnect(dev->phydev); |
| 100 | - |
| 101 | /* reset BQL after forced tx reclaim to not kernel panic */ |
| 102 | netdev_reset_queue(dev); |
| 103 | |
| 104 | @@ -1802,14 +1771,47 @@ static int bcm_enet_probe(struct platfor |
| 105 | |
| 106 | /* do minimal hardware init to be able to probe mii bus */ |
| 107 | bcm_enet_hw_preinit(priv); |
| 108 | + spin_lock_init(&priv->rx_lock); |
| 109 | + |
| 110 | + /* init rx timeout (used for oom) */ |
| 111 | + timer_setup(&priv->rx_timeout, bcm_enet_refill_rx_timer, 0); |
| 112 | + |
| 113 | + /* init the mib update lock&work */ |
| 114 | + mutex_init(&priv->mib_update_lock); |
| 115 | + INIT_WORK(&priv->mib_update_task, bcm_enet_update_mib_counters_defer); |
| 116 | + |
| 117 | + /* zero mib counters */ |
| 118 | + for (i = 0; i < ENET_MIB_REG_COUNT; i++) |
| 119 | + enet_writel(priv, 0, ENET_MIB_REG(i)); |
| 120 | + |
| 121 | + /* register netdevice */ |
| 122 | + dev->netdev_ops = &bcm_enet_ops; |
| 123 | + netif_napi_add(dev, &priv->napi, bcm_enet_poll, 16); |
| 124 | + |
| 125 | + dev->ethtool_ops = &bcm_enet_ethtool_ops; |
| 126 | + /* MTU range: 46 - 2028 */ |
| 127 | + dev->min_mtu = ETH_ZLEN - ETH_HLEN; |
| 128 | + dev->max_mtu = BCMENET_MAX_MTU - VLAN_ETH_HLEN; |
| 129 | + SET_NETDEV_DEV(dev, &pdev->dev); |
| 130 | + |
| 131 | + ret = register_netdev(dev); |
| 132 | + if (ret) |
| 133 | + goto out_uninit_hw; |
| 134 | + |
| 135 | + netif_carrier_off(dev); |
| 136 | + platform_set_drvdata(pdev, dev); |
| 137 | + priv->pdev = pdev; |
| 138 | + priv->net_dev = dev; |
| 139 | |
| 140 | /* MII bus registration */ |
| 141 | if (priv->has_phy) { |
| 142 | + struct phy_device *phydev; |
| 143 | + char phy_id[MII_BUS_ID_SIZE + 3]; |
| 144 | |
| 145 | priv->mii_bus = mdiobus_alloc(); |
| 146 | if (!priv->mii_bus) { |
| 147 | ret = -ENOMEM; |
| 148 | - goto out_uninit_hw; |
| 149 | + goto out_unregister_netdev; |
| 150 | } |
| 151 | |
| 152 | bus = priv->mii_bus; |
| 153 | @@ -1833,6 +1835,26 @@ static int bcm_enet_probe(struct platfor |
| 154 | dev_err(&pdev->dev, "unable to register mdio bus\n"); |
| 155 | goto out_free_mdio; |
| 156 | } |
| 157 | + |
| 158 | + /* connect to PHY */ |
| 159 | + snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, |
| 160 | + priv->mii_bus->id, priv->phy_id); |
| 161 | + |
| 162 | + phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link, |
| 163 | + PHY_INTERFACE_MODE_MII); |
| 164 | + |
| 165 | + if (IS_ERR(phydev)) { |
| 166 | + dev_err(&pdev->dev, "could not attach to PHY\n"); |
| 167 | + goto out_unregister_mdio; |
| 168 | + } |
| 169 | + |
| 170 | + /* mask with MAC supported features */ |
| 171 | + phy_support_sym_pause(phydev); |
| 172 | + phy_set_max_speed(phydev, SPEED_100); |
| 173 | + phy_set_sym_pause(phydev, priv->pause_rx, priv->pause_rx, |
| 174 | + priv->pause_auto); |
| 175 | + |
| 176 | + phy_attached_info(phydev); |
| 177 | } else { |
| 178 | |
| 179 | /* run platform code to initialize PHY device */ |
| 180 | @@ -1840,45 +1862,16 @@ static int bcm_enet_probe(struct platfor |
| 181 | pd->mii_config(dev, 1, bcm_enet_mdio_read_mii, |
| 182 | bcm_enet_mdio_write_mii)) { |
| 183 | dev_err(&pdev->dev, "unable to configure mdio bus\n"); |
| 184 | - goto out_uninit_hw; |
| 185 | + goto out_unregister_netdev; |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | - spin_lock_init(&priv->rx_lock); |
| 190 | - |
| 191 | - /* init rx timeout (used for oom) */ |
| 192 | - timer_setup(&priv->rx_timeout, bcm_enet_refill_rx_timer, 0); |
| 193 | - |
| 194 | - /* init the mib update lock&work */ |
| 195 | - mutex_init(&priv->mib_update_lock); |
| 196 | - INIT_WORK(&priv->mib_update_task, bcm_enet_update_mib_counters_defer); |
| 197 | - |
| 198 | - /* zero mib counters */ |
| 199 | - for (i = 0; i < ENET_MIB_REG_COUNT; i++) |
| 200 | - enet_writel(priv, 0, ENET_MIB_REG(i)); |
| 201 | - |
| 202 | - /* register netdevice */ |
| 203 | - dev->netdev_ops = &bcm_enet_ops; |
| 204 | - netif_napi_add(dev, &priv->napi, bcm_enet_poll, 16); |
| 205 | - |
| 206 | - dev->ethtool_ops = &bcm_enet_ethtool_ops; |
| 207 | - /* MTU range: 46 - 2028 */ |
| 208 | - dev->min_mtu = ETH_ZLEN - ETH_HLEN; |
| 209 | - dev->max_mtu = BCMENET_MAX_MTU - VLAN_ETH_HLEN; |
| 210 | - SET_NETDEV_DEV(dev, &pdev->dev); |
| 211 | - |
| 212 | - ret = register_netdev(dev); |
| 213 | - if (ret) |
| 214 | - goto out_unregister_mdio; |
| 215 | - |
| 216 | - netif_carrier_off(dev); |
| 217 | - platform_set_drvdata(pdev, dev); |
| 218 | - priv->pdev = pdev; |
| 219 | - priv->net_dev = dev; |
| 220 | - |
| 221 | return 0; |
| 222 | |
| 223 | out_unregister_mdio: |
| 224 | + if (dev->phydev) |
| 225 | + phy_disconnect(dev->phydev); |
| 226 | + |
| 227 | if (priv->mii_bus) |
| 228 | mdiobus_unregister(priv->mii_bus); |
| 229 | |
| 230 | @@ -1886,6 +1879,9 @@ out_free_mdio: |
| 231 | if (priv->mii_bus) |
| 232 | mdiobus_free(priv->mii_bus); |
| 233 | |
| 234 | +out_unregister_netdev: |
| 235 | + unregister_netdev(dev); |
| 236 | + |
| 237 | out_uninit_hw: |
| 238 | /* turn off mdc clock */ |
| 239 | enet_writel(priv, 0, ENET_MIISC_REG); |
| 240 | @@ -1916,6 +1912,7 @@ static int bcm_enet_remove(struct platfo |
| 241 | enet_writel(priv, 0, ENET_MIISC_REG); |
| 242 | |
| 243 | if (priv->has_phy) { |
| 244 | + phy_disconnect(dev->phydev); |
| 245 | mdiobus_unregister(priv->mii_bus); |
| 246 | mdiobus_free(priv->mii_bus); |
| 247 | } else { |