diff options
Diffstat (limited to 'drivers/net/ethernet/atheros/ag71xx.c')
-rw-r--r-- | drivers/net/ethernet/atheros/ag71xx.c | 406 |
1 files changed, 296 insertions, 110 deletions
diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c index e95687a780fb..cc932b3cf873 100644 --- a/drivers/net/ethernet/atheros/ag71xx.c +++ b/drivers/net/ethernet/atheros/ag71xx.c @@ -32,10 +32,12 @@ #include <linux/of_mdio.h> #include <linux/of_net.h> #include <linux/of_platform.h> +#include <linux/phylink.h> #include <linux/regmap.h> #include <linux/reset.h> #include <linux/clk.h> #include <linux/io.h> +#include <net/selftests.h> /* For our NAPI weight bigger does *NOT* mean better - it means more * D-cache misses and lots more wasted cycles than we'll ever @@ -222,8 +224,6 @@ #define AG71XX_REG_RX_SM 0x01b0 #define AG71XX_REG_TX_SM 0x01b4 -#define ETH_SWITCH_HEADER_LEN 2 - #define AG71XX_DEFAULT_MSG_ENABLE \ (NETIF_MSG_DRV \ | NETIF_MSG_PROBE \ @@ -234,6 +234,59 @@ | NETIF_MSG_RX_ERR \ | NETIF_MSG_TX_ERR) +struct ag71xx_statistic { + unsigned short offset; + u32 mask; + const char name[ETH_GSTRING_LEN]; +}; + +static const struct ag71xx_statistic ag71xx_statistics[] = { + { 0x0080, GENMASK(17, 0), "Tx/Rx 64 Byte", }, + { 0x0084, GENMASK(17, 0), "Tx/Rx 65-127 Byte", }, + { 0x0088, GENMASK(17, 0), "Tx/Rx 128-255 Byte", }, + { 0x008C, GENMASK(17, 0), "Tx/Rx 256-511 Byte", }, + { 0x0090, GENMASK(17, 0), "Tx/Rx 512-1023 Byte", }, + { 0x0094, GENMASK(17, 0), "Tx/Rx 1024-1518 Byte", }, + { 0x0098, GENMASK(17, 0), "Tx/Rx 1519-1522 Byte VLAN", }, + { 0x009C, GENMASK(23, 0), "Rx Byte", }, + { 0x00A0, GENMASK(17, 0), "Rx Packet", }, + { 0x00A4, GENMASK(11, 0), "Rx FCS Error", }, + { 0x00A8, GENMASK(17, 0), "Rx Multicast Packet", }, + { 0x00AC, GENMASK(21, 0), "Rx Broadcast Packet", }, + { 0x00B0, GENMASK(17, 0), "Rx Control Frame Packet", }, + { 0x00B4, GENMASK(11, 0), "Rx Pause Frame Packet", }, + { 0x00B8, GENMASK(11, 0), "Rx Unknown OPCode Packet", }, + { 0x00BC, GENMASK(11, 0), "Rx Alignment Error", }, + { 0x00C0, GENMASK(15, 0), "Rx Frame Length Error", }, + { 0x00C4, GENMASK(11, 0), "Rx Code Error", }, + { 0x00C8, GENMASK(11, 0), "Rx Carrier Sense Error", }, + { 0x00CC, GENMASK(11, 0), "Rx Undersize Packet", }, + { 0x00D0, GENMASK(11, 0), "Rx Oversize Packet", }, + { 0x00D4, GENMASK(11, 0), "Rx Fragments", }, + { 0x00D8, GENMASK(11, 0), "Rx Jabber", }, + { 0x00DC, GENMASK(11, 0), "Rx Dropped Packet", }, + { 0x00E0, GENMASK(23, 0), "Tx Byte", }, + { 0x00E4, GENMASK(17, 0), "Tx Packet", }, + { 0x00E8, GENMASK(17, 0), "Tx Multicast Packet", }, + { 0x00EC, GENMASK(17, 0), "Tx Broadcast Packet", }, + { 0x00F0, GENMASK(11, 0), "Tx Pause Control Frame", }, + { 0x00F4, GENMASK(11, 0), "Tx Deferral Packet", }, + { 0x00F8, GENMASK(11, 0), "Tx Excessive Deferral Packet", }, + { 0x00FC, GENMASK(11, 0), "Tx Single Collision Packet", }, + { 0x0100, GENMASK(11, 0), "Tx Multiple Collision", }, + { 0x0104, GENMASK(11, 0), "Tx Late Collision Packet", }, + { 0x0108, GENMASK(11, 0), "Tx Excessive Collision Packet", }, + { 0x010C, GENMASK(12, 0), "Tx Total Collision", }, + { 0x0110, GENMASK(11, 0), "Tx Pause Frames Honored", }, + { 0x0114, GENMASK(11, 0), "Tx Drop Frame", }, + { 0x0118, GENMASK(11, 0), "Tx Jabber Frame", }, + { 0x011C, GENMASK(11, 0), "Tx FCS Error", }, + { 0x0120, GENMASK(11, 0), "Tx Control Frame", }, + { 0x0124, GENMASK(11, 0), "Tx Oversize Frame", }, + { 0x0128, GENMASK(11, 0), "Tx Undersize Frame", }, + { 0x012C, GENMASK(11, 0), "Tx Fragment", }, +}; + #define DESC_EMPTY BIT(31) #define DESC_MORE BIT(24) #define DESC_PKTLEN_M 0xfff @@ -314,6 +367,8 @@ struct ag71xx { dma_addr_t stop_desc_dma; phy_interface_t phy_if_mode; + struct phylink *phylink; + struct phylink_config phylink_config; struct delayed_work restart_work; struct timer_list oom_timer; @@ -391,6 +446,110 @@ static void ag71xx_int_disable(struct ag71xx *ag, u32 ints) ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints); } +static void ag71xx_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct ag71xx *ag = netdev_priv(ndev); + + strscpy(info->driver, "ag71xx", sizeof(info->driver)); + strscpy(info->bus_info, of_node_full_name(ag->pdev->dev.of_node), + sizeof(info->bus_info)); +} + +static int ag71xx_get_link_ksettings(struct net_device *ndev, + struct ethtool_link_ksettings *kset) +{ + struct ag71xx *ag = netdev_priv(ndev); + + return phylink_ethtool_ksettings_get(ag->phylink, kset); +} + +static int ag71xx_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *kset) +{ + struct ag71xx *ag = netdev_priv(ndev); + + return phylink_ethtool_ksettings_set(ag->phylink, kset); +} + +static int ag71xx_ethtool_nway_reset(struct net_device *ndev) +{ + struct ag71xx *ag = netdev_priv(ndev); + + return phylink_ethtool_nway_reset(ag->phylink); +} + +static void ag71xx_ethtool_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pause) +{ + struct ag71xx *ag = netdev_priv(ndev); + + phylink_ethtool_get_pauseparam(ag->phylink, pause); +} + +static int ag71xx_ethtool_set_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pause) +{ + struct ag71xx *ag = netdev_priv(ndev); + + return phylink_ethtool_set_pauseparam(ag->phylink, pause); +} + +static void ag71xx_ethtool_get_strings(struct net_device *netdev, u32 sset, + u8 *data) +{ + int i; + + switch (sset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(ag71xx_statistics); i++) + memcpy(data + i * ETH_GSTRING_LEN, + ag71xx_statistics[i].name, ETH_GSTRING_LEN); + break; + case ETH_SS_TEST: + net_selftest_get_strings(data); + break; + } +} + +static void ag71xx_ethtool_get_stats(struct net_device *ndev, + struct ethtool_stats *stats, u64 *data) +{ + struct ag71xx *ag = netdev_priv(ndev); + int i; + + for (i = 0; i < ARRAY_SIZE(ag71xx_statistics); i++) + *data++ = ag71xx_rr(ag, ag71xx_statistics[i].offset) + & ag71xx_statistics[i].mask; +} + +static int ag71xx_ethtool_get_sset_count(struct net_device *ndev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ag71xx_statistics); + case ETH_SS_TEST: + return net_selftest_get_count(); + default: + return -EOPNOTSUPP; + } +} + +static const struct ethtool_ops ag71xx_ethtool_ops = { + .get_drvinfo = ag71xx_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, + .get_link_ksettings = ag71xx_get_link_ksettings, + .set_link_ksettings = ag71xx_set_link_ksettings, + .nway_reset = ag71xx_ethtool_nway_reset, + .get_pauseparam = ag71xx_ethtool_get_pauseparam, + .set_pauseparam = ag71xx_ethtool_set_pauseparam, + .get_strings = ag71xx_ethtool_get_strings, + .get_ethtool_stats = ag71xx_ethtool_get_stats, + .get_sset_count = ag71xx_ethtool_get_sset_count, + .self_test = net_selftest, +}; + static int ag71xx_mdio_wait_busy(struct ag71xx *ag) { struct net_device *ndev = ag->ndev; @@ -553,7 +712,8 @@ static int ag71xx_mdio_probe(struct ag71xx *ag) ag->mdio_reset = of_reset_control_get_exclusive(np, "mdio"); if (IS_ERR(ag->mdio_reset)) { netif_err(ag, probe, ndev, "Failed to get reset mdio.\n"); - return PTR_ERR(ag->mdio_reset); + err = PTR_ERR(ag->mdio_reset); + goto mdio_err_put_clk; } mii_bus->name = "ag71xx_mdio"; @@ -606,7 +766,7 @@ static bool ag71xx_check_dma_stuck(struct ag71xx *ag) unsigned long timestamp; u32 rx_sm, tx_sm, rx_fd; - timestamp = netdev_get_tx_queue(ag->ndev, 0)->trans_start; + timestamp = READ_ONCE(netdev_get_tx_queue(ag->ndev, 0)->trans_start); if (likely(time_before(jiffies, timestamp + HZ / 10))) return false; @@ -626,7 +786,7 @@ static bool ag71xx_check_dma_stuck(struct ag71xx *ag) return false; } -static int ag71xx_tx_packets(struct ag71xx *ag, bool flush) +static int ag71xx_tx_packets(struct ag71xx *ag, bool flush, int budget) { struct ag71xx_ring *ring = &ag->tx_ring; int sent = 0, bytes_compl = 0, n = 0; @@ -665,7 +825,7 @@ static int ag71xx_tx_packets(struct ag71xx *ag, bool flush) if (!skb) continue; - dev_kfree_skb_any(skb); + napi_consume_skb(skb, budget); ring->buf[i].tx.skb = NULL; bytes_compl += ring->buf[i].tx.len; @@ -783,10 +943,10 @@ static void ag71xx_hw_setup(struct ag71xx *ag) static unsigned int ag71xx_max_frame_len(unsigned int mtu) { - return ETH_SWITCH_HEADER_LEN + ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN; + return ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN; } -static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac) +static void ag71xx_hw_set_macaddr(struct ag71xx *ag, const unsigned char *mac) { u32 t; @@ -810,7 +970,7 @@ static void ag71xx_fast_reset(struct ag71xx *ag) mii_reg = ag71xx_rr(ag, AG71XX_REG_MII_CFG); rx_ds = ag71xx_rr(ag, AG71XX_REG_RX_DESC); - ag71xx_tx_packets(ag, true); + ag71xx_tx_packets(ag, true, 0); reset_control_assert(ag->mac_reset); usleep_range(10, 20); @@ -845,24 +1005,47 @@ static void ag71xx_hw_start(struct ag71xx *ag) netif_wake_queue(ag->ndev); } -static void ag71xx_link_adjust(struct ag71xx *ag, bool update) +static void ag71xx_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) { - struct phy_device *phydev = ag->ndev->phydev; - u32 cfg2; - u32 ifctl; - u32 fifo5; + struct ag71xx *ag = netdev_priv(to_net_dev(config->dev)); - if (!phydev->link && update) { - ag71xx_hw_stop(ag); + if (phylink_autoneg_inband(mode)) return; - } if (!ag71xx_is(ag, AR7100) && !ag71xx_is(ag, AR9130)) ag71xx_fast_reset(ag); + if (ag->tx_ring.desc_split) { + ag->fifodata[2] &= 0xffff; + ag->fifodata[2] |= ((2048 - ag->tx_ring.desc_split) / 4) << 16; + } + + ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, ag->fifodata[2]); +} + +static void ag71xx_mac_link_down(struct phylink_config *config, + unsigned int mode, phy_interface_t interface) +{ + struct ag71xx *ag = netdev_priv(to_net_dev(config->dev)); + + ag71xx_hw_stop(ag); +} + +static void ag71xx_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 ag71xx *ag = netdev_priv(to_net_dev(config->dev)); + u32 cfg1, cfg2; + u32 ifctl; + u32 fifo5; + cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2); cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX); - cfg2 |= (phydev->duplex) ? MAC_CFG2_FDX : 0; + cfg2 |= duplex ? MAC_CFG2_FDX : 0; ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL); ifctl &= ~(MAC_IFCTL_SPEED); @@ -870,7 +1053,7 @@ static void ag71xx_link_adjust(struct ag71xx *ag, bool update) fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5); fifo5 &= ~FIFO_CFG5_BM; - switch (phydev->speed) { + switch (speed) { case SPEED_1000: cfg2 |= MAC_CFG2_IF_1000; fifo5 |= FIFO_CFG5_BM; @@ -883,72 +1066,73 @@ static void ag71xx_link_adjust(struct ag71xx *ag, bool update) cfg2 |= MAC_CFG2_IF_10_100; break; default: - WARN(1, "not supported speed %i\n", phydev->speed); return; } - if (ag->tx_ring.desc_split) { - ag->fifodata[2] &= 0xffff; - ag->fifodata[2] |= ((2048 - ag->tx_ring.desc_split) / 4) << 16; - } - - ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, ag->fifodata[2]); - ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2); ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5); ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl); - ag71xx_hw_start(ag); - - if (update) - phy_print_status(phydev); -} + cfg1 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG1); + cfg1 &= ~(MAC_CFG1_TFC | MAC_CFG1_RFC); + if (tx_pause) + cfg1 |= MAC_CFG1_TFC; -static void ag71xx_phy_link_adjust(struct net_device *ndev) -{ - struct ag71xx *ag = netdev_priv(ndev); + if (rx_pause) + cfg1 |= MAC_CFG1_RFC; + ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, cfg1); - ag71xx_link_adjust(ag, true); + ag71xx_hw_start(ag); } -static int ag71xx_phy_connect(struct ag71xx *ag) -{ - struct device_node *np = ag->pdev->dev.of_node; - struct net_device *ndev = ag->ndev; - struct device_node *phy_node; - struct phy_device *phydev; - int ret; - - if (of_phy_is_fixed_link(np)) { - ret = of_phy_register_fixed_link(np); - if (ret < 0) { - netif_err(ag, probe, ndev, "Failed to register fixed PHY link: %d\n", - ret); - return ret; - } - - phy_node = of_node_get(np); - } else { - phy_node = of_parse_phandle(np, "phy-handle", 0); - } - - if (!phy_node) { - netif_err(ag, probe, ndev, "Could not find valid phy node\n"); - return -ENODEV; - } - - phydev = of_phy_connect(ag->ndev, phy_node, ag71xx_phy_link_adjust, - 0, ag->phy_if_mode); - - of_node_put(phy_node); - - if (!phydev) { - netif_err(ag, probe, ndev, "Could not connect to PHY device\n"); - return -ENODEV; - } - - phy_attached_info(phydev); +static const struct phylink_mac_ops ag71xx_phylink_mac_ops = { + .validate = phylink_generic_validate, + .mac_config = ag71xx_mac_config, + .mac_link_down = ag71xx_mac_link_down, + .mac_link_up = ag71xx_mac_link_up, +}; +static int ag71xx_phylink_setup(struct ag71xx *ag) +{ + struct phylink *phylink; + + ag->phylink_config.dev = &ag->ndev->dev; + ag->phylink_config.type = PHYLINK_NETDEV; + ag->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE | + MAC_10 | MAC_100 | MAC_1000FD; + + if ((ag71xx_is(ag, AR9330) && ag->mac_idx == 0) || + ag71xx_is(ag, AR9340) || + ag71xx_is(ag, QCA9530) || + (ag71xx_is(ag, QCA9550) && ag->mac_idx == 1)) + __set_bit(PHY_INTERFACE_MODE_MII, + ag->phylink_config.supported_interfaces); + + if ((ag71xx_is(ag, AR9330) && ag->mac_idx == 1) || + (ag71xx_is(ag, AR9340) && ag->mac_idx == 1) || + (ag71xx_is(ag, QCA9530) && ag->mac_idx == 1)) + __set_bit(PHY_INTERFACE_MODE_GMII, + ag->phylink_config.supported_interfaces); + + if (ag71xx_is(ag, QCA9550) && ag->mac_idx == 0) + __set_bit(PHY_INTERFACE_MODE_SGMII, + ag->phylink_config.supported_interfaces); + + if (ag71xx_is(ag, AR9340) && ag->mac_idx == 0) + __set_bit(PHY_INTERFACE_MODE_RMII, + ag->phylink_config.supported_interfaces); + + if ((ag71xx_is(ag, AR9340) && ag->mac_idx == 0) || + (ag71xx_is(ag, QCA9550) && ag->mac_idx == 1)) + __set_bit(PHY_INTERFACE_MODE_RGMII, + ag->phylink_config.supported_interfaces); + + phylink = phylink_create(&ag->phylink_config, ag->pdev->dev.fwnode, + ag->phy_if_mode, &ag71xx_phylink_mac_ops); + if (IS_ERR(phylink)) + return PTR_ERR(phylink); + + ag->phylink = phylink; return 0; } @@ -1239,6 +1423,13 @@ static int ag71xx_open(struct net_device *ndev) unsigned int max_frame_len; int ret; + ret = phylink_of_phy_connect(ag->phylink, ag->pdev->dev.of_node, 0); + if (ret) { + netif_err(ag, link, ndev, "phylink_of_phy_connect filed with err: %i\n", + ret); + goto err; + } + max_frame_len = ag71xx_max_frame_len(ndev->mtu); ag->rx_buf_size = SKB_DATA_ALIGN(max_frame_len + NET_SKB_PAD + NET_IP_ALIGN); @@ -1251,11 +1442,7 @@ static int ag71xx_open(struct net_device *ndev) if (ret) goto err; - ret = ag71xx_phy_connect(ag); - if (ret) - goto err; - - phy_start(ndev->phydev); + phylink_start(ag->phylink); return 0; @@ -1268,8 +1455,8 @@ static int ag71xx_stop(struct net_device *ndev) { struct ag71xx *ag = netdev_priv(ndev); - phy_stop(ndev->phydev); - phy_disconnect(ndev->phydev); + phylink_stop(ag->phylink); + phylink_disconnect_phy(ag->phylink); ag71xx_hw_disable(ag); return 0; @@ -1414,13 +1601,14 @@ static void ag71xx_restart_work_func(struct work_struct *work) { struct ag71xx *ag = container_of(work, struct ag71xx, restart_work.work); - struct net_device *ndev = ag->ndev; rtnl_lock(); ag71xx_hw_disable(ag); ag71xx_hw_enable(ag); - if (ndev->phydev->link) - ag71xx_link_adjust(ag, false); + + phylink_stop(ag->phylink); + phylink_start(ag->phylink); + rtnl_unlock(); } @@ -1429,9 +1617,9 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) struct net_device *ndev = ag->ndev; int ring_mask, ring_size, done = 0; unsigned int pktlen_mask, offset; - struct sk_buff *next, *skb; struct ag71xx_ring *ring; struct list_head rx_list; + struct sk_buff *skb; ring = &ag->rx_ring; pktlen_mask = ag->dcfg->desc_pktlen_mask; @@ -1469,7 +1657,7 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) ndev->stats.rx_packets++; ndev->stats.rx_bytes += pktlen; - skb = build_skb(ring->buf[i].rx.rx_buf, ag71xx_buffer_size(ag)); + skb = napi_build_skb(ring->buf[i].rx.rx_buf, ag71xx_buffer_size(ag)); if (!skb) { skb_free_frag(ring->buf[i].rx.rx_buf); goto next; @@ -1496,7 +1684,7 @@ next: ag71xx_ring_rx_refill(ag); - list_for_each_entry_safe(skb, next, &rx_list, list) + list_for_each_entry(skb, &rx_list, list) skb->protocol = eth_type_trans(skb, ndev); netif_receive_skb_list(&rx_list); @@ -1515,7 +1703,7 @@ static int ag71xx_poll(struct napi_struct *napi, int limit) int tx_done, rx_done; u32 status; - tx_done = ag71xx_tx_packets(ag, false); + tx_done = ag71xx_tx_packets(ag, false, limit); netif_dbg(ag, rx_status, ndev, "processing RX ring\n"); rx_done = ag71xx_rx_packets(ag, limit); @@ -1610,7 +1798,7 @@ static const struct net_device_ops ag71xx_netdev_ops = { .ndo_open = ag71xx_open, .ndo_stop = ag71xx_stop, .ndo_start_xmit = ag71xx_hard_start_xmit, - .ndo_do_ioctl = phy_do_ioctl, + .ndo_eth_ioctl = phy_do_ioctl, .ndo_tx_timeout = ag71xx_tx_timeout, .ndo_change_mtu = ag71xx_change_mtu, .ndo_set_mac_address = eth_mac_addr, @@ -1627,7 +1815,6 @@ static int ag71xx_probe(struct platform_device *pdev) const struct ag71xx_dcfg *dcfg; struct net_device *ndev; struct resource *res; - const void *mac_addr; int tx_size, err, i; struct ag71xx *ag; @@ -1675,15 +1862,12 @@ static int ag71xx_probe(struct platform_device *pdev) ag->mac_reset = devm_reset_control_get(&pdev->dev, "mac"); if (IS_ERR(ag->mac_reset)) { netif_err(ag, probe, ndev, "missing mac reset\n"); - err = PTR_ERR(ag->mac_reset); - goto err_free; + return PTR_ERR(ag->mac_reset); } ag->mac_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!ag->mac_base) { - err = -ENOMEM; - goto err_free; - } + if (!ag->mac_base) + return -ENOMEM; ndev->irq = platform_get_irq(pdev, 0); err = devm_request_irq(&pdev->dev, ndev->irq, ag71xx_interrupt, @@ -1691,10 +1875,11 @@ static int ag71xx_probe(struct platform_device *pdev) if (err) { netif_err(ag, probe, ndev, "unable to request IRQ %d\n", ndev->irq); - goto err_free; + return err; } ndev->netdev_ops = &ag71xx_netdev_ops; + ndev->ethtool_ops = &ag71xx_ethtool_ops; INIT_DELAYED_WORK(&ag->restart_work, ag71xx_restart_work_func); timer_setup(&ag->oom_timer, ag71xx_oom_timer_handler, 0); @@ -1718,35 +1903,32 @@ static int ag71xx_probe(struct platform_device *pdev) ag->stop_desc = dmam_alloc_coherent(&pdev->dev, sizeof(struct ag71xx_desc), &ag->stop_desc_dma, GFP_KERNEL); - if (!ag->stop_desc) { - err = -ENOMEM; - goto err_free; - } + if (!ag->stop_desc) + return -ENOMEM; ag->stop_desc->data = 0; ag->stop_desc->ctrl = 0; ag->stop_desc->next = (u32)ag->stop_desc_dma; - mac_addr = of_get_mac_address(np); - if (!IS_ERR(mac_addr)) - memcpy(ndev->dev_addr, mac_addr, ETH_ALEN); - if (IS_ERR(mac_addr) || !is_valid_ether_addr(ndev->dev_addr)) { + err = of_get_ethdev_address(np, ndev); + if (err) { netif_err(ag, probe, ndev, "invalid MAC address, using random address\n"); - eth_random_addr(ndev->dev_addr); + eth_hw_addr_random(ndev); } err = of_get_phy_mode(np, &ag->phy_if_mode); if (err) { netif_err(ag, probe, ndev, "missing phy-mode property in DT\n"); - goto err_free; + return err; } - netif_napi_add(ndev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT); + netif_napi_add_weight(ndev, &ag->napi, ag71xx_poll, + AG71XX_NAPI_WEIGHT); err = clk_prepare_enable(ag->clk_eth); if (err) { netif_err(ag, probe, ndev, "Failed to enable eth clk.\n"); - goto err_free; + return err; } ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, 0); @@ -1759,6 +1941,12 @@ static int ag71xx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); + err = ag71xx_phylink_setup(ag); + if (err) { + netif_err(ag, probe, ndev, "failed to setup phylink (%d)\n", err); + goto err_mdio_remove; + } + err = register_netdev(ndev); if (err) { netif_err(ag, probe, ndev, "unable to register net device\n"); @@ -1776,8 +1964,6 @@ err_mdio_remove: ag71xx_mdio_remove(ag); err_put_clk: clk_disable_unprepare(ag->clk_eth); -err_free: - free_netdev(ndev); return err; } |