diff options
Diffstat (limited to 'drivers/net/ethernet/faraday/ftgmac100.c')
| -rw-r--r-- | drivers/net/ethernet/faraday/ftgmac100.c | 131 |
1 files changed, 93 insertions, 38 deletions
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index a03879a27b04..a863f7841210 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/clk.h> +#include <linux/reset.h> #include <linux/dma-mapping.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -24,6 +25,7 @@ #include <linux/crc32.h> #include <linux/if_vlan.h> #include <linux/of_net.h> +#include <linux/phy_fixed.h> #include <net/ip.h> #include <net/ncsi.h> @@ -50,6 +52,15 @@ #define FTGMAC_100MHZ 100000000 #define FTGMAC_25MHZ 25000000 +/* For NC-SI to register a fixed-link phy device */ +static struct fixed_phy_status ncsi_phy_status = { + .link = 1, + .speed = SPEED_100, + .duplex = DUPLEX_FULL, + .pause = 0, + .asym_pause = 0 +}; + struct ftgmac100 { /* Registers */ struct resource *res; @@ -91,6 +102,8 @@ struct ftgmac100 { /* AST2500/AST2600 RMII ref clock gate */ struct clk *rclk; + /* Aspeed reset control */ + struct reset_control *rst; /* Link management */ int cur_speed; @@ -138,6 +151,23 @@ static int ftgmac100_reset_and_config_mac(struct ftgmac100 *priv) { u32 maccr = 0; + /* Aspeed RMII needs SCU reset to clear status */ + if (priv->is_aspeed && priv->netdev->phydev->interface == PHY_INTERFACE_MODE_RMII) { + int err; + + err = reset_control_assert(priv->rst); + if (err) { + dev_err(priv->dev, "Failed to reset mac (%d)\n", err); + return err; + } + usleep_range(10000, 20000); + err = reset_control_deassert(priv->rst); + if (err) { + dev_err(priv->dev, "Failed to deassert mac reset (%d)\n", err); + return err; + } + } + switch (priv->cur_speed) { case SPEED_10: case 0: /* no link */ @@ -177,16 +207,20 @@ static void ftgmac100_write_mac_addr(struct ftgmac100 *priv, const u8 *mac) iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR); } -static void ftgmac100_initial_mac(struct ftgmac100 *priv) +static int ftgmac100_initial_mac(struct ftgmac100 *priv) { u8 mac[ETH_ALEN]; unsigned int m; unsigned int l; + int err; - if (!device_get_ethdev_address(priv->dev, priv->netdev)) { + err = of_get_ethdev_address(priv->dev->of_node, priv->netdev); + if (err == -EPROBE_DEFER) + return err; + if (!err) { dev_info(priv->dev, "Read MAC address %pM from device tree\n", priv->netdev->dev_addr); - return; + return 0; } m = ioread32(priv->base + FTGMAC100_OFFSET_MAC_MADR); @@ -207,6 +241,8 @@ static void ftgmac100_initial_mac(struct ftgmac100 *priv) dev_info(priv->dev, "Generated random MAC address %pM\n", priv->netdev->dev_addr); } + + return 0; } static int ftgmac100_set_mac_addr(struct net_device *dev, void *p) @@ -566,7 +602,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed) (*processed)++; return true; - drop: +drop: /* Clean rxdes0 (which resets own bit) */ rxdes->rxdes0 = cpu_to_le32(status & priv->rxdes0_edorr_mask); priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer); @@ -650,6 +686,11 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv) ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat); txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask); + /* Ensure the descriptor config is visible before setting the tx + * pointer. + */ + smp_wmb(); + priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv, pointer); return true; @@ -803,6 +844,11 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, dma_wmb(); first->txdes0 = cpu_to_le32(f_ctl_stat); + /* Ensure the descriptor config is visible before setting the tx + * pointer. + */ + smp_wmb(); + /* Update next TX pointer */ priv->tx_pointer = pointer; @@ -823,7 +869,7 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; - dma_err: +dma_err: if (net_ratelimit()) netdev_err(netdev, "map tx fragment failed\n"); @@ -845,7 +891,7 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, * last fragment, so we know ftgmac100_free_tx_packet() * hasn't freed the skb yet. */ - drop: +drop: /* Drop the packet */ dev_kfree_skb_any(skb); netdev->stats.tx_dropped++; @@ -1338,7 +1384,7 @@ static void ftgmac100_reset(struct ftgmac100 *priv) ftgmac100_init_all(priv, true); netdev_dbg(netdev, "Reset done !\n"); - bail: +bail: if (priv->mii_bus) mutex_unlock(&priv->mii_bus->mdio_lock); if (netdev->phydev) @@ -1402,7 +1448,7 @@ static void ftgmac100_adjust_link(struct net_device *netdev) /* Disable all interrupts */ iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); - /* Release phy lock to allow ftgmac100_reset to aquire it, keeping lock + /* Release phy lock to allow ftgmac100_reset to acquire it, keeping lock * order consistent to prevent dead lock. */ if (netdev->phydev) @@ -1525,7 +1571,8 @@ static int ftgmac100_open(struct net_device *netdev) if (netdev->phydev) { /* If we have a PHY, start polling */ phy_start(netdev->phydev); - } else if (priv->use_ncsi) { + } + if (priv->use_ncsi) { /* If using NC-SI, set our carrier on and start the stack */ netif_carrier_on(netdev); @@ -1537,15 +1584,16 @@ static int ftgmac100_open(struct net_device *netdev) return 0; - err_ncsi: +err_ncsi: + phy_stop(netdev->phydev); napi_disable(&priv->napi); netif_stop_queue(netdev); - err_alloc: +err_alloc: ftgmac100_free_buffers(priv); free_irq(netdev->irq, netdev); - err_irq: +err_irq: netif_napi_del(&priv->napi); - err_hw: +err_hw: iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); ftgmac100_free_rings(priv); return err; @@ -1571,7 +1619,7 @@ static int ftgmac100_stop(struct net_device *netdev) netif_napi_del(&priv->napi); if (netdev->phydev) phy_stop(netdev->phydev); - else if (priv->use_ncsi) + if (priv->use_ncsi) ncsi_stop_dev(priv->ndev); ftgmac100_stop_hw(priv); @@ -1702,13 +1750,17 @@ err_register_mdiobus: static void ftgmac100_phy_disconnect(struct net_device *netdev) { struct ftgmac100 *priv = netdev_priv(netdev); + struct phy_device *phydev = netdev->phydev; - if (!netdev->phydev) + if (!phydev) return; - phy_disconnect(netdev->phydev); + phy_disconnect(phydev); if (of_phy_is_fixed_link(priv->dev->of_node)) of_phy_deregister_fixed_link(priv->dev->of_node); + + if (priv->use_ncsi) + fixed_phy_unregister(phydev); } static void ftgmac100_destroy_mdio(struct net_device *netdev) @@ -1786,6 +1838,7 @@ static int ftgmac100_probe(struct platform_device *pdev) struct resource *res; int irq; struct net_device *netdev; + struct phy_device *phydev; struct ftgmac100 *priv; struct device_node *np; int err = 0; @@ -1843,7 +1896,9 @@ static int ftgmac100_probe(struct platform_device *pdev) priv->aneg_pause = true; /* MAC address from chip or random one */ - ftgmac100_initial_mac(priv); + err = ftgmac100_initial_mac(priv); + if (err) + goto err_phy_connect; np = pdev->dev.of_node; if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac") || @@ -1871,35 +1926,30 @@ static int ftgmac100_probe(struct platform_device *pdev) err = -EINVAL; goto err_phy_connect; } - } else if (np && of_phy_is_fixed_link(np)) { - struct phy_device *phy; - err = of_phy_register_fixed_link(np); - if (err) { - dev_err(&pdev->dev, "Failed to register fixed PHY\n"); + phydev = fixed_phy_register(&ncsi_phy_status, np); + if (IS_ERR(phydev)) { + dev_err(&pdev->dev, "failed to register fixed PHY device\n"); + err = PTR_ERR(phydev); goto err_phy_connect; } - - phy = of_phy_get_and_connect(priv->netdev, np, - &ftgmac100_adjust_link); - if (!phy) { - dev_err(&pdev->dev, "Failed to connect to fixed PHY\n"); - of_phy_deregister_fixed_link(np); - err = -EINVAL; + err = phy_connect_direct(netdev, phydev, ftgmac100_adjust_link, + PHY_INTERFACE_MODE_RMII); + if (err) { + dev_err(&pdev->dev, "Connecting PHY failed\n"); goto err_phy_connect; } - - /* Display what we found */ - phy_attached_info(phy); - } else if (np && of_get_property(np, "phy-handle", NULL)) { + } else if (np && (of_phy_is_fixed_link(np) || + of_get_property(np, "phy-handle", NULL))) { struct phy_device *phy; /* Support "mdio"/"phy" child nodes for ast2400/2500 with * an embedded MDIO controller. Automatically scan the DTS for * available PHYs and register them. */ - if (of_device_is_compatible(np, "aspeed,ast2400-mac") || - of_device_is_compatible(np, "aspeed,ast2500-mac")) { + if (of_get_property(np, "phy-handle", NULL) && + (of_device_is_compatible(np, "aspeed,ast2400-mac") || + of_device_is_compatible(np, "aspeed,ast2500-mac"))) { err = ftgmac100_setup_mdio(netdev); if (err) goto err_setup_mdio; @@ -1939,6 +1989,12 @@ static int ftgmac100_probe(struct platform_device *pdev) } + priv->rst = devm_reset_control_get_optional_exclusive(priv->dev, NULL); + if (IS_ERR(priv->rst)) { + err = PTR_ERR(priv->rst); + goto err_phy_connect; + } + if (priv->is_aspeed) { err = ftgmac100_setup_clk(priv); if (err) @@ -2004,7 +2060,7 @@ err_alloc_etherdev: return err; } -static int ftgmac100_remove(struct platform_device *pdev) +static void ftgmac100_remove(struct platform_device *pdev) { struct net_device *netdev; struct ftgmac100 *priv; @@ -2032,7 +2088,6 @@ static int ftgmac100_remove(struct platform_device *pdev) netif_napi_del(&priv->napi); free_netdev(netdev); - return 0; } static const struct of_device_id ftgmac100_of_match[] = { @@ -2043,7 +2098,7 @@ MODULE_DEVICE_TABLE(of, ftgmac100_of_match); static struct platform_driver ftgmac100_driver = { .probe = ftgmac100_probe, - .remove = ftgmac100_remove, + .remove = ftgmac100_remove, .driver = { .name = DRV_NAME, .of_match_table = ftgmac100_of_match, |
