diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 6e01f1fba068..522fe8dda6c3 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,9 @@ static void mtk_phy_link_adjust(struct net_device *dev) MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN; + if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) + return; + switch (mac->phy_dev->speed) { case SPEED_1000: mcr |= MAC_MCR_SPEED_1000; @@ -230,7 +234,7 @@ static int mtk_phy_connect(struct mtk_mac *mac) { struct mtk_eth *eth = mac->hw; struct device_node *np; - u32 val, ge_mode; + u32 val; np = of_parse_phandle(mac->of_node, "phy-handle", 0); if (!np && of_phy_is_fixed_link(mac->of_node)) @@ -244,18 +248,18 @@ static int mtk_phy_connect(struct mtk_mac *mac) case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII: - ge_mode = 0; + mac->ge_mode = 0; break; case PHY_INTERFACE_MODE_MII: - ge_mode = 1; + mac->ge_mode = 1; break; case PHY_INTERFACE_MODE_REVMII: - ge_mode = 2; + mac->ge_mode = 2; break; case PHY_INTERFACE_MODE_RMII: if (!mac->id) goto err_phy; - ge_mode = 3; + mac->ge_mode = 3; break; default: goto err_phy; @@ -264,7 +268,7 @@ static int mtk_phy_connect(struct mtk_mac *mac) /* put the gmac into the right mode */ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id); - val |= SYSCFG0_GE_MODE(ge_mode, mac->id); + val |= SYSCFG0_GE_MODE(mac->ge_mode, mac->id); regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); mtk_phy_connect_node(eth, mac, np); @@ -369,6 +373,9 @@ static int mtk_set_mac_address(struct net_device *dev, void *p) if (ret) return ret; + if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) + return -EBUSY; + spin_lock_bh(&mac->hw->page_lock); mtk_w32(mac->hw, (macaddr[0] << 8) | macaddr[1], MTK_GDMA_MAC_ADRH(mac->id)); @@ -769,6 +776,9 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) */ spin_lock(ð->page_lock); + if (unlikely(test_bit(MTK_RESETTING, ð->state))) + goto drop; + tx_num = mtk_cal_txd_req(skb); if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { mtk_stop_queue(eth); @@ -841,6 +851,9 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, netdev = eth->netdev[mac]; + if (unlikely(test_bit(MTK_RESETTING, ð->state))) + goto release_desc; + /* alloc new buffer */ new_data = napi_alloc_frag(ring->frag_size); if (unlikely(!new_data)) { @@ -1413,15 +1426,44 @@ static int mtk_stop(struct net_device *dev) return 0; } -static int __init mtk_hw_init(struct mtk_eth *eth) +static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits) { - int err, i; + regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, + reset_bits, + reset_bits); - /* reset the frame engine */ - reset_control_assert(eth->rstc); - usleep_range(10, 20); - reset_control_deassert(eth->rstc); - usleep_range(10, 20); + usleep_range(1000, 1100); + regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, + reset_bits, + ~reset_bits); + mdelay(10); +} + +static int mtk_hw_init(struct mtk_eth *eth) +{ + int i, val; + + if (test_and_set_bit(MTK_HW_INIT, ð->state)) + return 0; + + pm_runtime_enable(eth->dev); + pm_runtime_get_sync(eth->dev); + + clk_prepare_enable(eth->clks[MTK_CLK_ETHIF]); + clk_prepare_enable(eth->clks[MTK_CLK_ESW]); + clk_prepare_enable(eth->clks[MTK_CLK_GP1]); + clk_prepare_enable(eth->clks[MTK_CLK_GP2]); + ethsys_reset(eth, RSTCTRL_FE); + ethsys_reset(eth, RSTCTRL_PPE); + + regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); + for (i = 0; i < MTK_MAC_COUNT; i++) { + if (!eth->mac[i]) + continue; + val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, eth->mac[i]->id); + val |= SYSCFG0_GE_MODE(eth->mac[i]->ge_mode, eth->mac[i]->id); + } + regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); /* Set GE2 driving and slew rate */ regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00); @@ -1441,19 +1483,6 @@ static int __init mtk_hw_init(struct mtk_eth *eth) /* Enable RX VLan Offloading */ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); - err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, - dev_name(eth->dev), eth); - if (err) - return err; - err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, - dev_name(eth->dev), eth); - if (err) - return err; - - err = mtk_mdio_init(eth); - if (err) - return err; - /* disable delay and normal interrupt */ mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); mtk_w32(eth, 0, MTK_PDMA_DELAY_INT); @@ -1485,6 +1514,22 @@ static int __init mtk_hw_init(struct mtk_eth *eth) return 0; } +static int mtk_hw_deinit(struct mtk_eth *eth) +{ + if (!test_and_clear_bit(MTK_HW_INIT, ð->state)) + return 0; + + clk_disable_unprepare(eth->clks[MTK_CLK_GP2]); + clk_disable_unprepare(eth->clks[MTK_CLK_GP1]); + clk_disable_unprepare(eth->clks[MTK_CLK_ESW]); + clk_disable_unprepare(eth->clks[MTK_CLK_ETHIF]); + + pm_runtime_put_sync(eth->dev); + pm_runtime_disable(eth->dev); + + return 0; +} + static int __init mtk_init(struct net_device *dev) { struct mtk_mac *mac = netdev_priv(dev); @@ -1543,6 +1588,12 @@ static void mtk_pending_work(struct work_struct *work) rtnl_lock(); + dev_dbg(eth->dev, "[%s][%d] reset\n", __func__, __LINE__); + + while (test_and_set_bit_lock(MTK_RESETTING, ð->state)) + cpu_relax(); + + dev_dbg(eth->dev, "[%s][%d] mtk_stop starts\n", __func__, __LINE__); /* stop all devices to make sure that dma is properly shut down */ for (i = 0; i < MTK_MAC_COUNT; i++) { if (!eth->netdev[i]) @@ -1550,6 +1601,27 @@ static void mtk_pending_work(struct work_struct *work) mtk_stop(eth->netdev[i]); __set_bit(i, &restart); } + dev_dbg(eth->dev, "[%s][%d] mtk_stop ends\n", __func__, __LINE__); + + /* restart underlying hardware such as power, clock, pin mux + * and the connected phy + */ + mtk_hw_deinit(eth); + + if (eth->dev->pins) + pinctrl_select_state(eth->dev->pins->p, + eth->dev->pins->default_state); + mtk_hw_init(eth); + + for (i = 0; i < MTK_MAC_COUNT; i++) { + if (!eth->mac[i] || + of_phy_is_fixed_link(eth->mac[i]->of_node)) + continue; + err = phy_init_hw(eth->mac[i]->phy_dev); + if (err) + dev_err(eth->dev, "%s: PHY init failed.\n", + eth->netdev[i]->name); + } /* restart DMA and enable IRQs */ for (i = 0; i < MTK_MAC_COUNT; i++) { @@ -1562,20 +1634,44 @@ static void mtk_pending_work(struct work_struct *work) dev_close(eth->netdev[i]); } } + + dev_dbg(eth->dev, "[%s][%d] reset done\n", __func__, __LINE__); + + clear_bit_unlock(MTK_RESETTING, ð->state); + rtnl_unlock(); } -static int mtk_cleanup(struct mtk_eth *eth) +static int mtk_free_dev(struct mtk_eth *eth) { int i; for (i = 0; i < MTK_MAC_COUNT; i++) { if (!eth->netdev[i]) continue; - - unregister_netdev(eth->netdev[i]); free_netdev(eth->netdev[i]); } + + return 0; +} + +static int mtk_unreg_dev(struct mtk_eth *eth) +{ + int i; + + for (i = 0; i < MTK_MAC_COUNT; i++) { + if (!eth->netdev[i]) + continue; + unregister_netdev(eth->netdev[i]); + } + + return 0; +} + +static int mtk_cleanup(struct mtk_eth *eth) +{ + mtk_unreg_dev(eth); + mtk_free_dev(eth); cancel_work_sync(ð->pending_work); return 0; @@ -1587,6 +1683,9 @@ static int mtk_get_settings(struct net_device *dev, struct mtk_mac *mac = netdev_priv(dev); int err; + if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) + return -EBUSY; + err = phy_read_status(mac->phy_dev); if (err) return -ENODEV; @@ -1637,6 +1736,9 @@ static int mtk_nway_reset(struct net_device *dev) { struct mtk_mac *mac = netdev_priv(dev); + if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) + return -EBUSY; + return genphy_restart_aneg(mac->phy_dev); } @@ -1645,6 +1747,9 @@ static u32 mtk_get_link(struct net_device *dev) struct mtk_mac *mac = netdev_priv(dev); int err; + if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) + return -EBUSY; + err = genphy_update_link(mac->phy_dev); if (err) return ethtool_op_get_link(dev); @@ -1685,6 +1790,9 @@ static void mtk_get_ethtool_stats(struct net_device *dev, unsigned int start; int i; + if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) + return; + if (netif_running(dev) && netif_device_present(dev)) { if (spin_trylock(&hwstats->stats_lock)) { mtk_stats_update_mac(mac); @@ -1786,16 +1894,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) eth->netdev[id]->features |= MTK_HW_FEATURES; eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops; - err = register_netdev(eth->netdev[id]); - if (err) { - dev_err(eth->dev, "error bringing up device\n"); - goto free_netdev; - } eth->netdev[id]->irq = eth->irq[0]; - netif_info(eth, probe, eth->netdev[id], - "mediatek frame engine at 0x%08lx, irq %d\n", - eth->netdev[id]->base_addr, eth->irq[0]); - return 0; free_netdev: @@ -1842,12 +1941,6 @@ static int mtk_probe(struct platform_device *pdev) return PTR_ERR(eth->pctl); } - eth->rstc = devm_reset_control_get(&pdev->dev, "eth"); - if (IS_ERR(eth->rstc)) { - dev_err(&pdev->dev, "no eth reset found\n"); - return PTR_ERR(eth->rstc); - } - for (i = 0; i < 3; i++) { eth->irq[i] = platform_get_irq(pdev, i); if (eth->irq[i] < 0) { @@ -1865,11 +1958,6 @@ static int mtk_probe(struct platform_device *pdev) } } - clk_prepare_enable(eth->clks[MTK_CLK_ETHIF]); - clk_prepare_enable(eth->clks[MTK_CLK_ESW]); - clk_prepare_enable(eth->clks[MTK_CLK_GP1]); - clk_prepare_enable(eth->clks[MTK_CLK_GP2]); - eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE); INIT_WORK(ð->pending_work, mtk_pending_work); @@ -1887,7 +1975,35 @@ static int mtk_probe(struct platform_device *pdev) err = mtk_add_mac(eth, mac_np); if (err) - goto err_free_dev; + goto err_deinit_hw; + } + + err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, + dev_name(eth->dev), eth); + if (err) + goto err_free_dev; + + err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, + dev_name(eth->dev), eth); + if (err) + goto err_free_dev; + + err = mtk_mdio_init(eth); + if (err) + goto err_free_dev; + + for (i = 0; i < MTK_MAX_DEVS; i++) { + if (!eth->netdev[i]) + continue; + + err = register_netdev(eth->netdev[i]); + if (err) { + dev_err(eth->dev, "error bringing up device\n"); + goto err_deinit_mdio; + } else + netif_info(eth, probe, eth->netdev[i], + "mediatek frame engine at 0x%08lx, irq %d\n", + eth->netdev[i]->base_addr, eth->irq[0]); } /* we run 2 devices on the same DMA ring so we need a dummy device @@ -1903,8 +2019,13 @@ static int mtk_probe(struct platform_device *pdev) return 0; +err_deinit_mdio: + mtk_mdio_cleanup(eth); err_free_dev: - mtk_cleanup(eth); + mtk_free_dev(eth); +err_deinit_hw: + mtk_hw_deinit(eth); + return err; } @@ -1920,10 +2041,7 @@ static int mtk_remove(struct platform_device *pdev) mtk_stop(eth->netdev[i]); } - clk_disable_unprepare(eth->clks[MTK_CLK_ETHIF]); - clk_disable_unprepare(eth->clks[MTK_CLK_ESW]); - clk_disable_unprepare(eth->clks[MTK_CLK_GP1]); - clk_disable_unprepare(eth->clks[MTK_CLK_GP2]); + mtk_hw_deinit(eth); netif_napi_del(ð->tx_napi); netif_napi_del(ð->rx_napi); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 0b984dca462e..79954b419b53 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -266,6 +266,11 @@ #define SYSCFG0_GE_MASK 0x3 #define SYSCFG0_GE_MODE(x, y) (x << (12 + (y * 2))) +/*ethernet reset control register*/ +#define ETHSYS_RSTCTRL 0x34 +#define RSTCTRL_FE BIT(6) +#define RSTCTRL_PPE BIT(31) + struct mtk_rx_dma { unsigned int rxd1; unsigned int rxd2; @@ -330,6 +335,11 @@ enum mtk_clks_map { MTK_CLK_MAX }; +enum mtk_dev_state { + MTK_HW_INIT, + MTK_RESETTING +}; + /* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at * by the TX descriptor s * @skb: The SKB pointer of the packet being sent @@ -413,12 +423,12 @@ struct mtk_rx_ring { * @clks: clock array for all clocks required * @mii_bus: If there is a bus we need to create an instance for it * @pending_work: The workqueue used to reset the dma ring + * @state Initialization and runtime state of the device. */ struct mtk_eth { struct device *dev; void __iomem *base; - struct reset_control *rstc; spinlock_t page_lock; spinlock_t irq_lock; struct net_device dummy_dev; @@ -441,11 +451,13 @@ struct mtk_eth { struct mii_bus *mii_bus; struct work_struct pending_work; + unsigned long state; }; /* struct mtk_mac - the structure that holds the info about the MACs of the * SoC * @id: The number of the MAC + * @ge_mode: Interface mode kept for setup restoring * @of_node: Our devicetree node * @hw: Backpointer to our main datastruture * @hw_stats: Packet statistics counter @@ -453,6 +465,7 @@ struct mtk_eth { */ struct mtk_mac { int id; + int ge_mode; struct device_node *of_node; struct mtk_eth *hw; struct mtk_hw_stats *hw_stats;