diff options
Diffstat (limited to 'drivers/net/ethernet/ti/davinci_emac.c')
-rw-r--r-- | drivers/net/ethernet/ti/davinci_emac.c | 182 |
1 files changed, 111 insertions, 71 deletions
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 75d4e16c692b..2eb9d5a32588 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -113,7 +113,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1"; #define EMAC_DEF_RX_NUM_DESC (128) #define EMAC_DEF_MAX_TX_CH (1) /* Max TX channels configured */ #define EMAC_DEF_MAX_RX_CH (1) /* Max RX channels configured */ -#define EMAC_POLL_WEIGHT (64) /* Default NAPI poll weight */ /* Buffer descriptor parameters */ #define EMAC_DEF_TX_MAX_SERVICE (32) /* TX max service BD's */ @@ -169,11 +168,11 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1"; /* EMAC mac_status register */ #define EMAC_MACSTATUS_TXERRCODE_MASK (0xF00000) #define EMAC_MACSTATUS_TXERRCODE_SHIFT (20) -#define EMAC_MACSTATUS_TXERRCH_MASK (0x7) +#define EMAC_MACSTATUS_TXERRCH_MASK (0x70000) #define EMAC_MACSTATUS_TXERRCH_SHIFT (16) #define EMAC_MACSTATUS_RXERRCODE_MASK (0xF000) #define EMAC_MACSTATUS_RXERRCODE_SHIFT (12) -#define EMAC_MACSTATUS_RXERRCH_MASK (0x7) +#define EMAC_MACSTATUS_RXERRCH_MASK (0x700) #define EMAC_MACSTATUS_RXERRCH_SHIFT (8) /* EMAC RX register masks */ @@ -375,20 +374,24 @@ static char *emac_rxhost_errcodes[16] = { static void emac_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { - strlcpy(info->driver, emac_version_string, sizeof(info->driver)); - strlcpy(info->version, EMAC_MODULE_VERSION, sizeof(info->version)); + strscpy(info->driver, emac_version_string, sizeof(info->driver)); + strscpy(info->version, EMAC_MODULE_VERSION, sizeof(info->version)); } /** * emac_get_coalesce - Get interrupt coalesce settings for this device * @ndev : The DaVinci EMAC network adapter * @coal : ethtool coalesce settings structure + * @kernel_coal: ethtool CQE mode setting structure + * @extack: extack for reporting error messages * * Fetch the current interrupt coalesce settings * */ static int emac_get_coalesce(struct net_device *ndev, - struct ethtool_coalesce *coal) + struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) { struct emac_priv *priv = netdev_priv(ndev); @@ -401,19 +404,35 @@ static int emac_get_coalesce(struct net_device *ndev, * emac_set_coalesce - Set interrupt coalesce settings for this device * @ndev : The DaVinci EMAC network adapter * @coal : ethtool coalesce settings structure + * @kernel_coal: ethtool CQE mode setting structure + * @extack: extack for reporting error messages * * Set interrupt coalesce parameters * */ static int emac_set_coalesce(struct net_device *ndev, - struct ethtool_coalesce *coal) + struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) { struct emac_priv *priv = netdev_priv(ndev); u32 int_ctrl, num_interrupts = 0; u32 prescale = 0, addnl_dvdr = 1, coal_intvl = 0; - if (!coal->rx_coalesce_usecs) - return -EINVAL; + if (!coal->rx_coalesce_usecs) { + priv->coal_intvl = 0; + + switch (priv->version) { + case EMAC_VERSION_2: + emac_ctrl_write(EMAC_DM646X_CMINTCTRL, 0); + break; + default: + emac_ctrl_write(EMAC_CTRL_EWINTTCNT, 0); + break; + } + + return 0; + } coal_intvl = coal->rx_coalesce_usecs; @@ -481,6 +500,7 @@ static int emac_set_coalesce(struct net_device *ndev, * Ethtool support for EMAC adapter */ static const struct ethtool_ops ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, .get_drvinfo = emac_get_drvinfo, .get_link = ethtool_op_get_link, .get_coalesce = emac_get_coalesce, @@ -670,7 +690,7 @@ static int emac_hash_del(struct emac_priv *priv, u8 *mac_addr) * emac_add_mcast - Set multicast address in the EMAC adapter (Internal) * @priv: The DaVinci EMAC private adapter structure * @action: multicast operation to perform - * mac_addr: mac address to set + * @mac_addr: mac address to set * * Set multicast addresses in EMAC adapter - internal function * @@ -929,7 +949,7 @@ static void emac_tx_handler(void *token, int len, int status) * * Returns success(NETDEV_TX_OK) or error code (typically out of desc's) */ -static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev) { struct device *emac_dev = &ndev->dev; int ret_code; @@ -942,7 +962,7 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev) goto fail_tx; } - ret_code = skb_padto(skb, EMAC_DEF_MIN_ETHPKTSIZE); + ret_code = skb_put_padto(skb, EMAC_DEF_MIN_ETHPKTSIZE); if (unlikely(ret_code < 0)) { if (netif_msg_tx_err(priv) && net_ratelimit()) dev_err(emac_dev, "DaVinci EMAC: packet pad failed"); @@ -976,6 +996,7 @@ fail_tx: /** * emac_dev_tx_timeout - EMAC Transmit timeout function * @ndev: The DaVinci EMAC network adapter + * @txqueue: the index of the hung transmit queue * * Called when system detects that a skb timeout period has expired * potentially due to a fault in the adapter in not being able to send @@ -1122,7 +1143,7 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr) /* Store mac addr in priv and rx channel and set it in EMAC hw */ memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len); - memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len); + eth_hw_addr_set(ndev, sa->sa_data); /* MAC address is configured only after the interface is enabled. */ if (netif_running(ndev)) { @@ -1208,7 +1229,7 @@ static int emac_hw_enable(struct emac_priv *priv) /** * emac_poll - EMAC NAPI Poll function - * @ndev: The DaVinci EMAC network adapter + * @napi: pointer to the napi_struct containing The DaVinci EMAC network adapter * @budget: Number of receive packets to process (as told by NAPI layer) * * NAPI Poll function implemented to process packets as per budget. We check @@ -1226,7 +1247,7 @@ static int emac_poll(struct napi_struct *napi, int budget) struct net_device *ndev = priv->ndev; struct device *emac_dev = &ndev->dev; u32 status = 0; - u32 num_tx_pkts = 0, num_rx_pkts = 0; + u32 num_rx_pkts = 0; /* Check interrupt vectors and call packet processing */ status = emac_read(EMAC_MACINVECTOR); @@ -1237,8 +1258,7 @@ static int emac_poll(struct napi_struct *napi, int budget) mask = EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC; if (status & mask) { - num_tx_pkts = cpdma_chan_process(priv->txchan, - EMAC_DEF_TX_MAX_SERVICE); + cpdma_chan_process(priv->txchan, EMAC_DEF_TX_MAX_SERVICE); } /* TX processing */ mask = EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC; @@ -1393,7 +1413,6 @@ static int match_first_device(struct device *dev, const void *data) static int emac_dev_open(struct net_device *ndev) { struct device *emac_dev = &ndev->dev; - u32 cnt; struct resource *res; int q, m, ret; int res_num = 0, irq_num = 0; @@ -1402,17 +1421,15 @@ static int emac_dev_open(struct net_device *ndev) struct phy_device *phydev = NULL; struct device *phy = NULL; - ret = pm_runtime_get_sync(&priv->pdev->dev); + ret = pm_runtime_resume_and_get(&priv->pdev->dev); if (ret < 0) { - pm_runtime_put_noidle(&priv->pdev->dev); dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n", __func__, ret); return ret; } netif_carrier_off(ndev); - for (cnt = 0; cnt < ETH_ALEN; cnt++) - ndev->dev_addr[cnt] = priv->mac_addr[cnt]; + eth_hw_addr_set(ndev, priv->mac_addr); /* Configuration items */ priv->rx_buf_size = EMAC_DEF_MAX_FRAME_SIZE + NET_IP_ALIGN; @@ -1435,23 +1452,33 @@ static int emac_dev_open(struct net_device *ndev) } /* Request IRQ */ - while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, - res_num))) { - for (irq_num = res->start; irq_num <= res->end; irq_num++) { - if (request_irq(irq_num, emac_irq, 0, ndev->name, - ndev)) { - dev_err(emac_dev, - "DaVinci EMAC: request_irq() failed\n"); - ret = -EBUSY; + if (dev_of_node(&priv->pdev->dev)) { + while ((ret = platform_get_irq_optional(priv->pdev, res_num)) != -ENXIO) { + if (ret < 0) + goto rollback; + ret = request_irq(ret, emac_irq, 0, ndev->name, ndev); + if (ret) { + dev_err(emac_dev, "DaVinci EMAC: request_irq() failed\n"); goto rollback; } + res_num++; } - res_num++; + } else { + while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, res_num))) { + for (irq_num = res->start; irq_num <= res->end; irq_num++) { + ret = request_irq(irq_num, emac_irq, 0, ndev->name, ndev); + if (ret) { + dev_err(emac_dev, "DaVinci EMAC: request_irq() failed\n"); + goto rollback; + } + } + res_num++; + } + /* prepare counters for rollback in case of an error */ + res_num--; + irq_num--; } - /* prepare counters for rollback in case of an error */ - res_num--; - irq_num--; /* Start/Enable EMAC hardware */ emac_hw_enable(priv); @@ -1461,7 +1488,7 @@ static int emac_dev_open(struct net_device *ndev) struct ethtool_coalesce coal; coal.rx_coalesce_usecs = (priv->coal_intvl << 4); - emac_set_coalesce(ndev, &coal); + emac_set_coalesce(ndev, &coal, NULL, NULL); } cpdma_ctlr_start(priv->dma); @@ -1535,16 +1562,24 @@ err: napi_disable(&priv->napi); rollback: - for (q = res_num; q >= 0; q--) { - res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, q); - /* at the first iteration, irq_num is already set to the - * right value - */ - if (q != res_num) - irq_num = res->end; + if (dev_of_node(&priv->pdev->dev)) { + for (q = res_num - 1; q >= 0; q--) { + irq_num = platform_get_irq(priv->pdev, q); + if (irq_num > 0) + free_irq(irq_num, ndev); + } + } else { + for (q = res_num; q >= 0; q--) { + res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, q); + /* at the first iteration, irq_num is already set to the + * right value + */ + if (q != res_num) + irq_num = res->end; - for (m = irq_num; m >= res->start; m--) - free_irq(m, ndev); + for (m = irq_num; m >= res->start; m--) + free_irq(m, ndev); + } } cpdma_ctlr_stop(priv->dma); pm_runtime_put(&priv->pdev->dev); @@ -1567,6 +1602,7 @@ static int emac_dev_stop(struct net_device *ndev) int irq_num; struct emac_priv *priv = netdev_priv(ndev); struct device *emac_dev = &ndev->dev; + int ret = 0; /* inform the upper layers. */ netif_stop_queue(ndev); @@ -1581,17 +1617,31 @@ static int emac_dev_stop(struct net_device *ndev) phy_disconnect(ndev->phydev); /* Free IRQ */ - while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) { - for (irq_num = res->start; irq_num <= res->end; irq_num++) - free_irq(irq_num, priv->ndev); - i++; + if (dev_of_node(&priv->pdev->dev)) { + do { + ret = platform_get_irq_optional(priv->pdev, i); + if (ret < 0 && ret != -ENXIO) + break; + if (ret > 0) { + free_irq(ret, priv->ndev); + } else { + ret = 0; + break; + } + } while (++i); + } else { + while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) { + for (irq_num = res->start; irq_num <= res->end; irq_num++) + free_irq(irq_num, priv->ndev); + i++; + } } if (netif_msg_drv(priv)) dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name); pm_runtime_put(&priv->pdev->dev); - return 0; + return ret; } /** @@ -1609,9 +1659,8 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev) u32 stats_clear_mask; int err; - err = pm_runtime_get_sync(&priv->pdev->dev); + err = pm_runtime_resume_and_get(&priv->pdev->dev); if (err < 0) { - pm_runtime_put_noidle(&priv->pdev->dev); dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n", __func__, err); return &ndev->stats; @@ -1669,7 +1718,7 @@ static const struct net_device_ops emac_netdev_ops = { .ndo_start_xmit = emac_dev_xmit, .ndo_set_rx_mode = emac_dev_mcast_set, .ndo_set_mac_address = emac_dev_setmac_addr, - .ndo_do_ioctl = emac_devioctl, + .ndo_eth_ioctl = emac_devioctl, .ndo_tx_timeout = emac_dev_tx_timeout, .ndo_get_stats = emac_dev_getnetstats, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1686,7 +1735,6 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) const struct of_device_id *match; const struct emac_platform_data *auxdata; struct emac_platform_data *pdata = NULL; - const u8 *mac_addr; if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) return dev_get_platdata(&pdev->dev); @@ -1698,11 +1746,8 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) np = pdev->dev.of_node; pdata->version = EMAC_VERSION_2; - if (!is_valid_ether_addr(pdata->mac_addr)) { - mac_addr = of_get_mac_address(np); - if (!IS_ERR(mac_addr)) - ether_addr_copy(pdata->mac_addr, mac_addr); - } + if (!is_valid_ether_addr(pdata->mac_addr)) + of_get_mac_address(np, pdata->mac_addr); of_property_read_u32(np, "ti,davinci-ctrl-reg-offset", &pdata->ctrl_reg_offset); @@ -1817,13 +1862,12 @@ static int davinci_emac_probe(struct platform_device *pdev) priv->bus_freq_mhz = (u32)(emac_bus_frequency / 1000000); /* Get EMAC platform data */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->emac_base_phys = res->start + pdata->ctrl_reg_offset; - priv->remap_addr = devm_ioremap_resource(&pdev->dev, res); + priv->remap_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(priv->remap_addr)) { rc = PTR_ERR(priv->remap_addr); goto no_pdata; } + priv->emac_base_phys = res->start + pdata->ctrl_reg_offset; res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res_ctrl) { @@ -1885,17 +1929,14 @@ static int davinci_emac_probe(struct platform_device *pdev) goto err_free_txchan; } - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, "error getting irq res\n"); - rc = -ENOENT; + rc = platform_get_irq(pdev, 0); + if (rc < 0) goto err_free_rxchan; - } - ndev->irq = res->start; + ndev->irq = rc; rc = davinci_emac_try_get_mac(pdev, res_ctrl ? 0 : 1, priv->mac_addr); if (!rc) - ether_addr_copy(ndev->dev_addr, priv->mac_addr); + eth_hw_addr_set(ndev, priv->mac_addr); if (!is_valid_ether_addr(priv->mac_addr)) { /* Use random MAC if still none obtained. */ @@ -1907,12 +1948,11 @@ static int davinci_emac_probe(struct platform_device *pdev) ndev->netdev_ops = &emac_netdev_ops; ndev->ethtool_ops = ðtool_ops; - netif_napi_add(ndev, &priv->napi, emac_poll, EMAC_POLL_WEIGHT); + netif_napi_add(ndev, &priv->napi, emac_poll); pm_runtime_enable(&pdev->dev); - rc = pm_runtime_get_sync(&pdev->dev); + rc = pm_runtime_resume_and_get(&pdev->dev); if (rc < 0) { - pm_runtime_put_noidle(&pdev->dev); dev_err(&pdev->dev, "%s: failed to get_sync(%d)\n", __func__, rc); goto err_napi_del; |