diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac_main.c')
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 221 |
1 files changed, 166 insertions, 55 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 5836b21edd7e..1f319c9cee46 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -849,6 +849,38 @@ static void stmmac_validate(struct phylink_config *config, phylink_set(mac_supported, 10000baseKX4_Full); phylink_set(mac_supported, 10000baseKR_Full); } + if (!max_speed || (max_speed >= 25000)) { + phylink_set(mac_supported, 25000baseCR_Full); + phylink_set(mac_supported, 25000baseKR_Full); + phylink_set(mac_supported, 25000baseSR_Full); + } + if (!max_speed || (max_speed >= 40000)) { + phylink_set(mac_supported, 40000baseKR4_Full); + phylink_set(mac_supported, 40000baseCR4_Full); + phylink_set(mac_supported, 40000baseSR4_Full); + phylink_set(mac_supported, 40000baseLR4_Full); + } + if (!max_speed || (max_speed >= 50000)) { + phylink_set(mac_supported, 50000baseCR2_Full); + phylink_set(mac_supported, 50000baseKR2_Full); + phylink_set(mac_supported, 50000baseSR2_Full); + phylink_set(mac_supported, 50000baseKR_Full); + phylink_set(mac_supported, 50000baseSR_Full); + phylink_set(mac_supported, 50000baseCR_Full); + phylink_set(mac_supported, 50000baseLR_ER_FR_Full); + phylink_set(mac_supported, 50000baseDR_Full); + } + if (!max_speed || (max_speed >= 100000)) { + phylink_set(mac_supported, 100000baseKR4_Full); + phylink_set(mac_supported, 100000baseSR4_Full); + phylink_set(mac_supported, 100000baseCR4_Full); + phylink_set(mac_supported, 100000baseLR4_ER4_Full); + phylink_set(mac_supported, 100000baseKR2_Full); + phylink_set(mac_supported, 100000baseSR2_Full); + phylink_set(mac_supported, 100000baseCR2_Full); + phylink_set(mac_supported, 100000baseLR2_ER2_FR2_Full); + phylink_set(mac_supported, 100000baseDR2_Full); + } } /* Half-Duplex can only work with single queue */ @@ -858,33 +890,65 @@ static void stmmac_validate(struct phylink_config *config, phylink_set(mask, 1000baseT_Half); } - bitmap_and(supported, supported, mac_supported, - __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_andnot(supported, supported, mask, - __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_and(state->advertising, state->advertising, mac_supported, - __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_andnot(state->advertising, state->advertising, mask, - __ETHTOOL_LINK_MODE_MASK_NBITS); + linkmode_and(supported, supported, mac_supported); + linkmode_andnot(supported, supported, mask); + + linkmode_and(state->advertising, state->advertising, mac_supported); + linkmode_andnot(state->advertising, state->advertising, mask); + + /* If PCS is supported, check which modes it supports. */ + stmmac_xpcs_validate(priv, &priv->hw->xpcs_args, supported, state); } static void stmmac_mac_pcs_get_state(struct phylink_config *config, struct phylink_link_state *state) { + struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); + state->link = 0; + stmmac_xpcs_get_state(priv, &priv->hw->xpcs_args, state); } static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); + + stmmac_xpcs_config(priv, &priv->hw->xpcs_args, state); +} + +static void stmmac_mac_an_restart(struct phylink_config *config) +{ + /* Not Supported */ +} + +static void stmmac_mac_link_down(struct phylink_config *config, + unsigned int mode, phy_interface_t interface) +{ + struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); + + stmmac_mac_set(priv, priv->ioaddr, false); + priv->eee_active = false; + stmmac_eee_init(priv); + stmmac_set_eee_pls(priv, priv->hw, false); +} + +static void stmmac_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); u32 ctrl; + stmmac_xpcs_link_up(priv, &priv->hw->xpcs_args, speed, interface); + ctrl = readl(priv->ioaddr + MAC_CTRL_REG); ctrl &= ~priv->hw->link.speed_mask; - if (state->interface == PHY_INTERFACE_MODE_USXGMII) { - switch (state->speed) { + if (interface == PHY_INTERFACE_MODE_USXGMII) { + switch (speed) { case SPEED_10000: ctrl |= priv->hw->link.xgmii.speed10000; break; @@ -897,8 +961,34 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, default: return; } + } else if (interface == PHY_INTERFACE_MODE_XLGMII) { + switch (speed) { + case SPEED_100000: + ctrl |= priv->hw->link.xlgmii.speed100000; + break; + case SPEED_50000: + ctrl |= priv->hw->link.xlgmii.speed50000; + break; + case SPEED_40000: + ctrl |= priv->hw->link.xlgmii.speed40000; + break; + case SPEED_25000: + ctrl |= priv->hw->link.xlgmii.speed25000; + break; + case SPEED_10000: + ctrl |= priv->hw->link.xgmii.speed10000; + break; + case SPEED_2500: + ctrl |= priv->hw->link.speed2500; + break; + case SPEED_1000: + ctrl |= priv->hw->link.speed1000; + break; + default: + return; + } } else { - switch (state->speed) { + switch (speed) { case SPEED_2500: ctrl |= priv->hw->link.speed2500; break; @@ -916,44 +1006,21 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, } } - priv->speed = state->speed; + priv->speed = speed; if (priv->plat->fix_mac_speed) - priv->plat->fix_mac_speed(priv->plat->bsp_priv, state->speed); + priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed); - if (!state->duplex) + if (!duplex) ctrl &= ~priv->hw->link.duplex; else ctrl |= priv->hw->link.duplex; /* Flow Control operation */ - if (state->pause) - stmmac_mac_flow_ctrl(priv, state->duplex); + if (tx_pause && rx_pause) + stmmac_mac_flow_ctrl(priv, duplex); writel(ctrl, priv->ioaddr + MAC_CTRL_REG); -} - -static void stmmac_mac_an_restart(struct phylink_config *config) -{ - /* Not Supported */ -} - -static void stmmac_mac_link_down(struct phylink_config *config, - unsigned int mode, phy_interface_t interface) -{ - struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); - - stmmac_mac_set(priv, priv->ioaddr, false); - priv->eee_active = false; - stmmac_eee_init(priv); - stmmac_set_eee_pls(priv, priv->hw, false); -} - -static void stmmac_mac_link_up(struct phylink_config *config, - unsigned int mode, phy_interface_t interface, - struct phy_device *phy) -{ - struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); stmmac_mac_set(priv, priv->ioaddr, true); if (phy && priv->dma_cap.eee) { @@ -1043,6 +1110,10 @@ static int stmmac_phy_setup(struct stmmac_priv *priv) priv->phylink_config.dev = &priv->dev->dev; priv->phylink_config.type = PHYLINK_NETDEV; + priv->phylink_config.pcs_poll = true; + + if (!fwnode) + fwnode = dev_fwnode(priv->device); phylink = phylink_create(&priv->phylink_config, fwnode, mode, &stmmac_phylink_mac_ops); @@ -1251,11 +1322,11 @@ static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i) struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (buf->page) - page_pool_put_page(rx_q->page_pool, buf->page, false); + page_pool_put_full_page(rx_q->page_pool, buf->page, false); buf->page = NULL; if (buf->sec_page) - page_pool_put_page(rx_q->page_pool, buf->sec_page, false); + page_pool_put_full_page(rx_q->page_pool, buf->sec_page, false); buf->sec_page = NULL; } @@ -2687,7 +2758,8 @@ static int stmmac_open(struct net_device *dev) int ret; if (priv->hw->pcs != STMMAC_PCS_TBI && - priv->hw->pcs != STMMAC_PCS_RTBI) { + priv->hw->pcs != STMMAC_PCS_RTBI && + priv->hw->xpcs == NULL) { ret = stmmac_init_phy(dev); if (ret) { netdev_err(priv->dev, @@ -3988,7 +4060,7 @@ static int stmmac_set_features(struct net_device *netdev, /** * stmmac_interrupt - main ISR * @irq: interrupt number. - * @dev_id: to pass the net device pointer. + * @dev_id: to pass the net device pointer (must be valid). * Description: this is the main driver interrupt service routine. * It can call: * o DMA service routine (to manage incoming frame reception and transmission @@ -4012,11 +4084,6 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) if (priv->irq_wake) pm_wakeup_event(priv->device, 0); - if (unlikely(!dev)) { - netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); - return IRQ_NONE; - } - /* Check if adapter is up */ if (test_bit(STMMAC_DOWN, &priv->state)) return IRQ_HANDLED; @@ -4405,6 +4472,8 @@ static void stmmac_init_fs(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); + rtnl_lock(); + /* Create per netdev entries */ priv->dbgfs_dir = debugfs_create_dir(dev->name, stmmac_fs_dir); @@ -4416,14 +4485,13 @@ static void stmmac_init_fs(struct net_device *dev) debugfs_create_file("dma_cap", 0444, priv->dbgfs_dir, dev, &stmmac_dma_cap_fops); - register_netdevice_notifier(&stmmac_notifier); + rtnl_unlock(); } static void stmmac_exit_fs(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); - unregister_netdevice_notifier(&stmmac_notifier); debugfs_remove_recursive(priv->dbgfs_dir); } #endif /* CONFIG_DEBUG_FS */ @@ -4493,18 +4561,32 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid return ret; } - return ret; + if (priv->hw->num_vlan) { + ret = stmmac_add_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid); + if (ret) + return ret; + } + + return 0; } static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid) { struct stmmac_priv *priv = netdev_priv(ndev); bool is_double = false; + int ret; if (be16_to_cpu(proto) == ETH_P_8021AD) is_double = true; clear_bit(vid, priv->active_vlans); + + if (priv->hw->num_vlan) { + ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid); + if (ret) + return ret; + } + return stmmac_vlan_update(priv, is_double); } @@ -4899,12 +4981,22 @@ int stmmac_dvr_probe(struct device *device, goto error_netdev_register; } + if (priv->plat->serdes_powerup) { + ret = priv->plat->serdes_powerup(ndev, + priv->plat->bsp_priv); + + if (ret < 0) + goto error_serdes_powerup; + } + #ifdef CONFIG_DEBUG_FS stmmac_init_fs(ndev); #endif return ret; +error_serdes_powerup: + unregister_netdev(ndev); error_netdev_register: phylink_destroy(priv->phylink); error_phy_setup: @@ -4940,14 +5032,17 @@ int stmmac_dvr_remove(struct device *dev) netdev_info(priv->dev, "%s: removing driver", __func__); -#ifdef CONFIG_DEBUG_FS - stmmac_exit_fs(ndev); -#endif stmmac_stop_all_dma(priv); + if (priv->plat->serdes_powerdown) + priv->plat->serdes_powerdown(ndev, priv->plat->bsp_priv); + stmmac_mac_set(priv, priv->ioaddr, false); netif_carrier_off(ndev); unregister_netdev(ndev); +#ifdef CONFIG_DEBUG_FS + stmmac_exit_fs(ndev); +#endif phylink_destroy(priv->phylink); if (priv->plat->stmmac_rst) reset_control_assert(priv->plat->stmmac_rst); @@ -4994,6 +5089,9 @@ int stmmac_suspend(struct device *dev) /* Stop TX/RX DMA */ stmmac_stop_all_dma(priv); + if (priv->plat->serdes_powerdown) + priv->plat->serdes_powerdown(ndev, priv->plat->bsp_priv); + /* Enable Power down mode by programming the PMT regs */ if (device_may_wakeup(priv->device)) { stmmac_pmt(priv, priv->hw, priv->wolopts); @@ -5056,6 +5154,7 @@ int stmmac_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct stmmac_priv *priv = netdev_priv(ndev); + int ret; if (!netif_running(ndev)) return 0; @@ -5083,7 +5182,13 @@ int stmmac_resume(struct device *dev) stmmac_mdio_reset(priv->mii); } - netif_device_attach(ndev); + if (priv->plat->serdes_powerup) { + ret = priv->plat->serdes_powerup(ndev, + priv->plat->bsp_priv); + + if (ret < 0) + return ret; + } mutex_lock(&priv->lock); @@ -5095,6 +5200,8 @@ int stmmac_resume(struct device *dev) stmmac_init_coalesce(priv); stmmac_set_rx_mode(ndev); + stmmac_restore_hw_vlan_rx_fltr(priv, ndev, priv->hw); + stmmac_enable_all_queues(priv); stmmac_start_all_queues(priv); @@ -5109,6 +5216,8 @@ int stmmac_resume(struct device *dev) phylink_mac_change(priv->phylink, true); + netif_device_attach(ndev); + return 0; } EXPORT_SYMBOL_GPL(stmmac_resume); @@ -5166,6 +5275,7 @@ static int __init stmmac_init(void) /* Create debugfs main directory if it doesn't exist yet */ if (!stmmac_fs_dir) stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL); + register_netdevice_notifier(&stmmac_notifier); #endif return 0; @@ -5174,6 +5284,7 @@ static int __init stmmac_init(void) static void __exit stmmac_exit(void) { #ifdef CONFIG_DEBUG_FS + unregister_netdevice_notifier(&stmmac_notifier); debugfs_remove_recursive(stmmac_fs_dir); #endif } |