From patchwork Tue Aug 5 18:30:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Lendacky X-Patchwork-Id: 376766 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 6FE5B140092 for ; Wed, 6 Aug 2014 04:31:07 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756081AbaHESay (ORCPT ); Tue, 5 Aug 2014 14:30:54 -0400 Received: from mail-bn1lp0139.outbound.protection.outlook.com ([207.46.163.139]:14509 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932187AbaHESaw (ORCPT ); Tue, 5 Aug 2014 14:30:52 -0400 Received: from CO1PR02MB048.namprd02.prod.outlook.com (10.242.163.25) by CO1PR02MB237.namprd02.prod.outlook.com (10.242.165.143) with Microsoft SMTP Server (TLS) id 15.0.995.14; Tue, 5 Aug 2014 18:30:49 +0000 Received: from BY1PR0201CA0037.namprd02.prod.outlook.com (25.160.191.175) by CO1PR02MB048.namprd02.prod.outlook.com (10.242.163.25) with Microsoft SMTP Server (TLS) id 15.0.995.14; Tue, 5 Aug 2014 18:30:47 +0000 Received: from BN1AFFO11FD034.protection.gbl (2a01:111:f400:7c10::158) by BY1PR0201CA0037.outlook.office365.com (2a01:111:e400:4814::47) with Microsoft SMTP Server (TLS) id 15.0.995.14 via Frontend Transport; Tue, 5 Aug 2014 18:30:46 +0000 Received: from atltwp02.amd.com (165.204.84.222) by BN1AFFO11FD034.mail.protection.outlook.com (10.58.52.158) with Microsoft SMTP Server id 15.0.990.10 via Frontend Transport; Tue, 5 Aug 2014 18:30:46 +0000 X-WSS-ID: 0N9UJF8-08-6TI-02 X-M-MSG: Received: from satlvexedge01.amd.com (satlvexedge01.amd.com [10.177.96.28]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (No client certificate requested) by atltwp02.amd.com (Axway MailGate 5.3.1) with ESMTPS id 25E98D1601C; Tue, 5 Aug 2014 13:30:43 -0500 (CDT) Received: from SATLEXDAG01.amd.com (10.181.40.3) by satlvexedge01.amd.com (10.177.96.28) with Microsoft SMTP Server (TLS) id 14.2.328.9; Tue, 5 Aug 2014 13:31:15 -0500 Received: from tlendack-t1.amdoffice.net (10.180.168.240) by SATLEXDAG01.amd.com (10.181.40.3) with Microsoft SMTP Server id 14.2.328.9; Tue, 5 Aug 2014 14:30:43 -0400 Subject: [PATCH net-next v2 2/2] amd-xgbe: Perform phy connect/disconnect at dev open/stop To: From: Tom Lendacky CC: Date: Tue, 5 Aug 2014 13:30:44 -0500 Message-ID: <20140805183044.32561.20187.stgit@tlendack-t1.amdoffice.net> In-Reply-To: <20140805183032.32561.85828.stgit@tlendack-t1.amdoffice.net> References: <20140805183032.32561.85828.stgit@tlendack-t1.amdoffice.net> User-Agent: StGit/0.15 MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:165.204.84.222; CTRY:US; IPV:NLI; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(6009001)(428002)(199002)(189002)(80022001)(79102001)(77982001)(105586002)(102836001)(64706001)(101416001)(68736004)(83506001)(4396001)(81342001)(77096002)(95666004)(20776003)(47776003)(31966008)(2351001)(23676002)(74662001)(106466001)(21056001)(84676001)(46102001)(110136001)(92726001)(53416004)(85306004)(83072002)(92566001)(74502001)(99396002)(85852003)(44976005)(107046002)(229853001)(87936001)(81542001)(76176999)(19580395003)(103116003)(50986999)(97736001)(54356999)(19580405001)(86362001)(97746001)(33646002)(83322001)(50466002)(76482001)(71626003); DIR:OUT; SFP:; SCL:1; SRVR:CO1PR02MB048; H:atltwp02.amd.com; FPR:; MLV:sfv; PTR:InfoDomainNonexistent; MX:1; LANG:en; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID: X-Forefront-PRVS: 02945962BD Received-SPF: None (protection.outlook.com: amd.com does not designate permitted sender hosts) Authentication-Results: spf=none (sender IP is 165.204.84.222) smtp.mailfrom=Thomas.Lendacky@amd.com; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID: X-OriginatorOrg: amd4.onmicrosoft.com Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 122 +++++++++++++++++++++++++++++ drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 98 ----------------------- 2 files changed, 121 insertions(+), 99 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 3bf3c01..1f5487f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -122,6 +122,7 @@ #include #include #include +#include #include "xgbe.h" #include "xgbe-common.h" @@ -521,6 +522,114 @@ static void xgbe_free_rx_skbuff(struct xgbe_prv_data *pdata) DBGPR("<--xgbe_free_rx_skbuff\n"); } +static void xgbe_adjust_link(struct net_device *netdev) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct phy_device *phydev = pdata->phydev; + int new_state = 0; + + if (phydev == NULL) + return; + + if (phydev->link) { + /* Flow control support */ + if (pdata->pause_autoneg) { + if (phydev->pause || phydev->asym_pause) { + pdata->tx_pause = 1; + pdata->rx_pause = 1; + } else { + pdata->tx_pause = 0; + pdata->rx_pause = 0; + } + } + + if (pdata->tx_pause != pdata->phy_tx_pause) { + hw_if->config_tx_flow_control(pdata); + pdata->phy_tx_pause = pdata->tx_pause; + } + + if (pdata->rx_pause != pdata->phy_rx_pause) { + hw_if->config_rx_flow_control(pdata); + pdata->phy_rx_pause = pdata->rx_pause; + } + + /* Speed support */ + if (phydev->speed != pdata->phy_speed) { + new_state = 1; + + switch (phydev->speed) { + case SPEED_10000: + hw_if->set_xgmii_speed(pdata); + break; + + case SPEED_2500: + hw_if->set_gmii_2500_speed(pdata); + break; + + case SPEED_1000: + hw_if->set_gmii_speed(pdata); + break; + } + pdata->phy_speed = phydev->speed; + } + + if (phydev->link != pdata->phy_link) { + new_state = 1; + pdata->phy_link = 1; + } + } else if (pdata->phy_link) { + new_state = 1; + pdata->phy_link = 0; + pdata->phy_speed = SPEED_UNKNOWN; + } + + if (new_state) + phy_print_status(phydev); +} + +static int xgbe_phy_init(struct xgbe_prv_data *pdata) +{ + struct net_device *netdev = pdata->netdev; + struct phy_device *phydev = pdata->phydev; + int ret; + + pdata->phy_link = -1; + pdata->phy_speed = SPEED_UNKNOWN; + pdata->phy_tx_pause = pdata->tx_pause; + pdata->phy_rx_pause = pdata->rx_pause; + + ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link, + pdata->phy_mode); + if (ret) { + netdev_err(netdev, "phy_connect_direct failed\n"); + return ret; + } + + if (!phydev->drv || (phydev->drv->phy_id == 0)) { + netdev_err(netdev, "phy_id not valid\n"); + ret = -ENODEV; + goto err_phy_connect; + } + DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n", + dev_name(&phydev->dev), phydev->link); + + return 0; + +err_phy_connect: + phy_disconnect(phydev); + + return ret; +} + +static void xgbe_phy_exit(struct xgbe_prv_data *pdata) +{ + if (!pdata->phydev) + return; + + phy_disconnect(pdata->phydev); +} + int xgbe_powerdown(struct net_device *netdev, unsigned int caller) { struct xgbe_prv_data *pdata = netdev_priv(netdev); @@ -986,11 +1095,16 @@ static int xgbe_open(struct net_device *netdev) DBGPR("-->xgbe_open\n"); + /* Initialize the phy */ + ret = xgbe_phy_init(pdata); + if (ret) + return ret; + /* Enable the clocks */ ret = clk_prepare_enable(pdata->sysclk); if (ret) { netdev_alert(netdev, "dma clk_prepare_enable failed\n"); - return ret; + goto err_phy_init; } ret = clk_prepare_enable(pdata->ptpclk); @@ -1047,6 +1161,9 @@ err_ptpclk: err_sysclk: clk_disable_unprepare(pdata->sysclk); +err_phy_init: + xgbe_phy_exit(pdata); + return ret; } @@ -1077,6 +1194,9 @@ static int xgbe_close(struct net_device *netdev) clk_disable_unprepare(pdata->ptpclk); clk_disable_unprepare(pdata->sysclk); + /* Release the phy */ + xgbe_phy_exit(pdata); + DBGPR("<--xgbe_close\n"); return 0; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index eecd360..6d2221e 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -116,7 +116,6 @@ #include #include -#include #include #include #include @@ -158,77 +157,6 @@ static int xgbe_mdio_write(struct mii_bus *mii, int prtad, int mmd_reg, return 0; } -static void xgbe_adjust_link(struct net_device *netdev) -{ - struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct phy_device *phydev = pdata->phydev; - int new_state = 0; - - if (phydev == NULL) - return; - - DBGPR_MDIO("-->xgbe_adjust_link: address=%d, newlink=%d, curlink=%d\n", - phydev->addr, phydev->link, pdata->phy_link); - - if (phydev->link) { - /* Flow control support */ - if (pdata->pause_autoneg) { - if (phydev->pause || phydev->asym_pause) { - pdata->tx_pause = 1; - pdata->rx_pause = 1; - } else { - pdata->tx_pause = 0; - pdata->rx_pause = 0; - } - } - - if (pdata->tx_pause != pdata->phy_tx_pause) { - hw_if->config_tx_flow_control(pdata); - pdata->phy_tx_pause = pdata->tx_pause; - } - - if (pdata->rx_pause != pdata->phy_rx_pause) { - hw_if->config_rx_flow_control(pdata); - pdata->phy_rx_pause = pdata->rx_pause; - } - - /* Speed support */ - if (phydev->speed != pdata->phy_speed) { - new_state = 1; - - switch (phydev->speed) { - case SPEED_10000: - hw_if->set_xgmii_speed(pdata); - break; - - case SPEED_2500: - hw_if->set_gmii_2500_speed(pdata); - break; - - case SPEED_1000: - hw_if->set_gmii_speed(pdata); - break; - } - pdata->phy_speed = phydev->speed; - } - - if (phydev->link != pdata->phy_link) { - new_state = 1; - pdata->phy_link = 1; - } - } else if (pdata->phy_link) { - new_state = 1; - pdata->phy_link = 0; - pdata->phy_speed = SPEED_UNKNOWN; - } - - if (new_state) - phy_print_status(phydev); - - DBGPR_MDIO("<--xgbe_adjust_link\n"); -} - void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) { struct device *dev = pdata->dev; @@ -278,7 +206,6 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) int xgbe_mdio_register(struct xgbe_prv_data *pdata) { - struct net_device *netdev = pdata->netdev; struct device_node *phy_node; struct mii_bus *mii; struct phy_device *phydev; @@ -293,7 +220,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) return -EINVAL; } - /* Register with the MDIO bus */ mii = mdiobus_alloc(); if (mii == NULL) { dev_err(pdata->dev, "mdiobus_alloc failed\n"); @@ -348,26 +274,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) pdata->mii = mii; pdata->mdio_mmd = MDIO_MMD_PCS; - pdata->phy_link = -1; - pdata->phy_speed = SPEED_UNKNOWN; - pdata->phy_tx_pause = pdata->tx_pause; - pdata->phy_rx_pause = pdata->rx_pause; - - ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link, - pdata->phy_mode); - if (ret) { - netdev_err(netdev, "phy_connect_direct failed\n"); - goto err_phy_device; - } - - if (!phydev->drv || (phydev->drv->phy_id == 0)) { - netdev_err(netdev, "phy_id not valid\n"); - ret = -ENODEV; - goto err_phy_connect; - } - DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n", - dev_name(&phydev->dev), phydev->link); - phydev->autoneg = pdata->default_autoneg; if (phydev->autoneg == AUTONEG_DISABLE) { phydev->speed = pdata->default_speed; @@ -386,9 +292,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) return 0; -err_phy_connect: - phy_disconnect(phydev); - err_phy_device: phy_device_free(phydev); @@ -408,7 +311,6 @@ void xgbe_mdio_unregister(struct xgbe_prv_data *pdata) { DBGPR("-->xgbe_mdio_unregister\n"); - phy_disconnect(pdata->phydev); pdata->phydev = NULL; module_put(pdata->phy_module);