diff options
Diffstat (limited to 'drivers/net/ethernet')
91 files changed, 2733 insertions, 3577 deletions
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 05aa759..31c5e47 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -29,6 +29,7 @@ source "drivers/net/ethernet/apm/Kconfig" source "drivers/net/ethernet/apple/Kconfig" source "drivers/net/ethernet/arc/Kconfig" source "drivers/net/ethernet/atheros/Kconfig" +source "drivers/net/ethernet/aurora/Kconfig" source "drivers/net/ethernet/cadence/Kconfig" source "drivers/net/ethernet/adi/Kconfig" source "drivers/net/ethernet/broadcom/Kconfig" @@ -78,7 +79,6 @@ source "drivers/net/ethernet/ibm/Kconfig" source "drivers/net/ethernet/intel/Kconfig" source "drivers/net/ethernet/i825xx/Kconfig" source "drivers/net/ethernet/xscale/Kconfig" -source "drivers/net/ethernet/icplus/Kconfig" config JME tristate "JMicron(R) PCI-Express Gigabit Ethernet support" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index ddfc808..071f84e 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_NET_XGENE) += apm/ obj-$(CONFIG_NET_VENDOR_APPLE) += apple/ obj-$(CONFIG_NET_VENDOR_ARC) += arc/ obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/ +obj-$(CONFIG_NET_VENDOR_AURORA) += aurora/ obj-$(CONFIG_NET_CADENCE) += cadence/ obj-$(CONFIG_NET_BFIN) += adi/ obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/ @@ -41,7 +42,6 @@ obj-$(CONFIG_NET_VENDOR_IBM) += ibm/ obj-$(CONFIG_NET_VENDOR_INTEL) += intel/ obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/ obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/ -obj-$(CONFIG_IP1000) += icplus/ obj-$(CONFIG_JME) += jme.o obj-$(CONFIG_KORINA) += korina.o obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index e2afabf..7ccebae 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -1500,10 +1500,11 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENODEV; } - if (!pci_set_dma_mask(pdev, PCNET32_DMA_MASK)) { + err = pci_set_dma_mask(pdev, PCNET32_DMA_MASK); + if (err) { if (pcnet32_debug & NETIF_MSG_PROBE) pr_err("architecture does not support 32bit PCI busmaster DMA\n"); - return -ENODEV; + return err; } if (!request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci")) { if (pcnet32_debug & NETIF_MSG_PROBE) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 970781a..f6a7161 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1849,7 +1849,7 @@ static int xgbe_exit(struct xgbe_prv_data *pdata) usleep_range(10, 15); /* Poll Until Poll Condition */ - while (count-- && XGMAC_IOREAD_BITS(pdata, DMA_MR, SWR)) + while (--count && XGMAC_IOREAD_BITS(pdata, DMA_MR, SWR)) usleep_range(500, 600); if (!count) @@ -1873,7 +1873,7 @@ static int xgbe_flush_tx_queues(struct xgbe_prv_data *pdata) /* Poll Until Poll Condition */ for (i = 0; i < pdata->tx_q_count; i++) { count = 2000; - while (count-- && XGMAC_MTL_IOREAD_BITS(pdata, i, + while (--count && XGMAC_MTL_IOREAD_BITS(pdata, i, MTL_Q_TQOMR, FTQ)) usleep_range(500, 600); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 991412c..d0ae1a6 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -289,6 +289,7 @@ static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring, struct sk_buff *skb) { struct device *dev = ndev_to_dev(tx_ring->ndev); + struct xgene_enet_pdata *pdata = netdev_priv(tx_ring->ndev); struct xgene_enet_raw_desc *raw_desc; __le64 *exp_desc = NULL, *exp_bufs = NULL; dma_addr_t dma_addr, pbuf_addr, *frag_dma_addr; @@ -419,6 +420,7 @@ out: raw_desc->m0 = cpu_to_le64(SET_VAL(LL, ll) | SET_VAL(NV, nv) | SET_VAL(USERINFO, tx_ring->tail)); tx_ring->cp_ring->cp_skb[tx_ring->tail] = skb; + pdata->tx_level += count; tx_ring->tail = tail; return count; @@ -429,14 +431,13 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, { struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring; - struct xgene_enet_desc_ring *cp_ring = tx_ring->cp_ring; - u32 tx_level, cq_level; + u32 tx_level = pdata->tx_level; int count; - tx_level = pdata->ring_ops->len(tx_ring); - cq_level = pdata->ring_ops->len(cp_ring); - if (unlikely(tx_level > pdata->tx_qcnt_hi || - cq_level > pdata->cp_qcnt_hi)) { + if (tx_level < pdata->txc_level) + tx_level += ((typeof(pdata->tx_level))~0U); + + if ((tx_level - pdata->txc_level) > pdata->tx_qcnt_hi) { netif_stop_queue(ndev); return NETDEV_TX_BUSY; } @@ -450,12 +451,12 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } - pdata->ring_ops->wr_cmd(tx_ring, count); skb_tx_timestamp(skb); pdata->stats.tx_packets++; pdata->stats.tx_bytes += skb->len; + pdata->ring_ops->wr_cmd(tx_ring, count); return NETDEV_TX_OK; } @@ -539,10 +540,13 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, struct xgene_enet_raw_desc *raw_desc, *exp_desc; u16 head = ring->head; u16 slots = ring->slots - 1; - int ret, count = 0, processed = 0; + int ret, desc_count, count = 0, processed = 0; + bool is_completion; do { raw_desc = &ring->raw_desc[head]; + desc_count = 0; + is_completion = false; exp_desc = NULL; if (unlikely(xgene_enet_is_desc_slot_empty(raw_desc))) break; @@ -559,18 +563,24 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, } dma_rmb(); count++; + desc_count++; } - if (is_rx_desc(raw_desc)) + if (is_rx_desc(raw_desc)) { ret = xgene_enet_rx_frame(ring, raw_desc); - else + } else { ret = xgene_enet_tx_completion(ring, raw_desc); + is_completion = true; + } xgene_enet_mark_desc_slot_empty(raw_desc); if (exp_desc) xgene_enet_mark_desc_slot_empty(exp_desc); head = (head + 1) & slots; count++; + desc_count++; processed++; + if (is_completion) + pdata->txc_level += desc_count; if (ret) break; @@ -580,10 +590,8 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, pdata->ring_ops->wr_cmd(ring, -count); ring->head = head; - if (netif_queue_stopped(ring->ndev)) { - if (pdata->ring_ops->len(ring) < pdata->cp_qcnt_low) - netif_wake_queue(ring->ndev); - } + if (netif_queue_stopped(ring->ndev)) + netif_start_queue(ring->ndev); } return processed; @@ -688,10 +696,10 @@ static int xgene_enet_open(struct net_device *ndev) mac_ops->tx_enable(pdata); mac_ops->rx_enable(pdata); + xgene_enet_napi_enable(pdata); ret = xgene_enet_register_irq(ndev); if (ret) return ret; - xgene_enet_napi_enable(pdata); if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) phy_start(pdata->phy_dev); @@ -715,13 +723,13 @@ static int xgene_enet_close(struct net_device *ndev) else cancel_delayed_work_sync(&pdata->link_work); - xgene_enet_napi_disable(pdata); - xgene_enet_free_irq(ndev); - xgene_enet_process_ring(pdata->rx_ring, -1); - mac_ops->tx_disable(pdata); mac_ops->rx_disable(pdata); + xgene_enet_free_irq(ndev); + xgene_enet_napi_disable(pdata); + xgene_enet_process_ring(pdata->rx_ring, -1); + return 0; } @@ -1033,9 +1041,7 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) pdata->tx_ring->cp_ring = cp_ring; pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring); - pdata->tx_qcnt_hi = pdata->tx_ring->slots / 2; - pdata->cp_qcnt_hi = pdata->rx_ring->slots / 2; - pdata->cp_qcnt_low = pdata->cp_qcnt_hi / 2; + pdata->tx_qcnt_hi = pdata->tx_ring->slots - 128; return 0; @@ -1474,15 +1480,15 @@ static int xgene_enet_probe(struct platform_device *pdev) } ndev->hw_features = ndev->features; - ret = register_netdev(ndev); + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (ret) { - netdev_err(ndev, "Failed to register netdev\n"); + netdev_err(ndev, "No usable DMA configuration\n"); goto err; } - ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); + ret = register_netdev(ndev); if (ret) { - netdev_err(ndev, "No usable DMA configuration\n"); + netdev_err(ndev, "Failed to register netdev\n"); goto err; } @@ -1490,14 +1496,17 @@ static int xgene_enet_probe(struct platform_device *pdev) if (ret) goto err; - xgene_enet_napi_add(pdata); mac_ops = pdata->mac_ops; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { ret = xgene_enet_mdio_config(pdata); - else + if (ret) + goto err; + } else { INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state); + } - return ret; + xgene_enet_napi_add(pdata); + return 0; err: unregister_netdev(ndev); free_netdev(ndev); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index a6e56b8..1aa72c7 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -155,11 +155,11 @@ struct xgene_enet_pdata { enum xgene_enet_id enet_id; struct xgene_enet_desc_ring *tx_ring; struct xgene_enet_desc_ring *rx_ring; + u16 tx_level; + u16 txc_level; char *dev_name; u32 rx_buff_cnt; u32 tx_qcnt_hi; - u32 cp_qcnt_hi; - u32 cp_qcnt_low; u32 rx_irq; u32 txc_irq; u8 cq_cnt; diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index c8af3ce..bd377a6 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1534,6 +1534,8 @@ static const struct pci_device_id alx_pci_tbl[] = { .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200), .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, + { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2400), + .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162), .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) }, diff --git a/drivers/net/ethernet/atheros/alx/reg.h b/drivers/net/ethernet/atheros/alx/reg.h index af006b4..0959e68 100644 --- a/drivers/net/ethernet/atheros/alx/reg.h +++ b/drivers/net/ethernet/atheros/alx/reg.h @@ -37,6 +37,7 @@ #define ALX_DEV_ID_AR8161 0x1091 #define ALX_DEV_ID_E2200 0xe091 +#define ALX_DEV_ID_E2400 0xe0a1 #define ALX_DEV_ID_AR8162 0x1090 #define ALX_DEV_ID_AR8171 0x10A1 #define ALX_DEV_ID_AR8172 0x10A0 diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 2795d6d..8b5988e 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1016,13 +1016,12 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) sizeof(struct atl1c_recv_ret_status) * rx_desc_count + 8 * 4; - ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, - &ring_header->dma); + ring_header->desc = dma_zalloc_coherent(&pdev->dev, ring_header->size, + &ring_header->dma, GFP_KERNEL); if (unlikely(!ring_header->desc)) { - dev_err(&pdev->dev, "pci_alloc_consistend failed\n"); + dev_err(&pdev->dev, "could not get memory for DMA buffer\n"); goto err_nomem; } - memset(ring_header->desc, 0, ring_header->size); /* init TPD ring */ tpd_ring[0].dma = roundup(ring_header->dma, 8); diff --git a/drivers/net/ethernet/aurora/Kconfig b/drivers/net/ethernet/aurora/Kconfig new file mode 100644 index 0000000..8ba7f8f --- /dev/null +++ b/drivers/net/ethernet/aurora/Kconfig @@ -0,0 +1,21 @@ +config NET_VENDOR_AURORA + bool "Aurora VLSI devices" + help + If you have a network (Ethernet) device belonging to this class, + say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + questions about Aurora devices. If you say Y, you will be asked + for your specific device in the following questions. + +if NET_VENDOR_AURORA + +config AURORA_NB8800 + tristate "Aurora AU-NB8800 support" + depends on HAS_DMA + select PHYLIB + help + Support for the AU-NB8800 gigabit Ethernet controller. + +endif diff --git a/drivers/net/ethernet/aurora/Makefile b/drivers/net/ethernet/aurora/Makefile new file mode 100644 index 0000000..6cb528a --- /dev/null +++ b/drivers/net/ethernet/aurora/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_AURORA_NB8800) += nb8800.o diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c new file mode 100644 index 0000000..ecc4a33 --- /dev/null +++ b/drivers/net/ethernet/aurora/nb8800.c @@ -0,0 +1,1552 @@ +/* + * Copyright (C) 2015 Mans Rullgard <mans@mansr.com> + * + * Mostly rewritten, based on driver from Sigma Designs. Original + * copyright notice below. + * + * + * Driver for tangox SMP864x/SMP865x/SMP867x/SMP868x builtin Ethernet Mac. + * + * Copyright (C) 2005 Maxime Bizon <mbizon@freebox.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/etherdevice.h> +#include <linux/delay.h> +#include <linux/ethtool.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> +#include <linux/of_mdio.h> +#include <linux/of_net.h> +#include <linux/dma-mapping.h> +#include <linux/phy.h> +#include <linux/cache.h> +#include <linux/jiffies.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <asm/barrier.h> + +#include "nb8800.h" + +static void nb8800_tx_done(struct net_device *dev); +static int nb8800_dma_stop(struct net_device *dev); + +static inline u8 nb8800_readb(struct nb8800_priv *priv, int reg) +{ + return readb_relaxed(priv->base + reg); +} + +static inline u32 nb8800_readl(struct nb8800_priv *priv, int reg) +{ + return readl_relaxed(priv->base + reg); +} + +static inline void nb8800_writeb(struct nb8800_priv *priv, int reg, u8 val) +{ + writeb_relaxed(val, priv->base + reg); +} + +static inline void nb8800_writew(struct nb8800_priv *priv, int reg, u16 val) +{ + writew_relaxed(val, priv->base + reg); +} + +static inline void nb8800_writel(struct nb8800_priv *priv, int reg, u32 val) +{ + writel_relaxed(val, priv->base + reg); +} + +static inline void nb8800_maskb(struct nb8800_priv *priv, int reg, + u32 mask, u32 val) +{ + u32 old = nb8800_readb(priv, reg); + u32 new = (old & ~mask) | (val & mask); + + if (new != old) + nb8800_writeb(priv, reg, new); +} + +static inline void nb8800_maskl(struct nb8800_priv *priv, int reg, + u32 mask, u32 val) +{ + u32 old = nb8800_readl(priv, reg); + u32 new = (old & ~mask) | (val & mask); + + if (new != old) + nb8800_writel(priv, reg, new); +} + +static inline void nb8800_modb(struct nb8800_priv *priv, int reg, u8 bits, + bool set) +{ + nb8800_maskb(priv, reg, bits, set ? bits : 0); +} + +static inline void nb8800_setb(struct nb8800_priv *priv, int reg, u8 bits) +{ + nb8800_maskb(priv, reg, bits, bits); +} + +static inline void nb8800_clearb(struct nb8800_priv *priv, int reg, u8 bits) +{ + nb8800_maskb(priv, reg, bits, 0); +} + +static inline void nb8800_modl(struct nb8800_priv *priv, int reg, u32 bits, + bool set) +{ + nb8800_maskl(priv, reg, bits, set ? bits : 0); +} + +static inline void nb8800_setl(struct nb8800_priv *priv, int reg, u32 bits) +{ + nb8800_maskl(priv, reg, bits, bits); +} + +static inline void nb8800_clearl(struct nb8800_priv *priv, int reg, u32 bits) +{ + nb8800_maskl(priv, reg, bits, 0); +} + +static int nb8800_mdio_wait(struct mii_bus *bus) +{ + struct nb8800_priv *priv = bus->priv; + u32 val; + + return readl_poll_timeout_atomic(priv->base + NB8800_MDIO_CMD, + val, !(val & MDIO_CMD_GO), 1, 1000); +} + +static int nb8800_mdio_cmd(struct mii_bus *bus, u32 cmd) +{ + struct nb8800_priv *priv = bus->priv; + int err; + + err = nb8800_mdio_wait(bus); + if (err) + return err; + + nb8800_writel(priv, NB8800_MDIO_CMD, cmd); + udelay(10); + nb8800_writel(priv, NB8800_MDIO_CMD, cmd | MDIO_CMD_GO); + + return nb8800_mdio_wait(bus); +} + +static int nb8800_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct nb8800_priv *priv = bus->priv; + u32 val; + int err; + + err = nb8800_mdio_cmd(bus, MDIO_CMD_ADDR(phy_id) | MDIO_CMD_REG(reg)); + if (err) + return err; + + val = nb8800_readl(priv, NB8800_MDIO_STS); + if (val & MDIO_STS_ERR) + return 0xffff; + + return val & 0xffff; +} + +static int nb8800_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) +{ + u32 cmd = MDIO_CMD_ADDR(phy_id) | MDIO_CMD_REG(reg) | + MDIO_CMD_DATA(val) | MDIO_CMD_WR; + + return nb8800_mdio_cmd(bus, cmd); +} + +static void nb8800_mac_tx(struct net_device *dev, bool enable) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + while (nb8800_readl(priv, NB8800_TXC_CR) & TCR_EN) + cpu_relax(); + + nb8800_modb(priv, NB8800_TX_CTL1, TX_EN, enable); +} + +static void nb8800_mac_rx(struct net_device *dev, bool enable) +{ + nb8800_modb(netdev_priv(dev), NB8800_RX_CTL, RX_EN, enable); +} + +static void nb8800_mac_af(struct net_device *dev, bool enable) +{ + nb8800_modb(netdev_priv(dev), NB8800_RX_CTL, RX_AF_EN, enable); +} + +static void nb8800_start_rx(struct net_device *dev) +{ + nb8800_setl(netdev_priv(dev), NB8800_RXC_CR, RCR_EN); +} + +static int nb8800_alloc_rx(struct net_device *dev, unsigned int i, bool napi) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_rx_desc *rxd = &priv->rx_descs[i]; + struct nb8800_rx_buf *rxb = &priv->rx_bufs[i]; + int size = L1_CACHE_ALIGN(RX_BUF_SIZE); + dma_addr_t dma_addr; + struct page *page; + unsigned long offset; + void *data; + + data = napi ? napi_alloc_frag(size) : netdev_alloc_frag(size); + if (!data) + return -ENOMEM; + + page = virt_to_head_page(data); + offset = data - page_address(page); + + dma_addr = dma_map_page(&dev->dev, page, offset, RX_BUF_SIZE, + DMA_FROM_DEVICE); + + if (dma_mapping_error(&dev->dev, dma_addr)) { + skb_free_frag(data); + return -ENOMEM; + } + + rxb->page = page; + rxb->offset = offset; + rxd->desc.s_addr = dma_addr; + + return 0; +} + +static void nb8800_receive(struct net_device *dev, unsigned int i, + unsigned int len) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_rx_desc *rxd = &priv->rx_descs[i]; + struct page *page = priv->rx_bufs[i].page; + int offset = priv->rx_bufs[i].offset; + void *data = page_address(page) + offset; + dma_addr_t dma = rxd->desc.s_addr; + struct sk_buff *skb; + unsigned int size; + int err; + + size = len <= RX_COPYBREAK ? len : RX_COPYHDR; + + skb = napi_alloc_skb(&priv->napi, size); + if (!skb) { + netdev_err(dev, "rx skb allocation failed\n"); + dev->stats.rx_dropped++; + return; + } + + if (len <= RX_COPYBREAK) { + dma_sync_single_for_cpu(&dev->dev, dma, len, DMA_FROM_DEVICE); + memcpy(skb_put(skb, len), data, len); + dma_sync_single_for_device(&dev->dev, dma, len, + DMA_FROM_DEVICE); + } else { + err = nb8800_alloc_rx(dev, i, true); + if (err) { + netdev_err(dev, "rx buffer allocation failed\n"); + dev->stats.rx_dropped++; + return; + } + + dma_unmap_page(&dev->dev, dma, RX_BUF_SIZE, DMA_FROM_DEVICE); + memcpy(skb_put(skb, RX_COPYHDR), data, RX_COPYHDR); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + offset + RX_COPYHDR, len - RX_COPYHDR, + RX_BUF_SIZE); + } + + skb->protocol = eth_type_trans(skb, dev); + napi_gro_receive(&priv->napi, skb); +} + +static void nb8800_rx_error(struct net_device *dev, u32 report) +{ + if (report & RX_LENGTH_ERR) + dev->stats.rx_length_errors++; + + if (report & RX_FCS_ERR) + dev->stats.rx_crc_errors++; + + if (report & RX_FIFO_OVERRUN) + dev->stats.rx_fifo_errors++; + + if (report & RX_ALIGNMENT_ERROR) + dev->stats.rx_frame_errors++; + + dev->stats.rx_errors++; +} + +static int nb8800_poll(struct napi_struct *napi, int budget) +{ + struct net_device *dev = napi->dev; + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_rx_desc *rxd; + unsigned int last = priv->rx_eoc; + unsigned int next; + int work = 0; + + nb8800_tx_done(dev); + +again: + while (work < budget) { + struct nb8800_rx_buf *rxb; + unsigned int len; + + next = (last + 1) % RX_DESC_COUNT; + + rxb = &priv->rx_bufs[next]; + rxd = &priv->rx_descs[next]; + + if (!rxd->report) + break; + + len = RX_BYTES_TRANSFERRED(rxd->report); + + if (IS_RX_ERROR(rxd->report)) + nb8800_rx_error(dev, rxd->report); + else + nb8800_receive(dev, next, len); + + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; + + if (rxd->report & RX_MULTICAST_PKT) + dev->stats.multicast++; + + rxd->report = 0; + last = next; + work++; + } + + if (work) { + priv->rx_descs[last].desc.config |= DESC_EOC; + wmb(); /* ensure new EOC is written before clearing old */ + priv->rx_descs[priv->rx_eoc].desc.config &= ~DESC_EOC; + priv->rx_eoc = last; + nb8800_start_rx(dev); + } + + if (work < budget) { + nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_irq); + + /* If a packet arrived after we last checked but + * before writing RX_ITR, the interrupt will be + * delayed, so we retrieve it now. + */ + if (priv->rx_descs[next].report) + goto again; + + napi_complete_done(napi, work); + } + + return work; +} + +static void __nb8800_tx_dma_start(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_tx_buf *txb; + u32 txc_cr; + + txb = &priv->tx_bufs[priv->tx_queue]; + if (!txb->ready) + return; + + txc_cr = nb8800_readl(priv, NB8800_TXC_CR); + if (txc_cr & TCR_EN) + return; + + nb8800_writel(priv, NB8800_TX_DESC_ADDR, txb->dma_desc); + wmb(); /* ensure desc addr is written before starting DMA */ + nb8800_writel(priv, NB8800_TXC_CR, txc_cr | TCR_EN); + + priv->tx_queue = (priv->tx_queue + txb->chain_len) % TX_DESC_COUNT; +} + +static void nb8800_tx_dma_start(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + spin_lock_irq(&priv->tx_lock); + __nb8800_tx_dma_start(dev); + spin_unlock_irq(&priv->tx_lock); +} + +static void nb8800_tx_dma_start_irq(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + spin_lock(&priv->tx_lock); + __nb8800_tx_dma_start(dev); + spin_unlock(&priv->tx_lock); +} + +static int nb8800_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_tx_desc *txd; + struct nb8800_tx_buf *txb; + struct nb8800_dma_desc *desc; + dma_addr_t dma_addr; + unsigned int dma_len; + unsigned int align; + unsigned int next; + + if (atomic_read(&priv->tx_free) <= NB8800_DESC_LOW) { + netif_stop_queue(dev); + return NETDEV_TX_BUSY; + } + + align = (8 - (uintptr_t)skb->data) & 7; + + dma_len = skb->len - align; + dma_addr = dma_map_single(&dev->dev, skb->data + align, + dma_len, DMA_TO_DEVICE); + + if (dma_mapping_error(&dev->dev, dma_addr)) { + netdev_err(dev, "tx dma mapping error\n"); + kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + if (atomic_dec_return(&priv->tx_free) <= NB8800_DESC_LOW) { + netif_stop_queue(dev); + skb->xmit_more = 0; + } + + next = priv->tx_next; + txb = &priv->tx_bufs[next]; + txd = &priv->tx_descs[next]; + desc = &txd->desc[0]; + + next = (next + 1) % TX_DESC_COUNT; + + if (align) { + memcpy(txd->buf, skb->data, align); + + desc->s_addr = + txb->dma_desc + offsetof(struct nb8800_tx_desc, buf); + desc->n_addr = txb->dma_desc + sizeof(txd->desc[0]); + desc->config = DESC_BTS(2) | DESC_DS | align; + + desc++; + } + + desc->s_addr = dma_addr; + desc->n_addr = priv->tx_bufs[next].dma_desc; + desc->config = DESC_BTS(2) | DESC_DS | DESC_EOF | dma_len; + + if (!skb->xmit_more) + desc->config |= DESC_EOC; + + txb->skb = skb; + txb->dma_addr = dma_addr; + txb->dma_len = dma_len; + + if (!priv->tx_chain) { + txb->chain_len = 1; + priv->tx_chain = txb; + } else { + priv->tx_chain->chain_len++; + } + + netdev_sent_queue(dev, skb->len); + + priv->tx_next = next; + + if (!skb->xmit_more) { + smp_wmb(); + priv->tx_chain->ready = true; + priv->tx_chain = NULL; + nb8800_tx_dma_start(dev); + } + + return NETDEV_TX_OK; +} + +static void nb8800_tx_error(struct net_device *dev, u32 report) +{ + if (report & TX_LATE_COLLISION) + dev->stats.collisions++; + + if (report & TX_PACKET_DROPPED) + dev->stats.tx_dropped++; + + if (report & TX_FIFO_UNDERRUN) + dev->stats.tx_fifo_errors++; + + dev->stats.tx_errors++; +} + +static void nb8800_tx_done(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + unsigned int limit = priv->tx_next; + unsigned int done = priv->tx_done; + unsigned int packets = 0; + unsigned int len = 0; + + while (done != limit) { + struct nb8800_tx_desc *txd = &priv->tx_descs[done]; + struct nb8800_tx_buf *txb = &priv->tx_bufs[done]; + struct sk_buff *skb; + + if (!txd->report) + break; + + skb = txb->skb; + len += skb->len; + + dma_unmap_single(&dev->dev, txb->dma_addr, txb->dma_len, + DMA_TO_DEVICE); + + if (IS_TX_ERROR(txd->report)) { + nb8800_tx_error(dev, txd->report); + kfree_skb(skb); + } else { + consume_skb(skb); + } + + dev->stats.tx_packets++; + dev->stats.tx_bytes += TX_BYTES_TRANSFERRED(txd->report); + dev->stats.collisions += TX_EARLY_COLLISIONS(txd->report); + + txb->skb = NULL; + txb->ready = false; + txd->report = 0; + + done = (done + 1) % TX_DESC_COUNT; + packets++; + } + + if (packets) { + smp_mb__before_atomic(); + atomic_add(packets, &priv->tx_free); + netdev_completed_queue(dev, packets, len); + netif_wake_queue(dev); + priv->tx_done = done; + } +} + +static irqreturn_t nb8800_irq(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct nb8800_priv *priv = netdev_priv(dev); + irqreturn_t ret = IRQ_NONE; + u32 val; + + /* tx interrupt */ + val = nb8800_readl(priv, NB8800_TXC_SR); + if (val) { + nb8800_writel(priv, NB8800_TXC_SR, val); + + if (val & TSR_DI) + nb8800_tx_dma_start_irq(dev); + + if (val & TSR_TI) + napi_schedule_irqoff(&priv->napi); + + if (unlikely(val & TSR_DE)) + netdev_err(dev, "TX DMA error\n"); + + /* should never happen with automatic status retrieval */ + if (unlikely(val & TSR_TO)) + netdev_err(dev, "TX Status FIFO overflow\n"); + + ret = IRQ_HANDLED; + } + + /* rx interrupt */ + val = nb8800_readl(priv, NB8800_RXC_SR); + if (val) { + nb8800_writel(priv, NB8800_RXC_SR, val); + + if (likely(val & (RSR_RI | RSR_DI))) { + nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_poll); + napi_schedule_irqoff(&priv->napi); + } + + if (unlikely(val & RSR_DE)) + netdev_err(dev, "RX DMA error\n"); + + /* should never happen with automatic status retrieval */ + if (unlikely(val & RSR_RO)) + netdev_err(dev, "RX Status FIFO overflow\n"); + + ret = IRQ_HANDLED; + } + + return ret; +} + +static void nb8800_mac_config(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + bool gigabit = priv->speed == SPEED_1000; + u32 mac_mode_mask = RGMII_MODE | HALF_DUPLEX | GMAC_MODE; + u32 mac_mode = 0; + u32 slot_time; + u32 phy_clk; + u32 ict; + + if (!priv->duplex) + mac_mode |= HALF_DUPLEX; + + if (gigabit) { + if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII) + mac_mode |= RGMII_MODE; + + mac_mode |= GMAC_MODE; + phy_clk = 125000000; + + /* Should be 512 but register is only 8 bits */ + slot_time = 255; + } else { + phy_clk = 25000000; + slot_time = 128; + } + + ict = DIV_ROUND_UP(phy_clk, clk_get_rate(priv->clk)); + + nb8800_writeb(priv, NB8800_IC_THRESHOLD, ict); + nb8800_writeb(priv, NB8800_SLOT_TIME, slot_time); + nb8800_maskb(priv, NB8800_MAC_MODE, mac_mode_mask, mac_mode); +} + +static void nb8800_pause_config(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + u32 rxcr; + + if (priv->pause_aneg) { + if (!phydev || !phydev->link) + return; + + priv->pause_rx = phydev->pause; + priv->pause_tx = phydev->pause ^ phydev->asym_pause; + } + + nb8800_modb(priv, NB8800_RX_CTL, RX_PAUSE_EN, priv->pause_rx); + + rxcr = nb8800_readl(priv, NB8800_RXC_CR); + if (!!(rxcr & RCR_FL) == priv->pause_tx) + return; + + if (netif_running(dev)) { + napi_disable(&priv->napi); + netif_tx_lock_bh(dev); + nb8800_dma_stop(dev); + nb8800_modl(priv, NB8800_RXC_CR, RCR_FL, priv->pause_tx); + nb8800_start_rx(dev); + netif_tx_unlock_bh(dev); + napi_enable(&priv->napi); + } else { + nb8800_modl(priv, NB8800_RXC_CR, RCR_FL, priv->pause_tx); + } +} + +static void nb8800_link_reconfigure(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + int change = 0; + + if (phydev->link) { + if (phydev->speed != priv->speed) { + priv->speed = phydev->speed; + change = 1; + } + + if (phydev->duplex != priv->duplex) { + priv->duplex = phydev->duplex; + change = 1; + } + + if (change) + nb8800_mac_config(dev); + + nb8800_pause_config(dev); + } + + if (phydev->link != priv->link) { + priv->link = phydev->link; + change = 1; + } + + if (change) + phy_print_status(priv->phydev); +} + +static void nb8800_update_mac_addr(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + int i; + + for (i = 0; i < ETH_ALEN; i++) + nb8800_writeb(priv, NB8800_SRC_ADDR(i), dev->dev_addr[i]); + + for (i = 0; i < ETH_ALEN; i++) + nb8800_writeb(priv, NB8800_UC_ADDR(i), dev->dev_addr[i]); +} + +static int nb8800_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *sock = addr; + + if (netif_running(dev)) + return -EBUSY; + + ether_addr_copy(dev->dev_addr, sock->sa_data); + nb8800_update_mac_addr(dev); + + return 0; +} + +static void nb8800_mc_init(struct net_device *dev, int val) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + nb8800_writeb(priv, NB8800_MC_INIT, val); + readb_poll_timeout_atomic(priv->base + NB8800_MC_INIT, val, !val, + 1, 1000); +} + +static void nb8800_set_rx_mode(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct netdev_hw_addr *ha; + int i; + + if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { + nb8800_mac_af(dev, false); + return; + } + + nb8800_mac_af(dev, true); + nb8800_mc_init(dev, 0); + + netdev_for_each_mc_addr(ha, dev) { + for (i = 0; i < ETH_ALEN; i++) + nb8800_writeb(priv, NB8800_MC_ADDR(i), ha->addr[i]); + + nb8800_mc_init(dev, 0xff); + } +} + +#define RX_DESC_SIZE (RX_DESC_COUNT * sizeof(struct nb8800_rx_desc)) +#define TX_DESC_SIZE (TX_DESC_COUNT * sizeof(struct nb8800_tx_desc)) + +static void nb8800_dma_free(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + unsigned int i; + + if (priv->rx_bufs) { + for (i = 0; i < RX_DESC_COUNT; i++) + if (priv->rx_bufs[i].page) + put_page(priv->rx_bufs[i].page); + + kfree(priv->rx_bufs); + priv->rx_bufs = NULL; + } + + if (priv->tx_bufs) { + for (i = 0; i < TX_DESC_COUNT; i++) + kfree_skb(priv->tx_bufs[i].skb); + + kfree(priv->tx_bufs); + priv->tx_bufs = NULL; + } + + if (priv->rx_descs) { + dma_free_coherent(dev->dev.parent, RX_DESC_SIZE, priv->rx_descs, + priv->rx_desc_dma); + priv->rx_descs = NULL; + } + + if (priv->tx_descs) { + dma_free_coherent(dev->dev.parent, TX_DESC_SIZE, priv->tx_descs, + priv->tx_desc_dma); + priv->tx_descs = NULL; + } +} + +static void nb8800_dma_reset(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_rx_desc *rxd; + struct nb8800_tx_desc *txd; + unsigned int i; + + for (i = 0; i < RX_DESC_COUNT; i++) { + dma_addr_t rx_dma = priv->rx_desc_dma + i * sizeof(*rxd); + + rxd = &priv->rx_descs[i]; + rxd->desc.n_addr = rx_dma + sizeof(*rxd); + rxd->desc.r_addr = + rx_dma + offsetof(struct nb8800_rx_desc, report); + rxd->desc.config = priv->rx_dma_config; + rxd->report = 0; + } + + rxd->desc.n_addr = priv->rx_desc_dma; + rxd->desc.config |= DESC_EOC; + + priv->rx_eoc = RX_DESC_COUNT - 1; + + for (i = 0; i < TX_DESC_COUNT; i++) { + struct nb8800_tx_buf *txb = &priv->tx_bufs[i]; + dma_addr_t r_dma = txb->dma_desc + + offsetof(struct nb8800_tx_desc, report); + + txd = &priv->tx_descs[i]; + txd->desc[0].r_addr = r_dma; + txd->desc[1].r_addr = r_dma; + txd->report = 0; + } + + priv->tx_next = 0; + priv->tx_queue = 0; + priv->tx_done = 0; + atomic_set(&priv->tx_free, TX_DESC_COUNT); + + nb8800_writel(priv, NB8800_RX_DESC_ADDR, priv->rx_desc_dma); + + wmb(); /* ensure all setup is written before starting */ +} + +static int nb8800_dma_init(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + unsigned int n_rx = RX_DESC_COUNT; + unsigned int n_tx = TX_DESC_COUNT; + unsigned int i; + int err; + + priv->rx_descs = dma_alloc_coherent(dev->dev.parent, RX_DESC_SIZE, + &priv->rx_desc_dma, GFP_KERNEL); + if (!priv->rx_descs) + goto err_out; + + priv->rx_bufs = kcalloc(n_rx, sizeof(*priv->rx_bufs), GFP_KERNEL); + if (!priv->rx_bufs) + goto err_out; + + for (i = 0; i < n_rx; i++) { + err = nb8800_alloc_rx(dev, i, false); + if (err) + goto err_out; + } + + priv->tx_descs = dma_alloc_coherent(dev->dev.parent, TX_DESC_SIZE, + &priv->tx_desc_dma, GFP_KERNEL); + if (!priv->tx_descs) + goto err_out; + + priv->tx_bufs = kcalloc(n_tx, sizeof(*priv->tx_bufs), GFP_KERNEL); + if (!priv->tx_bufs) + goto err_out; + + for (i = 0; i < n_tx; i++) + priv->tx_bufs[i].dma_desc = + priv->tx_desc_dma + i * sizeof(struct nb8800_tx_desc); + + nb8800_dma_reset(dev); + + return 0; + +err_out: + nb8800_dma_free(dev); + + return -ENOMEM; +} + +static int nb8800_dma_stop(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_tx_buf *txb = &priv->tx_bufs[0]; + struct nb8800_tx_desc *txd = &priv->tx_descs[0]; + int retry = 5; + u32 txcr; + u32 rxcr; + int err; + unsigned int i; + + /* wait for tx to finish */ + err = readl_poll_timeout_atomic(priv->base + NB8800_TXC_CR, txcr, + !(txcr & TCR_EN) && + priv->tx_done == priv->tx_next, + 1000, 1000000); + if (err) + return err; + + /* The rx DMA only stops if it reaches the end of chain. + * To make this happen, we set the EOC flag on all rx + * descriptors, put the device in loopback mode, and send + * a few dummy frames. The interrupt handler will ignore + * these since NAPI is disabled and no real frames are in + * the tx queue. + */ + + for (i = 0; i < RX_DESC_COUNT; i++) + priv->rx_descs[i].desc.config |= DESC_EOC; + + txd->desc[0].s_addr = + txb->dma_desc + offsetof(struct nb8800_tx_desc, buf); + txd->desc[0].config = DESC_BTS(2) | DESC_DS | DESC_EOF | DESC_EOC | 8; + memset(txd->buf, 0, sizeof(txd->buf)); + + nb8800_mac_af(dev, false); + nb8800_setb(priv, NB8800_MAC_MODE, LOOPBACK_EN); + + do { + nb8800_writel(priv, NB8800_TX_DESC_ADDR, txb->dma_desc); + wmb(); + nb8800_writel(priv, NB8800_TXC_CR, txcr | TCR_EN); + + err = readl_poll_timeout_atomic(priv->base + NB8800_RXC_CR, + rxcr, !(rxcr & RCR_EN), + 1000, 100000); + } while (err && --retry); + + nb8800_mac_af(dev, true); + nb8800_clearb(priv, NB8800_MAC_MODE, LOOPBACK_EN); + nb8800_dma_reset(dev); + + return retry ? 0 : -ETIMEDOUT; +} + +static void nb8800_pause_adv(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + u32 adv = 0; + + if (!priv->phydev) + return; + + if (priv->pause_rx) + adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; + if (priv->pause_tx) + adv ^= ADVERTISED_Asym_Pause; + + priv->phydev->supported |= adv; + priv->phydev->advertising |= adv; +} + +static int nb8800_open(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + int err; + + /* clear any pending interrupts */ + nb8800_writel(priv, NB8800_RXC_SR, 0xf); + nb8800_writel(priv, NB8800_TXC_SR, 0xf); + + err = nb8800_dma_init(dev); + if (err) + return err; + + err = request_irq(dev->irq, nb8800_irq, 0, dev_name(&dev->dev), dev); + if (err) + goto err_free_dma; + + nb8800_mac_rx(dev, true); + nb8800_mac_tx(dev, true); + + priv->phydev = of_phy_connect(dev, priv->phy_node, + nb8800_link_reconfigure, 0, + priv->phy_mode); + if (!priv->phydev) + goto err_free_irq; + + nb8800_pause_adv(dev); + + netdev_reset_queue(dev); + napi_enable(&priv->napi); + netif_start_queue(dev); + + nb8800_start_rx(dev); + phy_start(priv->phydev); + + return 0; + +err_free_irq: + free_irq(dev->irq, dev); +err_free_dma: + nb8800_dma_free(dev); + + return err; +} + +static int nb8800_stop(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + phy_stop(priv->phydev); + + netif_stop_queue(dev); + napi_disable(&priv->napi); + + nb8800_dma_stop(dev); + nb8800_mac_rx(dev, false); + nb8800_mac_tx(dev, false); + + phy_disconnect(priv->phydev); + priv->phydev = NULL; + + free_irq(dev->irq, dev); + + nb8800_dma_free(dev); + + return 0; +} + +static int nb8800_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + return phy_mii_ioctl(priv->phydev, rq, cmd); +} + +static const struct net_device_ops nb8800_netdev_ops = { + .ndo_open = nb8800_open, + .ndo_stop = nb8800_stop, + .ndo_start_xmit = nb8800_xmit, + .ndo_set_mac_address = nb8800_set_mac_address, + .ndo_set_rx_mode = nb8800_set_rx_mode, + .ndo_do_ioctl = nb8800_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + +static int nb8800_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + if (!priv->phydev) + return -ENODEV; + + return phy_ethtool_gset(priv->phydev, cmd); +} + +static int nb8800_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + if (!priv->phydev) + return -ENODEV; + + return phy_ethtool_sset(priv->phydev, cmd); +} + +static int nb8800_nway_reset(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + if (!priv->phydev) + return -ENODEV; + + return genphy_restart_aneg(priv->phydev); +} + +static void nb8800_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pp) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + pp->autoneg = priv->pause_aneg; + pp->rx_pause = priv->pause_rx; + pp->tx_pause = priv->pause_tx; +} + +static int nb8800_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pp) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + priv->pause_aneg = pp->autoneg; + priv->pause_rx = pp->rx_pause; + priv->pause_tx = pp->tx_pause; + + nb8800_pause_adv(dev); + + if (!priv->pause_aneg) + nb8800_pause_config(dev); + else if (priv->phydev) + phy_start_aneg(priv->phydev); + + return 0; +} + +static const char nb8800_stats_names[][ETH_GSTRING_LEN] = { + "rx_bytes_ok", + "rx_frames_ok", + "rx_undersize_frames", + "rx_fragment_frames", + "rx_64_byte_frames", + "rx_127_byte_frames", + "rx_255_byte_frames", + "rx_511_byte_frames", + "rx_1023_byte_frames", + "rx_max_size_frames", + "rx_oversize_frames", + "rx_bad_fcs_frames", + "rx_broadcast_frames", + "rx_multicast_frames", + "rx_control_frames", + "rx_pause_frames", + "rx_unsup_control_frames", + "rx_align_error_frames", + "rx_overrun_frames", + "rx_jabber_frames", + "rx_bytes", + "rx_frames", + + "tx_bytes_ok", + "tx_frames_ok", + "tx_64_byte_frames", + "tx_127_byte_frames", + "tx_255_byte_frames", + "tx_511_byte_frames", + "tx_1023_byte_frames", + "tx_max_size_frames", + "tx_oversize_frames", + "tx_broadcast_frames", + "tx_multicast_frames", + "tx_control_frames", + "tx_pause_frames", + "tx_underrun_frames", + "tx_single_collision_frames", + "tx_multi_collision_frames", + "tx_deferred_collision_frames", + "tx_late_collision_frames", + "tx_excessive_collision_frames", + "tx_bytes", + "tx_frames", + "tx_collisions", +}; + +#define NB8800_NUM_STATS ARRAY_SIZE(nb8800_stats_names) + +static int nb8800_get_sset_count(struct net_device *dev, int sset) +{ + if (sset == ETH_SS_STATS) + return NB8800_NUM_STATS; + + return -EOPNOTSUPP; +} + +static void nb8800_get_strings(struct net_device *dev, u32 sset, u8 *buf) +{ + if (sset == ETH_SS_STATS) + memcpy(buf, &nb8800_stats_names, sizeof(nb8800_stats_names)); +} + +static u32 nb8800_read_stat(struct net_device *dev, int index) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + nb8800_writeb(priv, NB8800_STAT_INDEX, index); + + return nb8800_readl(priv, NB8800_STAT_DATA); +} + +static void nb8800_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *estats, u64 *st) +{ + unsigned int i; + u32 rx, tx; + + for (i = 0; i < NB8800_NUM_STATS / 2; i++) { + rx = nb8800_read_stat(dev, i); + tx = nb8800_read_stat(dev, i | 0x80); + st[i] = rx; + st[i + NB8800_NUM_STATS / 2] = tx; + } +} + +static const struct ethtool_ops nb8800_ethtool_ops = { + .get_settings = nb8800_get_settings, + .set_settings = nb8800_set_settings, + .nway_reset = nb8800_nway_reset, + .get_link = ethtool_op_get_link, + .get_pauseparam = nb8800_get_pauseparam, + .set_pauseparam = nb8800_set_pauseparam, + .get_sset_count = nb8800_get_sset_count, + .get_strings = nb8800_get_strings, + .get_ethtool_stats = nb8800_get_ethtool_stats, +}; + +static int nb8800_hw_init(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + u32 val; + + val = TX_RETRY_EN | TX_PAD_EN | TX_APPEND_FCS; + nb8800_writeb(priv, NB8800_TX_CTL1, val); + + /* Collision retry count */ + nb8800_writeb(priv, NB8800_TX_CTL2, 5); + + val = RX_PAD_STRIP | RX_AF_EN; + nb8800_writeb(priv, NB8800_RX_CTL, val); + + /* Chosen by fair dice roll */ + nb8800_writeb(priv, NB8800_RANDOM_SEED, 4); + + /* TX cycles per deferral period */ + nb8800_writeb(priv, NB8800_TX_SDP, 12); + + /* The following three threshold values have been + * experimentally determined for good results. + */ + + /* RX/TX FIFO threshold for partial empty (64-bit entries) */ + nb8800_writeb(priv, NB8800_PE_THRESHOLD, 0); + + /* RX/TX FIFO threshold for partial full (64-bit entries) */ + nb8800_writeb(priv, NB8800_PF_THRESHOLD, 255); + + /* Buffer size for transmit (64-bit entries) */ + nb8800_writeb(priv, NB8800_TX_BUFSIZE, 64); + + /* Configure tx DMA */ + + val = nb8800_readl(priv, NB8800_TXC_CR); + val &= TCR_LE; /* keep endian setting */ + val |= TCR_DM; /* DMA descriptor mode */ + val |= TCR_RS; /* automatically store tx status */ + val |= TCR_DIE; /* interrupt on DMA chain completion */ + val |= TCR_TFI(7); /* interrupt after 7 frames transmitted */ + val |= TCR_BTS(2); /* 32-byte bus transaction size */ + nb8800_writel(priv, NB8800_TXC_CR, val); + + /* TX complete interrupt after 10 ms or 7 frames (see above) */ + val = clk_get_rate(priv->clk) / 100; + nb8800_writel(priv, NB8800_TX_ITR, val); + + /* Configure rx DMA */ + + val = nb8800_readl(priv, NB8800_RXC_CR); + val &= RCR_LE; /* keep endian setting */ + val |= RCR_DM; /* DMA descriptor mode */ + val |= RCR_RS; /* automatically store rx status */ + val |= RCR_DIE; /* interrupt at end of DMA chain */ + val |= RCR_RFI(7); /* interrupt after 7 frames received */ + val |= RCR_BTS(2); /* 32-byte bus transaction size */ + nb8800_writel(priv, NB8800_RXC_CR, val); + + /* The rx interrupt can fire before the DMA has completed + * unless a small delay is added. 50 us is hopefully enough. + */ + priv->rx_itr_irq = clk_get_rate(priv->clk) / 20000; + + /* In NAPI poll mode we want to disable interrupts, but the + * hardware does not permit this. Delay 10 ms instead. + */ + priv->rx_itr_poll = clk_get_rate(priv->clk) / 100; + + nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_irq); + + priv->rx_dma_config = RX_BUF_SIZE | DESC_BTS(2) | DESC_DS | DESC_EOF; + + /* Flow control settings */ + + /* Pause time of 0.1 ms */ + val = 100000 / 512; + nb8800_writeb(priv, NB8800_PQ1, val >> 8); + nb8800_writeb(priv, NB8800_PQ2, val & 0xff); + + /* Auto-negotiate by default */ + priv->pause_aneg = true; + priv->pause_rx = true; + priv->pause_tx = true; + + nb8800_mc_init(dev, 0); + + return 0; +} + +static int nb8800_tangox_init(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + u32 pad_mode = PAD_MODE_MII; + + switch (priv->phy_mode) { + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: + pad_mode = PAD_MODE_MII; + break; + + case PHY_INTERFACE_MODE_RGMII: + pad_mode = PAD_MODE_RGMII; + break; + + case PHY_INTERFACE_MODE_RGMII_TXID: + pad_mode = PAD_MODE_RGMII | PAD_MODE_GTX_CLK_DELAY; + break; + + default: + dev_err(dev->dev.parent, "unsupported phy mode %s\n", + phy_modes(priv->phy_mode)); + return -EINVAL; + } + + nb8800_writeb(priv, NB8800_TANGOX_PAD_MODE, pad_mode); + + return 0; +} + +static int nb8800_tangox_reset(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + int clk_div; + + nb8800_writeb(priv, NB8800_TANGOX_RESET, 0); + usleep_range(1000, 10000); + nb8800_writeb(priv, NB8800_TANGOX_RESET, 1); + + wmb(); /* ensure reset is cleared before proceeding */ + + clk_div = DIV_ROUND_UP(clk_get_rate(priv->clk), 2 * MAX_MDC_CLOCK); + nb8800_writew(priv, NB8800_TANGOX_MDIO_CLKDIV, clk_div); + + return 0; +} + +static const struct nb8800_ops nb8800_tangox_ops = { + .init = nb8800_tangox_init, + .reset = nb8800_tangox_reset, +}; + +static int nb8800_tango4_init(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + int err; + + err = nb8800_tangox_init(dev); + if (err) + return err; + + /* On tango4 interrupt on DMA completion per frame works and gives + * better performance despite generating more rx interrupts. + */ + + /* Disable unnecessary interrupt on rx completion */ + nb8800_clearl(priv, NB8800_RXC_CR, RCR_RFI(7)); + + /* Request interrupt on descriptor DMA completion */ + priv->rx_dma_config |= DESC_ID; + + return 0; +} + +static const struct nb8800_ops nb8800_tango4_ops = { + .init = nb8800_tango4_init, + .reset = nb8800_tangox_reset, +}; + +static const struct of_device_id nb8800_dt_ids[] = { + { + .compatible = "aurora,nb8800", + }, + { + .compatible = "sigma,smp8642-ethernet", + .data = &nb8800_tangox_ops, + }, + { + .compatible = "sigma,smp8734-ethernet", + .data = &nb8800_tango4_ops, + }, + { } +}; + +static int nb8800_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct nb8800_ops *ops = NULL; + struct nb8800_priv *priv; + struct resource *res; + struct net_device *dev; + struct mii_bus *bus; + const unsigned char *mac; + void __iomem *base; + int irq; + int ret; + + match = of_match_device(nb8800_dt_ids, &pdev->dev); + if (match) + ops = match->data; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "No IRQ\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + dev_dbg(&pdev->dev, "AU-NB8800 Ethernet at %pa\n", &res->start); + + dev = alloc_etherdev(sizeof(*priv)); + if (!dev) + return -ENOMEM; + + platform_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + priv = netdev_priv(dev); + priv->base = base; + + priv->phy_mode = of_get_phy_mode(pdev->dev.of_node); + if (priv->phy_mode < 0) + priv->phy_mode = PHY_INTERFACE_MODE_RGMII; + + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + ret = PTR_ERR(priv->clk); + goto err_free_dev; + } + + ret = clk_prepare_enable(priv->clk); + if (ret) + goto err_free_dev; + + spin_lock_init(&priv->tx_lock); + + if (ops && ops->reset) { + ret = ops->reset(dev); + if (ret) + goto err_free_dev; + } + + bus = devm_mdiobus_alloc(&pdev->dev); + if (!bus) { + ret = -ENOMEM; + goto err_disable_clk; + } + + bus->name = "nb8800-mii"; + bus->read = nb8800_mdio_read; + bus->write = nb8800_mdio_write; + bus->parent = &pdev->dev; + snprintf(bus->id, MII_BUS_ID_SIZE, "%lx.nb8800-mii", + (unsigned long)res->start); + bus->priv = priv; + + ret = of_mdiobus_register(bus, pdev->dev.of_node); + if (ret) { + dev_err(&pdev->dev, "failed to register MII bus\n"); + goto err_disable_clk; + } + + priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); + if (!priv->phy_node) { + dev_err(&pdev->dev, "no PHY specified\n"); + ret = -ENODEV; + goto err_free_bus; + } + + priv->mii_bus = bus; + + ret = nb8800_hw_init(dev); + if (ret) + goto err_free_bus; + + if (ops && ops->init) { + ret = ops->init(dev); + if (ret) + goto err_free_bus; + } + + dev->netdev_ops = &nb8800_netdev_ops; + dev->ethtool_ops = &nb8800_ethtool_ops; + dev->flags |= IFF_MULTICAST; + dev->irq = irq; + + mac = of_get_mac_address(pdev->dev.of_node); + if (mac) + ether_addr_copy(dev->dev_addr, mac); + + if (!is_valid_ether_addr(dev->dev_addr)) + eth_hw_addr_random(dev); + + nb8800_update_mac_addr(dev); + + netif_carrier_off(dev); + + ret = register_netdev(dev); + if (ret) { + netdev_err(dev, "failed to register netdev\n"); + goto err_free_dma; + } + + netif_napi_add(dev, &priv->napi, nb8800_poll, NAPI_POLL_WEIGHT); + + netdev_info(dev, "MAC address %pM\n", dev->dev_addr); + + return 0; + +err_free_dma: + nb8800_dma_free(dev); +err_free_bus: + mdiobus_unregister(bus); +err_disable_clk: + clk_disable_unprepare(priv->clk); +err_free_dev: + free_netdev(dev); + + return ret; +} + +static int nb8800_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct nb8800_priv *priv = netdev_priv(ndev); + + unregister_netdev(ndev); + + mdiobus_unregister(priv->mii_bus); + + clk_disable_unprepare(priv->clk); + + nb8800_dma_free(ndev); + free_netdev(ndev); + + return 0; +} + +static struct platform_driver nb8800_driver = { + .driver = { + .name = "nb8800", + .of_match_table = nb8800_dt_ids, + }, + .probe = nb8800_probe, + .remove = nb8800_remove, +}; + +module_platform_driver(nb8800_driver); + +MODULE_DESCRIPTION("Aurora AU-NB8800 Ethernet driver"); +MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/aurora/nb8800.h b/drivers/net/ethernet/aurora/nb8800.h new file mode 100644 index 0000000..e5adbc2 --- /dev/null +++ b/drivers/net/ethernet/aurora/nb8800.h @@ -0,0 +1,316 @@ +#ifndef _NB8800_H_ +#define _NB8800_H_ + +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/phy.h> +#include <linux/clk.h> +#include <linux/bitops.h> + +#define RX_DESC_COUNT 256 +#define TX_DESC_COUNT 256 + +#define NB8800_DESC_LOW 4 + +#define RX_BUF_SIZE 1552 + +#define RX_COPYBREAK 256 +#define RX_COPYHDR 128 + +#define MAX_MDC_CLOCK 2500000 + +/* Stargate Solutions SSN8800 core registers */ +#define NB8800_TX_CTL1 0x000 +#define TX_TPD BIT(5) +#define TX_APPEND_FCS BIT(4) +#define TX_PAD_EN BIT(3) +#define TX_RETRY_EN BIT(2) +#define TX_EN BIT(0) + +#define NB8800_TX_CTL2 0x001 + +#define NB8800_RX_CTL 0x004 +#define RX_BC_DISABLE BIT(7) +#define RX_RUNT BIT(6) +#define RX_AF_EN BIT(5) +#define RX_PAUSE_EN BIT(3) +#define RX_SEND_CRC BIT(2) +#define RX_PAD_STRIP BIT(1) +#define RX_EN BIT(0) + +#define NB8800_RANDOM_SEED 0x008 +#define NB8800_TX_SDP 0x14 +#define NB8800_TX_TPDP1 0x18 +#define NB8800_TX_TPDP2 0x19 +#define NB8800_SLOT_TIME 0x1c + +#define NB8800_MDIO_CMD 0x020 +#define MDIO_CMD_GO BIT(31) +#define MDIO_CMD_WR BIT(26) +#define MDIO_CMD_ADDR(x) ((x) << 21) +#define MDIO_CMD_REG(x) ((x) << 16) +#define MDIO_CMD_DATA(x) ((x) << 0) + +#define NB8800_MDIO_STS 0x024 +#define MDIO_STS_ERR BIT(31) + +#define NB8800_MC_ADDR(i) (0x028 + (i)) +#define NB8800_MC_INIT 0x02e +#define NB8800_UC_ADDR(i) (0x03c + (i)) + +#define NB8800_MAC_MODE 0x044 +#define RGMII_MODE BIT(7) +#define HALF_DUPLEX BIT(4) +#define BURST_EN BIT(3) +#define LOOPBACK_EN BIT(2) +#define GMAC_MODE BIT(0) + +#define NB8800_IC_THRESHOLD 0x050 +#define NB8800_PE_THRESHOLD 0x051 +#define NB8800_PF_THRESHOLD 0x052 +#define NB8800_TX_BUFSIZE 0x054 +#define NB8800_FIFO_CTL 0x056 +#define NB8800_PQ1 0x060 +#define NB8800_PQ2 0x061 +#define NB8800_SRC_ADDR(i) (0x06a + (i)) +#define NB8800_STAT_DATA 0x078 +#define NB8800_STAT_INDEX 0x07c +#define NB8800_STAT_CLEAR 0x07d + +#define NB8800_SLEEP_MODE 0x07e +#define SLEEP_MODE BIT(0) + +#define NB8800_WAKEUP 0x07f +#define WAKEUP BIT(0) + +/* Aurora NB8800 host interface registers */ +#define NB8800_TXC_CR 0x100 +#define TCR_LK BIT(12) +#define TCR_DS BIT(11) +#define TCR_BTS(x) (((x) & 0x7) << 8) +#define TCR_DIE BIT(7) +#define TCR_TFI(x) (((x) & 0x7) << 4) +#define TCR_LE BIT(3) +#define TCR_RS BIT(2) +#define TCR_DM BIT(1) +#define TCR_EN BIT(0) + +#define NB8800_TXC_SR 0x104 +#define TSR_DE BIT(3) +#define TSR_DI BIT(2) +#define TSR_TO BIT(1) +#define TSR_TI BIT(0) + +#define NB8800_TX_SAR 0x108 +#define NB8800_TX_DESC_ADDR 0x10c + +#define NB8800_TX_REPORT_ADDR 0x110 +#define TX_BYTES_TRANSFERRED(x) (((x) >> 16) & 0xffff) +#define TX_FIRST_DEFERRAL BIT(7) +#define TX_EARLY_COLLISIONS(x) (((x) >> 3) & 0xf) +#define TX_LATE_COLLISION BIT(2) +#define TX_PACKET_DROPPED BIT(1) +#define TX_FIFO_UNDERRUN BIT(0) +#define IS_TX_ERROR(r) ((r) & 0x07) + +#define NB8800_TX_FIFO_SR 0x114 +#define NB8800_TX_ITR 0x118 + +#define NB8800_RXC_CR 0x200 +#define RCR_FL BIT(13) +#define RCR_LK BIT(12) +#define RCR_DS BIT(11) +#define RCR_BTS(x) (((x) & 7) << 8) +#define RCR_DIE BIT(7) +#define RCR_RFI(x) (((x) & 7) << 4) +#define RCR_LE BIT(3) +#define RCR_RS BIT(2) +#define RCR_DM BIT(1) +#define RCR_EN BIT(0) + +#define NB8800_RXC_SR 0x204 +#define RSR_DE BIT(3) +#define RSR_DI BIT(2) +#define RSR_RO BIT(1) +#define RSR_RI BIT(0) + +#define NB8800_RX_SAR 0x208 +#define NB8800_RX_DESC_ADDR 0x20c + +#define NB8800_RX_REPORT_ADDR 0x210 +#define RX_BYTES_TRANSFERRED(x) (((x) >> 16) & 0xFFFF) +#define RX_MULTICAST_PKT BIT(9) +#define RX_BROADCAST_PKT BIT(8) +#define RX_LENGTH_ERR BIT(7) +#define RX_FCS_ERR BIT(6) +#define RX_RUNT_PKT BIT(5) +#define RX_FIFO_OVERRUN BIT(4) +#define RX_LATE_COLLISION BIT(3) +#define RX_ALIGNMENT_ERROR BIT(2) +#define RX_ERROR_MASK 0xfc +#define IS_RX_ERROR(r) ((r) & RX_ERROR_MASK) + +#define NB8800_RX_FIFO_SR 0x214 +#define NB8800_RX_ITR 0x218 + +/* Sigma Designs SMP86xx additional registers */ +#define NB8800_TANGOX_PAD_MODE 0x400 +#define PAD_MODE_MASK 0x7 +#define PAD_MODE_MII 0x0 +#define PAD_MODE_RGMII 0x1 +#define PAD_MODE_GTX_CLK_INV BIT(3) +#define PAD_MODE_GTX_CLK_DELAY BIT(4) + +#define NB8800_TANGOX_MDIO_CLKDIV 0x420 +#define NB8800_TANGOX_RESET 0x424 + +/* Hardware DMA descriptor */ +struct nb8800_dma_desc { + u32 s_addr; /* start address */ + u32 n_addr; /* next descriptor address */ + u32 r_addr; /* report address */ + u32 config; +} __aligned(8); + +#define DESC_ID BIT(23) +#define DESC_EOC BIT(22) +#define DESC_EOF BIT(21) +#define DESC_LK BIT(20) +#define DESC_DS BIT(19) +#define DESC_BTS(x) (((x) & 0x7) << 16) + +/* DMA descriptor and associated data for rx. + * Allocated from coherent memory. + */ +struct nb8800_rx_desc { + /* DMA descriptor */ + struct nb8800_dma_desc desc; + + /* Status report filled in by hardware */ + u32 report; +}; + +/* Address of buffer on rx ring */ +struct nb8800_rx_buf { + struct page *page; + unsigned long offset; +}; + +/* DMA descriptors and associated data for tx. + * Allocated from coherent memory. + */ +struct nb8800_tx_desc { + /* DMA descriptor. The second descriptor is used if packet + * data is unaligned. + */ + struct nb8800_dma_desc desc[2]; + + /* Status report filled in by hardware */ + u32 report; + + /* Bounce buffer for initial unaligned part of packet */ + u8 buf[8] __aligned(8); +}; + +/* Packet in tx queue */ +struct nb8800_tx_buf { + /* Currently queued skb */ + struct sk_buff *skb; + + /* DMA address of the first descriptor */ + dma_addr_t dma_desc; + + /* DMA address of packet data */ + dma_addr_t dma_addr; + + /* Length of DMA mapping, less than skb->len if alignment + * buffer is used. + */ + unsigned int dma_len; + + /* Number of packets in chain starting here */ + unsigned int chain_len; + + /* Packet chain ready to be submitted to hardware */ + bool ready; +}; + +struct nb8800_priv { + struct napi_struct napi; + + void __iomem *base; + + /* RX DMA descriptors */ + struct nb8800_rx_desc *rx_descs; + + /* RX buffers referenced by DMA descriptors */ + struct nb8800_rx_buf *rx_bufs; + + /* Current end of chain */ + u32 rx_eoc; + + /* Value for rx interrupt time register in NAPI interrupt mode */ + u32 rx_itr_irq; + + /* Value for rx interrupt time register in NAPI poll mode */ + u32 rx_itr_poll; + + /* Value for config field of rx DMA descriptors */ + u32 rx_dma_config; + + /* TX DMA descriptors */ + struct nb8800_tx_desc *tx_descs; + + /* TX packet queue */ + struct nb8800_tx_buf *tx_bufs; + + /* Number of free tx queue entries */ + atomic_t tx_free; + + /* First free tx queue entry */ + u32 tx_next; + + /* Next buffer to transmit */ + u32 tx_queue; + + /* Start of current packet chain */ + struct nb8800_tx_buf *tx_chain; + + /* Next buffer to reclaim */ + u32 tx_done; + + /* Lock for DMA activation */ + spinlock_t tx_lock; + + struct mii_bus *mii_bus; + struct device_node *phy_node; + struct phy_device *phydev; + + /* PHY connection type from DT */ + int phy_mode; + + /* Current link status */ + int speed; + int duplex; + int link; + + /* Pause settings */ + bool pause_aneg; + bool pause_rx; + bool pause_tx; + + /* DMA base address of rx descriptors, see rx_descs above */ + dma_addr_t rx_desc_dma; + + /* DMA base address of tx descriptors, see tx_descs above */ + dma_addr_t tx_desc_dma; + + struct clk *clk; +}; + +struct nb8800_ops { + int (*init)(struct net_device *dev); + int (*reset)(struct net_device *dev); +}; + +#endif /* _NB8800_H_ */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index f1d62d5..2e611dc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -10139,8 +10139,8 @@ static void __bnx2x_del_vxlan_port(struct bnx2x *bp, u16 port) DP(BNX2X_MSG_SP, "Invalid vxlan port\n"); return; } - bp->vxlan_dst_port--; - if (bp->vxlan_dst_port) + bp->vxlan_dst_port_count--; + if (bp->vxlan_dst_port_count) return; if (netif_running(bp->dev)) { @@ -13207,7 +13207,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev, /* VF with OLD Hypervisor or old PF do not support filtering */ if (IS_PF(bp)) { - if (CHIP_IS_E1x(bp)) + if (chip_is_e1x) bp->accept_any_vlan = true; else dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index db15c5e..07f5f23 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2693,17 +2693,16 @@ static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp) req.ver_upd = DRV_VER_UPD; if (BNXT_PF(bp)) { - unsigned long vf_req_snif_bmap[4]; + DECLARE_BITMAP(vf_req_snif_bmap, 256); u32 *data = (u32 *)vf_req_snif_bmap; - memset(vf_req_snif_bmap, 0, 32); + memset(vf_req_snif_bmap, 0, sizeof(vf_req_snif_bmap)); for (i = 0; i < ARRAY_SIZE(bnxt_vf_req_snif); i++) __set_bit(bnxt_vf_req_snif[i], vf_req_snif_bmap); - for (i = 0; i < 8; i++) { - req.vf_req_fwd[i] = cpu_to_le32(*data); - data++; - } + for (i = 0; i < 8; i++) + req.vf_req_fwd[i] = cpu_to_le32(data[i]); + req.enables |= cpu_to_le32(FUNC_DRV_RGTR_REQ_ENABLES_VF_REQ_FWD); } @@ -3625,6 +3624,7 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp) pf->fw_fid = le16_to_cpu(resp->fid); pf->port_id = le16_to_cpu(resp->port_id); memcpy(pf->mac_addr, resp->perm_mac_address, ETH_ALEN); + memcpy(bp->dev->dev_addr, pf->mac_addr, ETH_ALEN); pf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx); pf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings); pf->max_tx_rings = le16_to_cpu(resp->max_tx_rings); @@ -3648,8 +3648,11 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp) vf->fw_fid = le16_to_cpu(resp->fid); memcpy(vf->mac_addr, resp->perm_mac_address, ETH_ALEN); - if (!is_valid_ether_addr(vf->mac_addr)) - random_ether_addr(vf->mac_addr); + if (is_valid_ether_addr(vf->mac_addr)) + /* overwrite netdev dev_adr with admin VF MAC */ + memcpy(bp->dev->dev_addr, vf->mac_addr, ETH_ALEN); + else + random_ether_addr(bp->dev->dev_addr); vf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx); vf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings); @@ -3880,6 +3883,8 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp) #endif } +static int bnxt_cfg_rx_mode(struct bnxt *); + static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) { int rc = 0; @@ -3946,11 +3951,9 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) bp->vnic_info[0].rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS; - rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0); - if (rc) { - netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n", rc); + rc = bnxt_cfg_rx_mode(bp); + if (rc) goto err_out; - } rc = bnxt_hwrm_set_coal(bp); if (rc) @@ -4599,7 +4602,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) bp->nge_port_cnt = 1; } - bp->state = BNXT_STATE_OPEN; + set_bit(BNXT_STATE_OPEN, &bp->state); bnxt_enable_int(bp); /* Enable TX queues */ bnxt_tx_enable(bp); @@ -4675,8 +4678,10 @@ int bnxt_close_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) /* Change device state to avoid TX queue wake up's */ bnxt_tx_disable(bp); - bp->state = BNXT_STATE_CLOSED; - cancel_work_sync(&bp->sp_task); + clear_bit(BNXT_STATE_OPEN, &bp->state); + smp_mb__after_atomic(); + while (test_bit(BNXT_STATE_IN_SP_TASK, &bp->state)) + msleep(20); /* Flush rings before disabling interrupts */ bnxt_shutdown_nic(bp, irq_re_init); @@ -4865,7 +4870,7 @@ static void bnxt_set_rx_mode(struct net_device *dev) } } -static void bnxt_cfg_rx_mode(struct bnxt *bp) +static int bnxt_cfg_rx_mode(struct bnxt *bp) { struct net_device *dev = bp->dev; struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; @@ -4914,6 +4919,7 @@ static void bnxt_cfg_rx_mode(struct bnxt *bp) netdev_err(bp->dev, "HWRM vnic filter failure rc: %x\n", rc); vnic->uc_filter_count = i; + return rc; } } @@ -4922,6 +4928,8 @@ skip_uc: if (rc) netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n", rc); + + return rc; } static netdev_features_t bnxt_fix_features(struct net_device *dev, @@ -5023,8 +5031,10 @@ static void bnxt_dbg_dump_states(struct bnxt *bp) static void bnxt_reset_task(struct bnxt *bp) { bnxt_dbg_dump_states(bp); - if (netif_running(bp->dev)) - bnxt_tx_disable(bp); /* prevent tx timout again */ + if (netif_running(bp->dev)) { + bnxt_close_nic(bp, false, false); + bnxt_open_nic(bp, false, false); + } } static void bnxt_tx_timeout(struct net_device *dev) @@ -5074,8 +5084,12 @@ static void bnxt_sp_task(struct work_struct *work) struct bnxt *bp = container_of(work, struct bnxt, sp_task); int rc; - if (bp->state != BNXT_STATE_OPEN) + set_bit(BNXT_STATE_IN_SP_TASK, &bp->state); + smp_mb__after_atomic(); + if (!test_bit(BNXT_STATE_OPEN, &bp->state)) { + clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); return; + } if (test_and_clear_bit(BNXT_RX_MASK_SP_EVENT, &bp->sp_event)) bnxt_cfg_rx_mode(bp); @@ -5099,8 +5113,19 @@ static void bnxt_sp_task(struct work_struct *work) bnxt_hwrm_tunnel_dst_port_free( bp, TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN); } - if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event)) + if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event)) { + /* bnxt_reset_task() calls bnxt_close_nic() which waits + * for BNXT_STATE_IN_SP_TASK to clear. + */ + clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); + rtnl_lock(); bnxt_reset_task(bp); + set_bit(BNXT_STATE_IN_SP_TASK, &bp->state); + rtnl_unlock(); + } + + smp_mb__before_atomic(); + clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); } static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev) @@ -5179,7 +5204,7 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev) bp->timer.function = bnxt_timer; bp->current_interval = BNXT_TIMER_INTERVAL; - bp->state = BNXT_STATE_CLOSED; + clear_bit(BNXT_STATE_OPEN, &bp->state); return 0; @@ -5212,13 +5237,27 @@ init_err: static int bnxt_change_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; + struct bnxt *bp = netdev_priv(dev); + int rc = 0; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; +#ifdef CONFIG_BNXT_SRIOV + if (BNXT_VF(bp) && is_valid_ether_addr(bp->vf.mac_addr)) + return -EADDRNOTAVAIL; +#endif + + if (ether_addr_equal(addr->sa_data, dev->dev_addr)) + return 0; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + if (netif_running(dev)) { + bnxt_close_nic(bp, false, false); + rc = bnxt_open_nic(bp, false, false); + } - return 0; + return rc; } /* rtnl_lock held */ @@ -5686,15 +5725,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bnxt_set_tpa_flags(bp); bnxt_set_ring_params(bp); dflt_rings = netif_get_num_default_rss_queues(); - if (BNXT_PF(bp)) { - memcpy(dev->dev_addr, bp->pf.mac_addr, ETH_ALEN); + if (BNXT_PF(bp)) bp->pf.max_irqs = max_irqs; - } else { #if defined(CONFIG_BNXT_SRIOV) - memcpy(dev->dev_addr, bp->vf.mac_addr, ETH_ALEN); + else bp->vf.max_irqs = max_irqs; #endif - } bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings); bp->rx_nr_rings = min_t(int, dflt_rings, max_rx_rings); bp->tx_nr_rings_per_tc = min_t(int, dflt_rings, max_tx_rings); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 674bc51..f199f4c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -925,9 +925,9 @@ struct bnxt { struct timer_list timer; - int state; -#define BNXT_STATE_CLOSED 0 -#define BNXT_STATE_OPEN 1 + unsigned long state; +#define BNXT_STATE_OPEN 0 +#define BNXT_STATE_IN_SP_TASK 1 struct bnxt_irq *irq_tbl; u8 mac_addr[ETH_ALEN]; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index f4cf688..ea044bb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -21,7 +21,7 @@ #ifdef CONFIG_BNXT_SRIOV static int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id) { - if (bp->state != BNXT_STATE_OPEN) { + if (!test_bit(BNXT_STATE_OPEN, &bp->state)) { netdev_err(bp->dev, "vf ndo called though PF is down\n"); return -EINVAL; } @@ -804,10 +804,9 @@ void bnxt_update_vf_mac(struct bnxt *bp) if (!is_valid_ether_addr(resp->perm_mac_address)) goto update_vf_mac_exit; - if (ether_addr_equal(resp->perm_mac_address, bp->vf.mac_addr)) - goto update_vf_mac_exit; - - memcpy(bp->vf.mac_addr, resp->perm_mac_address, ETH_ALEN); + if (!ether_addr_equal(resp->perm_mac_address, bp->vf.mac_addr)) + memcpy(bp->vf.mac_addr, resp->perm_mac_address, ETH_ALEN); + /* overwrite netdev dev_adr with admin VF MAC */ memcpy(bp->dev->dev_addr, bp->vf.mac_addr, ETH_ALEN); update_vf_mac_exit: mutex_unlock(&bp->hwrm_cmd_lock); diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 88c1e1a..169059c 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1682,6 +1682,8 @@ static void macb_init_hw(struct macb *bp) macb_set_hwaddr(bp); config = macb_mdc_clk_div(bp); + if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) + config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ @@ -2416,6 +2418,8 @@ static int macb_init(struct platform_device *pdev) /* Set MII management clock divider */ val = macb_mdc_clk_div(bp); val |= macb_dbw(bp); + if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) + val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); macb_writel(bp, NCFGR, val); return 0; diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 6e1faea..d83b0db 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -215,12 +215,17 @@ /* GEM specific NCFGR bitfields. */ #define GEM_GBE_OFFSET 10 /* Gigabit mode enable */ #define GEM_GBE_SIZE 1 +#define GEM_PCSSEL_OFFSET 11 +#define GEM_PCSSEL_SIZE 1 #define GEM_CLK_OFFSET 18 /* MDC clock division */ #define GEM_CLK_SIZE 3 #define GEM_DBW_OFFSET 21 /* Data bus width */ #define GEM_DBW_SIZE 2 #define GEM_RXCOEN_OFFSET 24 #define GEM_RXCOEN_SIZE 1 +#define GEM_SGMIIEN_OFFSET 27 +#define GEM_SGMIIEN_SIZE 1 + /* Constants for data bus width. */ #define GEM_DBW32 0 /* 32 bit AMBA AHB data bus width */ diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index f683d97..b895044 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -560,7 +560,7 @@ static int liquidio_resume(struct pci_dev *pdev) #endif /* For PCI-E Advanced Error Recovery (AER) Interface */ -static struct pci_error_handlers liquidio_err_handler = { +static const struct pci_error_handlers liquidio_err_handler = { .error_detected = liquidio_pcie_error_detected, .mmio_enabled = liquidio_pcie_mmio_enabled, .slot_reset = liquidio_pcie_slot_reset, diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index d3950b2..39ca674 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h @@ -120,10 +120,9 @@ * Calculated for SCLK of 700Mhz * value written should be a 1/16th of what is expected * - * 1 tick per 0.05usec = value of 2.2 - * This 10% would be covered in CQ timer thresh value + * 1 tick per 0.025usec */ -#define NICPF_CLK_PER_INT_TICK 2 +#define NICPF_CLK_PER_INT_TICK 1 /* Time to wait before we decide that a SQ is stuck. * diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c index c561fdc..5f24d11 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_main.c +++ b/drivers/net/ethernet/cavium/thunder/nic_main.c @@ -615,6 +615,21 @@ static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk) return 0; } +static void nic_enable_vf(struct nicpf *nic, int vf, bool enable) +{ + int bgx, lmac; + + nic->vf_enabled[vf] = enable; + + if (vf >= nic->num_vf_en) + return; + + bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + + bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, enable); +} + /* Interrupt handler to handle mailbox messages from VFs */ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) { @@ -714,14 +729,14 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) break; case NIC_MBOX_MSG_CFG_DONE: /* Last message of VF config msg sequence */ - nic->vf_enabled[vf] = true; + nic_enable_vf(nic, vf, true); goto unlock; case NIC_MBOX_MSG_SHUTDOWN: /* First msg in VF teardown sequence */ - nic->vf_enabled[vf] = false; if (vf >= nic->num_vf_en) nic->sqs_used[vf - nic->num_vf_en] = false; nic->pqs_vf[vf] = 0; + nic_enable_vf(nic, vf, false); break; case NIC_MBOX_MSG_ALLOC_SQS: nic_alloc_sqs(nic, &mbx.sqs_alloc); @@ -1074,8 +1089,7 @@ static void nic_remove(struct pci_dev *pdev) if (nic->check_link) { /* Destroy work Queue */ - cancel_delayed_work(&nic->dwork); - flush_workqueue(nic->check_link); + cancel_delayed_work_sync(&nic->dwork); destroy_workqueue(nic->check_link); } diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c index af54c10..a12b2e3 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c @@ -112,6 +112,13 @@ static int nicvf_get_settings(struct net_device *netdev, cmd->supported = 0; cmd->transceiver = XCVR_EXTERNAL; + + if (!nic->link_up) { + cmd->duplex = DUPLEX_UNKNOWN; + ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN); + return 0; + } + if (nic->speed <= 1000) { cmd->port = PORT_MII; cmd->autoneg = AUTONEG_ENABLE; @@ -125,6 +132,13 @@ static int nicvf_get_settings(struct net_device *netdev, return 0; } +static u32 nicvf_get_link(struct net_device *netdev) +{ + struct nicvf *nic = netdev_priv(netdev); + + return nic->link_up; +} + static void nicvf_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) { @@ -660,7 +674,7 @@ static int nicvf_set_channels(struct net_device *dev, static const struct ethtool_ops nicvf_ethtool_ops = { .get_settings = nicvf_get_settings, - .get_link = ethtool_op_get_link, + .get_link = nicvf_get_link, .get_drvinfo = nicvf_get_drvinfo, .get_msglevel = nicvf_get_msglevel, .set_msglevel = nicvf_set_msglevel, diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index a937772..dde8dc7 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -1057,6 +1057,7 @@ int nicvf_stop(struct net_device *netdev) netif_carrier_off(netdev); netif_tx_stop_all_queues(nic->netdev); + nic->link_up = false; /* Teardown secondary qsets first */ if (!nic->sqs_mode) { @@ -1211,9 +1212,6 @@ int nicvf_open(struct net_device *netdev) nic->drv_stats.txq_stop = 0; nic->drv_stats.txq_wake = 0; - netif_carrier_on(netdev); - netif_tx_start_all_queues(netdev); - return 0; cleanup: nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0); @@ -1583,8 +1581,14 @@ err_disable_device: static void nicvf_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct nicvf *nic = netdev_priv(netdev); - struct net_device *pnetdev = nic->pnicvf->netdev; + struct nicvf *nic; + struct net_device *pnetdev; + + if (!netdev) + return; + + nic = netdev_priv(netdev); + pnetdev = nic->pnicvf->netdev; /* Check if this Qset is assigned to different VF. * If yes, clean primary and all secondary Qsets. diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index e404ea8..206b6a7 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -592,7 +592,7 @@ void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs, /* Set threshold value for interrupt generation */ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_THRESH, qidx, cq->thresh); nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2, - qidx, nic->cq_coalesce_usecs); + qidx, CMP_QUEUE_TIMER_THRESH); } /* Configures transmit queue */ diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h index fb4957d..033e830 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h @@ -76,7 +76,7 @@ #define CMP_QSIZE CMP_QUEUE_SIZE2 #define CMP_QUEUE_LEN (1ULL << (CMP_QSIZE + 10)) #define CMP_QUEUE_CQE_THRESH 0 -#define CMP_QUEUE_TIMER_THRESH 220 /* 10usec */ +#define CMP_QUEUE_TIMER_THRESH 80 /* ~2usec */ #define RBDR_SIZE RBDR_SIZE0 #define RCV_BUF_COUNT (1ULL << (RBDR_SIZE + 13)) diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 180aa9f..9df26c2 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -186,6 +186,23 @@ void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac) } EXPORT_SYMBOL(bgx_set_lmac_mac); +void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable) +{ + struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx]; + u64 cfg; + + if (!bgx) + return; + + cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG); + if (enable) + cfg |= CMR_PKT_RX_EN | CMR_PKT_TX_EN; + else + cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN); + bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg); +} +EXPORT_SYMBOL(bgx_lmac_rx_tx_enable); + static void bgx_sgmii_change_link_state(struct lmac *lmac) { struct bgx *bgx = lmac->bgx; @@ -612,6 +629,8 @@ static void bgx_poll_for_link(struct work_struct *work) lmac->last_duplex = 1; } else { lmac->link_up = 0; + lmac->last_speed = SPEED_UNKNOWN; + lmac->last_duplex = DUPLEX_UNKNOWN; } if (lmac->last_link != lmac->link_up) { @@ -654,8 +673,7 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) } /* Enable lmac */ - bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, - CMR_EN | CMR_PKT_RX_EN | CMR_PKT_TX_EN); + bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN); /* Restore default cfg, incase low level firmware changed it */ bgx_reg_write(bgx, lmacid, BGX_CMRX_RX_DMAC_CTL, 0x03); @@ -695,8 +713,7 @@ static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid) lmac = &bgx->lmac[lmacid]; if (lmac->check_link) { /* Destroy work queue */ - cancel_delayed_work(&lmac->dwork); - flush_workqueue(lmac->check_link); + cancel_delayed_work_sync(&lmac->dwork); destroy_workqueue(lmac->check_link); } @@ -1009,6 +1026,9 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct bgx *bgx = NULL; u8 lmac; + /* Load octeon mdio driver */ + octeon_mdiobus_force_mod_depencency(); + bgx = devm_kzalloc(dev, sizeof(*bgx), GFP_KERNEL); if (!bgx) return -ENOMEM; diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h index 07b7ec66..149e179 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h @@ -182,6 +182,8 @@ enum MCAST_MODE { #define BCAST_ACCEPT 1 #define CAM_ACCEPT 1 +void octeon_mdiobus_force_mod_depencency(void); +void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable); void bgx_add_dmac_addr(u64 dmac, int node, int bgx_idx, int lmac); unsigned bgx_get_map(int node); int bgx_get_lmac_count(int node, int bgx); diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c index ed41559..b553409 100644 --- a/drivers/net/ethernet/dec/tulip/tulip_core.c +++ b/drivers/net/ethernet/dec/tulip/tulip_core.c @@ -98,8 +98,7 @@ static int csr0 = 0x01A00000 | 0x4800; #elif defined(__mips__) static int csr0 = 0x00200000 | 0x4000; #else -#warning Processor architecture undefined! -static int csr0 = 0x00A00000 | 0x4800; +static int csr0; #endif /* Operational parameters that usually are not changed. */ @@ -1982,6 +1981,12 @@ static int __init tulip_init (void) pr_info("%s", version); #endif + if (!csr0) { + pr_warn("tulip: unknown CPU architecture, using default csr0\n"); + /* default to 8 longword cache line alignment */ + csr0 = 0x00A00000 | 0x4800; + } + /* copy module parms into globals */ tulip_rx_copybreak = rx_copybreak; tulip_max_interrupt_work = max_interrupt_work; diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index 9beb3d3..3c0e4d5 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -907,7 +907,7 @@ static void init_registers(struct net_device *dev) #elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) || defined(CONFIG_ARM) i |= 0x4800; #else -#warning Processor architecture undefined + dev_warn(&dev->dev, "unknown CPU architecture, using default csr0 setting\n"); i |= 0x4800; #endif iowrite32(i, ioaddr + PCIBusCfg); diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig index f6e858d..ebdc832 100644 --- a/drivers/net/ethernet/dlink/Kconfig +++ b/drivers/net/ethernet/dlink/Kconfig @@ -17,15 +17,16 @@ config NET_VENDOR_DLINK if NET_VENDOR_DLINK config DL2K - tristate "DL2000/TC902x-based Gigabit Ethernet support" + tristate "DL2000/TC902x/IP1000A-based Gigabit Ethernet support" depends on PCI select CRC32 ---help--- - This driver supports DL2000/TC902x-based Gigabit ethernet cards, + This driver supports DL2000/TC902x/IP1000A-based Gigabit ethernet cards, which includes D-Link DGE-550T Gigabit Ethernet Adapter. D-Link DL2000-based Gigabit Ethernet Adapter. Sundance/Tamarack TC902x Gigabit Ethernet Adapter. + ICPlus IP1000A-based cards To compile this driver as a module, choose M here: the module will be called dl2k. diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c index cf0a5fc..ccca479 100644 --- a/drivers/net/ethernet/dlink/dl2k.c +++ b/drivers/net/ethernet/dlink/dl2k.c @@ -253,6 +253,19 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_out_unmap_rx; + if (np->chip_id == CHIP_IP1000A && + (np->pdev->revision == 0x40 || np->pdev->revision == 0x41)) { + /* PHY magic taken from ipg driver, undocumented registers */ + mii_write(dev, np->phy_addr, 31, 0x0001); + mii_write(dev, np->phy_addr, 27, 0x01e0); + mii_write(dev, np->phy_addr, 31, 0x0002); + mii_write(dev, np->phy_addr, 27, 0xeb8e); + mii_write(dev, np->phy_addr, 31, 0x0000); + mii_write(dev, np->phy_addr, 30, 0x005e); + /* advertise 1000BASE-T half & full duplex, prefer MASTER */ + mii_write(dev, np->phy_addr, MII_CTRL1000, 0x0700); + } + /* Fiber device? */ np->phy_media = (dr16(ASICCtrl) & PhyMedia) ? 1 : 0; np->link_status = 0; @@ -361,6 +374,11 @@ parse_eeprom (struct net_device *dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = psrom->mac_addr[i]; + if (np->chip_id == CHIP_IP1000A) { + np->led_mode = psrom->led_mode; + return 0; + } + if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) { return 0; } @@ -406,6 +424,28 @@ parse_eeprom (struct net_device *dev) return 0; } +static void rio_set_led_mode(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->ioaddr; + u32 mode; + + if (np->chip_id != CHIP_IP1000A) + return; + + mode = dr32(ASICCtrl); + mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED); + + if (np->led_mode & 0x01) + mode |= IPG_AC_LED_MODE; + if (np->led_mode & 0x02) + mode |= IPG_AC_LED_MODE_BIT_1; + if (np->led_mode & 0x08) + mode |= IPG_AC_LED_SPEED; + + dw32(ASICCtrl, mode); +} + static int rio_open (struct net_device *dev) { @@ -424,6 +464,8 @@ rio_open (struct net_device *dev) GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset); mdelay(10); + rio_set_led_mode(dev); + /* DebugCtrl bit 4, 5, 9 must set */ dw32(DebugCtrl, dr32(DebugCtrl) | 0x0230); @@ -433,9 +475,13 @@ rio_open (struct net_device *dev) alloc_list (dev); - /* Get station address */ - for (i = 0; i < 6; i++) - dw8(StationAddr0 + i, dev->dev_addr[i]); + /* Set station address */ + /* 16 or 32-bit access is required by TC9020 datasheet but 8-bit works + * too. However, it doesn't work on IP1000A so we use 16-bit access. + */ + for (i = 0; i < 3; i++) + dw16(StationAddr0 + 2 * i, + cpu_to_le16(((u16 *)dev->dev_addr)[i])); set_multicast (dev); if (np->coalesce) { @@ -780,6 +826,7 @@ tx_error (struct net_device *dev, int tx_status) break; mdelay (1); } + rio_set_led_mode(dev); rio_free_tx (dev, 1); /* Reset TFDListPtr */ dw32(TFDListPtr0, np->tx_ring_dma + @@ -799,6 +846,7 @@ tx_error (struct net_device *dev, int tx_status) break; mdelay (1); } + rio_set_led_mode(dev); /* Let TxStartThresh stay default value */ } /* Maximum Collisions */ @@ -965,6 +1013,7 @@ rio_error (struct net_device *dev, int int_status) dev->name, int_status); dw16(ASICCtrl + 2, GlobalReset | HostReset); mdelay (500); + rio_set_led_mode(dev); } } diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h index 23c07b0..8f4f612 100644 --- a/drivers/net/ethernet/dlink/dl2k.h +++ b/drivers/net/ethernet/dlink/dl2k.h @@ -211,6 +211,10 @@ enum ASICCtrl_HiWord_bits { ResetBusy = 0x0400, }; +#define IPG_AC_LED_MODE BIT(14) +#define IPG_AC_LED_SPEED BIT(27) +#define IPG_AC_LED_MODE_BIT_1 BIT(29) + /* Transmit Frame Control bits */ enum TFC_bits { DwordAlign = 0x00000000, @@ -332,7 +336,10 @@ typedef struct t_SROM { u16 asic_ctrl; /* 0x02 */ u16 sub_vendor_id; /* 0x04 */ u16 sub_system_id; /* 0x06 */ - u16 reserved1[12]; /* 0x08-0x1f */ + u16 pci_base_1; /* 0x08 (IP1000A only) */ + u16 pci_base_2; /* 0x0a (IP1000A only) */ + u16 led_mode; /* 0x0c (IP1000A only) */ + u16 reserved1[9]; /* 0x0e-0x1f */ u8 mac_addr[6]; /* 0x20-0x25 */ u8 reserved2[10]; /* 0x26-0x2f */ u8 sib[204]; /* 0x30-0xfb */ @@ -397,6 +404,7 @@ struct netdev_private { u16 advertising; /* NWay media advertisement */ u16 negotiate; /* Negotiated media */ int phy_addr; /* PHY addresses. */ + u16 led_mode; /* LED mode read from EEPROM (IP1000A only) */ }; /* The station address location in the EEPROM. */ @@ -407,10 +415,15 @@ struct netdev_private { class_mask of the class are honored during the comparison. driver_data Data private to the driver. */ +#define CHIP_IP1000A 1 static const struct pci_device_id rio_pci_tbl[] = { {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, }, {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VDEVICE(SUNDANCE, 0x1023), CHIP_IP1000A }, + { PCI_VDEVICE(SUNDANCE, 0x2021), CHIP_IP1000A }, + { PCI_VDEVICE(DLINK, 0x9021), CHIP_IP1000A }, + { PCI_VDEVICE(DLINK, 0x4020), CHIP_IP1000A }, { } }; MODULE_DEVICE_TABLE (pci, rio_pci_tbl); diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index f4cb8e4..734f655 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -1062,9 +1062,7 @@ static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, static int be_set_rss_hash_opts(struct be_adapter *adapter, struct ethtool_rxnfc *cmd) { - struct be_rx_obj *rxo; - int status = 0, i, j; - u8 rsstable[128]; + int status; u32 rss_flags = adapter->rss_info.rss_flags; if (cmd->data != L3_RSS_FLAGS && @@ -1113,20 +1111,11 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter, } if (rss_flags == adapter->rss_info.rss_flags) - return status; - - if (be_multi_rxq(adapter)) { - for (j = 0; j < 128; j += adapter->num_rss_qs) { - for_all_rss_queues(adapter, rxo, i) { - if ((j + i) >= 128) - break; - rsstable[j + i] = rxo->rss_id; - } - } - } + return 0; status = be_cmd_rss_config(adapter, adapter->rss_info.rsstable, - rss_flags, 128, adapter->rss_info.rss_hkey); + rss_flags, RSS_INDIR_TABLE_LEN, + adapter->rss_info.rss_hkey); if (!status) adapter->rss_info.rss_flags = rss_flags; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index eb48a97..b6ad029 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3518,7 +3518,7 @@ static int be_rx_qs_create(struct be_adapter *adapter) netdev_rss_key_fill(rss_key, RSS_HASH_KEY_LEN); rc = be_cmd_rss_config(adapter, rss->rsstable, rss->rss_flags, - 128, rss_key); + RSS_INDIR_TABLE_LEN, rss_key); if (rc) { rss->rss_flags = RSS_ENABLE_NONE; return rc; diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 63c2bcf..b102668 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -48,21 +48,15 @@ static void nps_enet_read_rx_fifo(struct net_device *ndev, *reg = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); else { /* !dst_is_aligned */ for (i = 0; i < len; i++, reg++) { - u32 buf = - nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); - - /* to accommodate word-unaligned address of "reg" - * we have to do memcpy_toio() instead of simple "=". - */ - memcpy_toio((void __iomem *)reg, &buf, sizeof(buf)); + u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); + put_unaligned(buf, reg); } } /* copy last bytes (if any) */ if (last) { u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); - - memcpy_toio((void __iomem *)reg, &buf, last); + memcpy((u8*)reg, &buf, last); } } @@ -367,7 +361,7 @@ static void nps_enet_send_frame(struct net_device *ndev, struct nps_enet_tx_ctl tx_ctrl; short length = skb->len; u32 i, len = DIV_ROUND_UP(length, sizeof(u32)); - u32 *src = (u32 *)virt_to_phys(skb->data); + u32 *src = (void *)skb->data; bool src_is_aligned = IS_ALIGNED((unsigned long)src, sizeof(u32)); tx_ctrl.value = 0; @@ -375,17 +369,11 @@ static void nps_enet_send_frame(struct net_device *ndev, if (src_is_aligned) for (i = 0; i < len; i++, src++) nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, *src); - else { /* !src_is_aligned */ - for (i = 0; i < len; i++, src++) { - u32 buf; - - /* to accommodate word-unaligned address of "src" - * we have to do memcpy_fromio() instead of simple "=" - */ - memcpy_fromio(&buf, (void __iomem *)src, sizeof(buf)); - nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, buf); - } - } + else /* !src_is_aligned */ + for (i = 0; i < len; i++, src++) + nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, + get_unaligned(src)); + /* Write the length of the Frame */ tx_ctrl.nt = length; diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index ff76d4e..bee32a9 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -7,7 +7,8 @@ config NET_VENDOR_FREESCALE default y depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \ M523x || M527x || M5272 || M528x || M520x || M532x || \ - ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) + ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \ + ARCH_LAYERSCAPE ---help--- If you have a network (Ethernet) card belonging to this class, say Y. diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c index 08f5b91..52e0091 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c @@ -552,7 +552,7 @@ static void tx_restart(struct net_device *dev) cbd_t __iomem *prev_bd; cbd_t __iomem *last_tx_bd; - last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t)); + last_tx_bd = fep->tx_bd_base + ((fpi->tx_ring - 1) * sizeof(cbd_t)); /* get the current bd held in TBPTR and scan back from this point */ recheck_bd = curr_tbptr = (cbd_t __iomem *) diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index 55c3623..40071da 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -464,7 +464,7 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) * address). Print error message but continue anyway. */ if ((void *)tbipa > priv->map + resource_size(&res) - 4) - dev_err(&pdev->dev, "invalid register map (should be at least 0x%04x to contain TBI address)\n", + dev_err(&pdev->dev, "invalid register map (should be at least 0x%04zx to contain TBI address)\n", ((void *)tbipa - priv->map) + 4); iowrite32be(be32_to_cpup(prop), tbipa); diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 3e6b9b4..3e233d9 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -647,9 +647,9 @@ static int gfar_parse_group(struct device_node *np, if (model && strcasecmp(model, "FEC")) { gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1); gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2); - if (gfar_irq(grp, TX)->irq == NO_IRQ || - gfar_irq(grp, RX)->irq == NO_IRQ || - gfar_irq(grp, ER)->irq == NO_IRQ) + if (!gfar_irq(grp, TX)->irq || + !gfar_irq(grp, RX)->irq || + !gfar_irq(grp, ER)->irq) return -EINVAL; } @@ -894,7 +894,8 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | FSL_GIANFAR_DEV_HAS_EXTENDED_HASH | - FSL_GIANFAR_DEV_HAS_TIMER; + FSL_GIANFAR_DEV_HAS_TIMER | + FSL_GIANFAR_DEV_HAS_RX_FILER; err = of_property_read_string(np, "phy-connection-type", &ctype); @@ -1396,8 +1397,9 @@ static int gfar_probe(struct platform_device *ofdev) priv->rx_queue[i]->rxic = DEFAULT_RXIC; } - /* always enable rx filer */ - priv->rx_filer_enable = 1; + /* Always enable rx filer if available */ + priv->rx_filer_enable = + (priv->device_flags & FSL_GIANFAR_DEV_HAS_RX_FILER) ? 1 : 0; /* Enable most messages by default */ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; /* use pritority h/w tx queue scheduling for single queue devices */ diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index f266b20..cb77667 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -923,6 +923,7 @@ struct gfar { #define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400 #define FSL_GIANFAR_DEV_HAS_TIMER 0x00000800 #define FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER 0x00001000 +#define FSL_GIANFAR_DEV_HAS_RX_FILER 0x00002000 #if (MAXGROUPS == 2) #define DEFAULT_MAPPING 0xAA diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index 664d0c2..b40fba9 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -467,7 +467,7 @@ static int gianfar_ptp_probe(struct platform_device *dev) etsects->irq = platform_get_irq(dev, 0); - if (etsects->irq == NO_IRQ) { + if (etsects->irq < 0) { pr_err("irq not in device tree\n"); goto no_node; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 2a98eba..b674414 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -1259,12 +1259,8 @@ int hns_dsaf_set_mac_uc_entry( if (MAC_IS_ALL_ZEROS(mac_entry->addr) || MAC_IS_BROADCAST(mac_entry->addr) || MAC_IS_MULTICAST(mac_entry->addr)) { - dev_err(dsaf_dev->dev, - "set_uc %s Mac %02x:%02x:%02x:%02x:%02x:%02x err!\n", - dsaf_dev->ae_dev.name, mac_entry->addr[0], - mac_entry->addr[1], mac_entry->addr[2], - mac_entry->addr[3], mac_entry->addr[4], - mac_entry->addr[5]); + dev_err(dsaf_dev->dev, "set_uc %s Mac %pM err!\n", + dsaf_dev->ae_dev.name, mac_entry->addr); return -EINVAL; } @@ -1331,12 +1327,8 @@ int hns_dsaf_set_mac_mc_entry( /* mac addr check */ if (MAC_IS_ALL_ZEROS(mac_entry->addr)) { - dev_err(dsaf_dev->dev, - "set uc %s Mac %02x:%02x:%02x:%02x:%02x:%02x err!\n", - dsaf_dev->ae_dev.name, mac_entry->addr[0], - mac_entry->addr[1], mac_entry->addr[2], - mac_entry->addr[3], - mac_entry->addr[4], mac_entry->addr[5]); + dev_err(dsaf_dev->dev, "set uc %s Mac %pM err!\n", + dsaf_dev->ae_dev.name, mac_entry->addr); return -EINVAL; } @@ -1410,11 +1402,8 @@ int hns_dsaf_add_mac_mc_port(struct dsaf_device *dsaf_dev, /*chechk mac addr */ if (MAC_IS_ALL_ZEROS(mac_entry->addr)) { - dev_err(dsaf_dev->dev, - "set_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x!\n", - mac_entry->addr[0], mac_entry->addr[1], - mac_entry->addr[2], mac_entry->addr[3], - mac_entry->addr[4], mac_entry->addr[5]); + dev_err(dsaf_dev->dev, "set_entry failed,addr %pM!\n", + mac_entry->addr); return -EINVAL; } @@ -1497,9 +1486,8 @@ int hns_dsaf_del_mac_entry(struct dsaf_device *dsaf_dev, u16 vlan_id, /*check mac addr */ if (MAC_IS_ALL_ZEROS(addr) || MAC_IS_BROADCAST(addr)) { - dev_err(dsaf_dev->dev, - "del_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x!\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + dev_err(dsaf_dev->dev, "del_entry failed,addr %pM!\n", + addr); return -EINVAL; } @@ -1563,11 +1551,8 @@ int hns_dsaf_del_mac_mc_port(struct dsaf_device *dsaf_dev, /*check mac addr */ if (MAC_IS_ALL_ZEROS(mac_entry->addr)) { - dev_err(dsaf_dev->dev, - "del_port failed, addr %02x:%02x:%02x:%02x:%02x:%02x!\n", - mac_entry->addr[0], mac_entry->addr[1], - mac_entry->addr[2], mac_entry->addr[3], - mac_entry->addr[4], mac_entry->addr[5]); + dev_err(dsaf_dev->dev, "del_port failed, addr %pM!\n", + mac_entry->addr); return -EINVAL; } @@ -1644,11 +1629,8 @@ int hns_dsaf_get_mac_uc_entry(struct dsaf_device *dsaf_dev, /* check macaddr */ if (MAC_IS_ALL_ZEROS(mac_entry->addr) || MAC_IS_BROADCAST(mac_entry->addr)) { - dev_err(dsaf_dev->dev, - "get_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x\n", - mac_entry->addr[0], mac_entry->addr[1], - mac_entry->addr[2], mac_entry->addr[3], - mac_entry->addr[4], mac_entry->addr[5]); + dev_err(dsaf_dev->dev, "get_entry failed,addr %pM\n", + mac_entry->addr); return -EINVAL; } @@ -1695,11 +1677,8 @@ int hns_dsaf_get_mac_mc_entry(struct dsaf_device *dsaf_dev, /*check mac addr */ if (MAC_IS_ALL_ZEROS(mac_entry->addr) || MAC_IS_BROADCAST(mac_entry->addr)) { - dev_err(dsaf_dev->dev, - "get_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x\n", - mac_entry->addr[0], mac_entry->addr[1], - mac_entry->addr[2], mac_entry->addr[3], - mac_entry->addr[4], mac_entry->addr[5]); + dev_err(dsaf_dev->dev, "get_entry failed,addr %pM\n", + mac_entry->addr); return -EINVAL; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h index b475e1b..bdbd804 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h @@ -898,7 +898,7 @@ #define XGMAC_PAUSE_CTL_RSP_MODE_B 2 #define XGMAC_PAUSE_CTL_TX_XOFF_B 3 -static inline void dsaf_write_reg(void *base, u32 reg, u32 value) +static inline void dsaf_write_reg(void __iomem *base, u32 reg, u32 value) { u8 __iomem *reg_addr = ACCESS_ONCE(base); @@ -908,7 +908,7 @@ static inline void dsaf_write_reg(void *base, u32 reg, u32 value) #define dsaf_write_dev(a, reg, value) \ dsaf_write_reg((a)->io_base, (reg), (value)) -static inline u32 dsaf_read_reg(u8 *base, u32 reg) +static inline u32 dsaf_read_reg(u8 __iomem *base, u32 reg) { u8 __iomem *reg_addr = ACCESS_ONCE(base); @@ -927,8 +927,8 @@ static inline u32 dsaf_read_reg(u8 *base, u32 reg) #define dsaf_set_bit(origin, shift, val) \ dsaf_set_field((origin), (1ull << (shift)), (shift), (val)) -static inline void dsaf_set_reg_field(void *base, u32 reg, u32 mask, u32 shift, - u32 val) +static inline void dsaf_set_reg_field(void __iomem *base, u32 reg, u32 mask, + u32 shift, u32 val) { u32 origin = dsaf_read_reg(base, reg); @@ -947,7 +947,8 @@ static inline void dsaf_set_reg_field(void *base, u32 reg, u32 mask, u32 shift, #define dsaf_get_bit(origin, shift) \ dsaf_get_field((origin), (1ull << (shift)), (shift)) -static inline u32 dsaf_get_reg_field(void *base, u32 reg, u32 mask, u32 shift) +static inline u32 dsaf_get_reg_field(void __iomem *base, u32 reg, u32 mask, + u32 shift) { u32 origin; diff --git a/drivers/net/ethernet/icplus/Kconfig b/drivers/net/ethernet/icplus/Kconfig deleted file mode 100644 index 14a66e9..0000000 --- a/drivers/net/ethernet/icplus/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# IC Plus device configuration -# - -config IP1000 - tristate "IP1000 Gigabit Ethernet support" - depends on PCI - select MII - ---help--- - This driver supports IP1000 gigabit Ethernet cards. - - To compile this driver as a module, choose M here: the module - will be called ipg. This is recommended. diff --git a/drivers/net/ethernet/icplus/Makefile b/drivers/net/ethernet/icplus/Makefile deleted file mode 100644 index 5bc87c1..0000000 --- a/drivers/net/ethernet/icplus/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for the IC Plus device drivers -# - -obj-$(CONFIG_IP1000) += ipg.o diff --git a/drivers/net/ethernet/icplus/ipg.c b/drivers/net/ethernet/icplus/ipg.c deleted file mode 100644 index c3b6af8..0000000 --- a/drivers/net/ethernet/icplus/ipg.c +++ /dev/null @@ -1,2300 +0,0 @@ -/* - * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter - * - * Copyright (C) 2003, 2007 IC Plus Corp - * - * Original Author: - * - * Craig Rich - * Sundance Technology, Inc. - * www.sundanceti.com - * craig_rich@sundanceti.com - * - * Current Maintainer: - * - * Sorbica Shieh. - * http://www.icplus.com.tw - * sorbica@icplus.com.tw - * - * Jesse Huang - * http://www.icplus.com.tw - * jesse@icplus.com.tw - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/crc32.h> -#include <linux/ethtool.h> -#include <linux/interrupt.h> -#include <linux/gfp.h> -#include <linux/mii.h> -#include <linux/mutex.h> - -#include <asm/div64.h> - -#define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH) -#define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH) -#define IPG_RESET_MASK \ - (IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \ - IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \ - IPG_AC_AUTO_INIT) - -#define ipg_w32(val32, reg) iowrite32((val32), ioaddr + (reg)) -#define ipg_w16(val16, reg) iowrite16((val16), ioaddr + (reg)) -#define ipg_w8(val8, reg) iowrite8((val8), ioaddr + (reg)) - -#define ipg_r32(reg) ioread32(ioaddr + (reg)) -#define ipg_r16(reg) ioread16(ioaddr + (reg)) -#define ipg_r8(reg) ioread8(ioaddr + (reg)) - -enum { - netdev_io_size = 128 -}; - -#include "ipg.h" -#define DRV_NAME "ipg" - -MODULE_AUTHOR("IC Plus Corp. 2003"); -MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver"); -MODULE_LICENSE("GPL"); - -/* - * Defaults - */ -#define IPG_MAX_RXFRAME_SIZE 0x0600 -#define IPG_RXFRAG_SIZE 0x0600 -#define IPG_RXSUPPORT_SIZE 0x0600 -#define IPG_IS_JUMBO false - -/* - * Variable record -- index by leading revision/length - * Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN - */ -static const unsigned short DefaultPhyParam[] = { - /* 11/12/03 IP1000A v1-3 rev=0x40 */ - /*-------------------------------------------------------------------------- - (0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2, - 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6, - 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7, 9, 0x0700, - --------------------------------------------------------------------------*/ - /* 12/17/03 IP1000A v1-4 rev=0x40 */ - (0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, - 0x0000, - 30, 0x005e, 9, 0x0700, - /* 01/09/04 IP1000A v1-5 rev=0x41 */ - (0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, - 0x0000, - 30, 0x005e, 9, 0x0700, - 0x0000 -}; - -static const char * const ipg_brand_name[] = { - "IC PLUS IP1000 1000/100/10 based NIC", - "Sundance Technology ST2021 based NIC", - "Tamarack Microelectronics TC9020/9021 based NIC", - "D-Link NIC IP1000A" -}; - -static const struct pci_device_id ipg_pci_tbl[] = { - { PCI_VDEVICE(SUNDANCE, 0x1023), 0 }, - { PCI_VDEVICE(SUNDANCE, 0x2021), 1 }, - { PCI_VDEVICE(DLINK, 0x9021), 2 }, - { PCI_VDEVICE(DLINK, 0x4020), 3 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, ipg_pci_tbl); - -static inline void __iomem *ipg_ioaddr(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - return sp->ioaddr; -} - -#ifdef IPG_DEBUG -static void ipg_dump_rfdlist(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - u32 offset; - - IPG_DEBUG_MSG("_dump_rfdlist\n"); - - netdev_info(dev, "rx_current = %02x\n", sp->rx_current); - netdev_info(dev, "rx_dirty = %02x\n", sp->rx_dirty); - netdev_info(dev, "RFDList start address = %016lx\n", - (unsigned long)sp->rxd_map); - netdev_info(dev, "RFDListPtr register = %08x%08x\n", - ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0)); - - for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { - offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd; - netdev_info(dev, "%02x %04x RFDNextPtr = %016lx\n", - i, offset, (unsigned long)sp->rxd[i].next_desc); - offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd; - netdev_info(dev, "%02x %04x RFS = %016lx\n", - i, offset, (unsigned long)sp->rxd[i].rfs); - offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd; - netdev_info(dev, "%02x %04x frag_info = %016lx\n", - i, offset, (unsigned long)sp->rxd[i].frag_info); - } -} - -static void ipg_dump_tfdlist(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - u32 offset; - - IPG_DEBUG_MSG("_dump_tfdlist\n"); - - netdev_info(dev, "tx_current = %02x\n", sp->tx_current); - netdev_info(dev, "tx_dirty = %02x\n", sp->tx_dirty); - netdev_info(dev, "TFDList start address = %016lx\n", - (unsigned long) sp->txd_map); - netdev_info(dev, "TFDListPtr register = %08x%08x\n", - ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0)); - - for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { - offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd; - netdev_info(dev, "%02x %04x TFDNextPtr = %016lx\n", - i, offset, (unsigned long)sp->txd[i].next_desc); - - offset = (u32) &sp->txd[i].tfc - (u32) sp->txd; - netdev_info(dev, "%02x %04x TFC = %016lx\n", - i, offset, (unsigned long) sp->txd[i].tfc); - offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd; - netdev_info(dev, "%02x %04x frag_info = %016lx\n", - i, offset, (unsigned long) sp->txd[i].frag_info); - } -} -#endif - -static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data) -{ - ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL); - ndelay(IPG_PC_PHYCTRLWAIT_NS); -} - -static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data) -{ - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data); - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data); -} - -static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity) -{ - phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR; - - ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity); -} - -static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity) -{ - ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR | - phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL); -} - -static u16 read_phy_bit(void __iomem *ioaddr, u8 phyctrlpolarity) -{ - u16 bit_data; - - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity); - - bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1; - - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity); - - return bit_data; -} - -/* - * Read a register from the Physical Layer device located - * on the IPG NIC, using the IPG PHYCTRL register. - */ -static int mdio_read(struct net_device *dev, int phy_id, int phy_reg) -{ - void __iomem *ioaddr = ipg_ioaddr(dev); - /* - * The GMII mangement frame structure for a read is as follows: - * - * |Preamble|st|op|phyad|regad|ta| data |idle| - * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z | - * - * <32 1s> = 32 consecutive logic 1 values - * A = bit of Physical Layer device address (MSB first) - * R = bit of register address (MSB first) - * z = High impedance state - * D = bit of read data (MSB first) - * - * Transmission order is 'Preamble' field first, bits transmitted - * left to right (first to last). - */ - struct { - u32 field; - unsigned int len; - } p[] = { - { GMII_PREAMBLE, 32 }, /* Preamble */ - { GMII_ST, 2 }, /* ST */ - { GMII_READ, 2 }, /* OP */ - { phy_id, 5 }, /* PHYAD */ - { phy_reg, 5 }, /* REGAD */ - { 0x0000, 2 }, /* TA */ - { 0x0000, 16 }, /* DATA */ - { 0x0000, 1 } /* IDLE */ - }; - unsigned int i, j; - u8 polarity, data; - - polarity = ipg_r8(PHY_CTRL); - polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY); - - /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */ - for (j = 0; j < 5; j++) { - for (i = 0; i < p[j].len; i++) { - /* For each variable length field, the MSB must be - * transmitted first. Rotate through the field bits, - * starting with the MSB, and move each bit into the - * the 1st (2^1) bit position (this is the bit position - * corresponding to the MgmtData bit of the PhyCtrl - * register for the IPG). - * - * Example: ST = 01; - * - * First write a '0' to bit 1 of the PhyCtrl - * register, then write a '1' to bit 1 of the - * PhyCtrl register. - * - * To do this, right shift the MSB of ST by the value: - * [field length - 1 - #ST bits already written] - * then left shift this result by 1. - */ - data = (p[j].field >> (p[j].len - 1 - i)) << 1; - data &= IPG_PC_MGMTDATA; - data |= polarity | IPG_PC_MGMTDIR; - - ipg_drive_phy_ctl_low_high(ioaddr, data); - } - } - - send_three_state(ioaddr, polarity); - - read_phy_bit(ioaddr, polarity); - - /* - * For a read cycle, the bits for the next two fields (TA and - * DATA) are driven by the PHY (the IPG reads these bits). - */ - for (i = 0; i < p[6].len; i++) { - p[6].field |= - (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i)); - } - - send_three_state(ioaddr, polarity); - send_three_state(ioaddr, polarity); - send_three_state(ioaddr, polarity); - send_end(ioaddr, polarity); - - /* Return the value of the DATA field. */ - return p[6].field; -} - -/* - * Write to a register from the Physical Layer device located - * on the IPG NIC, using the IPG PHYCTRL register. - */ -static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val) -{ - void __iomem *ioaddr = ipg_ioaddr(dev); - /* - * The GMII mangement frame structure for a read is as follows: - * - * |Preamble|st|op|phyad|regad|ta| data |idle| - * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z | - * - * <32 1s> = 32 consecutive logic 1 values - * A = bit of Physical Layer device address (MSB first) - * R = bit of register address (MSB first) - * z = High impedance state - * D = bit of write data (MSB first) - * - * Transmission order is 'Preamble' field first, bits transmitted - * left to right (first to last). - */ - struct { - u32 field; - unsigned int len; - } p[] = { - { GMII_PREAMBLE, 32 }, /* Preamble */ - { GMII_ST, 2 }, /* ST */ - { GMII_WRITE, 2 }, /* OP */ - { phy_id, 5 }, /* PHYAD */ - { phy_reg, 5 }, /* REGAD */ - { 0x0002, 2 }, /* TA */ - { val & 0xffff, 16 }, /* DATA */ - { 0x0000, 1 } /* IDLE */ - }; - unsigned int i, j; - u8 polarity, data; - - polarity = ipg_r8(PHY_CTRL); - polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY); - - /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */ - for (j = 0; j < 7; j++) { - for (i = 0; i < p[j].len; i++) { - /* For each variable length field, the MSB must be - * transmitted first. Rotate through the field bits, - * starting with the MSB, and move each bit into the - * the 1st (2^1) bit position (this is the bit position - * corresponding to the MgmtData bit of the PhyCtrl - * register for the IPG). - * - * Example: ST = 01; - * - * First write a '0' to bit 1 of the PhyCtrl - * register, then write a '1' to bit 1 of the - * PhyCtrl register. - * - * To do this, right shift the MSB of ST by the value: - * [field length - 1 - #ST bits already written] - * then left shift this result by 1. - */ - data = (p[j].field >> (p[j].len - 1 - i)) << 1; - data &= IPG_PC_MGMTDATA; - data |= polarity | IPG_PC_MGMTDIR; - - ipg_drive_phy_ctl_low_high(ioaddr, data); - } - } - - /* The last cycle is a tri-state, so read from the PHY. */ - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity); - ipg_r8(PHY_CTRL); - ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity); -} - -static void ipg_set_led_mode(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - u32 mode; - - mode = ipg_r32(ASIC_CTRL); - mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED); - - if ((sp->led_mode & 0x03) > 1) - mode |= IPG_AC_LED_MODE_BIT_1; /* Write Asic Control Bit 29 */ - - if ((sp->led_mode & 0x01) == 1) - mode |= IPG_AC_LED_MODE; /* Write Asic Control Bit 14 */ - - if ((sp->led_mode & 0x08) == 8) - mode |= IPG_AC_LED_SPEED; /* Write Asic Control Bit 27 */ - - ipg_w32(mode, ASIC_CTRL); -} - -static void ipg_set_phy_set(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - int physet; - - physet = ipg_r8(PHY_SET); - physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET); - physet |= ((sp->led_mode & 0x70) >> 4); - ipg_w8(physet, PHY_SET); -} - -static int ipg_reset(struct net_device *dev, u32 resetflags) -{ - /* Assert functional resets via the IPG AsicCtrl - * register as specified by the 'resetflags' input - * parameter. - */ - void __iomem *ioaddr = ipg_ioaddr(dev); - unsigned int timeout_count = 0; - - IPG_DEBUG_MSG("_reset\n"); - - ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL); - - /* Delay added to account for problem with 10Mbps reset. */ - mdelay(IPG_AC_RESETWAIT); - - while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) { - mdelay(IPG_AC_RESETWAIT); - if (++timeout_count > IPG_AC_RESET_TIMEOUT) - return -ETIME; - } - /* Set LED Mode in Asic Control */ - ipg_set_led_mode(dev); - - /* Set PHYSet Register Value */ - ipg_set_phy_set(dev); - return 0; -} - -/* Find the GMII PHY address. */ -static int ipg_find_phyaddr(struct net_device *dev) -{ - unsigned int phyaddr, i; - - for (i = 0; i < 32; i++) { - u32 status; - - /* Search for the correct PHY address among 32 possible. */ - phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32; - - /* 10/22/03 Grace change verify from GMII_PHY_STATUS to - GMII_PHY_ID1 - */ - - status = mdio_read(dev, phyaddr, MII_BMSR); - - if ((status != 0xFFFF) && (status != 0)) - return phyaddr; - } - - return 0x1f; -} - -/* - * Configure IPG based on result of IEEE 802.3 PHY - * auto-negotiation. - */ -static int ipg_config_autoneg(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int txflowcontrol; - unsigned int rxflowcontrol; - unsigned int fullduplex; - u32 mac_ctrl_val; - u32 asicctrl; - u8 phyctrl; - const char *speed; - const char *duplex; - const char *tx_desc; - const char *rx_desc; - - IPG_DEBUG_MSG("_config_autoneg\n"); - - asicctrl = ipg_r32(ASIC_CTRL); - phyctrl = ipg_r8(PHY_CTRL); - mac_ctrl_val = ipg_r32(MAC_CTRL); - - /* Set flags for use in resolving auto-negotiation, assuming - * non-1000Mbps, half duplex, no flow control. - */ - fullduplex = 0; - txflowcontrol = 0; - rxflowcontrol = 0; - - /* To accommodate a problem in 10Mbps operation, - * set a global flag if PHY running in 10Mbps mode. - */ - sp->tenmbpsmode = 0; - - /* Determine actual speed of operation. */ - switch (phyctrl & IPG_PC_LINK_SPEED) { - case IPG_PC_LINK_SPEED_10MBPS: - speed = "10Mbps"; - sp->tenmbpsmode = 1; - break; - case IPG_PC_LINK_SPEED_100MBPS: - speed = "100Mbps"; - break; - case IPG_PC_LINK_SPEED_1000MBPS: - speed = "1000Mbps"; - break; - default: - speed = "undefined!"; - return 0; - } - - netdev_info(dev, "Link speed = %s\n", speed); - if (sp->tenmbpsmode == 1) - netdev_info(dev, "10Mbps operational mode enabled\n"); - - if (phyctrl & IPG_PC_DUPLEX_STATUS) { - fullduplex = 1; - txflowcontrol = 1; - rxflowcontrol = 1; - } - - /* Configure full duplex, and flow control. */ - if (fullduplex == 1) { - - /* Configure IPG for full duplex operation. */ - - duplex = "full"; - - mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD; - - if (txflowcontrol == 1) { - tx_desc = ""; - mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE; - } else { - tx_desc = "no "; - mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE; - } - - if (rxflowcontrol == 1) { - rx_desc = ""; - mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE; - } else { - rx_desc = "no "; - mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE; - } - } else { - duplex = "half"; - tx_desc = "no "; - rx_desc = "no "; - mac_ctrl_val &= (~IPG_MC_DUPLEX_SELECT_FD & - ~IPG_MC_TX_FLOW_CONTROL_ENABLE & - ~IPG_MC_RX_FLOW_CONTROL_ENABLE); - } - - netdev_info(dev, "setting %s duplex, %sTX, %sRX flow control\n", - duplex, tx_desc, rx_desc); - ipg_w32(mac_ctrl_val, MAC_CTRL); - - return 0; -} - -/* Determine and configure multicast operation and set - * receive mode for IPG. - */ -static void ipg_nic_set_multicast_list(struct net_device *dev) -{ - void __iomem *ioaddr = ipg_ioaddr(dev); - struct netdev_hw_addr *ha; - unsigned int hashindex; - u32 hashtable[2]; - u8 receivemode; - - IPG_DEBUG_MSG("_nic_set_multicast_list\n"); - - receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST; - - if (dev->flags & IFF_PROMISC) { - /* NIC to be configured in promiscuous mode. */ - receivemode = IPG_RM_RECEIVEALLFRAMES; - } else if ((dev->flags & IFF_ALLMULTI) || - ((dev->flags & IFF_MULTICAST) && - (netdev_mc_count(dev) > IPG_MULTICAST_HASHTABLE_SIZE))) { - /* NIC to be configured to receive all multicast - * frames. */ - receivemode |= IPG_RM_RECEIVEMULTICAST; - } else if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) { - /* NIC to be configured to receive selected - * multicast addresses. */ - receivemode |= IPG_RM_RECEIVEMULTICASTHASH; - } - - /* Calculate the bits to set for the 64 bit, IPG HASHTABLE. - * The IPG applies a cyclic-redundancy-check (the same CRC - * used to calculate the frame data FCS) to the destination - * address all incoming multicast frames whose destination - * address has the multicast bit set. The least significant - * 6 bits of the CRC result are used as an addressing index - * into the hash table. If the value of the bit addressed by - * this index is a 1, the frame is passed to the host system. - */ - - /* Clear hashtable. */ - hashtable[0] = 0x00000000; - hashtable[1] = 0x00000000; - - /* Cycle through all multicast addresses to filter. */ - netdev_for_each_mc_addr(ha, dev) { - /* Calculate CRC result for each multicast address. */ - hashindex = crc32_le(0xffffffff, ha->addr, - ETH_ALEN); - - /* Use only the least significant 6 bits. */ - hashindex = hashindex & 0x3F; - - /* Within "hashtable", set bit number "hashindex" - * to a logic 1. - */ - set_bit(hashindex, (void *)hashtable); - } - - /* Write the value of the hashtable, to the 4, 16 bit - * HASHTABLE IPG registers. - */ - ipg_w32(hashtable[0], HASHTABLE_0); - ipg_w32(hashtable[1], HASHTABLE_1); - - ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE); - - IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE)); -} - -static int ipg_io_config(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = ipg_ioaddr(dev); - u32 origmacctrl; - u32 restoremacctrl; - - IPG_DEBUG_MSG("_io_config\n"); - - origmacctrl = ipg_r32(MAC_CTRL); - - restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE; - - /* Based on compilation option, determine if FCS is to be - * stripped on receive frames by IPG. - */ - if (!IPG_STRIP_FCS_ON_RX) - restoremacctrl |= IPG_MC_RCV_FCS; - - /* Determine if transmitter and/or receiver are - * enabled so we may restore MACCTRL correctly. - */ - if (origmacctrl & IPG_MC_TX_ENABLED) - restoremacctrl |= IPG_MC_TX_ENABLE; - - if (origmacctrl & IPG_MC_RX_ENABLED) - restoremacctrl |= IPG_MC_RX_ENABLE; - - /* Transmitter and receiver must be disabled before setting - * IFSSelect. - */ - ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) & - IPG_MC_RSVD_MASK, MAC_CTRL); - - /* Now that transmitter and receiver are disabled, write - * to IFSSelect. - */ - ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL); - - /* Set RECEIVEMODE register. */ - ipg_nic_set_multicast_list(dev); - - ipg_w16(sp->max_rxframe_size, MAX_FRAME_SIZE); - - ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE, RX_DMA_POLL_PERIOD); - ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH); - ipg_w8(IPG_RXDMABURSTTHRESH_VALUE, RX_DMA_BURST_THRESH); - ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE, TX_DMA_POLL_PERIOD); - ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH); - ipg_w8(IPG_TXDMABURSTTHRESH_VALUE, TX_DMA_BURST_THRESH); - ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE | - IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED | - IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT | - IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE); - ipg_w16(IPG_FLOWONTHRESH_VALUE, FLOW_ON_THRESH); - ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH); - - /* IPG multi-frag frame bug workaround. - * Per silicon revision B3 eratta. - */ - ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL); - - /* IPG TX poll now bug workaround. - * Per silicon revision B3 eratta. - */ - ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL); - - /* IPG RX poll now bug workaround. - * Per silicon revision B3 eratta. - */ - ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL); - - /* Now restore MACCTRL to original setting. */ - ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL); - - /* Disable unused RMON statistics. */ - ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK); - - /* Disable unused MIB statistics. */ - ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD | - IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES | - IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES | - IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK | - IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS | - IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK); - - return 0; -} - -/* - * Create a receive buffer within system memory and update - * NIC private structure appropriately. - */ -static int ipg_get_rxbuff(struct net_device *dev, int entry) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - struct ipg_rx *rxfd = sp->rxd + entry; - struct sk_buff *skb; - u64 rxfragsize; - - IPG_DEBUG_MSG("_get_rxbuff\n"); - - skb = netdev_alloc_skb_ip_align(dev, sp->rxsupport_size); - if (!skb) { - sp->rx_buff[entry] = NULL; - return -ENOMEM; - } - - /* Save the address of the sk_buff structure. */ - sp->rx_buff[entry] = skb; - - rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE)); - - /* Set the RFD fragment length. */ - rxfragsize = sp->rxfrag_size; - rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN); - - return 0; -} - -static int init_rfdlist(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - - IPG_DEBUG_MSG("_init_rfdlist\n"); - - for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { - struct ipg_rx *rxfd = sp->rxd + i; - - if (sp->rx_buff[i]) { - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb_irq(sp->rx_buff[i]); - sp->rx_buff[i] = NULL; - } - - /* Clear out the RFS field. */ - rxfd->rfs = 0x0000000000000000; - - if (ipg_get_rxbuff(dev, i) < 0) { - /* - * A receive buffer was not ready, break the - * RFD list here. - */ - IPG_DEBUG_MSG("Cannot allocate Rx buffer\n"); - - /* Just in case we cannot allocate a single RFD. - * Should not occur. - */ - if (i == 0) { - netdev_err(dev, "No memory available for RFD list\n"); - return -ENOMEM; - } - } - - rxfd->next_desc = cpu_to_le64(sp->rxd_map + - sizeof(struct ipg_rx)*(i + 1)); - } - sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map); - - sp->rx_current = 0; - sp->rx_dirty = 0; - - /* Write the location of the RFDList to the IPG. */ - ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0); - ipg_w32(0x00000000, RFD_LIST_PTR_1); - - return 0; -} - -static void init_tfdlist(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - - IPG_DEBUG_MSG("_init_tfdlist\n"); - - for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { - struct ipg_tx *txfd = sp->txd + i; - - txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); - - if (sp->tx_buff[i]) { - dev_kfree_skb_irq(sp->tx_buff[i]); - sp->tx_buff[i] = NULL; - } - - txfd->next_desc = cpu_to_le64(sp->txd_map + - sizeof(struct ipg_tx)*(i + 1)); - } - sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map); - - sp->tx_current = 0; - sp->tx_dirty = 0; - - /* Write the location of the TFDList to the IPG. */ - IPG_DDEBUG_MSG("Starting TFDListPtr = %08x\n", - (u32) sp->txd_map); - ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0); - ipg_w32(0x00000000, TFD_LIST_PTR_1); - - sp->reset_current_tfd = 1; -} - -/* - * Free all transmit buffers which have already been transferred - * via DMA to the IPG. - */ -static void ipg_nic_txfree(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int released, pending, dirty; - - IPG_DEBUG_MSG("_nic_txfree\n"); - - pending = sp->tx_current - sp->tx_dirty; - dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH; - - for (released = 0; released < pending; released++) { - struct sk_buff *skb = sp->tx_buff[dirty]; - struct ipg_tx *txfd = sp->txd + dirty; - - IPG_DEBUG_MSG("TFC = %016lx\n", (unsigned long) txfd->tfc); - - /* Look at each TFD's TFC field beginning - * at the last freed TFD up to the current TFD. - * If the TFDDone bit is set, free the associated - * buffer. - */ - if (!(txfd->tfc & cpu_to_le64(IPG_TFC_TFDDONE))) - break; - - /* Free the transmit buffer. */ - if (skb) { - pci_unmap_single(sp->pdev, - le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN, - skb->len, PCI_DMA_TODEVICE); - - dev_kfree_skb_irq(skb); - - sp->tx_buff[dirty] = NULL; - } - dirty = (dirty + 1) % IPG_TFDLIST_LENGTH; - } - - sp->tx_dirty += released; - - if (netif_queue_stopped(dev) && - (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) { - netif_wake_queue(dev); - } -} - -static void ipg_tx_timeout(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - - ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK | - IPG_AC_FIFO); - - spin_lock_irq(&sp->lock); - - /* Re-configure after DMA reset. */ - if (ipg_io_config(dev) < 0) - netdev_info(dev, "Error during re-configuration\n"); - - init_tfdlist(dev); - - spin_unlock_irq(&sp->lock); - - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK, - MAC_CTRL); -} - -/* - * For TxComplete interrupts, free all transmit - * buffers which have already been transferred via DMA - * to the IPG. - */ -static void ipg_nic_txcleanup(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - - IPG_DEBUG_MSG("_nic_txcleanup\n"); - - for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { - /* Reading the TXSTATUS register clears the - * TX_COMPLETE interrupt. - */ - u32 txstatusdword = ipg_r32(TX_STATUS); - - IPG_DEBUG_MSG("TxStatus = %08x\n", txstatusdword); - - /* Check for Transmit errors. Error bits only valid if - * TX_COMPLETE bit in the TXSTATUS register is a 1. - */ - if (!(txstatusdword & IPG_TS_TX_COMPLETE)) - break; - - /* If in 10Mbps mode, indicate transmit is ready. */ - if (sp->tenmbpsmode) { - netif_wake_queue(dev); - } - - /* Transmit error, increment stat counters. */ - if (txstatusdword & IPG_TS_TX_ERROR) { - IPG_DEBUG_MSG("Transmit error\n"); - sp->stats.tx_errors++; - } - - /* Late collision, re-enable transmitter. */ - if (txstatusdword & IPG_TS_LATE_COLLISION) { - IPG_DEBUG_MSG("Late collision on transmit\n"); - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & - IPG_MC_RSVD_MASK, MAC_CTRL); - } - - /* Maximum collisions, re-enable transmitter. */ - if (txstatusdword & IPG_TS_TX_MAX_COLL) { - IPG_DEBUG_MSG("Maximum collisions on transmit\n"); - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & - IPG_MC_RSVD_MASK, MAC_CTRL); - } - - /* Transmit underrun, reset and re-enable - * transmitter. - */ - if (txstatusdword & IPG_TS_TX_UNDERRUN) { - IPG_DEBUG_MSG("Transmitter underrun\n"); - sp->stats.tx_fifo_errors++; - ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | - IPG_AC_NETWORK | IPG_AC_FIFO); - - /* Re-configure after DMA reset. */ - if (ipg_io_config(dev) < 0) { - netdev_info(dev, "Error during re-configuration\n"); - } - init_tfdlist(dev); - - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & - IPG_MC_RSVD_MASK, MAC_CTRL); - } - } - - ipg_nic_txfree(dev); -} - -/* Provides statistical information about the IPG NIC. */ -static struct net_device_stats *ipg_nic_get_stats(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - u16 temp1; - u16 temp2; - - IPG_DEBUG_MSG("_nic_get_stats\n"); - - /* Check to see if the NIC has been initialized via nic_open, - * before trying to read statistic registers. - */ - if (!netif_running(dev)) - return &sp->stats; - - sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK); - sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK); - sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK); - sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK); - temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS); - sp->stats.rx_errors += temp1; - sp->stats.rx_missed_errors += temp1; - temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) + - ipg_r32(IPG_LATECOLLISIONS); - temp2 = ipg_r16(IPG_CARRIERSENSEERRORS); - sp->stats.collisions += temp1; - sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS); - sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) + - ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2; - sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK); - - /* detailed tx_errors */ - sp->stats.tx_carrier_errors += temp2; - - /* detailed rx_errors */ - sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) + - ipg_r16(IPG_FRAMETOOLONGERRORS); - sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS); - - /* Unutilized IPG statistic registers. */ - ipg_r32(IPG_MCSTFRAMESRCVDOK); - - return &sp->stats; -} - -/* Restore used receive buffers. */ -static int ipg_nic_rxrestore(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - const unsigned int curr = sp->rx_current; - unsigned int dirty = sp->rx_dirty; - - IPG_DEBUG_MSG("_nic_rxrestore\n"); - - for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) { - unsigned int entry = dirty % IPG_RFDLIST_LENGTH; - - /* rx_copybreak may poke hole here and there. */ - if (sp->rx_buff[entry]) - continue; - - /* Generate a new receive buffer to replace the - * current buffer (which will be released by the - * Linux system). - */ - if (ipg_get_rxbuff(dev, entry) < 0) { - IPG_DEBUG_MSG("Cannot allocate new Rx buffer\n"); - - break; - } - - /* Reset the RFS field. */ - sp->rxd[entry].rfs = 0x0000000000000000; - } - sp->rx_dirty = dirty; - - return 0; -} - -/* use jumboindex and jumbosize to control jumbo frame status - * initial status is jumboindex=-1 and jumbosize=0 - * 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done. - * 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving - * 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump - * previous receiving and need to continue dumping the current one - */ -enum { - NORMAL_PACKET, - ERROR_PACKET -}; - -enum { - FRAME_NO_START_NO_END = 0, - FRAME_WITH_START = 1, - FRAME_WITH_END = 10, - FRAME_WITH_START_WITH_END = 11 -}; - -static void ipg_nic_rx_free_skb(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; - - if (sp->rx_buff[entry]) { - struct ipg_rx *rxfd = sp->rxd + entry; - - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb_irq(sp->rx_buff[entry]); - sp->rx_buff[entry] = NULL; - } -} - -static int ipg_nic_rx_check_frame_type(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH); - int type = FRAME_NO_START_NO_END; - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) - type += FRAME_WITH_START; - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND) - type += FRAME_WITH_END; - return type; -} - -static int ipg_nic_rx_check_error(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; - struct ipg_rx *rxfd = sp->rxd + entry; - - if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & - (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | - IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | - IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) { - IPG_DEBUG_MSG("Rx error, RFS = %016lx\n", - (unsigned long) rxfd->rfs); - - /* Increment general receive error statistic. */ - sp->stats.rx_errors++; - - /* Increment detailed receive error statistics. */ - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { - IPG_DEBUG_MSG("RX FIFO overrun occurred\n"); - - sp->stats.rx_fifo_errors++; - } - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { - IPG_DEBUG_MSG("RX runt occurred\n"); - sp->stats.rx_length_errors++; - } - - /* Do nothing for IPG_RFS_RXOVERSIZEDFRAME, - * error count handled by a IPG statistic register. - */ - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { - IPG_DEBUG_MSG("RX alignment error occurred\n"); - sp->stats.rx_frame_errors++; - } - - /* Do nothing for IPG_RFS_RXFCSERROR, error count - * handled by a IPG statistic register. - */ - - /* Free the memory associated with the RX - * buffer since it is erroneous and we will - * not pass it to higher layer processes. - */ - if (sp->rx_buff[entry]) { - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - - dev_kfree_skb_irq(sp->rx_buff[entry]); - sp->rx_buff[entry] = NULL; - } - return ERROR_PACKET; - } - return NORMAL_PACKET; -} - -static void ipg_nic_rx_with_start_and_end(struct net_device *dev, - struct ipg_nic_private *sp, - struct ipg_rx *rxfd, unsigned entry) -{ - struct ipg_jumbo *jumbo = &sp->jumbo; - struct sk_buff *skb; - int framelen; - - if (jumbo->found_start) { - dev_kfree_skb_irq(jumbo->skb); - jumbo->found_start = 0; - jumbo->current_size = 0; - jumbo->skb = NULL; - } - - /* 1: found error, 0 no error */ - if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET) - return; - - skb = sp->rx_buff[entry]; - if (!skb) - return; - - /* accept this frame and send to upper layer */ - framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; - if (framelen > sp->rxfrag_size) - framelen = sp->rxfrag_size; - - skb_put(skb, framelen); - skb->protocol = eth_type_trans(skb, dev); - skb_checksum_none_assert(skb); - netif_rx(skb); - sp->rx_buff[entry] = NULL; -} - -static void ipg_nic_rx_with_start(struct net_device *dev, - struct ipg_nic_private *sp, - struct ipg_rx *rxfd, unsigned entry) -{ - struct ipg_jumbo *jumbo = &sp->jumbo; - struct pci_dev *pdev = sp->pdev; - struct sk_buff *skb; - - /* 1: found error, 0 no error */ - if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET) - return; - - /* accept this frame and send to upper layer */ - skb = sp->rx_buff[entry]; - if (!skb) - return; - - if (jumbo->found_start) - dev_kfree_skb_irq(jumbo->skb); - - pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - - skb_put(skb, sp->rxfrag_size); - - jumbo->found_start = 1; - jumbo->current_size = sp->rxfrag_size; - jumbo->skb = skb; - - sp->rx_buff[entry] = NULL; -} - -static void ipg_nic_rx_with_end(struct net_device *dev, - struct ipg_nic_private *sp, - struct ipg_rx *rxfd, unsigned entry) -{ - struct ipg_jumbo *jumbo = &sp->jumbo; - - /* 1: found error, 0 no error */ - if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) { - struct sk_buff *skb = sp->rx_buff[entry]; - - if (!skb) - return; - - if (jumbo->found_start) { - int framelen, endframelen; - - framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; - - endframelen = framelen - jumbo->current_size; - if (framelen > sp->rxsupport_size) - dev_kfree_skb_irq(jumbo->skb); - else { - memcpy(skb_put(jumbo->skb, endframelen), - skb->data, endframelen); - - jumbo->skb->protocol = - eth_type_trans(jumbo->skb, dev); - - skb_checksum_none_assert(jumbo->skb); - netif_rx(jumbo->skb); - } - } - - jumbo->found_start = 0; - jumbo->current_size = 0; - jumbo->skb = NULL; - - ipg_nic_rx_free_skb(dev); - } else { - dev_kfree_skb_irq(jumbo->skb); - jumbo->found_start = 0; - jumbo->current_size = 0; - jumbo->skb = NULL; - } -} - -static void ipg_nic_rx_no_start_no_end(struct net_device *dev, - struct ipg_nic_private *sp, - struct ipg_rx *rxfd, unsigned entry) -{ - struct ipg_jumbo *jumbo = &sp->jumbo; - - /* 1: found error, 0 no error */ - if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) { - struct sk_buff *skb = sp->rx_buff[entry]; - - if (skb) { - if (jumbo->found_start) { - jumbo->current_size += sp->rxfrag_size; - if (jumbo->current_size <= sp->rxsupport_size) { - memcpy(skb_put(jumbo->skb, - sp->rxfrag_size), - skb->data, sp->rxfrag_size); - } - } - ipg_nic_rx_free_skb(dev); - } - } else { - dev_kfree_skb_irq(jumbo->skb); - jumbo->found_start = 0; - jumbo->current_size = 0; - jumbo->skb = NULL; - } -} - -static int ipg_nic_rx_jumbo(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int curr = sp->rx_current; - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - - IPG_DEBUG_MSG("_nic_rx\n"); - - for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { - unsigned int entry = curr % IPG_RFDLIST_LENGTH; - struct ipg_rx *rxfd = sp->rxd + entry; - - if (!(rxfd->rfs & cpu_to_le64(IPG_RFS_RFDDONE))) - break; - - switch (ipg_nic_rx_check_frame_type(dev)) { - case FRAME_WITH_START_WITH_END: - ipg_nic_rx_with_start_and_end(dev, sp, rxfd, entry); - break; - case FRAME_WITH_START: - ipg_nic_rx_with_start(dev, sp, rxfd, entry); - break; - case FRAME_WITH_END: - ipg_nic_rx_with_end(dev, sp, rxfd, entry); - break; - case FRAME_NO_START_NO_END: - ipg_nic_rx_no_start_no_end(dev, sp, rxfd, entry); - break; - } - } - - sp->rx_current = curr; - - if (i == IPG_MAXRFDPROCESS_COUNT) { - /* There are more RFDs to process, however the - * allocated amount of RFD processing time has - * expired. Assert Interrupt Requested to make - * sure we come back to process the remaining RFDs. - */ - ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL); - } - - ipg_nic_rxrestore(dev); - - return 0; -} - -static int ipg_nic_rx(struct net_device *dev) -{ - /* Transfer received Ethernet frames to higher network layers. */ - struct ipg_nic_private *sp = netdev_priv(dev); - unsigned int curr = sp->rx_current; - void __iomem *ioaddr = sp->ioaddr; - struct ipg_rx *rxfd; - unsigned int i; - - IPG_DEBUG_MSG("_nic_rx\n"); - -#define __RFS_MASK \ - cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND) - - for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { - unsigned int entry = curr % IPG_RFDLIST_LENGTH; - struct sk_buff *skb = sp->rx_buff[entry]; - unsigned int framelen; - - rxfd = sp->rxd + entry; - - if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb) - break; - - /* Get received frame length. */ - framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; - - /* Check for jumbo frame arrival with too small - * RXFRAG_SIZE. - */ - if (framelen > sp->rxfrag_size) { - IPG_DEBUG_MSG - ("RFS FrameLen > allocated fragment size\n"); - - framelen = sp->rxfrag_size; - } - - if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & - (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | - IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | - IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) { - - IPG_DEBUG_MSG("Rx error, RFS = %016lx\n", - (unsigned long int) rxfd->rfs); - - /* Increment general receive error statistic. */ - sp->stats.rx_errors++; - - /* Increment detailed receive error statistics. */ - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { - IPG_DEBUG_MSG("RX FIFO overrun occurred\n"); - sp->stats.rx_fifo_errors++; - } - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { - IPG_DEBUG_MSG("RX runt occurred\n"); - sp->stats.rx_length_errors++; - } - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXOVERSIZEDFRAME) ; - /* Do nothing, error count handled by a IPG - * statistic register. - */ - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { - IPG_DEBUG_MSG("RX alignment error occurred\n"); - sp->stats.rx_frame_errors++; - } - - if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFCSERROR) ; - /* Do nothing, error count handled by a IPG - * statistic register. - */ - - /* Free the memory associated with the RX - * buffer since it is erroneous and we will - * not pass it to higher layer processes. - */ - if (skb) { - __le64 info = rxfd->frag_info; - - pci_unmap_single(sp->pdev, - le64_to_cpu(info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - - dev_kfree_skb_irq(skb); - } - } else { - - /* Adjust the new buffer length to accommodate the size - * of the received frame. - */ - skb_put(skb, framelen); - - /* Set the buffer's protocol field to Ethernet. */ - skb->protocol = eth_type_trans(skb, dev); - - /* The IPG encountered an error with (or - * there were no) IP/TCP/UDP checksums. - * This may or may not indicate an invalid - * IP/TCP/UDP frame was received. Let the - * upper layer decide. - */ - skb_checksum_none_assert(skb); - - /* Hand off frame for higher layer processing. - * The function netif_rx() releases the sk_buff - * when processing completes. - */ - netif_rx(skb); - } - - /* Assure RX buffer is not reused by IPG. */ - sp->rx_buff[entry] = NULL; - } - - /* - * If there are more RFDs to process and the allocated amount of RFD - * processing time has expired, assert Interrupt Requested to make - * sure we come back to process the remaining RFDs. - */ - if (i == IPG_MAXRFDPROCESS_COUNT) - ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL); - -#ifdef IPG_DEBUG - /* Check if the RFD list contained no receive frame data. */ - if (!i) - sp->EmptyRFDListCount++; -#endif - while ((le64_to_cpu(rxfd->rfs) & IPG_RFS_RFDDONE) && - !((le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) && - (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND))) { - unsigned int entry = curr++ % IPG_RFDLIST_LENGTH; - - rxfd = sp->rxd + entry; - - IPG_DEBUG_MSG("Frame requires multiple RFDs\n"); - - /* An unexpected event, additional code needed to handle - * properly. So for the time being, just disregard the - * frame. - */ - - /* Free the memory associated with the RX - * buffer since it is erroneous and we will - * not pass it to higher layer processes. - */ - if (sp->rx_buff[entry]) { - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb_irq(sp->rx_buff[entry]); - } - - /* Assure RX buffer is not reused by IPG. */ - sp->rx_buff[entry] = NULL; - } - - sp->rx_current = curr; - - /* Check to see if there are a minimum number of used - * RFDs before restoring any (should improve performance.) - */ - if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE) - ipg_nic_rxrestore(dev); - - return 0; -} - -static void ipg_reset_after_host_error(struct work_struct *work) -{ - struct ipg_nic_private *sp = - container_of(work, struct ipg_nic_private, task.work); - struct net_device *dev = sp->dev; - - /* - * Acknowledge HostError interrupt by resetting - * IPG DMA and HOST. - */ - ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA); - - init_rfdlist(dev); - init_tfdlist(dev); - - if (ipg_io_config(dev) < 0) { - netdev_info(dev, "Cannot recover from PCI error\n"); - schedule_delayed_work(&sp->task, HZ); - } -} - -static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst) -{ - struct net_device *dev = dev_inst; - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int handled = 0; - u16 status; - - IPG_DEBUG_MSG("_interrupt_handler\n"); - - if (sp->is_jumbo) - ipg_nic_rxrestore(dev); - - spin_lock(&sp->lock); - - /* Get interrupt source information, and acknowledge - * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly, - * IntRequested, MacControlFrame, LinkEvent) interrupts - * if issued. Also, all IPG interrupts are disabled by - * reading IntStatusAck. - */ - status = ipg_r16(INT_STATUS_ACK); - - IPG_DEBUG_MSG("IntStatusAck = %04x\n", status); - - /* Shared IRQ of remove event. */ - if (!(status & IPG_IS_RSVD_MASK)) - goto out_enable; - - handled = 1; - - if (unlikely(!netif_running(dev))) - goto out_unlock; - - /* If RFDListEnd interrupt, restore all used RFDs. */ - if (status & IPG_IS_RFD_LIST_END) { - IPG_DEBUG_MSG("RFDListEnd Interrupt\n"); - - /* The RFD list end indicates an RFD was encountered - * with a 0 NextPtr, or with an RFDDone bit set to 1 - * (indicating the RFD is not read for use by the - * IPG.) Try to restore all RFDs. - */ - ipg_nic_rxrestore(dev); - -#ifdef IPG_DEBUG - /* Increment the RFDlistendCount counter. */ - sp->RFDlistendCount++; -#endif - } - - /* If RFDListEnd, RxDMAPriority, RxDMAComplete, or - * IntRequested interrupt, process received frames. */ - if ((status & IPG_IS_RX_DMA_PRIORITY) || - (status & IPG_IS_RFD_LIST_END) || - (status & IPG_IS_RX_DMA_COMPLETE) || - (status & IPG_IS_INT_REQUESTED)) { -#ifdef IPG_DEBUG - /* Increment the RFD list checked counter if interrupted - * only to check the RFD list. */ - if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END | - IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) & - (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE | - IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE | - IPG_IS_UPDATE_STATS))) - sp->RFDListCheckedCount++; -#endif - - if (sp->is_jumbo) - ipg_nic_rx_jumbo(dev); - else - ipg_nic_rx(dev); - } - - /* If TxDMAComplete interrupt, free used TFDs. */ - if (status & IPG_IS_TX_DMA_COMPLETE) - ipg_nic_txfree(dev); - - /* TxComplete interrupts indicate one of numerous actions. - * Determine what action to take based on TXSTATUS register. - */ - if (status & IPG_IS_TX_COMPLETE) - ipg_nic_txcleanup(dev); - - /* If UpdateStats interrupt, update Linux Ethernet statistics */ - if (status & IPG_IS_UPDATE_STATS) - ipg_nic_get_stats(dev); - - /* If HostError interrupt, reset IPG. */ - if (status & IPG_IS_HOST_ERROR) { - IPG_DDEBUG_MSG("HostError Interrupt\n"); - - schedule_delayed_work(&sp->task, 0); - } - - /* If LinkEvent interrupt, resolve autonegotiation. */ - if (status & IPG_IS_LINK_EVENT) { - if (ipg_config_autoneg(dev) < 0) - netdev_info(dev, "Auto-negotiation error\n"); - } - - /* If MACCtrlFrame interrupt, do nothing. */ - if (status & IPG_IS_MAC_CTRL_FRAME) - IPG_DEBUG_MSG("MACCtrlFrame interrupt\n"); - - /* If RxComplete interrupt, do nothing. */ - if (status & IPG_IS_RX_COMPLETE) - IPG_DEBUG_MSG("RxComplete interrupt\n"); - - /* If RxEarly interrupt, do nothing. */ - if (status & IPG_IS_RX_EARLY) - IPG_DEBUG_MSG("RxEarly interrupt\n"); - -out_enable: - /* Re-enable IPG interrupts. */ - ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE | - IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE | - IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE); -out_unlock: - spin_unlock(&sp->lock); - - return IRQ_RETVAL(handled); -} - -static void ipg_rx_clear(struct ipg_nic_private *sp) -{ - unsigned int i; - - for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { - if (sp->rx_buff[i]) { - struct ipg_rx *rxfd = sp->rxd + i; - - dev_kfree_skb_irq(sp->rx_buff[i]); - sp->rx_buff[i] = NULL; - pci_unmap_single(sp->pdev, - le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, - sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - } - } -} - -static void ipg_tx_clear(struct ipg_nic_private *sp) -{ - unsigned int i; - - for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { - if (sp->tx_buff[i]) { - struct ipg_tx *txfd = sp->txd + i; - - pci_unmap_single(sp->pdev, - le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN, - sp->tx_buff[i]->len, PCI_DMA_TODEVICE); - - dev_kfree_skb_irq(sp->tx_buff[i]); - - sp->tx_buff[i] = NULL; - } - } -} - -static int ipg_nic_open(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - struct pci_dev *pdev = sp->pdev; - int rc; - - IPG_DEBUG_MSG("_nic_open\n"); - - sp->rx_buf_sz = sp->rxsupport_size; - - /* Check for interrupt line conflicts, and request interrupt - * line for IPG. - * - * IMPORTANT: Disable IPG interrupts prior to registering - * IRQ. - */ - ipg_w16(0x0000, INT_ENABLE); - - /* Register the interrupt line to be used by the IPG within - * the Linux system. - */ - rc = request_irq(pdev->irq, ipg_interrupt_handler, IRQF_SHARED, - dev->name, dev); - if (rc < 0) { - netdev_info(dev, "Error when requesting interrupt\n"); - goto out; - } - - dev->irq = pdev->irq; - - rc = -ENOMEM; - - sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES, - &sp->rxd_map, GFP_KERNEL); - if (!sp->rxd) - goto err_free_irq_0; - - sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES, - &sp->txd_map, GFP_KERNEL); - if (!sp->txd) - goto err_free_rx_1; - - rc = init_rfdlist(dev); - if (rc < 0) { - netdev_info(dev, "Error during configuration\n"); - goto err_free_tx_2; - } - - init_tfdlist(dev); - - rc = ipg_io_config(dev); - if (rc < 0) { - netdev_info(dev, "Error during configuration\n"); - goto err_release_tfdlist_3; - } - - /* Resolve autonegotiation. */ - if (ipg_config_autoneg(dev) < 0) - netdev_info(dev, "Auto-negotiation error\n"); - - /* initialize JUMBO Frame control variable */ - sp->jumbo.found_start = 0; - sp->jumbo.current_size = 0; - sp->jumbo.skb = NULL; - - /* Enable transmit and receive operation of the IPG. */ - ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) & - IPG_MC_RSVD_MASK, MAC_CTRL); - - netif_start_queue(dev); -out: - return rc; - -err_release_tfdlist_3: - ipg_tx_clear(sp); - ipg_rx_clear(sp); -err_free_tx_2: - dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map); -err_free_rx_1: - dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map); -err_free_irq_0: - free_irq(pdev->irq, dev); - goto out; -} - -static int ipg_nic_stop(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - struct pci_dev *pdev = sp->pdev; - - IPG_DEBUG_MSG("_nic_stop\n"); - - netif_stop_queue(dev); - - IPG_DUMPTFDLIST(dev); - - do { - (void) ipg_r16(INT_STATUS_ACK); - - ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA); - - synchronize_irq(pdev->irq); - } while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK); - - ipg_rx_clear(sp); - - ipg_tx_clear(sp); - - pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map); - pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map); - - free_irq(pdev->irq, dev); - - return 0; -} - -static netdev_tx_t ipg_nic_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH; - unsigned long flags; - struct ipg_tx *txfd; - - IPG_DDEBUG_MSG("_nic_hard_start_xmit\n"); - - /* If in 10Mbps mode, stop the transmit queue so - * no more transmit frames are accepted. - */ - if (sp->tenmbpsmode) - netif_stop_queue(dev); - - if (sp->reset_current_tfd) { - sp->reset_current_tfd = 0; - entry = 0; - } - - txfd = sp->txd + entry; - - sp->tx_buff[entry] = skb; - - /* Clear all TFC fields, except TFDDONE. */ - txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); - - /* Specify the TFC field within the TFD. */ - txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED | - (IPG_TFC_FRAMEID & sp->tx_current) | - (IPG_TFC_FRAGCOUNT & (1 << 24))); - /* - * 16--17 (WordAlign) <- 3 (disable), - * 0--15 (FrameId) <- sp->tx_current, - * 24--27 (FragCount) <- 1 - */ - - /* Request TxComplete interrupts at an interval defined - * by the constant IPG_FRAMESBETWEENTXCOMPLETES. - * Request TxComplete interrupt for every frame - * if in 10Mbps mode to accommodate problem with 10Mbps - * processing. - */ - if (sp->tenmbpsmode) - txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE); - txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE); - /* Based on compilation option, determine if FCS is to be - * appended to transmit frame by IPG. - */ - if (!(IPG_APPEND_FCS_ON_TX)) - txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE); - - /* Based on compilation option, determine if IP, TCP and/or - * UDP checksums are to be added to transmit frame by IPG. - */ - if (IPG_ADD_IPCHECKSUM_ON_TX) - txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE); - - if (IPG_ADD_TCPCHECKSUM_ON_TX) - txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE); - - if (IPG_ADD_UDPCHECKSUM_ON_TX) - txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE); - - /* Based on compilation option, determine if VLAN tag info is to be - * inserted into transmit frame by IPG. - */ - if (IPG_INSERT_MANUAL_VLAN_TAG) { - txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT | - ((u64) IPG_MANUAL_VLAN_VID << 32) | - ((u64) IPG_MANUAL_VLAN_CFI << 44) | - ((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45)); - } - - /* The fragment start location within system memory is defined - * by the sk_buff structure's data field. The physical address - * of this location within the system's virtual memory space - * is determined using the IPG_HOST2BUS_MAP function. - */ - txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - - /* The length of the fragment within system memory is defined by - * the sk_buff structure's len field. - */ - txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN & - ((u64) (skb->len & 0xffff) << 48)); - - /* Clear the TFDDone bit last to indicate the TFD is ready - * for transfer to the IPG. - */ - txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE); - - spin_lock_irqsave(&sp->lock, flags); - - sp->tx_current++; - - mmiowb(); - - ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL); - - if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH)) - netif_stop_queue(dev); - - spin_unlock_irqrestore(&sp->lock, flags); - - return NETDEV_TX_OK; -} - -static void ipg_set_phy_default_param(unsigned char rev, - struct net_device *dev, int phy_address) -{ - unsigned short length; - unsigned char revision; - const unsigned short *phy_param; - unsigned short address, value; - - phy_param = &DefaultPhyParam[0]; - length = *phy_param & 0x00FF; - revision = (unsigned char)((*phy_param) >> 8); - phy_param++; - while (length != 0) { - if (rev == revision) { - while (length > 1) { - address = *phy_param; - value = *(phy_param + 1); - phy_param += 2; - mdio_write(dev, phy_address, address, value); - length -= 4; - } - break; - } else { - phy_param += length / 2; - length = *phy_param & 0x00FF; - revision = (unsigned char)((*phy_param) >> 8); - phy_param++; - } - } -} - -static int read_eeprom(struct net_device *dev, int eep_addr) -{ - void __iomem *ioaddr = ipg_ioaddr(dev); - unsigned int i; - int ret = 0; - u16 value; - - value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff); - ipg_w16(value, EEPROM_CTRL); - - for (i = 0; i < 1000; i++) { - u16 data; - - mdelay(10); - data = ipg_r16(EEPROM_CTRL); - if (!(data & IPG_EC_EEPROM_BUSY)) { - ret = ipg_r16(EEPROM_DATA); - break; - } - } - return ret; -} - -static void ipg_init_mii(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - struct mii_if_info *mii_if = &sp->mii_if; - int phyaddr; - - mii_if->dev = dev; - mii_if->mdio_read = mdio_read; - mii_if->mdio_write = mdio_write; - mii_if->phy_id_mask = 0x1f; - mii_if->reg_num_mask = 0x1f; - - mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev); - - if (phyaddr != 0x1f) { - u16 mii_phyctrl, mii_1000cr; - - mii_1000cr = mdio_read(dev, phyaddr, MII_CTRL1000); - mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF | - GMII_PHY_1000BASETCONTROL_PreferMaster; - mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr); - - mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR); - - /* Set default phyparam */ - ipg_set_phy_default_param(sp->pdev->revision, dev, phyaddr); - - /* Reset PHY */ - mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART; - mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl); - - } -} - -static int ipg_hw_init(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int i; - int rc; - - /* Read/Write and Reset EEPROM Value */ - /* Read LED Mode Configuration from EEPROM */ - sp->led_mode = read_eeprom(dev, 6); - - /* Reset all functions within the IPG. Do not assert - * RST_OUT as not compatible with some PHYs. - */ - rc = ipg_reset(dev, IPG_RESET_MASK); - if (rc < 0) - goto out; - - ipg_init_mii(dev); - - /* Read MAC Address from EEPROM */ - for (i = 0; i < 3; i++) - sp->station_addr[i] = read_eeprom(dev, 16 + i); - - for (i = 0; i < 3; i++) - ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i); - - /* Set station address in ethernet_device structure. */ - dev->dev_addr[0] = ipg_r16(STATION_ADDRESS_0) & 0x00ff; - dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8; - dev->dev_addr[2] = ipg_r16(STATION_ADDRESS_1) & 0x00ff; - dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8; - dev->dev_addr[4] = ipg_r16(STATION_ADDRESS_2) & 0x00ff; - dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8; -out: - return rc; -} - -static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int rc; - - mutex_lock(&sp->mii_mutex); - rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL); - mutex_unlock(&sp->mii_mutex); - - return rc; -} - -static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int err; - - /* Function to accommodate changes to Maximum Transfer Unit - * (or MTU) of IPG NIC. Cannot use default function since - * the default will not allow for MTU > 1500 bytes. - */ - - IPG_DEBUG_MSG("_nic_change_mtu\n"); - - /* - * Check that the new MTU value is between 68 (14 byte header, 46 byte - * payload, 4 byte FCS) and 10 KB, which is the largest supported MTU. - */ - if (new_mtu < 68 || new_mtu > 10240) - return -EINVAL; - - err = ipg_nic_stop(dev); - if (err) - return err; - - dev->mtu = new_mtu; - - sp->max_rxframe_size = new_mtu; - - sp->rxfrag_size = new_mtu; - if (sp->rxfrag_size > 4088) - sp->rxfrag_size = 4088; - - sp->rxsupport_size = sp->max_rxframe_size; - - if (new_mtu > 0x0600) - sp->is_jumbo = true; - else - sp->is_jumbo = false; - - return ipg_nic_open(dev); -} - -static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int rc; - - mutex_lock(&sp->mii_mutex); - rc = mii_ethtool_gset(&sp->mii_if, cmd); - mutex_unlock(&sp->mii_mutex); - - return rc; -} - -static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int rc; - - mutex_lock(&sp->mii_mutex); - rc = mii_ethtool_sset(&sp->mii_if, cmd); - mutex_unlock(&sp->mii_mutex); - - return rc; -} - -static int ipg_nway_reset(struct net_device *dev) -{ - struct ipg_nic_private *sp = netdev_priv(dev); - int rc; - - mutex_lock(&sp->mii_mutex); - rc = mii_nway_restart(&sp->mii_if); - mutex_unlock(&sp->mii_mutex); - - return rc; -} - -static const struct ethtool_ops ipg_ethtool_ops = { - .get_settings = ipg_get_settings, - .set_settings = ipg_set_settings, - .nway_reset = ipg_nway_reset, -}; - -static void ipg_remove(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct ipg_nic_private *sp = netdev_priv(dev); - - IPG_DEBUG_MSG("_remove\n"); - - /* Un-register Ethernet device. */ - unregister_netdev(dev); - - pci_iounmap(pdev, sp->ioaddr); - - pci_release_regions(pdev); - - free_netdev(dev); - pci_disable_device(pdev); -} - -static const struct net_device_ops ipg_netdev_ops = { - .ndo_open = ipg_nic_open, - .ndo_stop = ipg_nic_stop, - .ndo_start_xmit = ipg_nic_hard_start_xmit, - .ndo_get_stats = ipg_nic_get_stats, - .ndo_set_rx_mode = ipg_nic_set_multicast_list, - .ndo_do_ioctl = ipg_ioctl, - .ndo_tx_timeout = ipg_tx_timeout, - .ndo_change_mtu = ipg_nic_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int ipg_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - unsigned int i = id->driver_data; - struct ipg_nic_private *sp; - struct net_device *dev; - void __iomem *ioaddr; - int rc; - - rc = pci_enable_device(pdev); - if (rc < 0) - goto out; - - pr_info("%s: %s\n", pci_name(pdev), ipg_brand_name[i]); - - pci_set_master(pdev); - - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(40)); - if (rc < 0) { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc < 0) { - pr_err("%s: DMA config failed\n", pci_name(pdev)); - goto err_disable_0; - } - } - - /* - * Initialize net device. - */ - dev = alloc_etherdev(sizeof(struct ipg_nic_private)); - if (!dev) { - rc = -ENOMEM; - goto err_disable_0; - } - - sp = netdev_priv(dev); - spin_lock_init(&sp->lock); - mutex_init(&sp->mii_mutex); - - sp->is_jumbo = IPG_IS_JUMBO; - sp->rxfrag_size = IPG_RXFRAG_SIZE; - sp->rxsupport_size = IPG_RXSUPPORT_SIZE; - sp->max_rxframe_size = IPG_MAX_RXFRAME_SIZE; - - /* Declare IPG NIC functions for Ethernet device methods. - */ - dev->netdev_ops = &ipg_netdev_ops; - SET_NETDEV_DEV(dev, &pdev->dev); - dev->ethtool_ops = &ipg_ethtool_ops; - - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - goto err_free_dev_1; - - ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1)); - if (!ioaddr) { - pr_err("%s: cannot map MMIO\n", pci_name(pdev)); - rc = -EIO; - goto err_release_regions_2; - } - - /* Save the pointer to the PCI device information. */ - sp->ioaddr = ioaddr; - sp->pdev = pdev; - sp->dev = dev; - - INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error); - - pci_set_drvdata(pdev, dev); - - rc = ipg_hw_init(dev); - if (rc < 0) - goto err_unmap_3; - - rc = register_netdev(dev); - if (rc < 0) - goto err_unmap_3; - - netdev_info(dev, "Ethernet device registered\n"); -out: - return rc; - -err_unmap_3: - pci_iounmap(pdev, ioaddr); -err_release_regions_2: - pci_release_regions(pdev); -err_free_dev_1: - free_netdev(dev); -err_disable_0: - pci_disable_device(pdev); - goto out; -} - -static struct pci_driver ipg_pci_driver = { - .name = IPG_DRIVER_NAME, - .id_table = ipg_pci_tbl, - .probe = ipg_probe, - .remove = ipg_remove, -}; - -module_pci_driver(ipg_pci_driver); diff --git a/drivers/net/ethernet/icplus/ipg.h b/drivers/net/ethernet/icplus/ipg.h deleted file mode 100644 index de60628..0000000 --- a/drivers/net/ethernet/icplus/ipg.h +++ /dev/null @@ -1,748 +0,0 @@ -/* - * Include file for Gigabit Ethernet device driver for Network - * Interface Cards (NICs) utilizing the Tamarack Microelectronics - * Inc. IPG Gigabit or Triple Speed Ethernet Media Access - * Controller. - */ -#ifndef __LINUX_IPG_H -#define __LINUX_IPG_H - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/ioport.h> -#include <linux/errno.h> -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <asm/bitops.h> - -/* - * Constants - */ - -/* GMII based PHY IDs */ -#define NS 0x2000 -#define MARVELL 0x0141 -#define ICPLUS_PHY 0x243 - -/* NIC Physical Layer Device MII register fields. */ -#define MII_PHY_SELECTOR_IEEE8023 0x0001 -#define MII_PHY_TECHABILITYFIELD 0x1FE0 - -/* GMII_PHY_1000 need to set to prefer master */ -#define GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400 - -/* NIC Physical Layer Device GMII constants. */ -#define GMII_PREAMBLE 0xFFFFFFFF -#define GMII_ST 0x1 -#define GMII_READ 0x2 -#define GMII_WRITE 0x1 -#define GMII_TA_READ_MASK 0x1 -#define GMII_TA_WRITE 0x2 - -/* I/O register offsets. */ -enum ipg_regs { - DMA_CTRL = 0x00, - RX_DMA_STATUS = 0x08, /* Unused + reserved */ - TFD_LIST_PTR_0 = 0x10, - TFD_LIST_PTR_1 = 0x14, - TX_DMA_BURST_THRESH = 0x18, - TX_DMA_URGENT_THRESH = 0x19, - TX_DMA_POLL_PERIOD = 0x1a, - RFD_LIST_PTR_0 = 0x1c, - RFD_LIST_PTR_1 = 0x20, - RX_DMA_BURST_THRESH = 0x24, - RX_DMA_URGENT_THRESH = 0x25, - RX_DMA_POLL_PERIOD = 0x26, - DEBUG_CTRL = 0x2c, - ASIC_CTRL = 0x30, - FIFO_CTRL = 0x38, /* Unused */ - FLOW_OFF_THRESH = 0x3c, - FLOW_ON_THRESH = 0x3e, - EEPROM_DATA = 0x48, - EEPROM_CTRL = 0x4a, - EXPROM_ADDR = 0x4c, /* Unused */ - EXPROM_DATA = 0x50, /* Unused */ - WAKE_EVENT = 0x51, /* Unused */ - COUNTDOWN = 0x54, /* Unused */ - INT_STATUS_ACK = 0x5a, - INT_ENABLE = 0x5c, - INT_STATUS = 0x5e, /* Unused */ - TX_STATUS = 0x60, - MAC_CTRL = 0x6c, - VLAN_TAG = 0x70, /* Unused */ - PHY_SET = 0x75, - PHY_CTRL = 0x76, - STATION_ADDRESS_0 = 0x78, - STATION_ADDRESS_1 = 0x7a, - STATION_ADDRESS_2 = 0x7c, - MAX_FRAME_SIZE = 0x86, - RECEIVE_MODE = 0x88, - HASHTABLE_0 = 0x8c, - HASHTABLE_1 = 0x90, - RMON_STATISTICS_MASK = 0x98, - STATISTICS_MASK = 0x9c, - RX_JUMBO_FRAMES = 0xbc, /* Unused */ - TCP_CHECKSUM_ERRORS = 0xc0, /* Unused */ - IP_CHECKSUM_ERRORS = 0xc2, /* Unused */ - UDP_CHECKSUM_ERRORS = 0xc4, /* Unused */ - TX_JUMBO_FRAMES = 0xf4 /* Unused */ -}; - -/* Ethernet MIB statistic register offsets. */ -#define IPG_OCTETRCVOK 0xA8 -#define IPG_MCSTOCTETRCVDOK 0xAC -#define IPG_BCSTOCTETRCVOK 0xB0 -#define IPG_FRAMESRCVDOK 0xB4 -#define IPG_MCSTFRAMESRCVDOK 0xB8 -#define IPG_BCSTFRAMESRCVDOK 0xBE -#define IPG_MACCONTROLFRAMESRCVD 0xC6 -#define IPG_FRAMETOOLONGERRORS 0xC8 -#define IPG_INRANGELENGTHERRORS 0xCA -#define IPG_FRAMECHECKSEQERRORS 0xCC -#define IPG_FRAMESLOSTRXERRORS 0xCE -#define IPG_OCTETXMTOK 0xD0 -#define IPG_MCSTOCTETXMTOK 0xD4 -#define IPG_BCSTOCTETXMTOK 0xD8 -#define IPG_FRAMESXMTDOK 0xDC -#define IPG_MCSTFRAMESXMTDOK 0xE0 -#define IPG_FRAMESWDEFERREDXMT 0xE4 -#define IPG_LATECOLLISIONS 0xE8 -#define IPG_MULTICOLFRAMES 0xEC -#define IPG_SINGLECOLFRAMES 0xF0 -#define IPG_BCSTFRAMESXMTDOK 0xF6 -#define IPG_CARRIERSENSEERRORS 0xF8 -#define IPG_MACCONTROLFRAMESXMTDOK 0xFA -#define IPG_FRAMESABORTXSCOLLS 0xFC -#define IPG_FRAMESWEXDEFERRAL 0xFE - -/* RMON statistic register offsets. */ -#define IPG_ETHERSTATSCOLLISIONS 0x100 -#define IPG_ETHERSTATSOCTETSTRANSMIT 0x104 -#define IPG_ETHERSTATSPKTSTRANSMIT 0x108 -#define IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT 0x10C -#define IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT 0x110 -#define IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT 0x114 -#define IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT 0x118 -#define IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT 0x11C -#define IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT 0x120 -#define IPG_ETHERSTATSCRCALIGNERRORS 0x124 -#define IPG_ETHERSTATSUNDERSIZEPKTS 0x128 -#define IPG_ETHERSTATSFRAGMENTS 0x12C -#define IPG_ETHERSTATSJABBERS 0x130 -#define IPG_ETHERSTATSOCTETS 0x134 -#define IPG_ETHERSTATSPKTS 0x138 -#define IPG_ETHERSTATSPKTS64OCTESTS 0x13C -#define IPG_ETHERSTATSPKTS65TO127OCTESTS 0x140 -#define IPG_ETHERSTATSPKTS128TO255OCTESTS 0x144 -#define IPG_ETHERSTATSPKTS256TO511OCTESTS 0x148 -#define IPG_ETHERSTATSPKTS512TO1023OCTESTS 0x14C -#define IPG_ETHERSTATSPKTS1024TO1518OCTESTS 0x150 - -/* RMON statistic register equivalents. */ -#define IPG_ETHERSTATSMULTICASTPKTSTRANSMIT 0xE0 -#define IPG_ETHERSTATSBROADCASTPKTSTRANSMIT 0xF6 -#define IPG_ETHERSTATSMULTICASTPKTS 0xB8 -#define IPG_ETHERSTATSBROADCASTPKTS 0xBE -#define IPG_ETHERSTATSOVERSIZEPKTS 0xC8 -#define IPG_ETHERSTATSDROPEVENTS 0xCE - -/* Serial EEPROM offsets */ -#define IPG_EEPROM_CONFIGPARAM 0x00 -#define IPG_EEPROM_ASICCTRL 0x01 -#define IPG_EEPROM_SUBSYSTEMVENDORID 0x02 -#define IPG_EEPROM_SUBSYSTEMID 0x03 -#define IPG_EEPROM_STATIONADDRESS0 0x10 -#define IPG_EEPROM_STATIONADDRESS1 0x11 -#define IPG_EEPROM_STATIONADDRESS2 0x12 - -/* Register & data structure bit masks */ - -/* PCI register masks. */ - -/* IOBaseAddress */ -#define IPG_PIB_RSVD_MASK 0xFFFFFE01 -#define IPG_PIB_IOBASEADDRESS 0xFFFFFF00 -#define IPG_PIB_IOBASEADDRIND 0x00000001 - -/* MemBaseAddress */ -#define IPG_PMB_RSVD_MASK 0xFFFFFE07 -#define IPG_PMB_MEMBASEADDRIND 0x00000001 -#define IPG_PMB_MEMMAPTYPE 0x00000006 -#define IPG_PMB_MEMMAPTYPE0 0x00000002 -#define IPG_PMB_MEMMAPTYPE1 0x00000004 -#define IPG_PMB_MEMBASEADDRESS 0xFFFFFE00 - -/* ConfigStatus */ -#define IPG_CS_RSVD_MASK 0xFFB0 -#define IPG_CS_CAPABILITIES 0x0010 -#define IPG_CS_66MHZCAPABLE 0x0020 -#define IPG_CS_FASTBACK2BACK 0x0080 -#define IPG_CS_DATAPARITYREPORTED 0x0100 -#define IPG_CS_DEVSELTIMING 0x0600 -#define IPG_CS_SIGNALEDTARGETABORT 0x0800 -#define IPG_CS_RECEIVEDTARGETABORT 0x1000 -#define IPG_CS_RECEIVEDMASTERABORT 0x2000 -#define IPG_CS_SIGNALEDSYSTEMERROR 0x4000 -#define IPG_CS_DETECTEDPARITYERROR 0x8000 - -/* TFD data structure masks. */ - -/* TFDList, TFC */ -#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFFULL -#define IPG_TFC_FRAMEID 0x000000000000FFFFULL -#define IPG_TFC_WORDALIGN 0x0000000000030000ULL -#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000ULL -#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000ULL -#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000ULL -#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000ULL -#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000ULL -#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000ULL -#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000ULL -#define IPG_TFC_TXINDICATE 0x0000000000400000ULL -#define IPG_TFC_TXDMAINDICATE 0x0000000000800000ULL -#define IPG_TFC_FRAGCOUNT 0x000000000F000000ULL -#define IPG_TFC_VLANTAGINSERT 0x0000000010000000ULL -#define IPG_TFC_TFDDONE 0x0000000080000000ULL -#define IPG_TFC_VID 0x00000FFF00000000ULL -#define IPG_TFC_CFI 0x0000100000000000ULL -#define IPG_TFC_USERPRIORITY 0x0000E00000000000ULL - -/* TFDList, FragInfo */ -#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL -#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFFULL -#define IPG_TFI_FRAGLEN 0xFFFF000000000000ULL - -/* RFD data structure masks. */ - -/* RFDList, RFS */ -#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFFULL -#define IPG_RFS_RXFRAMELEN 0x000000000000FFFFULL -#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000ULL -#define IPG_RFS_RXRUNTFRAME 0x0000000000020000ULL -#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000ULL -#define IPG_RFS_RXFCSERROR 0x0000000000080000ULL -#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000ULL -#define IPG_RFS_RXLENGTHERROR 0x0000000000200000ULL -#define IPG_RFS_VLANDETECTED 0x0000000000400000ULL -#define IPG_RFS_TCPDETECTED 0x0000000000800000ULL -#define IPG_RFS_TCPERROR 0x0000000001000000ULL -#define IPG_RFS_UDPDETECTED 0x0000000002000000ULL -#define IPG_RFS_UDPERROR 0x0000000004000000ULL -#define IPG_RFS_IPDETECTED 0x0000000008000000ULL -#define IPG_RFS_IPERROR 0x0000000010000000ULL -#define IPG_RFS_FRAMESTART 0x0000000020000000ULL -#define IPG_RFS_FRAMEEND 0x0000000040000000ULL -#define IPG_RFS_RFDDONE 0x0000000080000000ULL -#define IPG_RFS_TCI 0x0000FFFF00000000ULL - -/* RFDList, FragInfo */ -#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL -#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFFULL -#define IPG_RFI_FRAGLEN 0xFFFF000000000000ULL - -/* I/O Register masks. */ - -/* RMON Statistics Mask */ -#define IPG_RZ_ALL 0x0FFFFFFF - -/* Statistics Mask */ -#define IPG_SM_ALL 0x0FFFFFFF -#define IPG_SM_OCTETRCVOK_FRAMESRCVDOK 0x00000001 -#define IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK 0x00000002 -#define IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK 0x00000004 -#define IPG_SM_RXJUMBOFRAMES 0x00000008 -#define IPG_SM_TCPCHECKSUMERRORS 0x00000010 -#define IPG_SM_IPCHECKSUMERRORS 0x00000020 -#define IPG_SM_UDPCHECKSUMERRORS 0x00000040 -#define IPG_SM_MACCONTROLFRAMESRCVD 0x00000080 -#define IPG_SM_FRAMESTOOLONGERRORS 0x00000100 -#define IPG_SM_INRANGELENGTHERRORS 0x00000200 -#define IPG_SM_FRAMECHECKSEQERRORS 0x00000400 -#define IPG_SM_FRAMESLOSTRXERRORS 0x00000800 -#define IPG_SM_OCTETXMTOK_FRAMESXMTOK 0x00001000 -#define IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK 0x00002000 -#define IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK 0x00004000 -#define IPG_SM_FRAMESWDEFERREDXMT 0x00008000 -#define IPG_SM_LATECOLLISIONS 0x00010000 -#define IPG_SM_MULTICOLFRAMES 0x00020000 -#define IPG_SM_SINGLECOLFRAMES 0x00040000 -#define IPG_SM_TXJUMBOFRAMES 0x00080000 -#define IPG_SM_CARRIERSENSEERRORS 0x00100000 -#define IPG_SM_MACCONTROLFRAMESXMTD 0x00200000 -#define IPG_SM_FRAMESABORTXSCOLLS 0x00400000 -#define IPG_SM_FRAMESWEXDEFERAL 0x00800000 - -/* Countdown */ -#define IPG_CD_RSVD_MASK 0x0700FFFF -#define IPG_CD_COUNT 0x0000FFFF -#define IPG_CD_COUNTDOWNSPEED 0x01000000 -#define IPG_CD_COUNTDOWNMODE 0x02000000 -#define IPG_CD_COUNTINTENABLED 0x04000000 - -/* TxDMABurstThresh */ -#define IPG_TB_RSVD_MASK 0xFF - -/* TxDMAUrgentThresh */ -#define IPG_TU_RSVD_MASK 0xFF - -/* TxDMAPollPeriod */ -#define IPG_TP_RSVD_MASK 0xFF - -/* RxDMAUrgentThresh */ -#define IPG_RU_RSVD_MASK 0xFF - -/* RxDMAPollPeriod */ -#define IPG_RP_RSVD_MASK 0xFF - -/* ReceiveMode */ -#define IPG_RM_RSVD_MASK 0x3F -#define IPG_RM_RECEIVEUNICAST 0x01 -#define IPG_RM_RECEIVEMULTICAST 0x02 -#define IPG_RM_RECEIVEBROADCAST 0x04 -#define IPG_RM_RECEIVEALLFRAMES 0x08 -#define IPG_RM_RECEIVEMULTICASTHASH 0x10 -#define IPG_RM_RECEIVEIPMULTICAST 0x20 - -/* PhySet */ -#define IPG_PS_MEM_LENB9B 0x01 -#define IPG_PS_MEM_LEN9 0x02 -#define IPG_PS_NON_COMPDET 0x04 - -/* PhyCtrl */ -#define IPG_PC_RSVD_MASK 0xFF -#define IPG_PC_MGMTCLK_LO 0x00 -#define IPG_PC_MGMTCLK_HI 0x01 -#define IPG_PC_MGMTCLK 0x01 -#define IPG_PC_MGMTDATA 0x02 -#define IPG_PC_MGMTDIR 0x04 -#define IPG_PC_DUPLEX_POLARITY 0x08 -#define IPG_PC_DUPLEX_STATUS 0x10 -#define IPG_PC_LINK_POLARITY 0x20 -#define IPG_PC_LINK_SPEED 0xC0 -#define IPG_PC_LINK_SPEED_10MBPS 0x40 -#define IPG_PC_LINK_SPEED_100MBPS 0x80 -#define IPG_PC_LINK_SPEED_1000MBPS 0xC0 - -/* DMACtrl */ -#define IPG_DC_RSVD_MASK 0xC07D9818 -#define IPG_DC_RX_DMA_COMPLETE 0x00000008 -#define IPG_DC_RX_DMA_POLL_NOW 0x00000010 -#define IPG_DC_TX_DMA_COMPLETE 0x00000800 -#define IPG_DC_TX_DMA_POLL_NOW 0x00001000 -#define IPG_DC_TX_DMA_IN_PROG 0x00008000 -#define IPG_DC_RX_EARLY_DISABLE 0x00010000 -#define IPG_DC_MWI_DISABLE 0x00040000 -#define IPG_DC_TX_WRITE_BACK_DISABLE 0x00080000 -#define IPG_DC_TX_BURST_LIMIT 0x00700000 -#define IPG_DC_TARGET_ABORT 0x40000000 -#define IPG_DC_MASTER_ABORT 0x80000000 - -/* ASICCtrl */ -#define IPG_AC_RSVD_MASK 0x07FFEFF2 -#define IPG_AC_EXP_ROM_SIZE 0x00000002 -#define IPG_AC_PHY_SPEED10 0x00000010 -#define IPG_AC_PHY_SPEED100 0x00000020 -#define IPG_AC_PHY_SPEED1000 0x00000040 -#define IPG_AC_PHY_MEDIA 0x00000080 -#define IPG_AC_FORCED_CFG 0x00000700 -#define IPG_AC_D3RESETDISABLE 0x00000800 -#define IPG_AC_SPEED_UP_MODE 0x00002000 -#define IPG_AC_LED_MODE 0x00004000 -#define IPG_AC_RST_OUT_POLARITY 0x00008000 -#define IPG_AC_GLOBAL_RESET 0x00010000 -#define IPG_AC_RX_RESET 0x00020000 -#define IPG_AC_TX_RESET 0x00040000 -#define IPG_AC_DMA 0x00080000 -#define IPG_AC_FIFO 0x00100000 -#define IPG_AC_NETWORK 0x00200000 -#define IPG_AC_HOST 0x00400000 -#define IPG_AC_AUTO_INIT 0x00800000 -#define IPG_AC_RST_OUT 0x01000000 -#define IPG_AC_INT_REQUEST 0x02000000 -#define IPG_AC_RESET_BUSY 0x04000000 -#define IPG_AC_LED_SPEED 0x08000000 -#define IPG_AC_LED_MODE_BIT_1 0x20000000 - -/* EepromCtrl */ -#define IPG_EC_RSVD_MASK 0x83FF -#define IPG_EC_EEPROM_ADDR 0x00FF -#define IPG_EC_EEPROM_OPCODE 0x0300 -#define IPG_EC_EEPROM_SUBCOMMAD 0x0000 -#define IPG_EC_EEPROM_WRITEOPCODE 0x0100 -#define IPG_EC_EEPROM_READOPCODE 0x0200 -#define IPG_EC_EEPROM_ERASEOPCODE 0x0300 -#define IPG_EC_EEPROM_BUSY 0x8000 - -/* FIFOCtrl */ -#define IPG_FC_RSVD_MASK 0xC001 -#define IPG_FC_RAM_TEST_MODE 0x0001 -#define IPG_FC_TRANSMITTING 0x4000 -#define IPG_FC_RECEIVING 0x8000 - -/* TxStatus */ -#define IPG_TS_RSVD_MASK 0xFFFF00DD -#define IPG_TS_TX_ERROR 0x00000001 -#define IPG_TS_LATE_COLLISION 0x00000004 -#define IPG_TS_TX_MAX_COLL 0x00000008 -#define IPG_TS_TX_UNDERRUN 0x00000010 -#define IPG_TS_TX_IND_REQD 0x00000040 -#define IPG_TS_TX_COMPLETE 0x00000080 -#define IPG_TS_TX_FRAMEID 0xFFFF0000 - -/* WakeEvent */ -#define IPG_WE_WAKE_PKT_ENABLE 0x01 -#define IPG_WE_MAGIC_PKT_ENABLE 0x02 -#define IPG_WE_LINK_EVT_ENABLE 0x04 -#define IPG_WE_WAKE_POLARITY 0x08 -#define IPG_WE_WAKE_PKT_EVT 0x10 -#define IPG_WE_MAGIC_PKT_EVT 0x20 -#define IPG_WE_LINK_EVT 0x40 -#define IPG_WE_WOL_ENABLE 0x80 - -/* IntEnable */ -#define IPG_IE_RSVD_MASK 0x1FFE -#define IPG_IE_HOST_ERROR 0x0002 -#define IPG_IE_TX_COMPLETE 0x0004 -#define IPG_IE_MAC_CTRL_FRAME 0x0008 -#define IPG_IE_RX_COMPLETE 0x0010 -#define IPG_IE_RX_EARLY 0x0020 -#define IPG_IE_INT_REQUESTED 0x0040 -#define IPG_IE_UPDATE_STATS 0x0080 -#define IPG_IE_LINK_EVENT 0x0100 -#define IPG_IE_TX_DMA_COMPLETE 0x0200 -#define IPG_IE_RX_DMA_COMPLETE 0x0400 -#define IPG_IE_RFD_LIST_END 0x0800 -#define IPG_IE_RX_DMA_PRIORITY 0x1000 - -/* IntStatus */ -#define IPG_IS_RSVD_MASK 0x1FFF -#define IPG_IS_INTERRUPT_STATUS 0x0001 -#define IPG_IS_HOST_ERROR 0x0002 -#define IPG_IS_TX_COMPLETE 0x0004 -#define IPG_IS_MAC_CTRL_FRAME 0x0008 -#define IPG_IS_RX_COMPLETE 0x0010 -#define IPG_IS_RX_EARLY 0x0020 -#define IPG_IS_INT_REQUESTED 0x0040 -#define IPG_IS_UPDATE_STATS 0x0080 -#define IPG_IS_LINK_EVENT 0x0100 -#define IPG_IS_TX_DMA_COMPLETE 0x0200 -#define IPG_IS_RX_DMA_COMPLETE 0x0400 -#define IPG_IS_RFD_LIST_END 0x0800 -#define IPG_IS_RX_DMA_PRIORITY 0x1000 - -/* MACCtrl */ -#define IPG_MC_RSVD_MASK 0x7FE33FA3 -#define IPG_MC_IFS_SELECT 0x00000003 -#define IPG_MC_IFS_4352BIT 0x00000003 -#define IPG_MC_IFS_1792BIT 0x00000002 -#define IPG_MC_IFS_1024BIT 0x00000001 -#define IPG_MC_IFS_96BIT 0x00000000 -#define IPG_MC_DUPLEX_SELECT 0x00000020 -#define IPG_MC_DUPLEX_SELECT_FD 0x00000020 -#define IPG_MC_DUPLEX_SELECT_HD 0x00000000 -#define IPG_MC_TX_FLOW_CONTROL_ENABLE 0x00000080 -#define IPG_MC_RX_FLOW_CONTROL_ENABLE 0x00000100 -#define IPG_MC_RCV_FCS 0x00000200 -#define IPG_MC_FIFO_LOOPBACK 0x00000400 -#define IPG_MC_MAC_LOOPBACK 0x00000800 -#define IPG_MC_AUTO_VLAN_TAGGING 0x00001000 -#define IPG_MC_AUTO_VLAN_UNTAGGING 0x00002000 -#define IPG_MC_COLLISION_DETECT 0x00010000 -#define IPG_MC_CARRIER_SENSE 0x00020000 -#define IPG_MC_STATISTICS_ENABLE 0x00200000 -#define IPG_MC_STATISTICS_DISABLE 0x00400000 -#define IPG_MC_STATISTICS_ENABLED 0x00800000 -#define IPG_MC_TX_ENABLE 0x01000000 -#define IPG_MC_TX_DISABLE 0x02000000 -#define IPG_MC_TX_ENABLED 0x04000000 -#define IPG_MC_RX_ENABLE 0x08000000 -#define IPG_MC_RX_DISABLE 0x10000000 -#define IPG_MC_RX_ENABLED 0x20000000 -#define IPG_MC_PAUSED 0x40000000 - -/* - * Tune - */ - -/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */ -#define IPG_APPEND_FCS_ON_TX 1 - -/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */ -#define IPG_STRIP_FCS_ON_RX 1 - -/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with - * Ethernet errors. - */ -#define IPG_DROP_ON_RX_ETH_ERRORS 1 - -/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually - * (via TFC). - */ -#define IPG_INSERT_MANUAL_VLAN_TAG 0 - -/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */ -#define IPG_ADD_IPCHECKSUM_ON_TX 0 - -/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX. - * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. - */ -#define IPG_ADD_TCPCHECKSUM_ON_TX 0 - -/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX. - * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. - */ -#define IPG_ADD_UDPCHECKSUM_ON_TX 0 - -/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx - * constants as desired. - */ -#define IPG_MANUAL_VLAN_VID 0xABC -#define IPG_MANUAL_VLAN_CFI 0x1 -#define IPG_MANUAL_VLAN_USERPRIORITY 0x5 - -#define IPG_IO_REG_RANGE 0xFF -#define IPG_MEM_REG_RANGE 0x154 -#define IPG_DRIVER_NAME "Sundance Technology IPG Triple-Speed Ethernet" -#define IPG_NIC_PHY_ADDRESS 0x01 -#define IPG_DMALIST_ALIGN_PAD 0x07 -#define IPG_MULTICAST_HASHTABLE_SIZE 0x40 - -/* Number of milliseconds to wait after issuing a software reset. - * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation. - */ -#define IPG_AC_RESETWAIT 0x05 - -/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */ -#define IPG_AC_RESET_TIMEOUT 0x0A - -/* Minimum number of nanoseconds used to toggle MDC clock during - * MII/GMII register access. - */ -#define IPG_PC_PHYCTRLWAIT_NS 200 - -#define IPG_TFDLIST_LENGTH 0x100 - -/* Number of frames between TxDMAComplete interrupt. - * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH - */ -#define IPG_FRAMESBETWEENTXDMACOMPLETES 0x1 - -#define IPG_RFDLIST_LENGTH 0x100 - -/* Maximum number of RFDs to process per interrupt. - * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH - */ -#define IPG_MAXRFDPROCESS_COUNT 0x80 - -/* Minimum margin between last freed RFD, and current RFD. - * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH - */ -#define IPG_MINUSEDRFDSTOFREE 0x80 - -/* specify the jumbo frame maximum size - * per unit is 0x600 (the rx_buffer size that one RFD can carry) - */ -#define MAX_JUMBOSIZE 0x8 /* max is 12K */ - -/* Key register values loaded at driver start up. */ - -/* TXDMAPollPeriod is specified in 320ns increments. - * - * Value Time - * --------------------- - * 0x00-0x01 320ns - * 0x03 ~1us - * 0x1F ~10us - * 0xFF ~82us - */ -#define IPG_TXDMAPOLLPERIOD_VALUE 0x26 - -/* TxDMAUrgentThresh specifies the minimum amount of - * data in the transmit FIFO before asserting an - * urgent transmit DMA request. - * - * Value Min TxFIFO occupied space before urgent TX request - * --------------------------------------------------------------- - * 0x00-0x04 128 bytes (1024 bits) - * 0x27 1248 bytes (~10000 bits) - * 0x30 1536 bytes (12288 bits) - * 0xFF 8192 bytes (65535 bits) - */ -#define IPG_TXDMAURGENTTHRESH_VALUE 0x04 - -/* TxDMABurstThresh specifies the minimum amount of - * free space in the transmit FIFO before asserting an - * transmit DMA request. - * - * Value Min TxFIFO free space before TX request - * ---------------------------------------------------- - * 0x00-0x08 256 bytes - * 0x30 1536 bytes - * 0xFF 8192 bytes - */ -#define IPG_TXDMABURSTTHRESH_VALUE 0x30 - -/* RXDMAPollPeriod is specified in 320ns increments. - * - * Value Time - * --------------------- - * 0x00-0x01 320ns - * 0x03 ~1us - * 0x1F ~10us - * 0xFF ~82us - */ -#define IPG_RXDMAPOLLPERIOD_VALUE 0x01 - -/* RxDMAUrgentThresh specifies the minimum amount of - * free space within the receive FIFO before asserting - * a urgent receive DMA request. - * - * Value Min RxFIFO free space before urgent RX request - * --------------------------------------------------------------- - * 0x00-0x04 128 bytes (1024 bits) - * 0x27 1248 bytes (~10000 bits) - * 0x30 1536 bytes (12288 bits) - * 0xFF 8192 bytes (65535 bits) - */ -#define IPG_RXDMAURGENTTHRESH_VALUE 0x30 - -/* RxDMABurstThresh specifies the minimum amount of - * occupied space within the receive FIFO before asserting - * a receive DMA request. - * - * Value Min TxFIFO free space before TX request - * ---------------------------------------------------- - * 0x00-0x08 256 bytes - * 0x30 1536 bytes - * 0xFF 8192 bytes - */ -#define IPG_RXDMABURSTTHRESH_VALUE 0x30 - -/* FlowOnThresh specifies the maximum amount of occupied - * space in the receive FIFO before a PAUSE frame with - * maximum pause time transmitted. - * - * Value Max RxFIFO occupied space before PAUSE - * --------------------------------------------------- - * 0x0000 0 bytes - * 0x0740 29,696 bytes - * 0x07FF 32,752 bytes - */ -#define IPG_FLOWONTHRESH_VALUE 0x0740 - -/* FlowOffThresh specifies the minimum amount of occupied - * space in the receive FIFO before a PAUSE frame with - * zero pause time is transmitted. - * - * Value Max RxFIFO occupied space before PAUSE - * --------------------------------------------------- - * 0x0000 0 bytes - * 0x00BF 3056 bytes - * 0x07FF 32,752 bytes - */ -#define IPG_FLOWOFFTHRESH_VALUE 0x00BF - -/* - * Miscellaneous macros. - */ - -/* Macros for printing debug statements. */ -#ifdef IPG_DEBUG -# define IPG_DEBUG_MSG(fmt, args...) \ -do { \ - if (0) \ - printk(KERN_DEBUG "IPG: " fmt, ##args); \ -} while (0) -# define IPG_DDEBUG_MSG(fmt, args...) \ - printk(KERN_DEBUG "IPG: " fmt, ##args) -# define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args) -# define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args) -#else -# define IPG_DEBUG_MSG(fmt, args...) \ -do { \ - if (0) \ - printk(KERN_DEBUG "IPG: " fmt, ##args); \ -} while (0) -# define IPG_DDEBUG_MSG(fmt, args...) \ -do { \ - if (0) \ - printk(KERN_DEBUG "IPG: " fmt, ##args); \ -} while (0) -# define IPG_DUMPRFDLIST(args) -# define IPG_DUMPTFDLIST(args) -#endif - -/* - * End miscellaneous macros. - */ - -/* Transmit Frame Descriptor. The IPG supports 15 fragments, - * however Linux requires only a single fragment. Note, each - * TFD field is 64 bits wide. - */ -struct ipg_tx { - __le64 next_desc; - __le64 tfc; - __le64 frag_info; -}; - -/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide. - */ -struct ipg_rx { - __le64 next_desc; - __le64 rfs; - __le64 frag_info; -}; - -struct ipg_jumbo { - int found_start; - int current_size; - struct sk_buff *skb; -}; - -/* Structure of IPG NIC specific data. */ -struct ipg_nic_private { - void __iomem *ioaddr; - struct ipg_tx *txd; - struct ipg_rx *rxd; - dma_addr_t txd_map; - dma_addr_t rxd_map; - struct sk_buff *tx_buff[IPG_TFDLIST_LENGTH]; - struct sk_buff *rx_buff[IPG_RFDLIST_LENGTH]; - unsigned int tx_current; - unsigned int tx_dirty; - unsigned int rx_current; - unsigned int rx_dirty; - bool is_jumbo; - struct ipg_jumbo jumbo; - unsigned long rxfrag_size; - unsigned long rxsupport_size; - unsigned long max_rxframe_size; - unsigned int rx_buf_sz; - struct pci_dev *pdev; - struct net_device *dev; - struct net_device_stats stats; - spinlock_t lock; - int tenmbpsmode; - - u16 led_mode; - u16 station_addr[3]; /* Station Address in EEPROM Reg 0x10..0x12 */ - - struct mutex mii_mutex; - struct mii_if_info mii_if; - int reset_current_tfd; -#ifdef IPG_DEBUG - int RFDlistendCount; - int RFDListCheckedCount; - int EmptyRFDListCount; -#endif - struct delayed_work task; -}; - -#endif /* __LINUX_IPG_H */ diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 639263d..7781e80 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -627,8 +627,10 @@ static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* verify the skb head is not shared */ err = skb_cow_head(skb, 0); - if (err) + if (err) { + dev_kfree_skb(skb); return NETDEV_TX_OK; + } /* locate vlan header */ vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN); diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 0ff8f01..1fd5ea8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -567,10 +567,6 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw) goto init_adminq_exit; } - /* initialize locks */ - mutex_init(&hw->aq.asq_mutex); - mutex_init(&hw->aq.arq_mutex); - /* Set up register offsets */ i40e_adminq_init_regs(hw); @@ -664,8 +660,6 @@ i40e_status i40e_shutdown_adminq(struct i40e_hw *hw) i40e_shutdown_asq(hw); i40e_shutdown_arq(hw); - /* destroy the locks */ - if (hw->nvm_buff.va) i40e_free_virt_mem(hw, &hw->nvm_buff); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b825f97..4a9873ec 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -10295,6 +10295,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* set up a default setting for link flow control */ pf->hw.fc.requested_mode = I40E_FC_NONE; + /* set up the locks for the AQ, do this only once in probe + * and destroy them only once in remove + */ + mutex_init(&hw->aq.asq_mutex); + mutex_init(&hw->aq.arq_mutex); + err = i40e_init_adminq(hw); /* provide nvm, fw, api versions */ @@ -10697,7 +10703,6 @@ static void i40e_remove(struct pci_dev *pdev) set_bit(__I40E_DOWN, &pf->state); del_timer_sync(&pf->service_timer); cancel_work_sync(&pf->service_task); - i40e_fdir_teardown(pf); if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { i40e_free_vfs(pf); @@ -10740,6 +10745,10 @@ static void i40e_remove(struct pci_dev *pdev) "Failed to destroy the Admin Queue resources: %d\n", ret_code); + /* destroy the locks only once, here */ + mutex_destroy(&hw->aq.arq_mutex); + mutex_destroy(&hw->aq.asq_mutex); + /* Clear all dynamic memory lists of rings, q_vectors, and VSIs */ i40e_clear_interrupt_scheme(pf); for (i = 0; i < pf->num_alloc_vsi; i++) { diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index fd123ca..3f65e39 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -551,10 +551,6 @@ i40e_status i40evf_init_adminq(struct i40e_hw *hw) goto init_adminq_exit; } - /* initialize locks */ - mutex_init(&hw->aq.asq_mutex); - mutex_init(&hw->aq.arq_mutex); - /* Set up register offsets */ i40e_adminq_init_regs(hw); @@ -596,8 +592,6 @@ i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw) i40e_shutdown_asq(hw); i40e_shutdown_arq(hw); - /* destroy the locks */ - if (hw->nvm_buff.va) i40e_free_virt_mem(hw, &hw->nvm_buff); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index d962164..99d2cff 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2476,6 +2476,12 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->bus.device = PCI_SLOT(pdev->devfn); hw->bus.func = PCI_FUNC(pdev->devfn); + /* set up the locks for the AQ, do this only once in probe + * and destroy them only once in remove + */ + mutex_init(&hw->aq.asq_mutex); + mutex_init(&hw->aq.arq_mutex); + INIT_LIST_HEAD(&adapter->mac_filter_list); INIT_LIST_HEAD(&adapter->vlan_filter_list); @@ -2629,6 +2635,10 @@ static void i40evf_remove(struct pci_dev *pdev) if (hw->aq.asq.count) i40evf_shutdown_adminq(hw); + /* destroy the locks only once, here */ + mutex_destroy(&hw->aq.arq_mutex); + mutex_destroy(&hw->aq.asq_mutex); + iounmap(hw->hw_addr); pci_release_regions(pdev); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 47395ff..aed8d02 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7920,6 +7920,9 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc) */ if (netif_running(dev)) ixgbe_close(dev); + else + ixgbe_reset(adapter); + ixgbe_clear_interrupt_scheme(adapter); #ifdef CONFIG_IXGBE_DCB diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index e84c7f2..ed622fa 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -36,7 +36,7 @@ /* Registers */ #define MVNETA_RXQ_CONFIG_REG(q) (0x1400 + ((q) << 2)) -#define MVNETA_RXQ_HW_BUF_ALLOC BIT(1) +#define MVNETA_RXQ_HW_BUF_ALLOC BIT(0) #define MVNETA_RXQ_PKT_OFFSET_ALL_MASK (0xf << 8) #define MVNETA_RXQ_PKT_OFFSET_MASK(offs) ((offs) << 8) #define MVNETA_RXQ_THRESHOLD_REG(q) (0x14c0 + ((q) << 2)) @@ -62,6 +62,7 @@ #define MVNETA_WIN_SIZE(w) (0x2204 + ((w) << 3)) #define MVNETA_WIN_REMAP(w) (0x2280 + ((w) << 2)) #define MVNETA_BASE_ADDR_ENABLE 0x2290 +#define MVNETA_ACCESS_PROTECT_ENABLE 0x2294 #define MVNETA_PORT_CONFIG 0x2400 #define MVNETA_UNI_PROMISC_MODE BIT(0) #define MVNETA_DEF_RXQ(q) ((q) << 1) @@ -159,7 +160,7 @@ #define MVNETA_INTR_ENABLE 0x25b8 #define MVNETA_TXQ_INTR_ENABLE_ALL_MASK 0x0000ff00 -#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0xff000000 // note: neta says it's 0x000000FF +#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0x000000ff #define MVNETA_RXQ_CMD 0x2680 #define MVNETA_RXQ_DISABLE_SHIFT 8 @@ -242,6 +243,7 @@ #define MVNETA_VLAN_TAG_LEN 4 #define MVNETA_CPU_D_CACHE_LINE_SIZE 32 +#define MVNETA_TX_CSUM_DEF_SIZE 1600 #define MVNETA_TX_CSUM_MAX_SIZE 9800 #define MVNETA_ACC_MODE_EXT 1 @@ -1579,12 +1581,16 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo, } skb = build_skb(data, pp->frag_size > PAGE_SIZE ? 0 : pp->frag_size); - if (!skb) - goto err_drop_frame; + /* After refill old buffer has to be unmapped regardless + * the skb is successfully built or not. + */ dma_unmap_single(dev->dev.parent, phys_addr, MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE); + if (!skb) + goto err_drop_frame; + rcvd_pkts++; rcvd_bytes += rx_bytes; @@ -3191,6 +3197,7 @@ static void mvneta_conf_mbus_windows(struct mvneta_port *pp, } mvreg_write(pp, MVNETA_BASE_ADDR_ENABLE, win_enable); + mvreg_write(pp, MVNETA_ACCESS_PROTECT_ENABLE, win_protect); } /* Power up the port */ @@ -3250,6 +3257,7 @@ static int mvneta_probe(struct platform_device *pdev) char hw_mac_addr[ETH_ALEN]; const char *mac_from; const char *managed; + int tx_csum_limit; int phy_mode; int err; int cpu; @@ -3350,8 +3358,21 @@ static int mvneta_probe(struct platform_device *pdev) } } - if (of_device_is_compatible(dn, "marvell,armada-370-neta")) - pp->tx_csum_limit = 1600; + if (!of_property_read_u32(dn, "tx-csum-limit", &tx_csum_limit)) { + if (tx_csum_limit < 0 || + tx_csum_limit > MVNETA_TX_CSUM_MAX_SIZE) { + tx_csum_limit = MVNETA_TX_CSUM_DEF_SIZE; + dev_info(&pdev->dev, + "Wrong TX csum limit in DT, set to %dB\n", + MVNETA_TX_CSUM_DEF_SIZE); + } + } else if (of_device_is_compatible(dn, "marvell,armada-370-neta")) { + tx_csum_limit = MVNETA_TX_CSUM_DEF_SIZE; + } else { + tx_csum_limit = MVNETA_TX_CSUM_MAX_SIZE; + } + + pp->tx_csum_limit = tx_csum_limit; pp->tx_ring_size = MVNETA_MAX_TXD; pp->rx_ring_size = MVNETA_MAX_RXD; diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index d9884fd..a4beccf 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -3413,16 +3413,23 @@ static void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv, } /* Free all buffers from the pool */ -static void mvpp2_bm_bufs_free(struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool) +static void mvpp2_bm_bufs_free(struct device *dev, struct mvpp2 *priv, + struct mvpp2_bm_pool *bm_pool) { int i; for (i = 0; i < bm_pool->buf_num; i++) { + dma_addr_t buf_phys_addr; u32 vaddr; /* Get buffer virtual address (indirect access) */ - mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id)); + buf_phys_addr = mvpp2_read(priv, + MVPP2_BM_PHY_ALLOC_REG(bm_pool->id)); vaddr = mvpp2_read(priv, MVPP2_BM_VIRT_ALLOC_REG); + + dma_unmap_single(dev, buf_phys_addr, + bm_pool->buf_size, DMA_FROM_DEVICE); + if (!vaddr) break; dev_kfree_skb_any((struct sk_buff *)vaddr); @@ -3439,7 +3446,7 @@ static int mvpp2_bm_pool_destroy(struct platform_device *pdev, { u32 val; - mvpp2_bm_bufs_free(priv, bm_pool); + mvpp2_bm_bufs_free(&pdev->dev, priv, bm_pool); if (bm_pool->buf_num) { WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id); return 0; @@ -3692,7 +3699,8 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, MVPP2_BM_LONG_BUF_NUM : MVPP2_BM_SHORT_BUF_NUM; else - mvpp2_bm_bufs_free(port->priv, new_pool); + mvpp2_bm_bufs_free(port->dev->dev.parent, + port->priv, new_pool); new_pool->pkt_size = pkt_size; @@ -3756,7 +3764,7 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu) int pkt_size = MVPP2_RX_PKT_SIZE(mtu); /* Update BM pool with new buffer size */ - mvpp2_bm_bufs_free(port->priv, port_pool); + mvpp2_bm_bufs_free(dev->dev.parent, port->priv, port_pool); if (port_pool->buf_num) { WARN(1, "cannot free all buffers in pool %d\n", port_pool->id); return -EIO; @@ -4401,11 +4409,10 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, mvpp2_txq_inc_get(txq_pcpu); - if (!skb) - continue; - dma_unmap_single(port->dev->dev.parent, buf_phys_addr, skb_headlen(skb), DMA_TO_DEVICE); + if (!skb) + continue; dev_kfree_skb_any(skb); } } @@ -5092,7 +5099,8 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, struct mvpp2_rx_queue *rxq) { struct net_device *dev = port->dev; - int rx_received, rx_filled, i; + int rx_received; + int rx_done = 0; u32 rcvd_pkts = 0; u32 rcvd_bytes = 0; @@ -5101,17 +5109,18 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, if (rx_todo > rx_received) rx_todo = rx_received; - rx_filled = 0; - for (i = 0; i < rx_todo; i++) { + while (rx_done < rx_todo) { struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq); struct mvpp2_bm_pool *bm_pool; struct sk_buff *skb; + dma_addr_t phys_addr; u32 bm, rx_status; int pool, rx_bytes, err; - rx_filled++; + rx_done++; rx_status = rx_desc->status; rx_bytes = rx_desc->data_size - MVPP2_MH_SIZE; + phys_addr = rx_desc->buf_phys_addr; bm = mvpp2_bm_cookie_build(rx_desc); pool = mvpp2_bm_cookie_pool_get(bm); @@ -5128,8 +5137,10 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, * comprised by the RX descriptor. */ if (rx_status & MVPP2_RXD_ERR_SUMMARY) { + err_drop_frame: dev->stats.rx_errors++; mvpp2_rx_error(port, rx_desc); + /* Return the buffer to the pool */ mvpp2_pool_refill(port, bm, rx_desc->buf_phys_addr, rx_desc->buf_cookie); continue; @@ -5137,6 +5148,15 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, skb = (struct sk_buff *)rx_desc->buf_cookie; + err = mvpp2_rx_refill(port, bm_pool, bm, 0); + if (err) { + netdev_err(port->dev, "failed to refill BM pools\n"); + goto err_drop_frame; + } + + dma_unmap_single(dev->dev.parent, phys_addr, + bm_pool->buf_size, DMA_FROM_DEVICE); + rcvd_pkts++; rcvd_bytes += rx_bytes; atomic_inc(&bm_pool->in_use); @@ -5147,12 +5167,6 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, mvpp2_rx_csum(port, rx_status, skb); napi_gro_receive(&port->napi, skb); - - err = mvpp2_rx_refill(port, bm_pool, bm, 0); - if (err) { - netdev_err(port->dev, "failed to refill BM pools\n"); - rx_filled--; - } } if (rcvd_pkts) { @@ -5166,7 +5180,7 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, /* Update Rx queue management counters */ wmb(); - mvpp2_rxq_status_update(port, rxq->id, rx_todo, rx_filled); + mvpp2_rxq_status_update(port, rxq->id, rx_done, rx_done); return rx_todo; } diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 2177e56..d48d579 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1010,7 +1010,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, if (!(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && smp->method == IB_MGMT_METHOD_GET) || network_view) { mlx4_err(dev, "Unprivileged slave %d is trying to execute a Subnet MGMT MAD, class 0x%x, method 0x%x, view=%s for attr 0x%x. Rejecting\n", - slave, smp->method, smp->mgmt_class, + slave, smp->mgmt_class, smp->method, network_view ? "Network" : "Host", be16_to_cpu(smp->attr_id)); return -EPERM; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 85f1b1e..31c491e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -892,9 +892,10 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) dev->caps.qp1_proxy[i - 1] = func_cap.qp1_proxy_qpn; dev->caps.port_mask[i] = dev->caps.port_type[i]; dev->caps.phys_port_id[i] = func_cap.phys_port_id; - if (mlx4_get_slave_pkey_gid_tbl_len(dev, i, - &dev->caps.gid_table_len[i], - &dev->caps.pkey_table_len[i])) + err = mlx4_get_slave_pkey_gid_tbl_len(dev, i, + &dev->caps.gid_table_len[i], + &dev->caps.pkey_table_len[i]); + if (err) goto err_mem; } @@ -906,6 +907,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) dev->caps.uar_page_size * dev->caps.num_uars, (unsigned long long) pci_resource_len(dev->persist->pdev, 2)); + err = -ENOMEM; goto err_mem; } diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 9813d34..cad6c44 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -4306,9 +4306,10 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, return -EOPNOTSUPP; ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; - ctrl->port = mlx4_slave_convert_port(dev, slave, ctrl->port); - if (ctrl->port <= 0) + err = mlx4_slave_convert_port(dev, slave, ctrl->port); + if (err <= 0) return -EINVAL; + ctrl->port = err; qpn = be32_to_cpu(ctrl->qpn) & 0xffffff; err = get_res(dev, slave, qpn, RES_QP, &rqp); if (err) { @@ -4952,26 +4953,41 @@ static void rem_slave_counters(struct mlx4_dev *dev, int slave) struct res_counter *counter; struct res_counter *tmp; int err; - int index; + int *counters_arr = NULL; + int i, j; err = move_all_busy(dev, slave, RES_COUNTER); if (err) mlx4_warn(dev, "rem_slave_counters: Could not move all counters - too busy for slave %d\n", slave); - spin_lock_irq(mlx4_tlock(dev)); - list_for_each_entry_safe(counter, tmp, counter_list, com.list) { - if (counter->com.owner == slave) { - index = counter->com.res_id; - rb_erase(&counter->com.node, - &tracker->res_tree[RES_COUNTER]); - list_del(&counter->com.list); - kfree(counter); - __mlx4_counter_free(dev, index); + counters_arr = kmalloc_array(dev->caps.max_counters, + sizeof(*counters_arr), GFP_KERNEL); + if (!counters_arr) + return; + + do { + i = 0; + j = 0; + spin_lock_irq(mlx4_tlock(dev)); + list_for_each_entry_safe(counter, tmp, counter_list, com.list) { + if (counter->com.owner == slave) { + counters_arr[i++] = counter->com.res_id; + rb_erase(&counter->com.node, + &tracker->res_tree[RES_COUNTER]); + list_del(&counter->com.list); + kfree(counter); + } + } + spin_unlock_irq(mlx4_tlock(dev)); + + while (j < i) { + __mlx4_counter_free(dev, counters_arr[j++]); mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0); } - } - spin_unlock_irq(mlx4_tlock(dev)); + } while (i); + + kfree(counters_arr); } static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index f2ae62d..22e72bf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -334,9 +334,15 @@ struct mlx5e_tx_skb_cb { #define MLX5E_TX_SKB_CB(__skb) ((struct mlx5e_tx_skb_cb *)__skb->cb) +enum mlx5e_dma_map_type { + MLX5E_DMA_MAP_SINGLE, + MLX5E_DMA_MAP_PAGE +}; + struct mlx5e_sq_dma { - dma_addr_t addr; - u32 size; + dma_addr_t addr; + u32 size; + enum mlx5e_dma_map_type type; }; enum { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 5fc4d2d..1e52db3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1332,6 +1332,42 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt) return err; } +static int mlx5e_refresh_tir_self_loopback_enable(struct mlx5_core_dev *mdev, + u32 tirn) +{ + void *in; + int inlen; + int err; + + inlen = MLX5_ST_SZ_BYTES(modify_tir_in); + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1); + + err = mlx5_core_modify_tir(mdev, tirn, in, inlen); + + kvfree(in); + + return err; +} + +static int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5e_priv *priv) +{ + int err; + int i; + + for (i = 0; i < MLX5E_NUM_TT; i++) { + err = mlx5e_refresh_tir_self_loopback_enable(priv->mdev, + priv->tirn[i]); + if (err) + return err; + } + + return 0; +} + static int mlx5e_set_dev_port_mtu(struct net_device *netdev) { struct mlx5e_priv *priv = netdev_priv(netdev); @@ -1376,6 +1412,13 @@ int mlx5e_open_locked(struct net_device *netdev) goto err_clear_state_opened_flag; } + err = mlx5e_refresh_tirs_self_loopback_enable(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_refresh_tirs_self_loopback_enable failed, %d\n", + __func__, err); + goto err_close_channels; + } + mlx5e_update_carrier(priv); mlx5e_redirect_rqts(priv); @@ -1383,6 +1426,8 @@ int mlx5e_open_locked(struct net_device *netdev) return 0; +err_close_channels: + mlx5e_close_channels(priv); err_clear_state_opened_flag: clear_bit(MLX5E_STATE_OPENED, &priv->state); return err; @@ -1856,6 +1901,8 @@ static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu) mlx5_query_port_max_mtu(mdev, &max_mtu, 1); + max_mtu = MLX5E_HW2SW_MTU(max_mtu); + if (new_mtu > max_mtu) { netdev_err(netdev, "%s: Bad MTU (%d) > (%d) Max\n", @@ -1909,6 +1956,9 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) "Not creating net device, some required device capabilities are missing\n"); return -ENOTSUPP; } + if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable)) + mlx5_core_warn(mdev, "Self loop back prevention is not supported\n"); + return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index cd8f85a..1341b1d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -61,39 +61,47 @@ void mlx5e_send_nop(struct mlx5e_sq *sq, bool notify_hw) } } -static void mlx5e_dma_pop_last_pushed(struct mlx5e_sq *sq, dma_addr_t *addr, - u32 *size) +static inline void mlx5e_tx_dma_unmap(struct device *pdev, + struct mlx5e_sq_dma *dma) { - sq->dma_fifo_pc--; - *addr = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr; - *size = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size; -} - -static void mlx5e_dma_unmap_wqe_err(struct mlx5e_sq *sq, struct sk_buff *skb) -{ - dma_addr_t addr; - u32 size; - int i; - - for (i = 0; i < MLX5E_TX_SKB_CB(skb)->num_dma; i++) { - mlx5e_dma_pop_last_pushed(sq, &addr, &size); - dma_unmap_single(sq->pdev, addr, size, DMA_TO_DEVICE); + switch (dma->type) { + case MLX5E_DMA_MAP_SINGLE: + dma_unmap_single(pdev, dma->addr, dma->size, DMA_TO_DEVICE); + break; + case MLX5E_DMA_MAP_PAGE: + dma_unmap_page(pdev, dma->addr, dma->size, DMA_TO_DEVICE); + break; + default: + WARN_ONCE(true, "mlx5e_tx_dma_unmap unknown DMA type!\n"); } } -static inline void mlx5e_dma_push(struct mlx5e_sq *sq, dma_addr_t addr, - u32 size) +static inline void mlx5e_dma_push(struct mlx5e_sq *sq, + dma_addr_t addr, + u32 size, + enum mlx5e_dma_map_type map_type) { sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr = addr; sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size = size; + sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].type = map_type; sq->dma_fifo_pc++; } -static inline void mlx5e_dma_get(struct mlx5e_sq *sq, u32 i, dma_addr_t *addr, - u32 *size) +static inline struct mlx5e_sq_dma *mlx5e_dma_get(struct mlx5e_sq *sq, u32 i) { - *addr = sq->dma_fifo[i & sq->dma_fifo_mask].addr; - *size = sq->dma_fifo[i & sq->dma_fifo_mask].size; + return &sq->dma_fifo[i & sq->dma_fifo_mask]; +} + +static void mlx5e_dma_unmap_wqe_err(struct mlx5e_sq *sq, struct sk_buff *skb) +{ + int i; + + for (i = 0; i < MLX5E_TX_SKB_CB(skb)->num_dma; i++) { + struct mlx5e_sq_dma *last_pushed_dma = + mlx5e_dma_get(sq, --sq->dma_fifo_pc); + + mlx5e_tx_dma_unmap(sq->pdev, last_pushed_dma); + } } u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, @@ -118,8 +126,15 @@ static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, */ #define MLX5E_MIN_INLINE ETH_HLEN - if (bf && (skb_headlen(skb) <= sq->max_inline)) - return skb_headlen(skb); + if (bf) { + u16 ihs = skb_headlen(skb); + + if (skb_vlan_tag_present(skb)) + ihs += VLAN_HLEN; + + if (ihs <= sq->max_inline) + return skb_headlen(skb); + } return MLX5E_MIN_INLINE; } @@ -218,7 +233,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) dseg->lkey = sq->mkey_be; dseg->byte_count = cpu_to_be32(headlen); - mlx5e_dma_push(sq, dma_addr, headlen); + mlx5e_dma_push(sq, dma_addr, headlen, MLX5E_DMA_MAP_SINGLE); MLX5E_TX_SKB_CB(skb)->num_dma++; dseg++; @@ -237,7 +252,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) dseg->lkey = sq->mkey_be; dseg->byte_count = cpu_to_be32(fsz); - mlx5e_dma_push(sq, dma_addr, fsz); + mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE); MLX5E_TX_SKB_CB(skb)->num_dma++; dseg++; @@ -353,13 +368,10 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq) } for (j = 0; j < MLX5E_TX_SKB_CB(skb)->num_dma; j++) { - dma_addr_t addr; - u32 size; + struct mlx5e_sq_dma *dma = + mlx5e_dma_get(sq, dma_fifo_cc++); - mlx5e_dma_get(sq, dma_fifo_cc, &addr, &size); - dma_fifo_cc++; - dma_unmap_single(sq->pdev, addr, size, - DMA_TO_DEVICE); + mlx5e_tx_dma_unmap(sq->pdev, dma); } npkts++; diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index b159ef8..0576651 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1326,7 +1326,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) /* Get platform resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if ((!res) || (irq < 0) || (irq >= NR_IRQS)) { + if (!res || irq < 0) { dev_err(&pdev->dev, "error getting resources.\n"); ret = -ENXIO; goto err_exit; diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index ac17d86..1292c36 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -299,6 +299,7 @@ struct qed_hwfn { /* Flag indicating whether interrupts are enabled or not*/ bool b_int_enabled; + bool b_int_requested; struct qed_mcp_info *mcp_info; @@ -491,6 +492,8 @@ u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, u8 *input_buf, u32 max_size, u8 *unzip_buf); +int qed_slowpath_irq_req(struct qed_hwfn *hwfn); + #define QED_ETH_INTERFACE_VERSION 300 #endif /* _QED_H */ diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 803b190..817bbd5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1385,52 +1385,63 @@ err0: return rc; } -static u32 qed_hw_bar_size(struct qed_dev *cdev, - u8 bar_id) +static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn, + u8 bar_id) { - u32 size = pci_resource_len(cdev->pdev, (bar_id > 0) ? 2 : 0); + u32 bar_reg = (bar_id == 0 ? PGLUE_B_REG_PF_BAR0_SIZE + : PGLUE_B_REG_PF_BAR1_SIZE); + u32 val = qed_rd(p_hwfn, p_hwfn->p_main_ptt, bar_reg); - return size / cdev->num_hwfns; + /* Get the BAR size(in KB) from hardware given val */ + return 1 << (val + 15); } int qed_hw_prepare(struct qed_dev *cdev, int personality) { - int rc, i; + struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); + int rc; /* Store the precompiled init data ptrs */ qed_init_iro_array(cdev); /* Initialize the first hwfn - will learn number of hwfns */ - rc = qed_hw_prepare_single(&cdev->hwfns[0], cdev->regview, + rc = qed_hw_prepare_single(p_hwfn, + cdev->regview, cdev->doorbells, personality); if (rc) return rc; - personality = cdev->hwfns[0].hw_info.personality; + personality = p_hwfn->hw_info.personality; /* Initialize the rest of the hwfns */ - for (i = 1; i < cdev->num_hwfns; i++) { + if (cdev->num_hwfns > 1) { void __iomem *p_regview, *p_doorbell; + u8 __iomem *addr; + + /* adjust bar offset for second engine */ + addr = cdev->regview + qed_hw_bar_size(p_hwfn, 0) / 2; + p_regview = addr; - p_regview = cdev->regview + - i * qed_hw_bar_size(cdev, 0); - p_doorbell = cdev->doorbells + - i * qed_hw_bar_size(cdev, 1); - rc = qed_hw_prepare_single(&cdev->hwfns[i], p_regview, + /* adjust doorbell bar offset for second engine */ + addr = cdev->doorbells + qed_hw_bar_size(p_hwfn, 1) / 2; + p_doorbell = addr; + + /* prepare second hw function */ + rc = qed_hw_prepare_single(&cdev->hwfns[1], p_regview, p_doorbell, personality); + + /* in case of error, need to free the previously + * initiliazed hwfn 0. + */ if (rc) { - /* Cleanup previously initialized hwfns */ - while (--i >= 0) { - qed_init_free(&cdev->hwfns[i]); - qed_mcp_free(&cdev->hwfns[i]); - qed_hw_hwfn_free(&cdev->hwfns[i]); - } - return rc; + qed_init_free(p_hwfn); + qed_mcp_free(p_hwfn); + qed_hw_hwfn_free(p_hwfn); } } - return 0; + return rc; } void qed_hw_remove(struct qed_dev *cdev) diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index de50e84..9cc9d62 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -783,22 +783,16 @@ void qed_int_igu_enable_int(struct qed_hwfn *p_hwfn, qed_wr(p_hwfn, p_ptt, IGU_REG_PF_CONFIGURATION, igu_pf_conf); } -void qed_int_igu_enable(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - enum qed_int_mode int_mode) +int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + enum qed_int_mode int_mode) { - int i; - - p_hwfn->b_int_enabled = 1; + int rc, i; /* Mask non-link attentions */ for (i = 0; i < 9; i++) qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_ENABLE1_IGU_OUT_0 + (i << 2), 0); - /* Enable interrupt Generation */ - qed_int_igu_enable_int(p_hwfn, p_ptt, int_mode); - /* Configure AEU signal change to produce attentions for link */ qed_wr(p_hwfn, p_ptt, IGU_REG_LEADING_EDGE_LATCH, 0xfff); qed_wr(p_hwfn, p_ptt, IGU_REG_TRAILING_EDGE_LATCH, 0xfff); @@ -808,6 +802,19 @@ void qed_int_igu_enable(struct qed_hwfn *p_hwfn, /* Unmask AEU signals toward IGU */ qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_MASK_ATTN_IGU, 0xff); + if ((int_mode != QED_INT_MODE_INTA) || IS_LEAD_HWFN(p_hwfn)) { + rc = qed_slowpath_irq_req(p_hwfn); + if (rc != 0) { + DP_NOTICE(p_hwfn, "Slowpath IRQ request failed\n"); + return -EINVAL; + } + p_hwfn->b_int_requested = true; + } + /* Enable interrupt Generation */ + qed_int_igu_enable_int(p_hwfn, p_ptt, int_mode); + p_hwfn->b_int_enabled = 1; + + return rc; } void qed_int_igu_disable_int(struct qed_hwfn *p_hwfn, @@ -1127,3 +1134,11 @@ int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn, return info->igu_sb_cnt; } + +void qed_int_disable_post_isr_release(struct qed_dev *cdev) +{ + int i; + + for_each_hwfn(cdev, i) + cdev->hwfns[i].b_int_requested = false; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index 16b5751..51e0b09 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -169,10 +169,14 @@ int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn, int *p_iov_blks); /** - * @file + * @brief qed_int_disable_post_isr_release - performs the cleanup post ISR + * release. The API need to be called after releasing all slowpath IRQs + * of the device. + * + * @param cdev * - * @brief Interrupt handler */ +void qed_int_disable_post_isr_release(struct qed_dev *cdev); #define QED_CAU_DEF_RX_TIMER_RES 0 #define QED_CAU_DEF_TX_TIMER_RES 0 @@ -366,10 +370,11 @@ void qed_int_setup(struct qed_hwfn *p_hwfn, * @param p_hwfn * @param p_ptt * @param int_mode + * + * @return int */ -void qed_int_igu_enable(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - enum qed_int_mode int_mode); +int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + enum qed_int_mode int_mode); /** * @brief - Initialize CAU status block entry diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 947c7af..174f734 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -476,41 +476,22 @@ static irqreturn_t qed_single_int(int irq, void *dev_instance) return rc; } -static int qed_slowpath_irq_req(struct qed_dev *cdev) +int qed_slowpath_irq_req(struct qed_hwfn *hwfn) { - int i = 0, rc = 0; + struct qed_dev *cdev = hwfn->cdev; + int rc = 0; + u8 id; if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { - /* Request all the slowpath MSI-X vectors */ - for (i = 0; i < cdev->num_hwfns; i++) { - snprintf(cdev->hwfns[i].name, NAME_SIZE, - "sp-%d-%02x:%02x.%02x", - i, cdev->pdev->bus->number, - PCI_SLOT(cdev->pdev->devfn), - cdev->hwfns[i].abs_pf_id); - - rc = request_irq(cdev->int_params.msix_table[i].vector, - qed_msix_sp_int, 0, - cdev->hwfns[i].name, - cdev->hwfns[i].sp_dpc); - if (rc) - break; - - DP_VERBOSE(&cdev->hwfns[i], - (NETIF_MSG_INTR | QED_MSG_SP), + id = hwfn->my_id; + snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x", + id, cdev->pdev->bus->number, + PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id); + rc = request_irq(cdev->int_params.msix_table[id].vector, + qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc); + if (!rc) + DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP), "Requested slowpath MSI-X\n"); - } - - if (i != cdev->num_hwfns) { - /* Free already request MSI-X vectors */ - for (i--; i >= 0; i--) { - unsigned int vec = - cdev->int_params.msix_table[i].vector; - synchronize_irq(vec); - free_irq(cdev->int_params.msix_table[i].vector, - cdev->hwfns[i].sp_dpc); - } - } } else { unsigned long flags = 0; @@ -534,13 +515,17 @@ static void qed_slowpath_irq_free(struct qed_dev *cdev) if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { for_each_hwfn(cdev, i) { + if (!cdev->hwfns[i].b_int_requested) + break; synchronize_irq(cdev->int_params.msix_table[i].vector); free_irq(cdev->int_params.msix_table[i].vector, cdev->hwfns[i].sp_dpc); } } else { - free_irq(cdev->pdev->irq, cdev); + if (QED_LEADING_HWFN(cdev)->b_int_requested) + free_irq(cdev->pdev->irq, cdev); } + qed_int_disable_post_isr_release(cdev); } static int qed_nic_stop(struct qed_dev *cdev) @@ -765,16 +750,11 @@ static int qed_slowpath_start(struct qed_dev *cdev, if (rc) goto err1; - /* Request the slowpath IRQ */ - rc = qed_slowpath_irq_req(cdev); - if (rc) - goto err2; - /* Allocate stream for unzipping */ rc = qed_alloc_stream_mem(cdev); if (rc) { DP_NOTICE(cdev, "Failed to allocate stream memory\n"); - goto err3; + goto err2; } /* Start the slowpath */ diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 7a5ce59..e8df123 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -363,4 +363,8 @@ 0x7 << 0) #define MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT \ 0 +#define PGLUE_B_REG_PF_BAR0_SIZE \ + 0x2aae60UL +#define PGLUE_B_REG_PF_BAR1_SIZE \ + 0x2aae64UL #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index 31a1f1e..287fadf 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -124,8 +124,12 @@ struct qed_spq { dma_addr_t p_phys; struct qed_spq_entry *p_virt; - /* Used as index for completions (returns on EQ by FW) */ - u16 echo_idx; +#define SPQ_RING_SIZE \ + (CORE_SPQE_PAGE_SIZE_BYTES / sizeof(struct slow_path_element)) + + /* Bitmap for handling out-of-order completions */ + DECLARE_BITMAP(p_comp_bitmap, SPQ_RING_SIZE); + u8 comp_bitmap_idx; /* Statistics */ u32 unlimited_pending_count; diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index 7c0b845..3dd548a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -112,8 +112,6 @@ static int qed_spq_fill_entry(struct qed_hwfn *p_hwfn, struct qed_spq_entry *p_ent) { - p_ent->elem.hdr.echo = 0; - p_hwfn->p_spq->echo_idx++; p_ent->flags = 0; switch (p_ent->comp_mode) { @@ -195,10 +193,12 @@ static int qed_spq_hw_post(struct qed_hwfn *p_hwfn, struct qed_spq *p_spq, struct qed_spq_entry *p_ent) { - struct qed_chain *p_chain = &p_hwfn->p_spq->chain; + struct qed_chain *p_chain = &p_hwfn->p_spq->chain; + u16 echo = qed_chain_get_prod_idx(p_chain); struct slow_path_element *elem; struct core_db_data db; + p_ent->elem.hdr.echo = cpu_to_le16(echo); elem = qed_chain_produce(p_chain); if (!elem) { DP_NOTICE(p_hwfn, "Failed to produce from SPQ chain\n"); @@ -437,7 +437,9 @@ void qed_spq_setup(struct qed_hwfn *p_hwfn) p_spq->comp_count = 0; p_spq->comp_sent_count = 0; p_spq->unlimited_pending_count = 0; - p_spq->echo_idx = 0; + + bitmap_zero(p_spq->p_comp_bitmap, SPQ_RING_SIZE); + p_spq->comp_bitmap_idx = 0; /* SPQ cid, cannot fail */ qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_CORE, &p_spq->cid); @@ -582,26 +584,32 @@ qed_spq_add_entry(struct qed_hwfn *p_hwfn, struct qed_spq *p_spq = p_hwfn->p_spq; if (p_ent->queue == &p_spq->unlimited_pending) { - struct qed_spq_entry *p_en2; if (list_empty(&p_spq->free_pool)) { list_add_tail(&p_ent->list, &p_spq->unlimited_pending); p_spq->unlimited_pending_count++; return 0; - } + } else { + struct qed_spq_entry *p_en2; - p_en2 = list_first_entry(&p_spq->free_pool, - struct qed_spq_entry, - list); - list_del(&p_en2->list); + p_en2 = list_first_entry(&p_spq->free_pool, + struct qed_spq_entry, + list); + list_del(&p_en2->list); + + /* Copy the ring element physical pointer to the new + * entry, since we are about to override the entire ring + * entry and don't want to lose the pointer. + */ + p_ent->elem.data_ptr = p_en2->elem.data_ptr; - /* Strcut assignment */ - *p_en2 = *p_ent; + *p_en2 = *p_ent; - kfree(p_ent); + kfree(p_ent); - p_ent = p_en2; + p_ent = p_en2; + } } /* entry is to be placed in 'pending' queue */ @@ -777,13 +785,38 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn, list_for_each_entry_safe(p_ent, tmp, &p_spq->completion_pending, list) { if (p_ent->elem.hdr.echo == echo) { + u16 pos = le16_to_cpu(echo) % SPQ_RING_SIZE; + list_del(&p_ent->list); - qed_chain_return_produced(&p_spq->chain); + /* Avoid overriding of SPQ entries when getting + * out-of-order completions, by marking the completions + * in a bitmap and increasing the chain consumer only + * for the first successive completed entries. + */ + bitmap_set(p_spq->p_comp_bitmap, pos, SPQ_RING_SIZE); + + while (test_bit(p_spq->comp_bitmap_idx, + p_spq->p_comp_bitmap)) { + bitmap_clear(p_spq->p_comp_bitmap, + p_spq->comp_bitmap_idx, + SPQ_RING_SIZE); + p_spq->comp_bitmap_idx++; + qed_chain_return_produced(&p_spq->chain); + } + p_spq->comp_count++; found = p_ent; break; } + + /* This is relatively uncommon - depends on scenarios + * which have mutliple per-PF sent ramrods. + */ + DP_VERBOSE(p_hwfn, QED_MSG_SPQ, + "Got completion for echo %04x - doesn't match echo %04x in completion pending list\n", + le16_to_cpu(echo), + le16_to_cpu(p_ent->elem.hdr.echo)); } /* Release lock before callback, as callback may post diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c index be7d7a6..b1a452f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c @@ -246,7 +246,8 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *adapter) u32 state; state = QLCRDX(ahw, QLC_83XX_VNIC_STATE); - while (state != QLCNIC_DEV_NPAR_OPER && idc->vnic_wait_limit--) { + while (state != QLCNIC_DEV_NPAR_OPER && idc->vnic_wait_limit) { + idc->vnic_wait_limit--; msleep(1000); state = QLCRDX(ahw, QLC_83XX_VNIC_STATE); } diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 02b7115..9979764 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -4211,8 +4211,9 @@ static int ql_change_rx_buffers(struct ql_adapter *qdev) /* Wait for an outstanding reset to complete. */ if (!test_bit(QL_ADAPTER_UP, &qdev->flags)) { - int i = 3; - while (i-- && !test_bit(QL_ADAPTER_UP, &qdev->flags)) { + int i = 4; + + while (--i && !test_bit(QL_ADAPTER_UP, &qdev->flags)) { netif_err(qdev, ifup, qdev->ndev, "Waiting for adapter UP...\n"); ssleep(1); diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index ddb2c6c..689a4a5 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -736,9 +736,8 @@ qcaspi_netdev_tx_timeout(struct net_device *dev) netdev_info(qca->net_dev, "Transmit timeout at %ld, latency %ld\n", jiffies, jiffies - dev->trans_start); qca->net_dev->stats.tx_errors++; - /* wake the queue if there is room */ - if (qcaspi_tx_ring_has_space(&qca->txr)) - netif_wake_queue(dev); + /* Trigger tx queue flush and QCA7000 reset */ + qca->sync = QCASPI_SYNC_UNKNOWN; } static int diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index b4f2123..79ef799 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -7429,15 +7429,15 @@ process_pkt: rtl8169_rx_vlan_tag(desc, skb); + if (skb->pkt_type == PACKET_MULTICAST) + dev->stats.multicast++; + napi_gro_receive(&tp->napi, skb); u64_stats_update_begin(&tp->rx_stats.syncp); tp->rx_stats.packets++; tp->rx_stats.bytes += pkt_size; u64_stats_update_end(&tp->rx_stats.syncp); - - if (skb->pkt_type == PACKET_MULTICAST) - dev->stats.multicast++; } release_descriptor: desc->opts2 = 0; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index aa7b208..467d416 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -408,8 +408,6 @@ static int ravb_dmac_init(struct net_device *ndev) /* Interrupt enable: */ /* Frame receive */ ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIC0); - /* Receive FIFO full warning */ - ravb_write(ndev, RIC1_RFWE, RIC1); /* Receive FIFO full error, descriptor empty */ ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIC2); /* Frame transmitted, timestamp FIFO updated */ @@ -733,8 +731,10 @@ static irqreturn_t ravb_interrupt(int irq, void *dev_id) ((tis & tic) & BIT(q))) { if (napi_schedule_prep(&priv->napi[q])) { /* Mask RX and TX interrupts */ - ravb_write(ndev, ric0 & ~BIT(q), RIC0); - ravb_write(ndev, tic & ~BIT(q), TIC); + ric0 &= ~BIT(q); + tic &= ~BIT(q); + ravb_write(ndev, ric0, RIC0); + ravb_write(ndev, tic, TIC); __napi_schedule(&priv->napi[q]); } else { netdev_warn(ndev, @@ -905,6 +905,9 @@ static int ravb_phy_init(struct net_device *ndev) netdev_info(ndev, "limited PHY to 100Mbit/s\n"); } + /* 10BASE is not supported */ + phydev->supported &= ~PHY_10BT_FEATURES; + netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n", phydev->addr, phydev->irq, phydev->drv->name); @@ -1037,7 +1040,7 @@ static const char ravb_gstrings_stats[][ETH_GSTRING_LEN] = { "rx_queue_1_mcast_packets", "rx_queue_1_errors", "rx_queue_1_crc_errors", - "rx_queue_1_frame_errors_", + "rx_queue_1_frame_errors", "rx_queue_1_length_errors", "rx_queue_1_missed_errors", "rx_queue_1_over_errors", @@ -1225,7 +1228,7 @@ static int ravb_open(struct net_device *ndev) /* Device init */ error = ravb_dmac_init(ndev); if (error) - goto out_free_irq; + goto out_free_irq2; ravb_emac_init(ndev); /* Initialise PTP Clock driver */ @@ -1243,9 +1246,11 @@ static int ravb_open(struct net_device *ndev) out_ptp_stop: /* Stop PTP Clock driver */ ravb_ptp_stop(ndev); +out_free_irq2: + if (priv->chip_id == RCAR_GEN3) + free_irq(priv->emac_irq, ndev); out_free_irq: free_irq(ndev->irq, ndev); - free_irq(priv->emac_irq, ndev); out_napi_off: napi_disable(&priv->napi[RAVB_NC]); napi_disable(&priv->napi[RAVB_BE]); diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index e7bab79..a0eaf50 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -52,6 +52,8 @@ NETIF_MSG_RX_ERR| \ NETIF_MSG_TX_ERR) +#define SH_ETH_OFFSET_INVALID ((u16)~0) + #define SH_ETH_OFFSET_DEFAULTS \ [0 ... SH_ETH_MAX_REGISTER_OFFSET - 1] = SH_ETH_OFFSET_INVALID @@ -404,6 +406,28 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = { static void sh_eth_rcv_snd_disable(struct net_device *ndev); static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev); +static void sh_eth_write(struct net_device *ndev, u32 data, int enum_index) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u16 offset = mdp->reg_offset[enum_index]; + + if (WARN_ON(offset == SH_ETH_OFFSET_INVALID)) + return; + + iowrite32(data, mdp->addr + offset); +} + +static u32 sh_eth_read(struct net_device *ndev, int enum_index) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u16 offset = mdp->reg_offset[enum_index]; + + if (WARN_ON(offset == SH_ETH_OFFSET_INVALID)) + return ~0U; + + return ioread32(mdp->addr + offset); +} + static bool sh_eth_is_gether(struct sh_eth_private *mdp) { return mdp->reg_offset == sh_eth_offset_gigabit; @@ -1172,7 +1196,7 @@ static void sh_eth_ring_format(struct net_device *ndev) break; } mdp->rx_skbuff[i] = skb; - rxdesc->addr = dma_addr; + rxdesc->addr = cpu_to_edmac(mdp, dma_addr); rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP); /* Rx descriptor address set */ @@ -1403,7 +1427,8 @@ static int sh_eth_txfree(struct net_device *ndev) entry, edmac_to_cpu(mdp, txdesc->status)); /* Free the original skb. */ if (mdp->tx_skbuff[entry]) { - dma_unmap_single(&ndev->dev, txdesc->addr, + dma_unmap_single(&ndev->dev, + edmac_to_cpu(mdp, txdesc->addr), txdesc->buffer_length, DMA_TO_DEVICE); dev_kfree_skb_irq(mdp->tx_skbuff[entry]); mdp->tx_skbuff[entry] = NULL; @@ -1462,6 +1487,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) if (mdp->cd->shift_rd0) desc_status >>= 16; + skb = mdp->rx_skbuff[entry]; if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 | RD_RFS5 | RD_RFS6 | RD_RFS10)) { ndev->stats.rx_errors++; @@ -1477,16 +1503,16 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) ndev->stats.rx_missed_errors++; if (desc_status & RD_RFS10) ndev->stats.rx_over_errors++; - } else { + } else if (skb) { + dma_addr = edmac_to_cpu(mdp, rxdesc->addr); if (!mdp->cd->hw_swap) sh_eth_soft_swap( - phys_to_virt(ALIGN(rxdesc->addr, 4)), + phys_to_virt(ALIGN(dma_addr, 4)), pkt_len + 2); - skb = mdp->rx_skbuff[entry]; mdp->rx_skbuff[entry] = NULL; if (mdp->cd->rpadir) skb_reserve(skb, NET_IP_ALIGN); - dma_unmap_single(&ndev->dev, rxdesc->addr, + dma_unmap_single(&ndev->dev, dma_addr, ALIGN(mdp->rx_buf_sz, 32), DMA_FROM_DEVICE); skb_put(skb, pkt_len); @@ -1523,7 +1549,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) mdp->rx_skbuff[entry] = skb; skb_checksum_none_assert(skb); - rxdesc->addr = dma_addr; + rxdesc->addr = cpu_to_edmac(mdp, dma_addr); } dma_wmb(); /* RACT bit must be set after all the above writes */ if (entry >= mdp->num_rx_ring - 1) @@ -2331,8 +2357,8 @@ static void sh_eth_tx_timeout(struct net_device *ndev) /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < mdp->num_rx_ring; i++) { rxdesc = &mdp->rx_ring[i]; - rxdesc->status = 0; - rxdesc->addr = 0xBADF00D0; + rxdesc->status = cpu_to_edmac(mdp, 0); + rxdesc->addr = cpu_to_edmac(mdp, 0xBADF00D0); dev_kfree_skb(mdp->rx_skbuff[i]); mdp->rx_skbuff[i] = NULL; } @@ -2350,6 +2376,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); struct sh_eth_txdesc *txdesc; + dma_addr_t dma_addr; u32 entry; unsigned long flags; @@ -2372,14 +2399,14 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) txdesc = &mdp->tx_ring[entry]; /* soft swap. */ if (!mdp->cd->hw_swap) - sh_eth_soft_swap(phys_to_virt(ALIGN(txdesc->addr, 4)), - skb->len + 2); - txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(&ndev->dev, txdesc->addr)) { + sh_eth_soft_swap(PTR_ALIGN(skb->data, 4), skb->len + 2); + dma_addr = dma_map_single(&ndev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(&ndev->dev, dma_addr)) { kfree_skb(skb); return NETDEV_TX_OK; } + txdesc->addr = cpu_to_edmac(mdp, dma_addr); txdesc->buffer_length = skb->len; dma_wmb(); /* TACT bit must be set after all the above writes */ diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 50382b1..26ad1cf 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -546,31 +546,6 @@ static inline void sh_eth_soft_swap(char *src, int len) #endif } -#define SH_ETH_OFFSET_INVALID ((u16) ~0) - -static inline void sh_eth_write(struct net_device *ndev, u32 data, - int enum_index) -{ - struct sh_eth_private *mdp = netdev_priv(ndev); - u16 offset = mdp->reg_offset[enum_index]; - - if (WARN_ON(offset == SH_ETH_OFFSET_INVALID)) - return; - - iowrite32(data, mdp->addr + offset); -} - -static inline u32 sh_eth_read(struct net_device *ndev, int enum_index) -{ - struct sh_eth_private *mdp = netdev_priv(ndev); - u16 offset = mdp->reg_offset[enum_index]; - - if (WARN_ON(offset == SH_ETH_OFFSET_INVALID)) - return ~0U; - - return ioread32(mdp->addr + offset); -} - static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp, int enum_index) { diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index bc6d21b..e6a084a 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3299,7 +3299,8 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx, new_spec.priority = EFX_FILTER_PRI_AUTO; new_spec.flags = (EFX_FILTER_FLAG_RX | - EFX_FILTER_FLAG_RX_RSS); + (efx_rss_enabled(efx) ? + EFX_FILTER_FLAG_RX_RSS : 0)); new_spec.dmaq_id = 0; new_spec.rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT; rc = efx_ef10_filter_push(efx, &new_spec, @@ -3921,6 +3922,7 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx, { struct efx_ef10_filter_table *table = efx->filter_state; struct efx_ef10_dev_addr *addr_list; + enum efx_filter_flags filter_flags; struct efx_filter_spec spec; u8 baddr[ETH_ALEN]; unsigned int i, j; @@ -3935,11 +3937,11 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx, addr_count = table->dev_uc_count; } + filter_flags = efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0; + /* Insert/renew filters */ for (i = 0; i < addr_count; i++) { - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0); efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, addr_list[i].addr); rc = efx_ef10_filter_insert(efx, &spec, true); @@ -3968,9 +3970,7 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx, if (multicast && rollback) { /* Also need an Ethernet broadcast filter */ - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0); eth_broadcast_addr(baddr); efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, baddr); rc = efx_ef10_filter_insert(efx, &spec, true); @@ -4000,13 +4000,14 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast, { struct efx_ef10_filter_table *table = efx->filter_state; struct efx_ef10_nic_data *nic_data = efx->nic_data; + enum efx_filter_flags filter_flags; struct efx_filter_spec spec; u8 baddr[ETH_ALEN]; int rc; - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); + filter_flags = efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0; + + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0); if (multicast) efx_filter_set_mc_def(&spec); @@ -4023,8 +4024,7 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast, if (!nic_data->workaround_26807) { /* Also need an Ethernet broadcast filter */ efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); + filter_flags, 0); eth_broadcast_addr(baddr); efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, baddr); diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index d288f1c..a3c42a3 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -3422,7 +3422,7 @@ out: * with our request for slot reset the mmio_enabled callback will never be * called, and the link_reset callback is not used by AER or EEH mechanisms. */ -static struct pci_error_handlers efx_err_handlers = { +static const struct pci_error_handlers efx_err_handlers = { .error_detected = efx_io_error_detected, .slot_reset = efx_io_slot_reset, .resume = efx_io_resume, diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 1aaf76c..1082747 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -76,6 +76,11 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue); #define EFX_TXQ_MAX_ENT(efx) (EFX_WORKAROUND_35388(efx) ? \ EFX_MAX_DMAQ_SIZE / 2 : EFX_MAX_DMAQ_SIZE) +static inline bool efx_rss_enabled(struct efx_nic *efx) +{ + return efx->rss_spread > 1; +} + /* Filters */ void efx_mac_reconfigure(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c index 5a1c5a8..133e9e3 100644 --- a/drivers/net/ethernet/sfc/farch.c +++ b/drivers/net/ethernet/sfc/farch.c @@ -2242,7 +2242,7 @@ efx_farch_filter_init_rx_auto(struct efx_nic *efx, */ spec->priority = EFX_FILTER_PRI_AUTO; spec->flags = (EFX_FILTER_FLAG_RX | - (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) | + (efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0) | (efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0)); spec->dmaq_id = 0; } diff --git a/drivers/net/ethernet/sfc/txc43128_phy.c b/drivers/net/ethernet/sfc/txc43128_phy.c index 3d5ee32..194f67d 100644 --- a/drivers/net/ethernet/sfc/txc43128_phy.c +++ b/drivers/net/ethernet/sfc/txc43128_phy.c @@ -418,7 +418,7 @@ static void txc_reset_logic_mmd(struct efx_nic *efx, int mmd) val |= (1 << TXC_GLCMD_LMTSWRST_LBN); efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, val); - while (tries--) { + while (--tries) { val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD); if (!(val & (1 << TXC_GLCMD_LMTSWRST_LBN))) break; diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index c860c90..219a99b 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -809,22 +809,17 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) static int smsc911x_phy_reset(struct smsc911x_data *pdata) { - struct phy_device *phy_dev = pdata->phy_dev; unsigned int temp; unsigned int i = 100000; - BUG_ON(!phy_dev); - BUG_ON(!phy_dev->bus); - - SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset"); - smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET); + temp = smsc911x_reg_read(pdata, PMT_CTRL); + smsc911x_reg_write(pdata, PMT_CTRL, temp | PMT_CTRL_PHY_RST_); do { msleep(1); - temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, - MII_BMCR); - } while ((i--) && (temp & BMCR_RESET)); + temp = smsc911x_reg_read(pdata, PMT_CTRL); + } while ((i--) && (temp & PMT_CTRL_PHY_RST_)); - if (temp & BMCR_RESET) { + if (unlikely(temp & PMT_CTRL_PHY_RST_)) { SMSC_WARN(pdata, hw, "PHY reset failed to complete"); return -EIO; } @@ -2296,7 +2291,7 @@ static int smsc911x_init(struct net_device *dev) } /* Reset the LAN911x */ - if (smsc911x_soft_reset(pdata)) + if (smsc911x_phy_reset(pdata) || smsc911x_soft_reset(pdata)) return -ENODEV; dev->flags |= IFF_MULTICAST; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 9d89bdb..82de68b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -337,11 +337,11 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) QSGMII_PHY_RX_SIGNAL_DETECT_EN | QSGMII_PHY_TX_DRIVER_EN | QSGMII_PHY_QSGMII_EN | - 0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET | - 0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET | - 0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET | - 0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET | - 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET); + 0x4ul << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET | + 0x3ul << QSGMII_PHY_RX_DC_BIAS_OFFSET | + 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | + 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | + 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET); } plat_dat->has_gmac = true; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index 7f6f4a4..58c05ac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -299,16 +299,17 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) { const char *rs; + dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN; + err = of_property_read_string(np, "st,tx-retime-src", &rs); if (err < 0) { dev_warn(dev, "Use internal clock source\n"); - dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN; - } else if (!strcasecmp(rs, "clk_125")) { - dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125; - } else if (!strcasecmp(rs, "txclk")) { - dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK; + } else { + if (!strcasecmp(rs, "clk_125")) + dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125; + else if (!strcasecmp(rs, "txclk")) + dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK; } - dwmac->speed = SPEED_1000; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index 52b8ed9..adff463 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -153,7 +153,11 @@ static int sun7i_gmac_probe(struct platform_device *pdev) if (ret) return ret; - return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) + sun7i_gmac_exit(pdev, plat_dat->bsp_priv); + + return ret; } static const struct of_device_id sun7i_dwmac_match[] = { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 64d8aa4..a5b869e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -185,7 +185,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv) priv->clk_csr = STMMAC_CSR_100_150M; else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M)) priv->clk_csr = STMMAC_CSR_150_250M; - else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M)) + else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M)) priv->clk_csr = STMMAC_CSR_250_300M; } } @@ -2232,6 +2232,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) frame_len = priv->hw->desc->get_rx_frame_len(p, coe); + /* check if frame_len fits the preallocated memory */ + if (frame_len > priv->dma_buf_sz) { + priv->dev->stats.rx_length_errors++; + break; + } + /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 * Type frames (LLC/LLC-SNAP) */ @@ -3040,8 +3046,6 @@ int stmmac_suspend(struct net_device *ndev) priv->hw->dma->stop_tx(priv->ioaddr); priv->hw->dma->stop_rx(priv->ioaddr); - stmmac_clear_descriptors(priv); - /* Enable Power down mode by programming the PMT regs */ if (device_may_wakeup(priv->device)) { priv->hw->mac->pmt(priv->hw, priv->wolopts); @@ -3099,9 +3103,15 @@ int stmmac_resume(struct net_device *ndev) netif_device_attach(ndev); - init_dma_desc_rings(ndev, GFP_ATOMIC); + priv->cur_rx = 0; + priv->dirty_rx = 0; + priv->dirty_tx = 0; + priv->cur_tx = 0; + stmmac_clear_descriptors(priv); + stmmac_hw_setup(ndev, false); stmmac_init_tx_coalesce(priv); + stmmac_set_rx_mode(ndev); napi_enable(&priv->napi); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index ebf6abc..bba670c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -138,7 +138,6 @@ int stmmac_mdio_reset(struct mii_bus *bus) #ifdef CONFIG_OF if (priv->device->of_node) { - int reset_gpio, active_low; if (data->reset_gpio < 0) { struct device_node *np = priv->device->of_node; @@ -154,24 +153,23 @@ int stmmac_mdio_reset(struct mii_bus *bus) "snps,reset-active-low"); of_property_read_u32_array(np, "snps,reset-delays-us", data->delays, 3); - } - reset_gpio = data->reset_gpio; - active_low = data->active_low; + if (gpio_request(data->reset_gpio, "mdio-reset")) + return 0; + } - if (!gpio_request(reset_gpio, "mdio-reset")) { - gpio_direction_output(reset_gpio, active_low ? 1 : 0); - if (data->delays[0]) - msleep(DIV_ROUND_UP(data->delays[0], 1000)); + gpio_direction_output(data->reset_gpio, + data->active_low ? 1 : 0); + if (data->delays[0]) + msleep(DIV_ROUND_UP(data->delays[0], 1000)); - gpio_set_value(reset_gpio, active_low ? 0 : 1); - if (data->delays[1]) - msleep(DIV_ROUND_UP(data->delays[1], 1000)); + gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1); + if (data->delays[1]) + msleep(DIV_ROUND_UP(data->delays[1], 1000)); - gpio_set_value(reset_gpio, active_low ? 1 : 0); - if (data->delays[2]) - msleep(DIV_ROUND_UP(data->delays[2], 1000)); - } + gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0); + if (data->delays[2]) + msleep(DIV_ROUND_UP(data->delays[2], 1000)); } #endif diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c index c08be62..1562ab4 100644 --- a/drivers/net/ethernet/ti/cpsw-common.c +++ b/drivers/net/ethernet/ti/cpsw-common.c @@ -78,6 +78,9 @@ static int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave, int ti_cm_get_macid(struct device *dev, int slave, u8 *mac_addr) { + if (of_machine_is_compatible("ti,dm8148")) + return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); + if (of_machine_is_compatible("ti,am33xx")) return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c index ae68afd..f38696c 100644 --- a/drivers/net/ethernet/via/via-velocity.c +++ b/drivers/net/ethernet/via/via-velocity.c @@ -345,13 +345,6 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability"); */ VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode"); -#define VAL_PKT_LEN_DEF 0 -/* ValPktLen[] is used for setting the checksum offload ability of NIC. - 0: Receive frame with invalid layer 2 length (Default) - 1: Drop frame with invalid layer 2 length -*/ -VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame"); - #define WOL_OPT_DEF 0 #define WOL_OPT_MIN 0 #define WOL_OPT_MAX 7 @@ -494,7 +487,6 @@ static void velocity_get_options(struct velocity_opt *opts, int index, velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname); velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname); - velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname); velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname); velocity_set_int_opt(&opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname); opts->numrx = (opts->numrx & ~3); @@ -2055,8 +2047,9 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff; struct sk_buff *skb; - if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { - VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame spans multiple RDs.\n", vptr->netdev->name); + if (unlikely(rd->rdesc0.RSR & (RSR_STP | RSR_EDP | RSR_RL))) { + if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) + VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame spans multiple RDs.\n", vptr->netdev->name); stats->rx_length_errors++; return -EINVAL; } @@ -2069,17 +2062,6 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) dma_sync_single_for_cpu(vptr->dev, rd_info->skb_dma, vptr->rx.buf_sz, DMA_FROM_DEVICE); - /* - * Drop frame not meeting IEEE 802.3 - */ - - if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) { - if (rd->rdesc0.RSR & RSR_RL) { - stats->rx_length_errors++; - return -EINVAL; - } - } - velocity_rx_csum(rd, skb); if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { |