diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom')
-rw-r--r-- | drivers/net/ethernet/broadcom/Kconfig | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/b44.h | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bcmsysport.c | 170 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bcmsysport.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bgmac.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 59 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 31 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.c | 67 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmmii.c | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 2 |
11 files changed, 286 insertions, 84 deletions
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index a6f9142b9048..8be9eab73320 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -26,8 +26,7 @@ config B44 select PHYLIB ---help--- If you have a network (Ethernet) controller of this type, say Y - or M and read the Ethernet-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. + or M here. To compile this driver as a module, choose M here. The module will be called b44. diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h index 3e9c3fc7591b..65d88d7c5581 100644 --- a/drivers/net/ethernet/broadcom/b44.h +++ b/drivers/net/ethernet/broadcom/b44.h @@ -1,6 +1,8 @@ #ifndef _B44_H #define _B44_H +#include <linux/brcmphy.h> + /* Register layout. (These correspond to struct _bcmenettregs in bcm4400.) */ #define B44_DEVCTRL 0x0000UL /* Device Control */ #define DEVCTRL_MPM 0x00000040 /* Magic Packet PME Enable (B0 only) */ @@ -281,8 +283,10 @@ struct ring_info { }; #define B44_MCAST_TABLE_SIZE 32 -#define B44_PHY_ADDR_NO_LOCAL_PHY 30 /* no local phy regs */ -#define B44_PHY_ADDR_NO_PHY 31 /* no phy present at all */ +/* no local phy regs, e.g: Broadcom switches pseudo-PHY */ +#define B44_PHY_ADDR_NO_LOCAL_PHY BRCM_PSEUDO_PHY_ADDR +/* no phy present at all */ +#define B44_PHY_ADDR_NO_PHY 31 #define B44_MDC_RATIO 5000000 #define B44_STAT_REG_DECLARE \ diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 783543ad1fcf..909ad7a0d480 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -456,6 +456,67 @@ static int bcm_sysport_set_wol(struct net_device *dev, return 0; } +static int bcm_sysport_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + u32 reg; + + reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(0)); + + ec->tx_coalesce_usecs = (reg >> RING_TIMEOUT_SHIFT) * 8192 / 1000; + ec->tx_max_coalesced_frames = reg & RING_INTR_THRESH_MASK; + + reg = rdma_readl(priv, RDMA_MBDONE_INTR); + + ec->rx_coalesce_usecs = (reg >> RDMA_TIMEOUT_SHIFT) * 8192 / 1000; + ec->rx_max_coalesced_frames = reg & RDMA_INTR_THRESH_MASK; + + return 0; +} + +static int bcm_sysport_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + unsigned int i; + u32 reg; + + /* Base system clock is 125Mhz, DMA timeout is this reference clock + * divided by 1024, which yield roughly 8.192 us, our maximum value has + * to fit in the RING_TIMEOUT_MASK (16 bits). + */ + if (ec->tx_max_coalesced_frames > RING_INTR_THRESH_MASK || + ec->tx_coalesce_usecs > (RING_TIMEOUT_MASK * 8) + 1 || + ec->rx_max_coalesced_frames > RDMA_INTR_THRESH_MASK || + ec->rx_coalesce_usecs > (RDMA_TIMEOUT_MASK * 8) + 1) + return -EINVAL; + + if ((ec->tx_coalesce_usecs == 0 && ec->tx_max_coalesced_frames == 0) || + (ec->rx_coalesce_usecs == 0 && ec->rx_max_coalesced_frames == 0)) + return -EINVAL; + + for (i = 0; i < dev->num_tx_queues; i++) { + reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(i)); + reg &= ~(RING_INTR_THRESH_MASK | + RING_TIMEOUT_MASK << RING_TIMEOUT_SHIFT); + reg |= ec->tx_max_coalesced_frames; + reg |= DIV_ROUND_UP(ec->tx_coalesce_usecs * 1000, 8192) << + RING_TIMEOUT_SHIFT; + tdma_writel(priv, reg, TDMA_DESC_RING_INTR_CONTROL(i)); + } + + reg = rdma_readl(priv, RDMA_MBDONE_INTR); + reg &= ~(RDMA_INTR_THRESH_MASK | + RDMA_TIMEOUT_MASK << RDMA_TIMEOUT_SHIFT); + reg |= ec->rx_max_coalesced_frames; + reg |= DIV_ROUND_UP(ec->rx_coalesce_usecs * 1000, 8192) << + RDMA_TIMEOUT_SHIFT; + rdma_writel(priv, reg, RDMA_MBDONE_INTR); + + return 0; +} + static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb) { dev_kfree_skb_any(cb->skb); @@ -463,67 +524,70 @@ static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb) dma_unmap_addr_set(cb, dma_addr, 0); } -static int bcm_sysport_rx_refill(struct bcm_sysport_priv *priv, - struct bcm_sysport_cb *cb) +static struct sk_buff *bcm_sysport_rx_refill(struct bcm_sysport_priv *priv, + struct bcm_sysport_cb *cb) { struct device *kdev = &priv->pdev->dev; struct net_device *ndev = priv->netdev; + struct sk_buff *skb, *rx_skb; dma_addr_t mapping; - int ret; - cb->skb = netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH); - if (!cb->skb) { + /* Allocate a new SKB for a new packet */ + skb = netdev_alloc_skb(priv->netdev, RX_BUF_LENGTH); + if (!skb) { + priv->mib.alloc_rx_buff_failed++; netif_err(priv, rx_err, ndev, "SKB alloc failed\n"); - return -ENOMEM; + return NULL; } - mapping = dma_map_single(kdev, cb->skb->data, + mapping = dma_map_single(kdev, skb->data, RX_BUF_LENGTH, DMA_FROM_DEVICE); - ret = dma_mapping_error(kdev, mapping); - if (ret) { + if (dma_mapping_error(kdev, mapping)) { priv->mib.rx_dma_failed++; - bcm_sysport_free_cb(cb); + dev_kfree_skb_any(skb); netif_err(priv, rx_err, ndev, "DMA mapping failure\n"); - return ret; + return NULL; } - dma_unmap_addr_set(cb, dma_addr, mapping); - dma_desc_set_addr(priv, priv->rx_bd_assign_ptr, mapping); + /* Grab the current SKB on the ring */ + rx_skb = cb->skb; + if (likely(rx_skb)) + dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr), + RX_BUF_LENGTH, DMA_FROM_DEVICE); - priv->rx_bd_assign_index++; - priv->rx_bd_assign_index &= (priv->num_rx_bds - 1); - priv->rx_bd_assign_ptr = priv->rx_bds + - (priv->rx_bd_assign_index * DESC_SIZE); + /* Put the new SKB on the ring */ + cb->skb = skb; + dma_unmap_addr_set(cb, dma_addr, mapping); + dma_desc_set_addr(priv, cb->bd_addr, mapping); netif_dbg(priv, rx_status, ndev, "RX refill\n"); - return 0; + /* Return the current SKB to the caller */ + return rx_skb; } static int bcm_sysport_alloc_rx_bufs(struct bcm_sysport_priv *priv) { struct bcm_sysport_cb *cb; - int ret = 0; + struct sk_buff *skb; unsigned int i; for (i = 0; i < priv->num_rx_bds; i++) { - cb = &priv->rx_cbs[priv->rx_bd_assign_index]; - if (cb->skb) - continue; - - ret = bcm_sysport_rx_refill(priv, cb); - if (ret) - break; + cb = &priv->rx_cbs[i]; + skb = bcm_sysport_rx_refill(priv, cb); + if (skb) + dev_kfree_skb(skb); + if (!cb->skb) + return -ENOMEM; } - return ret; + return 0; } /* Poll the hardware for up to budget packets to process */ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, unsigned int budget) { - struct device *kdev = &priv->pdev->dev; struct net_device *ndev = priv->netdev; unsigned int processed = 0, to_process; struct bcm_sysport_cb *cb; @@ -531,7 +595,6 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, unsigned int p_index; u16 len, status; struct bcm_rsb *rsb; - int ret; /* Determine how much we should process since last call */ p_index = rdma_readl(priv, RDMA_PROD_INDEX); @@ -549,13 +612,8 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, while ((processed < to_process) && (processed < budget)) { cb = &priv->rx_cbs[priv->rx_read_ptr]; - skb = cb->skb; + skb = bcm_sysport_rx_refill(priv, cb); - processed++; - priv->rx_read_ptr++; - - if (priv->rx_read_ptr == priv->num_rx_bds) - priv->rx_read_ptr = 0; /* We do not have a backing SKB, so we do not a corresponding * DMA mapping for this incoming packet since @@ -566,12 +624,9 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, netif_err(priv, rx_err, ndev, "out of memory!\n"); ndev->stats.rx_dropped++; ndev->stats.rx_errors++; - goto refill; + goto next; } - dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr), - RX_BUF_LENGTH, DMA_FROM_DEVICE); - /* Extract the Receive Status Block prepended */ rsb = (struct bcm_rsb *)skb->data; len = (rsb->rx_status_len >> DESC_LEN_SHIFT) & DESC_LEN_MASK; @@ -583,12 +638,20 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, p_index, priv->rx_c_index, priv->rx_read_ptr, len, status); + if (unlikely(len > RX_BUF_LENGTH)) { + netif_err(priv, rx_status, ndev, "oversized packet\n"); + ndev->stats.rx_length_errors++; + ndev->stats.rx_errors++; + dev_kfree_skb_any(skb); + goto next; + } + if (unlikely(!(status & DESC_EOP) || !(status & DESC_SOP))) { netif_err(priv, rx_status, ndev, "fragmented packet!\n"); ndev->stats.rx_dropped++; ndev->stats.rx_errors++; - bcm_sysport_free_cb(cb); - goto refill; + dev_kfree_skb_any(skb); + goto next; } if (unlikely(status & (RX_STATUS_ERR | RX_STATUS_OVFLOW))) { @@ -597,8 +660,8 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, ndev->stats.rx_over_errors++; ndev->stats.rx_dropped++; ndev->stats.rx_errors++; - bcm_sysport_free_cb(cb); - goto refill; + dev_kfree_skb_any(skb); + goto next; } skb_put(skb, len); @@ -625,10 +688,12 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, ndev->stats.rx_bytes += len; napi_gro_receive(&priv->napi, skb); -refill: - ret = bcm_sysport_rx_refill(priv, cb); - if (ret) - priv->mib.alloc_rx_buff_failed++; +next: + processed++; + priv->rx_read_ptr++; + + if (priv->rx_read_ptr == priv->num_rx_bds) + priv->rx_read_ptr = 0; } return processed; @@ -1269,14 +1334,14 @@ static inline int tdma_enable_set(struct bcm_sysport_priv *priv, static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv) { + struct bcm_sysport_cb *cb; u32 reg; int ret; + int i; /* Initialize SW view of the RX ring */ priv->num_rx_bds = NUM_RX_DESC; priv->rx_bds = priv->base + SYS_PORT_RDMA_OFFSET; - priv->rx_bd_assign_ptr = priv->rx_bds; - priv->rx_bd_assign_index = 0; priv->rx_c_index = 0; priv->rx_read_ptr = 0; priv->rx_cbs = kcalloc(priv->num_rx_bds, sizeof(struct bcm_sysport_cb), @@ -1286,6 +1351,11 @@ static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv) return -ENOMEM; } + for (i = 0; i < priv->num_rx_bds; i++) { + cb = priv->rx_cbs + i; + cb->bd_addr = priv->rx_bds + i * DESC_SIZE; + } + ret = bcm_sysport_alloc_rx_bufs(priv); if (ret) { netif_err(priv, hw, priv->netdev, "SKB allocation failed\n"); @@ -1641,6 +1711,8 @@ static struct ethtool_ops bcm_sysport_ethtool_ops = { .get_sset_count = bcm_sysport_get_sset_count, .get_wol = bcm_sysport_get_wol, .set_wol = bcm_sysport_set_wol, + .get_coalesce = bcm_sysport_get_coalesce, + .set_coalesce = bcm_sysport_set_coalesce, }; static const struct net_device_ops bcm_sysport_netdev_ops = { diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index e2c043eabbf3..f28bf545d7f4 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -292,7 +292,7 @@ struct bcm_rsb { #define RDMA_END_ADDR_LO 0x102c #define RDMA_MBDONE_INTR 0x1030 -#define RDMA_INTR_THRESH_MASK 0xff +#define RDMA_INTR_THRESH_MASK 0x1ff #define RDMA_TIMEOUT_SHIFT 16 #define RDMA_TIMEOUT_MASK 0xffff @@ -663,8 +663,6 @@ struct bcm_sysport_priv { /* Receive queue */ void __iomem *rx_bds; - void __iomem *rx_bd_assign_ptr; - unsigned int rx_bd_assign_index; struct bcm_sysport_cb *rx_cbs; unsigned int num_rx_bds; unsigned int rx_read_ptr; diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h index db27febbb215..4fbb093e0d84 100644 --- a/drivers/net/ethernet/broadcom/bgmac.h +++ b/drivers/net/ethernet/broadcom/bgmac.h @@ -13,6 +13,7 @@ dev_dbg(&(bgmac)->core->dev, fmt, ##__VA_ARGS__) #include <linux/bcma/bcma.h> +#include <linux/brcmphy.h> #include <linux/netdevice.h> #define BGMAC_DEV_CTL 0x000 @@ -349,7 +350,7 @@ #define BGMAC_DESC_CTL0_SOF 0x80000000 /* Start of frame */ #define BGMAC_DESC_CTL1_LEN 0x00001FFF -#define BGMAC_PHY_NOREGS 0x1E +#define BGMAC_PHY_NOREGS BRCM_PSEUDO_PHY_ADDR #define BGMAC_PHY_MASK 0x1F #define BGMAC_MAX_TX_RINGS 4 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 1f82a04ce01a..7a4aaa3c01b6 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -357,6 +357,7 @@ struct sw_tx_bd { struct sw_rx_page { struct page *page; DEFINE_DMA_UNMAP_ADDR(mapping); + unsigned int offset; }; union db_prod { @@ -381,9 +382,10 @@ union db_prod { #define PAGES_PER_SGE_SHIFT 0 #define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT) -#define SGE_PAGE_SIZE PAGE_SIZE -#define SGE_PAGE_SHIFT PAGE_SHIFT -#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))(addr)) +#define SGE_PAGE_SHIFT 12 +#define SGE_PAGE_SIZE (1 << SGE_PAGE_SHIFT) +#define SGE_PAGE_MASK (~(SGE_PAGE_SIZE - 1)) +#define SGE_PAGE_ALIGN(addr) (((addr) + SGE_PAGE_SIZE - 1) & SGE_PAGE_MASK) #define SGE_PAGES (SGE_PAGE_SIZE * PAGES_PER_SGE) #define TPA_AGG_SIZE min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) * \ SGE_PAGES), 0xffff) @@ -526,6 +528,12 @@ enum bnx2x_tpa_mode_t { TPA_MODE_GRO }; +struct bnx2x_alloc_pool { + struct page *page; + dma_addr_t dma; + unsigned int offset; +}; + struct bnx2x_fastpath { struct bnx2x *bp; /* parent */ @@ -599,6 +607,8 @@ struct bnx2x_fastpath { 4 (for the digits and to make it DWORD aligned) */ #define FP_NAME_SIZE (sizeof(((struct net_device *)0)->name) + 8) char name[FP_NAME_SIZE]; + + struct bnx2x_alloc_pool page_pool; }; #define bnx2x_fp(bp, nr, var) ((bp)->fp[(nr)].var) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index ec56a9b65dc3..e2a65334708d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -544,30 +544,49 @@ static void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags, static int bnx2x_alloc_rx_sge(struct bnx2x *bp, struct bnx2x_fastpath *fp, u16 index, gfp_t gfp_mask) { - struct page *page = alloc_pages(gfp_mask, PAGES_PER_SGE_SHIFT); struct sw_rx_page *sw_buf = &fp->rx_page_ring[index]; struct eth_rx_sge *sge = &fp->rx_sge_ring[index]; + struct bnx2x_alloc_pool *pool = &fp->page_pool; dma_addr_t mapping; - if (unlikely(page == NULL)) { - BNX2X_ERR("Can't alloc sge\n"); - return -ENOMEM; - } + if (!pool->page || (PAGE_SIZE - pool->offset) < SGE_PAGE_SIZE) { - mapping = dma_map_page(&bp->pdev->dev, page, 0, - SGE_PAGES, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { - __free_pages(page, PAGES_PER_SGE_SHIFT); - BNX2X_ERR("Can't map sge\n"); - return -ENOMEM; + /* put page reference used by the memory pool, since we + * won't be using this page as the mempool anymore. + */ + if (pool->page) + put_page(pool->page); + + pool->page = alloc_pages(gfp_mask, PAGES_PER_SGE_SHIFT); + if (unlikely(!pool->page)) { + BNX2X_ERR("Can't alloc sge\n"); + return -ENOMEM; + } + + pool->dma = dma_map_page(&bp->pdev->dev, pool->page, 0, + PAGE_SIZE, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(&bp->pdev->dev, + pool->dma))) { + __free_pages(pool->page, PAGES_PER_SGE_SHIFT); + pool->page = NULL; + BNX2X_ERR("Can't map sge\n"); + return -ENOMEM; + } + pool->offset = 0; } - sw_buf->page = page; + get_page(pool->page); + sw_buf->page = pool->page; + sw_buf->offset = pool->offset; + + mapping = pool->dma + sw_buf->offset; dma_unmap_addr_set(sw_buf, mapping, mapping); sge->addr_hi = cpu_to_le32(U64_HI(mapping)); sge->addr_lo = cpu_to_le32(U64_LO(mapping)); + pool->offset += SGE_PAGE_SIZE; + return 0; } @@ -629,20 +648,22 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp, return err; } - /* Unmap the page as we're going to pass it to the stack */ - dma_unmap_page(&bp->pdev->dev, - dma_unmap_addr(&old_rx_pg, mapping), - SGE_PAGES, DMA_FROM_DEVICE); + dma_unmap_single(&bp->pdev->dev, + dma_unmap_addr(&old_rx_pg, mapping), + SGE_PAGE_SIZE, DMA_FROM_DEVICE); /* Add one frag and update the appropriate fields in the skb */ if (fp->mode == TPA_MODE_LRO) - skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len); + skb_fill_page_desc(skb, j, old_rx_pg.page, + old_rx_pg.offset, frag_len); else { /* GRO */ int rem; int offset = 0; for (rem = frag_len; rem > 0; rem -= gro_size) { int len = rem > gro_size ? gro_size : rem; skb_fill_page_desc(skb, frag_id++, - old_rx_pg.page, offset, len); + old_rx_pg.page, + old_rx_pg.offset + offset, + len); if (offset) get_page(old_rx_pg.page); offset += len; @@ -662,7 +683,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp, static void bnx2x_frag_free(const struct bnx2x_fastpath *fp, void *data) { if (fp->rx_frag_size) - put_page(virt_to_head_page(data)); + skb_free_frag(data); else kfree(data); } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index d7a71758e876..2b30081ec26d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -804,9 +804,13 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp, if (!page) return; - dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping), - SGE_PAGES, DMA_FROM_DEVICE); - __free_pages(page, PAGES_PER_SGE_SHIFT); + /* Since many fragments can share the same page, make sure to + * only unmap and free the page once. + */ + dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping), + SGE_PAGE_SIZE, DMA_FROM_DEVICE); + + put_page(page); sw_buf->page = NULL; sge->addr_hi = 0; @@ -964,6 +968,25 @@ static inline void bnx2x_set_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid, ((u8 *)fw_lo)[1] = mac[4]; } +static inline void bnx2x_free_rx_mem_pool(struct bnx2x *bp, + struct bnx2x_alloc_pool *pool) +{ + if (!pool->page) + return; + + /* Page was not fully fragmented. Unmap unused space */ + if (pool->offset < PAGE_SIZE) { + dma_addr_t dma = pool->dma + pool->offset; + int size = PAGE_SIZE - pool->offset; + + dma_unmap_single(&bp->pdev->dev, dma, size, DMA_FROM_DEVICE); + } + + put_page(pool->page); + + pool->page = NULL; +} + static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp, struct bnx2x_fastpath *fp, int last) { @@ -974,6 +997,8 @@ static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp, for (i = 0; i < last; i++) bnx2x_free_rx_sge(bp, fp, i); + + bnx2x_free_rx_mem_pool(bp, &fp->page_pool); } static inline void bnx2x_set_next_page_rx_bd(struct bnx2x_fastpath *fp) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 6043734ea613..b43b2cb9b830 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2770,12 +2770,79 @@ static int bcmgenet_close(struct net_device *dev) return ret; } +static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) +{ + struct bcmgenet_priv *priv = ring->priv; + u32 p_index, c_index, intsts, intmsk; + struct netdev_queue *txq; + unsigned int free_bds; + unsigned long flags; + bool txq_stopped; + + if (!netif_msg_tx_err(priv)) + return; + + txq = netdev_get_tx_queue(priv->dev, ring->queue); + + spin_lock_irqsave(&ring->lock, flags); + if (ring->index == DESC_INDEX) { + intsts = ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); + intmsk = UMAC_IRQ_TXDMA_DONE | UMAC_IRQ_TXDMA_MBDONE; + } else { + intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); + intmsk = 1 << ring->index; + } + c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX); + p_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_PROD_INDEX); + txq_stopped = netif_tx_queue_stopped(txq); + free_bds = ring->free_bds; + spin_unlock_irqrestore(&ring->lock, flags); + + netif_err(priv, tx_err, priv->dev, "Ring %d queue %d status summary\n" + "TX queue status: %s, interrupts: %s\n" + "(sw)free_bds: %d (sw)size: %d\n" + "(sw)p_index: %d (hw)p_index: %d\n" + "(sw)c_index: %d (hw)c_index: %d\n" + "(sw)clean_p: %d (sw)write_p: %d\n" + "(sw)cb_ptr: %d (sw)end_ptr: %d\n", + ring->index, ring->queue, + txq_stopped ? "stopped" : "active", + intsts & intmsk ? "enabled" : "disabled", + free_bds, ring->size, + ring->prod_index, p_index & DMA_P_INDEX_MASK, + ring->c_index, c_index & DMA_C_INDEX_MASK, + ring->clean_ptr, ring->write_ptr, + ring->cb_ptr, ring->end_ptr); +} + static void bcmgenet_timeout(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); + u32 int0_enable = 0; + u32 int1_enable = 0; + unsigned int q; netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + bcmgenet_disable_tx_napi(priv); + + for (q = 0; q < priv->hw_params->tx_queues; q++) + bcmgenet_dump_tx_queue(&priv->tx_rings[q]); + bcmgenet_dump_tx_queue(&priv->tx_rings[DESC_INDEX]); + + bcmgenet_tx_reclaim_all(dev); + + for (q = 0; q < priv->hw_params->tx_queues; q++) + int1_enable |= (1 << q); + + int0_enable = UMAC_IRQ_TXDMA_DONE; + + /* Re-enable TX interrupts if disabled */ + bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); + + bcmgenet_enable_tx_napi(priv); + dev->trans_start = jiffies; dev->stats.tx_errors++; diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 420949cc55aa..6bef04e2f735 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -47,7 +47,12 @@ static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location) HZ / 100); ret = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD); - if (ret & MDIO_READ_FAIL) + /* Some broken devices are known not to release the line during + * turn-around, e.g: Broadcom BCM53125 external switches, so check for + * that condition here and ignore the MDIO controller read failure + * indication. + */ + if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (ret & MDIO_READ_FAIL)) return -EIO; return ret & 0xffff; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 069952fa5d64..73c934cf6c61 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6618,7 +6618,7 @@ static void tg3_tx(struct tg3_napi *tnapi) static void tg3_frag_free(bool is_frag, void *data) { if (is_frag) - put_page(virt_to_head_page(data)); + skb_free_frag(data); else kfree(data); } |