diff options
author | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-04-07 06:57:17 -0700 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-08-10 19:54:52 -0700 |
commit | f7917c009c28c941ba151ee66f04dc7f6a2e1e0b (patch) | |
tree | 91cd66b3b846b1113654de2ac31f085d0d7989ba /drivers/net/cxgb3/sge.c | |
parent | adfc5217e9db68d3f0cec8dd847c1a6d3ab549ee (diff) |
chelsio: Move the Chelsio drivers
Moves the drivers for the Chelsio chipsets into
drivers/net/ethernet/chelsio/ and the necessary Kconfig and Makefile
changes.
CC: Divy Le Ray <divy@chelsio.com>
CC: Dimitris Michailidis <dm@chelsio.com>
CC: Casey Leedom <leedom@chelsio.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/cxgb3/sge.c')
-rw-r--r-- | drivers/net/cxgb3/sge.c | 3303 |
1 files changed, 0 insertions, 3303 deletions
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c deleted file mode 100644 index d6fa1777a343..000000000000 --- a/drivers/net/cxgb3/sge.c +++ /dev/null @@ -1,3303 +0,0 @@ -/* - * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/if_vlan.h> -#include <linux/ip.h> -#include <linux/tcp.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> -#include <linux/prefetch.h> -#include <net/arp.h> -#include "common.h" -#include "regs.h" -#include "sge_defs.h" -#include "t3_cpl.h" -#include "firmware_exports.h" -#include "cxgb3_offload.h" - -#define USE_GTS 0 - -#define SGE_RX_SM_BUF_SIZE 1536 - -#define SGE_RX_COPY_THRES 256 -#define SGE_RX_PULL_LEN 128 - -#define SGE_PG_RSVD SMP_CACHE_BYTES -/* - * Page chunk size for FL0 buffers if FL0 is to be populated with page chunks. - * It must be a divisor of PAGE_SIZE. If set to 0 FL0 will use sk_buffs - * directly. - */ -#define FL0_PG_CHUNK_SIZE 2048 -#define FL0_PG_ORDER 0 -#define FL0_PG_ALLOC_SIZE (PAGE_SIZE << FL0_PG_ORDER) -#define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192) -#define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1) -#define FL1_PG_ALLOC_SIZE (PAGE_SIZE << FL1_PG_ORDER) - -#define SGE_RX_DROP_THRES 16 -#define RX_RECLAIM_PERIOD (HZ/4) - -/* - * Max number of Rx buffers we replenish at a time. - */ -#define MAX_RX_REFILL 16U -/* - * Period of the Tx buffer reclaim timer. This timer does not need to run - * frequently as Tx buffers are usually reclaimed by new Tx packets. - */ -#define TX_RECLAIM_PERIOD (HZ / 4) -#define TX_RECLAIM_TIMER_CHUNK 64U -#define TX_RECLAIM_CHUNK 16U - -/* WR size in bytes */ -#define WR_LEN (WR_FLITS * 8) - -/* - * Types of Tx queues in each queue set. Order here matters, do not change. - */ -enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL }; - -/* Values for sge_txq.flags */ -enum { - TXQ_RUNNING = 1 << 0, /* fetch engine is running */ - TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */ -}; - -struct tx_desc { - __be64 flit[TX_DESC_FLITS]; -}; - -struct rx_desc { - __be32 addr_lo; - __be32 len_gen; - __be32 gen2; - __be32 addr_hi; -}; - -struct tx_sw_desc { /* SW state per Tx descriptor */ - struct sk_buff *skb; - u8 eop; /* set if last descriptor for packet */ - u8 addr_idx; /* buffer index of first SGL entry in descriptor */ - u8 fragidx; /* first page fragment associated with descriptor */ - s8 sflit; /* start flit of first SGL entry in descriptor */ -}; - -struct rx_sw_desc { /* SW state per Rx descriptor */ - union { - struct sk_buff *skb; - struct fl_pg_chunk pg_chunk; - }; - DEFINE_DMA_UNMAP_ADDR(dma_addr); -}; - -struct rsp_desc { /* response queue descriptor */ - struct rss_header rss_hdr; - __be32 flags; - __be32 len_cq; - u8 imm_data[47]; - u8 intr_gen; -}; - -/* - * Holds unmapping information for Tx packets that need deferred unmapping. - * This structure lives at skb->head and must be allocated by callers. - */ -struct deferred_unmap_info { - struct pci_dev *pdev; - dma_addr_t addr[MAX_SKB_FRAGS + 1]; -}; - -/* - * Maps a number of flits to the number of Tx descriptors that can hold them. - * The formula is - * - * desc = 1 + (flits - 2) / (WR_FLITS - 1). - * - * HW allows up to 4 descriptors to be combined into a WR. - */ -static u8 flit_desc_map[] = { - 0, -#if SGE_NUM_GENBITS == 1 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 -#elif SGE_NUM_GENBITS == 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -#else -# error "SGE_NUM_GENBITS must be 1 or 2" -#endif -}; - -static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx) -{ - return container_of(q, struct sge_qset, fl[qidx]); -} - -static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q) -{ - return container_of(q, struct sge_qset, rspq); -} - -static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx) -{ - return container_of(q, struct sge_qset, txq[qidx]); -} - -/** - * refill_rspq - replenish an SGE response queue - * @adapter: the adapter - * @q: the response queue to replenish - * @credits: how many new responses to make available - * - * Replenishes a response queue by making the supplied number of responses - * available to HW. - */ -static inline void refill_rspq(struct adapter *adapter, - const struct sge_rspq *q, unsigned int credits) -{ - rmb(); - t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN, - V_RSPQ(q->cntxt_id) | V_CREDITS(credits)); -} - -/** - * need_skb_unmap - does the platform need unmapping of sk_buffs? - * - * Returns true if the platform needs sk_buff unmapping. The compiler - * optimizes away unnecessary code if this returns true. - */ -static inline int need_skb_unmap(void) -{ -#ifdef CONFIG_NEED_DMA_MAP_STATE - return 1; -#else - return 0; -#endif -} - -/** - * unmap_skb - unmap a packet main body and its page fragments - * @skb: the packet - * @q: the Tx queue containing Tx descriptors for the packet - * @cidx: index of Tx descriptor - * @pdev: the PCI device - * - * Unmap the main body of an sk_buff and its page fragments, if any. - * Because of the fairly complicated structure of our SGLs and the desire - * to conserve space for metadata, the information necessary to unmap an - * sk_buff is spread across the sk_buff itself (buffer lengths), the HW Tx - * descriptors (the physical addresses of the various data buffers), and - * the SW descriptor state (assorted indices). The send functions - * initialize the indices for the first packet descriptor so we can unmap - * the buffers held in the first Tx descriptor here, and we have enough - * information at this point to set the state for the next Tx descriptor. - * - * Note that it is possible to clean up the first descriptor of a packet - * before the send routines have written the next descriptors, but this - * race does not cause any problem. We just end up writing the unmapping - * info for the descriptor first. - */ -static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, - unsigned int cidx, struct pci_dev *pdev) -{ - const struct sg_ent *sgp; - struct tx_sw_desc *d = &q->sdesc[cidx]; - int nfrags, frag_idx, curflit, j = d->addr_idx; - - sgp = (struct sg_ent *)&q->desc[cidx].flit[d->sflit]; - frag_idx = d->fragidx; - - if (frag_idx == 0 && skb_headlen(skb)) { - pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), - skb_headlen(skb), PCI_DMA_TODEVICE); - j = 1; - } - - curflit = d->sflit + 1 + j; - nfrags = skb_shinfo(skb)->nr_frags; - - while (frag_idx < nfrags && curflit < WR_FLITS) { - pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]), - skb_shinfo(skb)->frags[frag_idx].size, - PCI_DMA_TODEVICE); - j ^= 1; - if (j == 0) { - sgp++; - curflit++; - } - curflit++; - frag_idx++; - } - - if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ - d = cidx + 1 == q->size ? q->sdesc : d + 1; - d->fragidx = frag_idx; - d->addr_idx = j; - d->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ - } -} - -/** - * free_tx_desc - reclaims Tx descriptors and their buffers - * @adapter: the adapter - * @q: the Tx queue to reclaim descriptors from - * @n: the number of descriptors to reclaim - * - * Reclaims Tx descriptors from an SGE Tx queue and frees the associated - * Tx buffers. Called with the Tx queue lock held. - */ -static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, - unsigned int n) -{ - struct tx_sw_desc *d; - struct pci_dev *pdev = adapter->pdev; - unsigned int cidx = q->cidx; - - const int need_unmap = need_skb_unmap() && - q->cntxt_id >= FW_TUNNEL_SGEEC_START; - - d = &q->sdesc[cidx]; - while (n--) { - if (d->skb) { /* an SGL is present */ - if (need_unmap) - unmap_skb(d->skb, q, cidx, pdev); - if (d->eop) { - kfree_skb(d->skb); - d->skb = NULL; - } - } - ++d; - if (++cidx == q->size) { - cidx = 0; - d = q->sdesc; - } - } - q->cidx = cidx; -} - -/** - * reclaim_completed_tx - reclaims completed Tx descriptors - * @adapter: the adapter - * @q: the Tx queue to reclaim completed descriptors from - * @chunk: maximum number of descriptors to reclaim - * - * Reclaims Tx descriptors that the SGE has indicated it has processed, - * and frees the associated buffers if possible. Called with the Tx - * queue's lock held. - */ -static inline unsigned int reclaim_completed_tx(struct adapter *adapter, - struct sge_txq *q, - unsigned int chunk) -{ - unsigned int reclaim = q->processed - q->cleaned; - - reclaim = min(chunk, reclaim); - if (reclaim) { - free_tx_desc(adapter, q, reclaim); - q->cleaned += reclaim; - q->in_use -= reclaim; - } - return q->processed - q->cleaned; -} - -/** - * should_restart_tx - are there enough resources to restart a Tx queue? - * @q: the Tx queue - * - * Checks if there are enough descriptors to restart a suspended Tx queue. - */ -static inline int should_restart_tx(const struct sge_txq *q) -{ - unsigned int r = q->processed - q->cleaned; - - return q->in_use - r < (q->size >> 1); -} - -static void clear_rx_desc(struct pci_dev *pdev, const struct sge_fl *q, - struct rx_sw_desc *d) -{ - if (q->use_pages && d->pg_chunk.page) { - (*d->pg_chunk.p_cnt)--; - if (!*d->pg_chunk.p_cnt) - pci_unmap_page(pdev, - d->pg_chunk.mapping, - q->alloc_size, PCI_DMA_FROMDEVICE); - - put_page(d->pg_chunk.page); - d->pg_chunk.page = NULL; - } else { - pci_unmap_single(pdev, dma_unmap_addr(d, dma_addr), - q->buf_size, PCI_DMA_FROMDEVICE); - kfree_skb(d->skb); - d->skb = NULL; - } -} - -/** - * free_rx_bufs - free the Rx buffers on an SGE free list - * @pdev: the PCI device associated with the adapter - * @rxq: the SGE free list to clean up - * - * Release the buffers on an SGE free-buffer Rx queue. HW fetching from - * this queue should be stopped before calling this function. - */ -static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) -{ - unsigned int cidx = q->cidx; - - while (q->credits--) { - struct rx_sw_desc *d = &q->sdesc[cidx]; - - - clear_rx_desc(pdev, q, d); - if (++cidx == q->size) - cidx = 0; - } - - if (q->pg_chunk.page) { - __free_pages(q->pg_chunk.page, q->order); - q->pg_chunk.page = NULL; - } -} - -/** - * add_one_rx_buf - add a packet buffer to a free-buffer list - * @va: buffer start VA - * @len: the buffer length - * @d: the HW Rx descriptor to write - * @sd: the SW Rx descriptor to write - * @gen: the generation bit value - * @pdev: the PCI device associated with the adapter - * - * Add a buffer of the given length to the supplied HW and SW Rx - * descriptors. - */ -static inline int add_one_rx_buf(void *va, unsigned int len, - struct rx_desc *d, struct rx_sw_desc *sd, - unsigned int gen, struct pci_dev *pdev) -{ - dma_addr_t mapping; - - mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(pdev, mapping))) - return -ENOMEM; - - dma_unmap_addr_set(sd, dma_addr, mapping); - - d->addr_lo = cpu_to_be32(mapping); - d->addr_hi = cpu_to_be32((u64) mapping >> 32); - wmb(); - d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); - d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); - return 0; -} - -static inline int add_one_rx_chunk(dma_addr_t mapping, struct rx_desc *d, - unsigned int gen) -{ - d->addr_lo = cpu_to_be32(mapping); - d->addr_hi = cpu_to_be32((u64) mapping >> 32); - wmb(); - d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); - d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); - return 0; -} - -static int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q, - struct rx_sw_desc *sd, gfp_t gfp, - unsigned int order) -{ - if (!q->pg_chunk.page) { - dma_addr_t mapping; - - q->pg_chunk.page = alloc_pages(gfp, order); - if (unlikely(!q->pg_chunk.page)) - return -ENOMEM; - q->pg_chunk.va = page_address(q->pg_chunk.page); - q->pg_chunk.p_cnt = q->pg_chunk.va + (PAGE_SIZE << order) - - SGE_PG_RSVD; - q->pg_chunk.offset = 0; - mapping = pci_map_page(adapter->pdev, q->pg_chunk.page, - 0, q->alloc_size, PCI_DMA_FROMDEVICE); - q->pg_chunk.mapping = mapping; - } - sd->pg_chunk = q->pg_chunk; - - prefetch(sd->pg_chunk.p_cnt); - - q->pg_chunk.offset += q->buf_size; - if (q->pg_chunk.offset == (PAGE_SIZE << order)) - q->pg_chunk.page = NULL; - else { - q->pg_chunk.va += q->buf_size; - get_page(q->pg_chunk.page); - } - - if (sd->pg_chunk.offset == 0) - *sd->pg_chunk.p_cnt = 1; - else - *sd->pg_chunk.p_cnt += 1; - - return 0; -} - -static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) -{ - if (q->pend_cred >= q->credits / 4) { - q->pend_cred = 0; - wmb(); - t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); - } -} - -/** - * refill_fl - refill an SGE free-buffer list - * @adapter: the adapter - * @q: the free-list to refill - * @n: the number of new buffers to allocate - * @gfp: the gfp flags for allocating new buffers - * - * (Re)populate an SGE free-buffer list with up to @n new packet buffers, - * allocated with the supplied gfp flags. The caller must assure that - * @n does not exceed the queue's capacity. - */ -static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) -{ - struct rx_sw_desc *sd = &q->sdesc[q->pidx]; - struct rx_desc *d = &q->desc[q->pidx]; - unsigned int count = 0; - - while (n--) { - dma_addr_t mapping; - int err; - - if (q->use_pages) { - if (unlikely(alloc_pg_chunk(adap, q, sd, gfp, - q->order))) { -nomem: q->alloc_failed++; - break; - } - mapping = sd->pg_chunk.mapping + sd->pg_chunk.offset; - dma_unmap_addr_set(sd, dma_addr, mapping); - - add_one_rx_chunk(mapping, d, q->gen); - pci_dma_sync_single_for_device(adap->pdev, mapping, - q->buf_size - SGE_PG_RSVD, - PCI_DMA_FROMDEVICE); - } else { - void *buf_start; - - struct sk_buff *skb = alloc_skb(q->buf_size, gfp); - if (!skb) - goto nomem; - - sd->skb = skb; - buf_start = skb->data; - err = add_one_rx_buf(buf_start, q->buf_size, d, sd, - q->gen, adap->pdev); - if (unlikely(err)) { - clear_rx_desc(adap->pdev, q, sd); - break; - } - } - - d++; - sd++; - if (++q->pidx == q->size) { - q->pidx = 0; - q->gen ^= 1; - sd = q->sdesc; - d = q->desc; - } - count++; - } - - q->credits += count; - q->pend_cred += count; - ring_fl_db(adap, q); - - return count; -} - -static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) -{ - refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits), - GFP_ATOMIC | __GFP_COMP); -} - -/** - * recycle_rx_buf - recycle a receive buffer - * @adapter: the adapter - * @q: the SGE free list - * @idx: index of buffer to recycle - * - * Recycles the specified buffer on the given free list by adding it at - * the next available slot on the list. - */ -static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, - unsigned int idx) -{ - struct rx_desc *from = &q->desc[idx]; - struct rx_desc *to = &q->desc[q->pidx]; - - q->sdesc[q->pidx] = q->sdesc[idx]; - to->addr_lo = from->addr_lo; /* already big endian */ - to->addr_hi = from->addr_hi; /* likewise */ - wmb(); - to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen)); - to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen)); - - if (++q->pidx == q->size) { - q->pidx = 0; - q->gen ^= 1; - } - - q->credits++; - q->pend_cred++; - ring_fl_db(adap, q); -} - -/** - * alloc_ring - allocate resources for an SGE descriptor ring - * @pdev: the PCI device - * @nelem: the number of descriptors - * @elem_size: the size of each descriptor - * @sw_size: the size of the SW state associated with each ring element - * @phys: the physical address of the allocated ring - * @metadata: address of the array holding the SW state for the ring - * - * Allocates resources for an SGE descriptor ring, such as Tx queues, - * free buffer lists, or response queues. Each SGE ring requires - * space for its HW descriptors plus, optionally, space for the SW state - * associated with each HW entry (the metadata). The function returns - * three values: the virtual address for the HW ring (the return value - * of the function), the physical address of the HW ring, and the address - * of the SW ring. - */ -static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, - size_t sw_size, dma_addr_t * phys, void *metadata) -{ - size_t len = nelem * elem_size; - void *s = NULL; - void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL); - - if (!p) - return NULL; - if (sw_size && metadata) { - s = kcalloc(nelem, sw_size, GFP_KERNEL); - - if (!s) { - dma_free_coherent(&pdev->dev, len, p, *phys); - return NULL; - } - *(void **)metadata = s; - } - memset(p, 0, len); - return p; -} - -/** - * t3_reset_qset - reset a sge qset - * @q: the queue set - * - * Reset the qset structure. - * the NAPI structure is preserved in the event of - * the qset's reincarnation, for example during EEH recovery. - */ -static void t3_reset_qset(struct sge_qset *q) -{ - if (q->adap && - !(q->adap->flags & NAPI_INIT)) { - memset(q, 0, sizeof(*q)); - return; - } - - q->adap = NULL; - memset(&q->rspq, 0, sizeof(q->rspq)); - memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET); - memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET); - q->txq_stopped = 0; - q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */ - q->rx_reclaim_timer.function = NULL; - q->nomem = 0; - napi_free_frags(&q->napi); -} - - -/** - * free_qset - free the resources of an SGE queue set - * @adapter: the adapter owning the queue set - * @q: the queue set - * - * Release the HW and SW resources associated with an SGE queue set, such - * as HW contexts, packet buffers, and descriptor rings. Traffic to the - * queue set must be quiesced prior to calling this. - */ -static void t3_free_qset(struct adapter *adapter, struct sge_qset *q) -{ - int i; - struct pci_dev *pdev = adapter->pdev; - - for (i = 0; i < SGE_RXQ_PER_SET; ++i) - if (q->fl[i].desc) { - spin_lock_irq(&adapter->sge.reg_lock); - t3_sge_disable_fl(adapter, q->fl[i].cntxt_id); - spin_unlock_irq(&adapter->sge.reg_lock); - free_rx_bufs(pdev, &q->fl[i]); - kfree(q->fl[i].sdesc); - dma_free_coherent(&pdev->dev, - q->fl[i].size * - sizeof(struct rx_desc), q->fl[i].desc, - q->fl[i].phys_addr); - } - - for (i = 0; i < SGE_TXQ_PER_SET; ++i) - if (q->txq[i].desc) { - spin_lock_irq(&adapter->sge.reg_lock); - t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0); - spin_unlock_irq(&adapter->sge.reg_lock); - if (q->txq[i].sdesc) { - free_tx_desc(adapter, &q->txq[i], - q->txq[i].in_use); - kfree(q->txq[i].sdesc); - } - dma_free_coherent(&pdev->dev, - q->txq[i].size * - sizeof(struct tx_desc), - q->txq[i].desc, q->txq[i].phys_addr); - __skb_queue_purge(&q->txq[i].sendq); - } - - if (q->rspq.desc) { - spin_lock_irq(&adapter->sge.reg_lock); - t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id); - spin_unlock_irq(&adapter->sge.reg_lock); - dma_free_coherent(&pdev->dev, - q->rspq.size * sizeof(struct rsp_desc), - q->rspq.desc, q->rspq.phys_addr); - } - - t3_reset_qset(q); -} - -/** - * init_qset_cntxt - initialize an SGE queue set context info - * @qs: the queue set - * @id: the queue set id - * - * Initializes the TIDs and context ids for the queues of a queue set. - */ -static void init_qset_cntxt(struct sge_qset *qs, unsigned int id) -{ - qs->rspq.cntxt_id = id; - qs->fl[0].cntxt_id = 2 * id; - qs->fl[1].cntxt_id = 2 * id + 1; - qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id; - qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id; - qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id; - qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id; - qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id; -} - -/** - * sgl_len - calculates the size of an SGL of the given capacity - * @n: the number of SGL entries - * - * Calculates the number of flits needed for a scatter/gather list that - * can hold the given number of entries. - */ -static inline unsigned int sgl_len(unsigned int n) -{ - /* alternatively: 3 * (n / 2) + 2 * (n & 1) */ - return (3 * n) / 2 + (n & 1); -} - -/** - * flits_to_desc - returns the num of Tx descriptors for the given flits - * @n: the number of flits - * - * Calculates the number of Tx descriptors needed for the supplied number - * of flits. - */ -static inline unsigned int flits_to_desc(unsigned int n) -{ - BUG_ON(n >= ARRAY_SIZE(flit_desc_map)); - return flit_desc_map[n]; -} - -/** - * get_packet - return the next ingress packet buffer from a free list - * @adap: the adapter that received the packet - * @fl: the SGE free list holding the packet - * @len: the packet length including any SGE padding - * @drop_thres: # of remaining buffers before we start dropping packets - * - * Get the next packet from a free list and complete setup of the - * sk_buff. If the packet is small we make a copy and recycle the - * original buffer, otherwise we use the original buffer itself. If a - * positive drop threshold is supplied packets are dropped and their - * buffers recycled if (a) the number of remaining buffers is under the - * threshold and the packet is too big to copy, or (b) the packet should - * be copied but there is no memory for the copy. - */ -static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, - unsigned int len, unsigned int drop_thres) -{ - struct sk_buff *skb = NULL; - struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; - - prefetch(sd->skb->data); - fl->credits--; - - if (len <= SGE_RX_COPY_THRES) { - skb = alloc_skb(len, GFP_ATOMIC); - if (likely(skb != NULL)) { - __skb_put(skb, len); - pci_dma_sync_single_for_cpu(adap->pdev, - dma_unmap_addr(sd, dma_addr), len, - PCI_DMA_FROMDEVICE); - memcpy(skb->data, sd->skb->data, len); - pci_dma_sync_single_for_device(adap->pdev, - dma_unmap_addr(sd, dma_addr), len, - PCI_DMA_FROMDEVICE); - } else if (!drop_thres) - goto use_orig_buf; -recycle: - recycle_rx_buf(adap, fl, fl->cidx); - return skb; - } - - if (unlikely(fl->credits < drop_thres) && - refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits - 1), - GFP_ATOMIC | __GFP_COMP) == 0) - goto recycle; - -use_orig_buf: - pci_unmap_single(adap->pdev, dma_unmap_addr(sd, dma_addr), - fl->buf_size, PCI_DMA_FROMDEVICE); - skb = sd->skb; - skb_put(skb, len); - __refill_fl(adap, fl); - return skb; -} - -/** - * get_packet_pg - return the next ingress packet buffer from a free list - * @adap: the adapter that received the packet - * @fl: the SGE free list holding the packet - * @len: the packet length including any SGE padding - * @drop_thres: # of remaining buffers before we start dropping packets - * - * Get the next packet from a free list populated with page chunks. - * If the packet is small we make a copy and recycle the original buffer, - * otherwise we attach the original buffer as a page fragment to a fresh - * sk_buff. If a positive drop threshold is supplied packets are dropped - * and their buffers recycled if (a) the number of remaining buffers is - * under the threshold and the packet is too big to copy, or (b) there's - * no system memory. - * - * Note: this function is similar to @get_packet but deals with Rx buffers - * that are page chunks rather than sk_buffs. - */ -static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, - struct sge_rspq *q, unsigned int len, - unsigned int drop_thres) -{ - struct sk_buff *newskb, *skb; - struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; - - dma_addr_t dma_addr = dma_unmap_addr(sd, dma_addr); - - newskb = skb = q->pg_skb; - if (!skb && (len <= SGE_RX_COPY_THRES)) { - newskb = alloc_skb(len, GFP_ATOMIC); - if (likely(newskb != NULL)) { - __skb_put(newskb, len); - pci_dma_sync_single_for_cpu(adap->pdev, dma_addr, len, - PCI_DMA_FROMDEVICE); - memcpy(newskb->data, sd->pg_chunk.va, len); - pci_dma_sync_single_for_device(adap->pdev, dma_addr, - len, - PCI_DMA_FROMDEVICE); - } else if (!drop_thres) - return NULL; -recycle: - fl->credits--; - recycle_rx_buf(adap, fl, fl->cidx); - q->rx_recycle_buf++; - return newskb; - } - - if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres))) - goto recycle; - - prefetch(sd->pg_chunk.p_cnt); - - if (!skb) - newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); - - if (unlikely(!newskb)) { - if (!drop_thres) - return NULL; - goto recycle; - } - - pci_dma_sync_single_for_cpu(adap->pdev, dma_addr, len, - PCI_DMA_FROMDEVICE); - (*sd->pg_chunk.p_cnt)--; - if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page) - pci_unmap_page(adap->pdev, - sd->pg_chunk.mapping, - fl->alloc_size, - PCI_DMA_FROMDEVICE); - if (!skb) { - __skb_put(newskb, SGE_RX_PULL_LEN); - memcpy(newskb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN); - skb_fill_page_desc(newskb, 0, sd->pg_chunk.page, - sd->pg_chunk.offset + SGE_RX_PULL_LEN, - len - SGE_RX_PULL_LEN); - newskb->len = len; - newskb->data_len = len - SGE_RX_PULL_LEN; - newskb->truesize += newskb->data_len; - } else { - skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags, - sd->pg_chunk.page, - sd->pg_chunk.offset, len); - newskb->len += len; - newskb->data_len += len; - newskb->truesize += len; - } - - fl->credits--; - /* - * We do not refill FLs here, we let the caller do it to overlap a - * prefetch. - */ - return newskb; -} - -/** - * get_imm_packet - return the next ingress packet buffer from a response - * @resp: the response descriptor containing the packet data - * - * Return a packet containing the immediate data of the given response. - */ -static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp) -{ - struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC); - - if (skb) { - __skb_put(skb, IMMED_PKT_SIZE); - skb_copy_to_linear_data(skb, resp->imm_data, IMMED_PKT_SIZE); - } - return skb; -} - -/** - * calc_tx_descs - calculate the number of Tx descriptors for a packet - * @skb: the packet - * - * Returns the number of Tx descriptors needed for the given Ethernet - * packet. Ethernet packets require addition of WR and CPL headers. - */ -static inline unsigned int calc_tx_descs(const struct sk_buff *skb) -{ - unsigned int flits; - - if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt)) - return 1; - - flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2; - if (skb_shinfo(skb)->gso_size) - flits++; - return flits_to_desc(flits); -} - -/** - * make_sgl - populate a scatter/gather list for a packet - * @skb: the packet - * @sgp: the SGL to populate - * @start: start address of skb main body data to include in the SGL - * @len: length of skb main body data to include in the SGL - * @pdev: the PCI device - * - * Generates a scatter/gather list for the buffers that make up a packet - * and returns the SGL size in 8-byte words. The caller must size the SGL - * appropriately. - */ -static inline unsigned int make_sgl(const struct sk_buff *skb, - struct sg_ent *sgp, unsigned char *start, - unsigned int len, struct pci_dev *pdev) -{ - dma_addr_t mapping; - unsigned int i, j = 0, nfrags; - - if (len) { - mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE); - sgp->len[0] = cpu_to_be32(len); - sgp->addr[0] = cpu_to_be64(mapping); - j = 1; - } - - nfrags = skb_shinfo(skb)->nr_frags; - for (i = 0; i < nfrags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - mapping = pci_map_page(pdev, frag->page, frag->page_offset, - frag->size, PCI_DMA_TODEVICE); - sgp->len[j] = cpu_to_be32(frag->size); - sgp->addr[j] = cpu_to_be64(mapping); - j ^= 1; - if (j == 0) - ++sgp; - } - if (j) - sgp->len[j] = 0; - return ((nfrags + (len != 0)) * 3) / 2 + j; -} - -/** - * check_ring_tx_db - check and potentially ring a Tx queue's doorbell - * @adap: the adapter - * @q: the Tx queue - * - * Ring the doorbel if a Tx queue is asleep. There is a natural race, - * where the HW is going to sleep just after we checked, however, - * then the interrupt handler will detect the outstanding TX packet - * and ring the doorbell for us. - * - * When GTS is disabled we unconditionally ring the doorbell. - */ -static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q) -{ -#if USE_GTS - clear_bit(TXQ_LAST_PKT_DB, &q->flags); - if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) { - set_bit(TXQ_LAST_PKT_DB, &q->flags); - t3_write_reg(adap, A_SG_KDOORBELL, - F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); - } -#else - wmb(); /* write descriptors before telling HW */ - t3_write_reg(adap, A_SG_KDOORBELL, - F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); -#endif -} - -static inline void wr_gen2(struct tx_desc *d, unsigned int gen) -{ -#if SGE_NUM_GENBITS == 2 - d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen); -#endif -} - -/** - * write_wr_hdr_sgl - write a WR header and, optionally, SGL - * @ndesc: number of Tx descriptors spanned by the SGL - * @skb: the packet corresponding to the WR - * @d: first Tx descriptor to be written - * @pidx: index of above descriptors - * @q: the SGE Tx queue - * @sgl: the SGL - * @flits: number of flits to the start of the SGL in the first descriptor - * @sgl_flits: the SGL size in flits - * @gen: the Tx descriptor generation - * @wr_hi: top 32 bits of WR header based on WR type (big endian) - * @wr_lo: low 32 bits of WR header based on WR type (big endian) - * - * Write a work request header and an associated SGL. If the SGL is - * small enough to fit into one Tx descriptor it has already been written - * and we just need to write the WR header. Otherwise we distribute the - * SGL across the number of descriptors it spans. - */ -static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, - struct tx_desc *d, unsigned int pidx, - const struct sge_txq *q, - const struct sg_ent *sgl, - unsigned int flits, unsigned int sgl_flits, - unsigned int gen, __be32 wr_hi, - __be32 wr_lo) -{ - struct work_request_hdr *wrp = (struct work_request_hdr *)d; - struct tx_sw_desc *sd = &q->sdesc[pidx]; - - sd->skb = skb; - if (need_skb_unmap()) { - sd->fragidx = 0; - sd->addr_idx = 0; - sd->sflit = flits; - } - - if (likely(ndesc == 1)) { - sd->eop = 1; - wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | - V_WR_SGLSFLT(flits)) | wr_hi; - wmb(); - wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) | - V_WR_GEN(gen)) | wr_lo; - wr_gen2(d, gen); - } else { - unsigned int ogen = gen; - const u64 *fp = (const u64 *)sgl; - struct work_request_hdr *wp = wrp; - - wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) | - V_WR_SGLSFLT(flits)) | wr_hi; - - while (sgl_flits) { - unsigned int avail = WR_FLITS - flits; - - if (avail > sgl_flits) - avail = sgl_flits; - memcpy(&d->flit[flits], fp, avail * sizeof(*fp)); - sgl_flits -= avail; - ndesc--; - if (!sgl_flits) - break; - - fp += avail; - d++; - sd->eop = 0; - sd++; - if (++pidx == q->size) { - pidx = 0; - gen ^= 1; - d = q->desc; - sd = q->sdesc; - } - - sd-&g |