aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLendacky, Thomas <Thomas.Lendacky@amd.com>2014-08-05 14:30:44 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-05 19:47:02 -0400
commit88131a812b16b45cf999e577ad8d89b41ad606e3 (patch)
tree19519ab7ec4444ccdd97e05b22a126ee6f511985 /drivers
parentf3d0e78d2e733176c2b0d23e7a7d871c7a33c2d6 (diff)
amd-xgbe: Perform phy connect/disconnect at dev open/stop
A change added to the mdiobus/phy api added a module_get/module_put during phy connect/disconnect processing. Currently, the driver performs a phy connect during module probe and a phy disconnect during module remove. With the addition of the module_get during phy connect the amd-xgbe module use count is incremented and can no longer be unloaded. Move the phy connect/disconnect from the driver probe/remove functions to the net_device_ops ndo_open/ndo_stop functions. This allows the module use count to be decremented when the device(s) are brought down and allows the module to be unloaded. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c122
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-mdio.c98
2 files changed, 121 insertions, 99 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 3bf3c0194ad3..1f5487f4888c 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -122,6 +122,7 @@
122#include <linux/clk.h> 122#include <linux/clk.h>
123#include <linux/if_ether.h> 123#include <linux/if_ether.h>
124#include <linux/net_tstamp.h> 124#include <linux/net_tstamp.h>
125#include <linux/phy.h>
125 126
126#include "xgbe.h" 127#include "xgbe.h"
127#include "xgbe-common.h" 128#include "xgbe-common.h"
@@ -521,6 +522,114 @@ static void xgbe_free_rx_skbuff(struct xgbe_prv_data *pdata)
521 DBGPR("<--xgbe_free_rx_skbuff\n"); 522 DBGPR("<--xgbe_free_rx_skbuff\n");
522} 523}
523 524
525static void xgbe_adjust_link(struct net_device *netdev)
526{
527 struct xgbe_prv_data *pdata = netdev_priv(netdev);
528 struct xgbe_hw_if *hw_if = &pdata->hw_if;
529 struct phy_device *phydev = pdata->phydev;
530 int new_state = 0;
531
532 if (phydev == NULL)
533 return;
534
535 if (phydev->link) {
536 /* Flow control support */
537 if (pdata->pause_autoneg) {
538 if (phydev->pause || phydev->asym_pause) {
539 pdata->tx_pause = 1;
540 pdata->rx_pause = 1;
541 } else {
542 pdata->tx_pause = 0;
543 pdata->rx_pause = 0;
544 }
545 }
546
547 if (pdata->tx_pause != pdata->phy_tx_pause) {
548 hw_if->config_tx_flow_control(pdata);
549 pdata->phy_tx_pause = pdata->tx_pause;
550 }
551
552 if (pdata->rx_pause != pdata->phy_rx_pause) {
553 hw_if->config_rx_flow_control(pdata);
554 pdata->phy_rx_pause = pdata->rx_pause;
555 }
556
557 /* Speed support */
558 if (phydev->speed != pdata->phy_speed) {
559 new_state = 1;
560
561 switch (phydev->speed) {
562 case SPEED_10000:
563 hw_if->set_xgmii_speed(pdata);
564 break;
565
566 case SPEED_2500:
567 hw_if->set_gmii_2500_speed(pdata);
568 break;
569
570 case SPEED_1000:
571 hw_if->set_gmii_speed(pdata);
572 break;
573 }
574 pdata->phy_speed = phydev->speed;
575 }
576
577 if (phydev->link != pdata->phy_link) {
578 new_state = 1;
579 pdata->phy_link = 1;
580 }
581 } else if (pdata->phy_link) {
582 new_state = 1;
583 pdata->phy_link = 0;
584 pdata->phy_speed = SPEED_UNKNOWN;
585 }
586
587 if (new_state)
588 phy_print_status(phydev);
589}
590
591static int xgbe_phy_init(struct xgbe_prv_data *pdata)
592{
593 struct net_device *netdev = pdata->netdev;
594 struct phy_device *phydev = pdata->phydev;
595 int ret;
596
597 pdata->phy_link = -1;
598 pdata->phy_speed = SPEED_UNKNOWN;
599 pdata->phy_tx_pause = pdata->tx_pause;
600 pdata->phy_rx_pause = pdata->rx_pause;
601
602 ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link,
603 pdata->phy_mode);
604 if (ret) {
605 netdev_err(netdev, "phy_connect_direct failed\n");
606 return ret;
607 }
608
609 if (!phydev->drv || (phydev->drv->phy_id == 0)) {
610 netdev_err(netdev, "phy_id not valid\n");
611 ret = -ENODEV;
612 goto err_phy_connect;
613 }
614 DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n",
615 dev_name(&phydev->dev), phydev->link);
616
617 return 0;
618
619err_phy_connect:
620 phy_disconnect(phydev);
621
622 return ret;
623}
624
625static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
626{
627 if (!pdata->phydev)
628 return;
629
630 phy_disconnect(pdata->phydev);
631}
632
524int xgbe_powerdown(struct net_device *netdev, unsigned int caller) 633int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
525{ 634{
526 struct xgbe_prv_data *pdata = netdev_priv(netdev); 635 struct xgbe_prv_data *pdata = netdev_priv(netdev);
@@ -986,11 +1095,16 @@ static int xgbe_open(struct net_device *netdev)
986 1095
987 DBGPR("-->xgbe_open\n"); 1096 DBGPR("-->xgbe_open\n");
988 1097
1098 /* Initialize the phy */
1099 ret = xgbe_phy_init(pdata);
1100 if (ret)
1101 return ret;
1102
989 /* Enable the clocks */ 1103 /* Enable the clocks */
990 ret = clk_prepare_enable(pdata->sysclk); 1104 ret = clk_prepare_enable(pdata->sysclk);
991 if (ret) { 1105 if (ret) {
992 netdev_alert(netdev, "dma clk_prepare_enable failed\n"); 1106 netdev_alert(netdev, "dma clk_prepare_enable failed\n");
993 return ret; 1107 goto err_phy_init;
994 } 1108 }
995 1109
996 ret = clk_prepare_enable(pdata->ptpclk); 1110 ret = clk_prepare_enable(pdata->ptpclk);
@@ -1047,6 +1161,9 @@ err_ptpclk:
1047err_sysclk: 1161err_sysclk:
1048 clk_disable_unprepare(pdata->sysclk); 1162 clk_disable_unprepare(pdata->sysclk);
1049 1163
1164err_phy_init:
1165 xgbe_phy_exit(pdata);
1166
1050 return ret; 1167 return ret;
1051} 1168}
1052 1169
@@ -1077,6 +1194,9 @@ static int xgbe_close(struct net_device *netdev)
1077 clk_disable_unprepare(pdata->ptpclk); 1194 clk_disable_unprepare(pdata->ptpclk);
1078 clk_disable_unprepare(pdata->sysclk); 1195 clk_disable_unprepare(pdata->sysclk);
1079 1196
1197 /* Release the phy */
1198 xgbe_phy_exit(pdata);
1199
1080 DBGPR("<--xgbe_close\n"); 1200 DBGPR("<--xgbe_close\n");
1081 1201
1082 return 0; 1202 return 0;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
index eecd360430a4..6d2221e023f4 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -116,7 +116,6 @@
116 116
117#include <linux/module.h> 117#include <linux/module.h>
118#include <linux/kmod.h> 118#include <linux/kmod.h>
119#include <linux/spinlock.h>
120#include <linux/mdio.h> 119#include <linux/mdio.h>
121#include <linux/phy.h> 120#include <linux/phy.h>
122#include <linux/of.h> 121#include <linux/of.h>
@@ -158,77 +157,6 @@ static int xgbe_mdio_write(struct mii_bus *mii, int prtad, int mmd_reg,
158 return 0; 157 return 0;
159} 158}
160 159
161static void xgbe_adjust_link(struct net_device *netdev)
162{
163 struct xgbe_prv_data *pdata = netdev_priv(netdev);
164 struct xgbe_hw_if *hw_if = &pdata->hw_if;
165 struct phy_device *phydev = pdata->phydev;
166 int new_state = 0;
167
168 if (phydev == NULL)
169 return;
170
171 DBGPR_MDIO("-->xgbe_adjust_link: address=%d, newlink=%d, curlink=%d\n",
172 phydev->addr, phydev->link, pdata->phy_link);
173
174 if (phydev->link) {
175 /* Flow control support */
176 if (pdata->pause_autoneg) {
177 if (phydev->pause || phydev->asym_pause) {
178 pdata->tx_pause = 1;
179 pdata->rx_pause = 1;
180 } else {
181 pdata->tx_pause = 0;
182 pdata->rx_pause = 0;
183 }
184 }
185
186 if (pdata->tx_pause != pdata->phy_tx_pause) {
187 hw_if->config_tx_flow_control(pdata);
188 pdata->phy_tx_pause = pdata->tx_pause;
189 }
190
191 if (pdata->rx_pause != pdata->phy_rx_pause) {
192 hw_if->config_rx_flow_control(pdata);
193 pdata->phy_rx_pause = pdata->rx_pause;
194 }
195
196 /* Speed support */
197 if (phydev->speed != pdata->phy_speed) {
198 new_state = 1;
199
200 switch (phydev->speed) {
201 case SPEED_10000:
202 hw_if->set_xgmii_speed(pdata);
203 break;
204
205 case SPEED_2500:
206 hw_if->set_gmii_2500_speed(pdata);
207 break;
208
209 case SPEED_1000:
210 hw_if->set_gmii_speed(pdata);
211 break;
212 }
213 pdata->phy_speed = phydev->speed;
214 }
215
216 if (phydev->link != pdata->phy_link) {
217 new_state = 1;
218 pdata->phy_link = 1;
219 }
220 } else if (pdata->phy_link) {
221 new_state = 1;
222 pdata->phy_link = 0;
223 pdata->phy_speed = SPEED_UNKNOWN;
224 }
225
226 if (new_state)
227 phy_print_status(phydev);
228
229 DBGPR_MDIO("<--xgbe_adjust_link\n");
230}
231
232void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) 160void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
233{ 161{
234 struct device *dev = pdata->dev; 162 struct device *dev = pdata->dev;
@@ -278,7 +206,6 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
278 206
279int xgbe_mdio_register(struct xgbe_prv_data *pdata) 207int xgbe_mdio_register(struct xgbe_prv_data *pdata)
280{ 208{
281 struct net_device *netdev = pdata->netdev;
282 struct device_node *phy_node; 209 struct device_node *phy_node;
283 struct mii_bus *mii; 210 struct mii_bus *mii;
284 struct phy_device *phydev; 211 struct phy_device *phydev;
@@ -293,7 +220,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
293 return -EINVAL; 220 return -EINVAL;
294 } 221 }
295 222
296 /* Register with the MDIO bus */
297 mii = mdiobus_alloc(); 223 mii = mdiobus_alloc();
298 if (mii == NULL) { 224 if (mii == NULL) {
299 dev_err(pdata->dev, "mdiobus_alloc failed\n"); 225 dev_err(pdata->dev, "mdiobus_alloc failed\n");
@@ -348,26 +274,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
348 pdata->mii = mii; 274 pdata->mii = mii;
349 pdata->mdio_mmd = MDIO_MMD_PCS; 275 pdata->mdio_mmd = MDIO_MMD_PCS;
350 276
351 pdata->phy_link = -1;
352 pdata->phy_speed = SPEED_UNKNOWN;
353 pdata->phy_tx_pause = pdata->tx_pause;
354 pdata->phy_rx_pause = pdata->rx_pause;
355
356 ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link,
357 pdata->phy_mode);
358 if (ret) {
359 netdev_err(netdev, "phy_connect_direct failed\n");
360 goto err_phy_device;
361 }
362
363 if (!phydev->drv || (phydev->drv->phy_id == 0)) {
364 netdev_err(netdev, "phy_id not valid\n");
365 ret = -ENODEV;
366 goto err_phy_connect;
367 }
368 DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n",
369 dev_name(&phydev->dev), phydev->link);
370
371 phydev->autoneg = pdata->default_autoneg; 277 phydev->autoneg = pdata->default_autoneg;
372 if (phydev->autoneg == AUTONEG_DISABLE) { 278 if (phydev->autoneg == AUTONEG_DISABLE) {
373 phydev->speed = pdata->default_speed; 279 phydev->speed = pdata->default_speed;
@@ -386,9 +292,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
386 292
387 return 0; 293 return 0;
388 294
389err_phy_connect:
390 phy_disconnect(phydev);
391
392err_phy_device: 295err_phy_device:
393 phy_device_free(phydev); 296 phy_device_free(phydev);
394 297
@@ -408,7 +311,6 @@ void xgbe_mdio_unregister(struct xgbe_prv_data *pdata)
408{ 311{
409 DBGPR("-->xgbe_mdio_unregister\n"); 312 DBGPR("-->xgbe_mdio_unregister\n");
410 313
411 phy_disconnect(pdata->phydev);
412 pdata->phydev = NULL; 314 pdata->phydev = NULL;
413 315
414 module_put(pdata->phy_module); 316 module_put(pdata->phy_module);