diff options
Diffstat (limited to 'drivers/net/ethernet/microchip/lan743x_main.c')
-rw-r--r-- | drivers/net/ethernet/microchip/lan743x_main.c | 646 |
1 files changed, 403 insertions, 243 deletions
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index e418539565b1..4dc5adcda6a3 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -15,6 +15,7 @@ #include <linux/rtnetlink.h> #include <linux/iopoll.h> #include <linux/crc16.h> +#include <linux/phylink.h> #include "lan743x_main.h" #include "lan743x_ethtool.h" @@ -992,6 +993,42 @@ static int lan743x_sgmii_write(struct lan743x_adapter *adapter, return ret; } +static int lan743x_get_lsd(int speed, int duplex, u8 mss) +{ + int lsd; + + switch (speed) { + case SPEED_2500: + if (mss == MASTER_SLAVE_STATE_SLAVE) + lsd = LINK_2500_SLAVE; + else + lsd = LINK_2500_MASTER; + break; + case SPEED_1000: + if (mss == MASTER_SLAVE_STATE_SLAVE) + lsd = LINK_1000_SLAVE; + else + lsd = LINK_1000_MASTER; + break; + case SPEED_100: + if (duplex == DUPLEX_FULL) + lsd = LINK_100FD; + else + lsd = LINK_100HD; + break; + case SPEED_10: + if (duplex == DUPLEX_FULL) + lsd = LINK_10FD; + else + lsd = LINK_10HD; + break; + default: + lsd = -EINVAL; + } + + return lsd; +} + static int lan743x_sgmii_mpll_set(struct lan743x_adapter *adapter, u16 baud) { @@ -1041,26 +1078,7 @@ static int lan743x_sgmii_2_5G_mode_set(struct lan743x_adapter *adapter, VR_MII_BAUD_RATE_1P25GBPS); } -static int lan743x_is_sgmii_2_5G_mode(struct lan743x_adapter *adapter, - bool *status) -{ - int ret; - - ret = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, - VR_MII_GEN2_4_MPLL_CTRL1); - if (ret < 0) - return ret; - - if (ret == VR_MII_MPLL_MULTIPLIER_125 || - ret == VR_MII_MPLL_MULTIPLIER_50) - *status = true; - else - *status = false; - - return 0; -} - -static int lan743x_sgmii_aneg_update(struct lan743x_adapter *adapter) +static int lan743x_serdes_clock_and_aneg_update(struct lan743x_adapter *adapter) { enum lan743x_sgmii_lsd lsd = adapter->sgmii_lsd; int mii_ctrl; @@ -1147,68 +1165,11 @@ static int lan743x_pcs_seq_state(struct lan743x_adapter *adapter, u8 state) return 0; } -static int lan743x_sgmii_config(struct lan743x_adapter *adapter) +static int lan743x_pcs_power_reset(struct lan743x_adapter *adapter) { - struct net_device *netdev = adapter->netdev; - struct phy_device *phydev = netdev->phydev; - enum lan743x_sgmii_lsd lsd = POWER_DOWN; int mii_ctl; - bool status; int ret; - switch (phydev->speed) { - case SPEED_2500: - if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER) - lsd = LINK_2500_MASTER; - else - lsd = LINK_2500_SLAVE; - break; - case SPEED_1000: - if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER) - lsd = LINK_1000_MASTER; - else - lsd = LINK_1000_SLAVE; - break; - case SPEED_100: - if (phydev->duplex) - lsd = LINK_100FD; - else - lsd = LINK_100HD; - break; - case SPEED_10: - if (phydev->duplex) - lsd = LINK_10FD; - else - lsd = LINK_10HD; - break; - default: - netif_err(adapter, drv, adapter->netdev, - "Invalid speed %d\n", phydev->speed); - return -EINVAL; - } - - adapter->sgmii_lsd = lsd; - ret = lan743x_sgmii_aneg_update(adapter); - if (ret < 0) { - netif_err(adapter, drv, adapter->netdev, - "error %d SGMII cfg failed\n", ret); - return ret; - } - - ret = lan743x_is_sgmii_2_5G_mode(adapter, &status); - if (ret < 0) { - netif_err(adapter, drv, adapter->netdev, - "error %d SGMII get mode failed\n", ret); - return ret; - } - - if (status) - netif_dbg(adapter, drv, adapter->netdev, - "SGMII 2.5G mode enable\n"); - else - netif_dbg(adapter, drv, adapter->netdev, - "SGMII 1G mode enable\n"); - /* SGMII/1000/2500BASE-X PCS power down */ mii_ctl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR); if (mii_ctl < 0) @@ -1229,11 +1190,7 @@ static int lan743x_sgmii_config(struct lan743x_adapter *adapter) if (ret < 0) return ret; - ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP); - if (ret < 0) - return ret; - - return 0; + return lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP); } static void lan743x_mac_set_address(struct lan743x_adapter *adapter, @@ -1389,103 +1346,11 @@ static int lan743x_phy_reset(struct lan743x_adapter *adapter) 50000, 1000000); } -static void lan743x_phy_update_flowcontrol(struct lan743x_adapter *adapter, - u16 local_adv, u16 remote_adv) -{ - struct lan743x_phy *phy = &adapter->phy; - u8 cap; - - if (phy->fc_autoneg) - cap = mii_resolve_flowctrl_fdx(local_adv, remote_adv); - else - cap = phy->fc_request_control; - - lan743x_mac_flow_ctrl_set_enables(adapter, - cap & FLOW_CTRL_TX, - cap & FLOW_CTRL_RX); -} - static int lan743x_phy_init(struct lan743x_adapter *adapter) { return lan743x_phy_reset(adapter); } -static void lan743x_phy_link_status_change(struct net_device *netdev) -{ - struct lan743x_adapter *adapter = netdev_priv(netdev); - struct phy_device *phydev = netdev->phydev; - u32 data; - - phy_print_status(phydev); - if (phydev->state == PHY_RUNNING) { - int remote_advertisement = 0; - int local_advertisement = 0; - - data = lan743x_csr_read(adapter, MAC_CR); - - /* set duplex mode */ - if (phydev->duplex) - data |= MAC_CR_DPX_; - else - data &= ~MAC_CR_DPX_; - - /* set bus speed */ - switch (phydev->speed) { - case SPEED_10: - data &= ~MAC_CR_CFG_H_; - data &= ~MAC_CR_CFG_L_; - break; - case SPEED_100: - data &= ~MAC_CR_CFG_H_; - data |= MAC_CR_CFG_L_; - break; - case SPEED_1000: - data |= MAC_CR_CFG_H_; - data &= ~MAC_CR_CFG_L_; - break; - case SPEED_2500: - data |= MAC_CR_CFG_H_; - data |= MAC_CR_CFG_L_; - break; - } - lan743x_csr_write(adapter, MAC_CR, data); - - local_advertisement = - linkmode_adv_to_mii_adv_t(phydev->advertising); - remote_advertisement = - linkmode_adv_to_mii_adv_t(phydev->lp_advertising); - - lan743x_phy_update_flowcontrol(adapter, local_advertisement, - remote_advertisement); - lan743x_ptp_update_latency(adapter, phydev->speed); - if (phydev->interface == PHY_INTERFACE_MODE_SGMII || - phydev->interface == PHY_INTERFACE_MODE_1000BASEX || - phydev->interface == PHY_INTERFACE_MODE_2500BASEX) - lan743x_sgmii_config(adapter); - - data = lan743x_csr_read(adapter, MAC_CR); - if (phydev->enable_tx_lpi) - data |= MAC_CR_EEE_EN_; - else - data &= ~MAC_CR_EEE_EN_; - lan743x_csr_write(adapter, MAC_CR, data); - } -} - -static void lan743x_phy_close(struct lan743x_adapter *adapter) -{ - struct net_device *netdev = adapter->netdev; - struct phy_device *phydev = netdev->phydev; - - phy_stop(netdev->phydev); - phy_disconnect(netdev->phydev); - - /* using phydev here as phy_disconnect NULLs netdev->phydev */ - if (phy_is_pseudo_fixed_link(phydev)) - fixed_phy_unregister(phydev); - -} - static void lan743x_phy_interface_select(struct lan743x_adapter *adapter) { u32 id_rev; @@ -1502,65 +1367,9 @@ static void lan743x_phy_interface_select(struct lan743x_adapter *adapter) adapter->phy_interface = PHY_INTERFACE_MODE_MII; else adapter->phy_interface = PHY_INTERFACE_MODE_RGMII; -} - -static int lan743x_phy_open(struct lan743x_adapter *adapter) -{ - struct net_device *netdev = adapter->netdev; - struct lan743x_phy *phy = &adapter->phy; - struct fixed_phy_status fphy_status = { - .link = 1, - .speed = SPEED_1000, - .duplex = DUPLEX_FULL, - }; - struct phy_device *phydev; - int ret = -EIO; - - /* try devicetree phy, or fixed link */ - phydev = of_phy_get_and_connect(netdev, adapter->pdev->dev.of_node, - lan743x_phy_link_status_change); - - if (!phydev) { - /* try internal phy */ - phydev = phy_find_first(adapter->mdiobus); - if (!phydev) { - if ((adapter->csr.id_rev & ID_REV_ID_MASK_) == - ID_REV_ID_LAN7431_) { - phydev = fixed_phy_register(PHY_POLL, - &fphy_status, NULL); - if (IS_ERR(phydev)) { - netdev_err(netdev, "No PHY/fixed_PHY found\n"); - return PTR_ERR(phydev); - } - } else { - goto return_error; - } - } - - lan743x_phy_interface_select(adapter); - - ret = phy_connect_direct(netdev, phydev, - lan743x_phy_link_status_change, - adapter->phy_interface); - if (ret) - goto return_error; - } - - /* MAC doesn't support 1000T Half */ - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); - - /* support both flow controls */ - phy_support_asym_pause(phydev); - phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX); - phy->fc_autoneg = phydev->autoneg; - - phy_start(phydev); - phy_start_aneg(phydev); - phy_attached_info(phydev); - return 0; -return_error: - return ret; + netif_dbg(adapter, drv, adapter->netdev, + "selected phy interface: 0x%X\n", adapter->phy_interface); } static void lan743x_rfe_open(struct lan743x_adapter *adapter) @@ -3061,6 +2870,336 @@ return_error: return ret; } +static int lan743x_phylink_sgmii_config(struct lan743x_adapter *adapter) +{ + u32 sgmii_ctl; + int ret; + + ret = lan743x_get_lsd(SPEED_1000, DUPLEX_FULL, + MASTER_SLAVE_STATE_MASTER); + if (ret < 0) { + netif_err(adapter, drv, adapter->netdev, + "error %d link-speed-duplex(LSD) invalid\n", ret); + return ret; + } + + adapter->sgmii_lsd = ret; + netif_dbg(adapter, drv, adapter->netdev, + "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd); + + /* LINK_STATUS_SOURCE from the External PHY via SGMII */ + sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); + sgmii_ctl &= ~SGMII_CTL_LINK_STATUS_SOURCE_; + lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); + + ret = lan743x_serdes_clock_and_aneg_update(adapter); + if (ret < 0) { + netif_err(adapter, drv, adapter->netdev, + "error %d sgmii aneg update failed\n", ret); + return ret; + } + + return lan743x_pcs_power_reset(adapter); +} + +static int lan743x_phylink_1000basex_config(struct lan743x_adapter *adapter) +{ + u32 sgmii_ctl; + int ret; + + ret = lan743x_get_lsd(SPEED_1000, DUPLEX_FULL, + MASTER_SLAVE_STATE_MASTER); + if (ret < 0) { + netif_err(adapter, drv, adapter->netdev, + "error %d link-speed-duplex(LSD) invalid\n", ret); + return ret; + } + + adapter->sgmii_lsd = ret; + netif_dbg(adapter, drv, adapter->netdev, + "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd); + + /* LINK_STATUS_SOURCE from 1000BASE-X PCS link status */ + sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); + sgmii_ctl |= SGMII_CTL_LINK_STATUS_SOURCE_; + lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); + + ret = lan743x_serdes_clock_and_aneg_update(adapter); + if (ret < 0) { + netif_err(adapter, drv, adapter->netdev, + "error %d 1000basex aneg update failed\n", ret); + return ret; + } + + return lan743x_pcs_power_reset(adapter); +} + +static int lan743x_phylink_2500basex_config(struct lan743x_adapter *adapter) +{ + u32 sgmii_ctl; + int ret; + + ret = lan743x_get_lsd(SPEED_2500, DUPLEX_FULL, + MASTER_SLAVE_STATE_MASTER); + if (ret < 0) { + netif_err(adapter, drv, adapter->netdev, + "error %d link-speed-duplex(LSD) invalid\n", ret); + return ret; + } + + adapter->sgmii_lsd = ret; + netif_dbg(adapter, drv, adapter->netdev, + "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd); + + /* LINK_STATUS_SOURCE from 2500BASE-X PCS link status */ + sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); + sgmii_ctl |= SGMII_CTL_LINK_STATUS_SOURCE_; + lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl); + + ret = lan743x_serdes_clock_and_aneg_update(adapter); + if (ret < 0) { + netif_err(adapter, drv, adapter->netdev, + "error %d 2500basex aneg update failed\n", ret); + return ret; + } + + return lan743x_pcs_power_reset(adapter); +} + +void lan743x_mac_eee_enable(struct lan743x_adapter *adapter, bool enable) +{ + u32 mac_cr; + + mac_cr = lan743x_csr_read(adapter, MAC_CR); + if (enable) + mac_cr |= MAC_CR_EEE_EN_; + else + mac_cr &= ~MAC_CR_EEE_EN_; + lan743x_csr_write(adapter, MAC_CR, mac_cr); +} + +static void lan743x_phylink_mac_config(struct phylink_config *config, + unsigned int link_an_mode, + const struct phylink_link_state *state) +{ + struct net_device *netdev = to_net_dev(config->dev); + struct lan743x_adapter *adapter = netdev_priv(netdev); + int ret; + + switch (state->interface) { + case PHY_INTERFACE_MODE_2500BASEX: + ret = lan743x_phylink_2500basex_config(adapter); + if (ret < 0) + netif_err(adapter, drv, adapter->netdev, + "2500BASEX config failed. Error %d\n", ret); + else + netif_dbg(adapter, drv, adapter->netdev, + "2500BASEX mode selected and configured\n"); + break; + case PHY_INTERFACE_MODE_1000BASEX: + ret = lan743x_phylink_1000basex_config(adapter); + if (ret < 0) + netif_err(adapter, drv, adapter->netdev, + "1000BASEX config failed. Error %d\n", ret); + else + netif_dbg(adapter, drv, adapter->netdev, + "1000BASEX mode selected and configured\n"); + break; + case PHY_INTERFACE_MODE_SGMII: + ret = lan743x_phylink_sgmii_config(adapter); + if (ret < 0) + netif_err(adapter, drv, adapter->netdev, + "SGMII config failed. Error %d\n", ret); + else + netif_dbg(adapter, drv, adapter->netdev, + "SGMII mode selected and configured\n"); + break; + default: + netif_dbg(adapter, drv, adapter->netdev, + "RGMII/GMII/MII(0x%X) mode enable\n", + state->interface); + break; + } +} + +static void lan743x_phylink_mac_link_down(struct phylink_config *config, + unsigned int link_an_mode, + phy_interface_t interface) +{ + struct net_device *netdev = to_net_dev(config->dev); + struct lan743x_adapter *adapter = netdev_priv(netdev); + + netif_tx_stop_all_queues(to_net_dev(config->dev)); + lan743x_mac_eee_enable(adapter, false); +} + +static void lan743x_phylink_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, + unsigned int link_an_mode, + phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + struct net_device *netdev = to_net_dev(config->dev); + struct lan743x_adapter *adapter = netdev_priv(netdev); + int mac_cr; + u8 cap; + + mac_cr = lan743x_csr_read(adapter, MAC_CR); + /* Pre-initialize register bits. + * Resulting value corresponds to SPEED_10 + */ + mac_cr &= ~(MAC_CR_CFG_H_ | MAC_CR_CFG_L_); + if (speed == SPEED_2500) + mac_cr |= MAC_CR_CFG_H_ | MAC_CR_CFG_L_; + else if (speed == SPEED_1000) + mac_cr |= MAC_CR_CFG_H_; + else if (speed == SPEED_100) + mac_cr |= MAC_CR_CFG_L_; + + lan743x_csr_write(adapter, MAC_CR, mac_cr); + + lan743x_ptp_update_latency(adapter, speed); + + /* Flow Control operation */ + cap = 0; + if (tx_pause) + cap |= FLOW_CTRL_TX; + if (rx_pause) + cap |= FLOW_CTRL_RX; + + lan743x_mac_flow_ctrl_set_enables(adapter, + cap & FLOW_CTRL_TX, + cap & FLOW_CTRL_RX); + + if (phydev) + lan743x_mac_eee_enable(adapter, phydev->enable_tx_lpi); + + netif_tx_wake_all_queues(netdev); +} + +static const struct phylink_mac_ops lan743x_phylink_mac_ops = { + .mac_config = lan743x_phylink_mac_config, + .mac_link_down = lan743x_phylink_mac_link_down, + .mac_link_up = lan743x_phylink_mac_link_up, +}; + +static int lan743x_phylink_create(struct lan743x_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct phylink *pl; + + adapter->phylink_config.dev = &netdev->dev; + adapter->phylink_config.type = PHYLINK_NETDEV; + adapter->phylink_config.mac_managed_pm = false; + + adapter->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | + MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD; + + lan743x_phy_interface_select(adapter); + + switch (adapter->phy_interface) { + case PHY_INTERFACE_MODE_SGMII: + __set_bit(PHY_INTERFACE_MODE_SGMII, + adapter->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, + adapter->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, + adapter->phylink_config.supported_interfaces); + adapter->phylink_config.mac_capabilities |= MAC_2500FD; + break; + case PHY_INTERFACE_MODE_GMII: + __set_bit(PHY_INTERFACE_MODE_GMII, + adapter->phylink_config.supported_interfaces); + break; + case PHY_INTERFACE_MODE_MII: + __set_bit(PHY_INTERFACE_MODE_MII, + adapter->phylink_config.supported_interfaces); + break; + default: + phy_interface_set_rgmii(adapter->phylink_config.supported_interfaces); + } + + pl = phylink_create(&adapter->phylink_config, NULL, + adapter->phy_interface, &lan743x_phylink_mac_ops); + + if (IS_ERR(pl)) { + netdev_err(netdev, "Could not create phylink (%pe)\n", pl); + return PTR_ERR(pl); + } + + adapter->phylink = pl; + netdev_dbg(netdev, "lan743x phylink created"); + + return 0; +} + +static bool lan743x_phy_handle_exists(struct device_node *dn) +{ + dn = of_parse_phandle(dn, "phy-handle", 0); + of_node_put(dn); + return dn != NULL; +} + +static int lan743x_phylink_connect(struct lan743x_adapter *adapter) +{ + struct device_node *dn = adapter->pdev->dev.of_node; + struct net_device *dev = adapter->netdev; + struct phy_device *phydev; + int ret; + + if (dn) + ret = phylink_of_phy_connect(adapter->phylink, dn, 0); + + if (!dn || (ret && !lan743x_phy_handle_exists(dn))) { + phydev = phy_find_first(adapter->mdiobus); + if (phydev) { + /* attach the mac to the phy */ + ret = phylink_connect_phy(adapter->phylink, phydev); + } else if (((adapter->csr.id_rev & ID_REV_ID_MASK_) == + ID_REV_ID_LAN7431_) || adapter->is_pci11x1x) { + struct phylink_link_state state; + unsigned long caps; + + caps = adapter->phylink_config.mac_capabilities; + if (caps & MAC_2500FD) { + state.speed = SPEED_2500; + state.duplex = DUPLEX_FULL; + } else if (caps & MAC_1000FD) { + state.speed = SPEED_1000; + state.duplex = DUPLEX_FULL; + } else { + state.speed = SPEED_UNKNOWN; + state.duplex = DUPLEX_UNKNOWN; + } + + ret = phylink_set_fixed_link(adapter->phylink, &state); + if (ret) { + netdev_err(dev, "Could not set fixed link\n"); + return ret; + } + } else { + netdev_err(dev, "no PHY found\n"); + return -ENXIO; + } + } + + if (ret) { + netdev_err(dev, "Could not attach PHY (%d)\n", ret); + return ret; + } + + phylink_start(adapter->phylink); + + return 0; +} + +static void lan743x_phylink_disconnect(struct lan743x_adapter *adapter) +{ + phylink_stop(adapter->phylink); + phylink_disconnect_phy(adapter->phylink); +} + static int lan743x_netdev_close(struct net_device *netdev) { struct lan743x_adapter *adapter = netdev_priv(netdev); @@ -3074,7 +3213,7 @@ static int lan743x_netdev_close(struct net_device *netdev) lan743x_ptp_close(adapter); - lan743x_phy_close(adapter); + lan743x_phylink_disconnect(adapter); lan743x_mac_close(adapter); @@ -3097,13 +3236,13 @@ static int lan743x_netdev_open(struct net_device *netdev) if (ret) goto close_intr; - ret = lan743x_phy_open(adapter); + ret = lan743x_phylink_connect(adapter); if (ret) goto close_mac; ret = lan743x_ptp_open(adapter); if (ret) - goto close_phy; + goto close_mac; lan743x_rfe_open(adapter); @@ -3119,6 +3258,9 @@ static int lan743x_netdev_open(struct net_device *netdev) goto close_tx; } + if (netdev->phydev) + phy_support_eee(netdev->phydev); + #ifdef CONFIG_PM if (adapter->netdev->phydev) { struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; @@ -3143,9 +3285,8 @@ close_rx: lan743x_rx_close(&adapter->rx[index]); } lan743x_ptp_close(adapter); - -close_phy: - lan743x_phy_close(adapter); + if (adapter->phylink) + lan743x_phylink_disconnect(adapter); close_mac: lan743x_mac_close(adapter); @@ -3174,11 +3315,14 @@ static netdev_tx_t lan743x_netdev_xmit_frame(struct sk_buff *skb, static int lan743x_netdev_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { + struct lan743x_adapter *adapter = netdev_priv(netdev); + if (!netif_running(netdev)) return -EINVAL; if (cmd == SIOCSHWTSTAMP) return lan743x_ptp_ioctl(netdev, ifr, cmd); - return phy_mii_ioctl(netdev->phydev, ifr, cmd); + + return phylink_mii_ioctl(adapter->phylink, ifr, cmd); } static void lan743x_netdev_set_multicast(struct net_device *netdev) @@ -3283,10 +3427,17 @@ static void lan743x_mdiobus_cleanup(struct lan743x_adapter *adapter) mdiobus_unregister(adapter->mdiobus); } +static void lan743x_destroy_phylink(struct lan743x_adapter *adapter) +{ + phylink_destroy(adapter->phylink); + adapter->phylink = NULL; +} + static void lan743x_full_cleanup(struct lan743x_adapter *adapter) { unregister_netdev(adapter->netdev); + lan743x_destroy_phylink(adapter); lan743x_mdiobus_cleanup(adapter); lan743x_hardware_cleanup(adapter); lan743x_pci_cleanup(adapter); @@ -3500,14 +3651,21 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev, NETIF_F_HW_CSUM | NETIF_F_RXCSUM; adapter->netdev->hw_features = adapter->netdev->features; - /* carrier off reporting is important to ethtool even BEFORE open */ - netif_carrier_off(netdev); + ret = lan743x_phylink_create(adapter); + if (ret < 0) { + netif_err(adapter, probe, netdev, + "failed to setup phylink (%d)\n", ret); + goto cleanup_mdiobus; + } ret = register_netdev(adapter->netdev); if (ret < 0) - goto cleanup_mdiobus; + goto cleanup_phylink; return 0; +cleanup_phylink: + lan743x_destroy_phylink(adapter); + cleanup_mdiobus: lan743x_mdiobus_cleanup(adapter); @@ -3763,6 +3921,7 @@ static int lan743x_pm_resume(struct device *dev) MAC_WK_SRC_WK_FR_SAVED_; lan743x_csr_write(adapter, MAC_WK_SRC, data); + rtnl_lock(); /* open netdev when netdev is at running state while resume. * For instance, it is true when system wakesup after pm-suspend * However, it is false when system wakes up after suspend GUI menu @@ -3771,6 +3930,7 @@ static int lan743x_pm_resume(struct device *dev) lan743x_netdev_open(netdev); netif_device_attach(netdev); + rtnl_unlock(); return 0; } |