aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/cxgb3
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/cxgb3')
-rw-r--r--drivers/net/cxgb3/adapter.h38
-rw-r--r--drivers/net/cxgb3/common.h28
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c43
-rw-r--r--drivers/net/cxgb3/regs.h11
-rw-r--r--drivers/net/cxgb3/sge.c423
-rw-r--r--drivers/net/cxgb3/t3_hw.c128
-rw-r--r--drivers/net/cxgb3/version.h2
7 files changed, 424 insertions, 249 deletions
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 80c3d8f268a..ab72563b81e 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -71,27 +71,29 @@ enum { /* adapter flags */
QUEUES_BOUND = (1 << 3),
};
+struct fl_pg_chunk {
+ struct page *page;
+ void *va;
+ unsigned int offset;
+};
+
struct rx_desc;
struct rx_sw_desc;
-struct sge_fl_page {
- struct skb_frag_struct frag;
- unsigned char *va;
-};
-
-struct sge_fl { /* SGE per free-buffer list state */
- unsigned int buf_size; /* size of each Rx buffer */
- unsigned int credits; /* # of available Rx buffers */
- unsigned int size; /* capacity of free list */
- unsigned int cidx; /* consumer index */
- unsigned int pidx; /* producer index */
- unsigned int gen; /* free list generation */
- unsigned int cntxt_id; /* SGE context id for the free list */
- struct sge_fl_page page;
- struct rx_desc *desc; /* address of HW Rx descriptor ring */
- struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */
- dma_addr_t phys_addr; /* physical address of HW ring start */
- unsigned long empty; /* # of times queue ran out of buffers */
+struct sge_fl { /* SGE per free-buffer list state */
+ unsigned int buf_size; /* size of each Rx buffer */
+ unsigned int credits; /* # of available Rx buffers */
+ unsigned int size; /* capacity of free list */
+ unsigned int cidx; /* consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned int gen; /* free list generation */
+ struct fl_pg_chunk pg_chunk;/* page chunk cache */
+ unsigned int use_pages; /* whether FL uses pages or sk_buffs */
+ struct rx_desc *desc; /* address of HW Rx descriptor ring */
+ struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */
+ dma_addr_t phys_addr; /* physical address of HW ring start */
+ unsigned int cntxt_id; /* SGE context id for the free list */
+ unsigned long empty; /* # of times queue ran out of buffers */
unsigned long alloc_failed; /* # of times buffer allocation failed */
};
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 8d137963369..16378004507 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -101,6 +101,7 @@ enum {
TCB_SIZE = 128, /* TCB size */
NMTUS = 16, /* size of MTU table */
NCCTRL_WIN = 32, /* # of congestion control windows */
+ PROTO_SRAM_LINES = 128, /* size of TP sram */
};
#define MAX_RX_COALESCING_LEN 16224U
@@ -124,6 +125,30 @@ enum { /* adapter interrupt-maintained statistics */
};
enum {
+ TP_VERSION_MAJOR = 1,
+ TP_VERSION_MINOR = 0,
+ TP_VERSION_MICRO = 44
+};
+
+#define S_TP_VERSION_MAJOR 16
+#define M_TP_VERSION_MAJOR 0xFF
+#define V_TP_VERSION_MAJOR(x) ((x) << S_TP_VERSION_MAJOR)
+#define G_TP_VERSION_MAJOR(x) \
+ (((x) >> S_TP_VERSION_MAJOR) & M_TP_VERSION_MAJOR)
+
+#define S_TP_VERSION_MINOR 8
+#define M_TP_VERSION_MINOR 0xFF
+#define V_TP_VERSION_MINOR(x) ((x) << S_TP_VERSION_MINOR)
+#define G_TP_VERSION_MINOR(x) \
+ (((x) >> S_TP_VERSION_MINOR) & M_TP_VERSION_MINOR)
+
+#define S_TP_VERSION_MICRO 0
+#define M_TP_VERSION_MICRO 0xFF
+#define V_TP_VERSION_MICRO(x) ((x) << S_TP_VERSION_MICRO)
+#define G_TP_VERSION_MICRO(x) \
+ (((x) >> S_TP_VERSION_MICRO) & M_TP_VERSION_MICRO)
+
+enum {
SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */
SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */
SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */
@@ -654,6 +679,9 @@ const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
int t3_seeprom_wp(struct adapter *adapter, int enable);
+int t3_check_tpsram_version(struct adapter *adapter);
+int t3_check_tpsram(struct adapter *adapter, u8 *tp_ram, unsigned int size);
+int t3_set_proto_sram(struct adapter *adap, u8 *data);
int t3_read_flash(struct adapter *adapter, unsigned int addr,
unsigned int nwords, u32 *data, int byte_oriented);
int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index d8a1f5452c5..15defe4c4f0 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -2088,6 +2088,42 @@ static void cxgb_netpoll(struct net_device *dev)
}
#endif
+#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
+int update_tpsram(struct adapter *adap)
+{
+ const struct firmware *tpsram;
+ char buf[64];
+ struct device *dev = &adap->pdev->dev;
+ int ret;
+ char rev;
+
+ rev = adap->params.rev == T3_REV_B2 ? 'b' : 'a';
+
+ snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
+ TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+
+ ret = request_firmware(&tpsram, buf, dev);
+ if (ret < 0) {
+ dev_err(dev, "could not load TP SRAM: unable to load %s\n",
+ buf);
+ return ret;
+ }
+
+ ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
+ if (ret)
+ goto release_tpsram;
+
+ ret = t3_set_proto_sram(adap, tpsram->data);
+ if (ret)
+ dev_err(dev, "loading protocol SRAM failed\n");
+
+release_tpsram:
+ release_firmware(tpsram);
+
+ return ret;
+}
+
+
/*
* Periodic accumulation of MAC statistics.
*/
@@ -2437,6 +2473,13 @@ static int __devinit init_one(struct pci_dev *pdev,
goto out_free_dev;
}
+ err = t3_check_tpsram_version(adapter);
+ if (err == -EINVAL)
+ err = update_tpsram(adapter);
+
+ if (err)
+ goto out_free_dev;
+
/*
* The card is now ready to go. If any errors occur during device
* registration we do not fail the whole card but rather proceed only
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index 020859c855d..aa80313c922 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -1160,6 +1160,8 @@
#define A_TP_MOD_CHANNEL_WEIGHT 0x434
+#define A_TP_MOD_RATE_LIMIT 0x438
+
#define A_TP_PIO_ADDR 0x440
#define A_TP_PIO_DATA 0x444
@@ -1214,6 +1216,15 @@
#define G_TXDROPCNTCH0RCVD(x) (((x) >> S_TXDROPCNTCH0RCVD) & \
M_TXDROPCNTCH0RCVD)
+#define A_TP_PROXY_FLOW_CNTL 0x4b0
+
+#define A_TP_EMBED_OP_FIELD0 0x4e8
+#define A_TP_EMBED_OP_FIELD1 0x4ec
+#define A_TP_EMBED_OP_FIELD2 0x4f0
+#define A_TP_EMBED_OP_FIELD3 0x4f4
+#define A_TP_EMBED_OP_FIELD4 0x4f8
+#define A_TP_EMBED_OP_FIELD5 0x4fc
+
#define A_ULPRX_CTL 0x500
#define S_ROUND_ROBIN 4
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index a60ec4d4707..a2cfd68ac75 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -46,23 +46,16 @@
#define SGE_RX_SM_BUF_SIZE 1536
-/*
- * If USE_RX_PAGE is defined, the small freelist populated with (partial)
- * pages instead of skbs. Pages are carved up into RX_PAGE_SIZE chunks (must
- * be a multiple of the host page size).
- */
-#define USE_RX_PAGE
-#define RX_PAGE_SIZE 2048
-
-/*
- * skb freelist packets are copied into a new skb (and the freelist one is
- * reused) if their len is <=
- */
#define SGE_RX_COPY_THRES 256
+#define SGE_RX_PULL_LEN 128
/*
- * Minimum number of freelist entries before we start dropping TUNNEL frames.
+ * 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 SGE_RX_DROP_THRES 16
/*
@@ -100,12 +93,12 @@ struct tx_sw_desc { /* SW state per Tx descriptor */
struct sk_buff *skb;
};
-struct rx_sw_desc { /* SW state per Rx descriptor */
+struct rx_sw_desc { /* SW state per Rx descriptor */
union {
struct sk_buff *skb;
- struct sge_fl_page page;
- } t;
- DECLARE_PCI_UNMAP_ADDR(dma_addr);
+ struct fl_pg_chunk pg_chunk;
+ };
+ DECLARE_PCI_UNMAP_ADDR(dma_addr);
};
struct rsp_desc { /* response queue descriptor */
@@ -351,27 +344,26 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
q->buf_size, PCI_DMA_FROMDEVICE);
-
- if (q->buf_size != RX_PAGE_SIZE) {
- kfree_skb(d->t.skb);
- d->t.skb = NULL;
+ if (q->use_pages) {
+ put_page(d->pg_chunk.page);
+ d->pg_chunk.page = NULL;
} else {
- if (d->t.page.frag.page)
- put_page(d->t.page.frag.page);
- d->t.page.frag.page = NULL;
+ kfree_skb(d->skb);
+ d->skb = NULL;
}
if (++cidx == q->size)
cidx = 0;
}
- if (q->page.frag.page)
- put_page(q->page.frag.page);
- q->page.frag.page = NULL;
+ if (q->pg_chunk.page) {
+ __free_page(q->pg_chunk.page);
+ q->pg_chunk.page = NULL;
+ }
}
/**
* add_one_rx_buf - add a packet buffer to a free-buffer list
- * @va: va of the buffer to add
+ * @va: buffer start VA
* @len: the buffer length
* @d: the HW Rx descriptor to write
* @sd: the SW Rx descriptor to write
@@ -381,7 +373,7 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
* Add a buffer of the given length to the supplied HW and SW Rx
* descriptors.
*/
-static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
+static inline void 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)
{
@@ -397,6 +389,27 @@ static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
}
+static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp)
+{
+ if (!q->pg_chunk.page) {
+ q->pg_chunk.page = alloc_page(gfp);
+ if (unlikely(!q->pg_chunk.page))
+ return -ENOMEM;
+ q->pg_chunk.va = page_address(q->pg_chunk.page);
+ q->pg_chunk.offset = 0;
+ }
+ sd->pg_chunk = q->pg_chunk;
+
+ q->pg_chunk.offset += q->buf_size;
+ if (q->pg_chunk.offset == PAGE_SIZE)
+ q->pg_chunk.page = NULL;
+ else {
+ q->pg_chunk.va += q->buf_size;
+ get_page(q->pg_chunk.page);
+ }
+ return 0;
+}
+
/**
* refill_fl - refill an SGE free-buffer list
* @adapter: the adapter
@@ -410,49 +423,29 @@ static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
*/
static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
{
+ void *buf_start;
struct rx_sw_desc *sd = &q->sdesc[q->pidx];
struct rx_desc *d = &q->desc[q->pidx];
- struct sge_fl_page *p = &q->page;
while (n--) {
- unsigned char *va;
-
- if (unlikely(q->buf_size != RX_PAGE_SIZE)) {
- struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
-
- if (!skb) {
- q->alloc_failed++;
+ if (q->use_pages) {
+ if (unlikely(alloc_pg_chunk(q, sd, gfp))) {
+nomem: q->alloc_failed++;
break;
}
- va = skb->data;
- sd->t.skb = skb;
+ buf_start = sd->pg_chunk.va;
} else {
- if (!p->frag.page) {
- p->frag.page = alloc_pages(gfp, 0);
- if (unlikely(!p->frag.page)) {
- q->alloc_failed++;
- break;
- } else {
- p->frag.size = RX_PAGE_SIZE;
- p->frag.page_offset = 0;
- p->va = page_address(p->frag.page);
- }
- }
+ struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
- memcpy(&sd->t, p, sizeof(*p));
- va = p->va;
+ if (!skb)
+ goto nomem;
- p->frag.page_offset += RX_PAGE_SIZE;
- BUG_ON(p->frag.page_offset > PAGE_SIZE);
- p->va += RX_PAGE_SIZE;
- if (p->frag.page_offset == PAGE_SIZE)
- p->frag.page = NULL;
- else
- get_page(p->frag.page);
+ sd->skb = skb;
+ buf_start = skb->data;
}
- add_one_rx_buf(va, q->buf_size, d, sd, q->gen, adap->pdev);
-
+ add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen,
+ adap->pdev);
d++;
sd++;
if (++q->pidx == q->size) {
@@ -487,7 +480,7 @@ static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
struct rx_desc *from = &q->desc[idx];
struct rx_desc *to = &q->desc[q->pidx];
- memcpy(&q->sdesc[q->pidx], &q->sdesc[idx], sizeof(struct rx_sw_desc));
+ q->sdesc[q->pidx] = q->sdesc[idx];
to->addr_lo = from->addr_lo; /* already big endian */
to->addr_hi = from->addr_hi; /* likewise */
wmb();
@@ -650,6 +643,132 @@ static inline unsigned int flits_to_desc(unsigned int 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,
+ pci_unmap_addr(sd, dma_addr), len,
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, sd->skb->data, len);
+ pci_dma_sync_single_for_device(adap->pdev,
+ pci_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))
+ goto recycle;
+
+use_orig_buf:
+ pci_unmap_single(adap->pdev, pci_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,
+ unsigned int len, unsigned int drop_thres)
+{
+ struct sk_buff *skb = NULL;
+ struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+ 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,
+ pci_unmap_addr(sd, dma_addr), len,
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, sd->pg_chunk.va, len);
+ pci_dma_sync_single_for_device(adap->pdev,
+ pci_unmap_addr(sd, dma_addr), len,
+ PCI_DMA_FROMDEVICE);
+ } else if (!drop_thres)
+ return NULL;
+recycle:
+ fl->credits--;
+ recycle_rx_buf(adap, fl, fl->cidx);
+ return skb;
+ }
+
+ if (unlikely(fl->credits <= drop_thres))
+ goto recycle;
+
+ skb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC);
+ if (unlikely(!skb)) {
+ if (!drop_thres)
+ return NULL;
+ goto recycle;
+ }
+
+ pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+ fl->buf_size, PCI_DMA_FROMDEVICE);
+ __skb_put(skb, SGE_RX_PULL_LEN);
+ memcpy(skb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN);
+ skb_fill_page_desc(skb, 0, sd->pg_chunk.page,
+ sd->pg_chunk.offset + SGE_RX_PULL_LEN,
+ len - SGE_RX_PULL_LEN);
+ skb->len = len;
+ skb->data_len = len - SGE_RX_PULL_LEN;
+ skb->truesize += skb->data_len;
+
+ fl->credits--;
+ /*
+ * We do not refill FLs here, we let the caller do it to overlap a
+ * prefetch.
+ */
+ return skb;
+}
+
+/**
* get_imm_packet - return the next ingress packet buffer from a response
* @resp: the response descriptor containing the packet data
*
@@ -1715,85 +1834,6 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
netif_rx(skb);
}
-#define SKB_DATA_SIZE 128
-
-static void skb_data_init(struct sk_buff *skb, struct sge_fl_page *p,
- unsigned int len)
-{
- skb->len = len;
- if (len <= SKB_DATA_SIZE) {
- skb_copy_to_linear_data(skb, p->va, len);
- skb->tail += len;
- put_page(p->frag.page);
- } else {
- skb_copy_to_linear_data(skb, p->va, SKB_DATA_SIZE);
- skb_shinfo(skb)->frags[0].page = p->frag.page;
- skb_shinfo(skb)->frags[0].page_offset =
- p->frag.page_offset + SKB_DATA_SIZE;
- skb_shinfo(skb)->frags[0].size = len - SKB_DATA_SIZE;
- skb_shinfo(skb)->nr_frags = 1;
- skb->data_len = len - SKB_DATA_SIZE;
- skb->tail += SKB_DATA_SIZE;
- skb->truesize += skb->data_len;
- }
-}
-
-/**
-* 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->t.skb->data);
-
- if (len <= SGE_RX_COPY_THRES) {
- skb = alloc_skb(len, GFP_ATOMIC);
- if (likely(skb != NULL)) {
- struct rx_desc *d = &fl->desc[fl->cidx];
- dma_addr_t mapping =
- (dma_addr_t)((u64) be32_to_cpu(d->addr_hi) << 32 |
- be32_to_cpu(d->addr_lo));
-
- __skb_put(skb, len);
- pci_dma_sync_single_for_cpu(adap->pdev, mapping, len,
- PCI_DMA_FROMDEVICE);
- skb_copy_from_linear_data(sd->t.skb, skb->data, len);
- pci_dma_sync_single_for_device(adap->pdev, mapping, 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))
- goto recycle;
-
-use_orig_buf:
- pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
- fl->buf_size, PCI_DMA_FROMDEVICE);
- skb = sd->t.skb;
- skb_put(skb, len);
- __refill_fl(adap, fl);
- return skb;
-}
-
/**
* handle_rsp_cntrl_info - handles control information in a response
* @qs: the queue set corresponding to the response
@@ -1935,7 +1975,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
} else if (flags & F_RSPD_IMM_DATA_VALID) {
skb = get_imm_packet(r);
if (unlikely(!skb)) {
- no_mem:
+no_mem:
q->next_holdoff = NOMEM_INTR_DELAY;
q->nomem++;
/* consume one credit since we tried */
@@ -1945,53 +1985,29 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
q->imm_data++;
ethpad = 0;
} else if ((len = ntohl(r->len_cq)) != 0) {
- struct sge_fl *fl =
- (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+ struct sge_fl *fl;
- if (fl->buf_size == RX_PAGE_SIZE) {
- struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
- struct sge_fl_page *p = &sd->t.page;
-
- prefetch(p->va);
- prefetch(p->va + L1_CACHE_BYTES);
+ fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+ if (fl->use_pages) {
+ void *addr = fl->sdesc[fl->cidx].pg_chunk.va;
+ prefetch(addr);
+#if L1_CACHE_BYTES < 128
+ prefetch(addr + L1_CACHE_BYTES);
+#endif
__refill_fl(adap, fl);
- pci_unmap_single(adap->pdev,
- pci_unmap_addr(sd, dma_addr),
- fl->buf_size,
- PCI_DMA_FROMDEVICE);
-
- if (eth) {
- if (unlikely(fl->credits <
- SGE_RX_DROP_THRES))
- goto eth_recycle;
-
- skb = alloc_skb(SKB_DATA_SIZE,
- GFP_ATOMIC);
- if (unlikely(!skb)) {
-eth_recycle:
- q->rx_drops++;
- recycle_rx_buf(adap, fl,
- fl->cidx);
- goto eth_done;
- }
- } else {
- skb = alloc_skb(SKB_DATA_SIZE,
- GFP_ATOMIC);
- if (unlikely(!skb))
- goto no_mem;
- }
-
- skb_data_init(skb, p, G_RSPD_LEN(len));
-eth_done:
- fl->credits--;
- q->eth_pkts++;
- } else {
- fl->credits--;
+ skb = get_packet_pg(adap, fl, G_RSPD_LEN(len),
+ eth ? SGE_RX_DROP_THRES : 0);
+ } else
skb = get_packet(adap, fl, G_RSPD_LEN(len),
eth ? SGE_RX_DROP_THRES : 0);
- }
+ if (unlikely(!skb)) {
+ if (!eth)
+ goto no_mem;
+ q->rx_drops++;
+ } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT))
+ __skb_pull(skb, 2);
if (++fl->cidx == fl->size)
fl->cidx = 0;
@@ -2016,20 +2032,15 @@ eth_done:
q->credits = 0;
}
- if (skb) {
- /* Preserve the RSS info in csum & priority */
- skb->csum = rss_hi;
- skb->priority = rss_lo;
-
+ if (likely(skb != NULL)) {
if (eth)
rx_eth(adap, q, skb, ethpad);
else {
- if (unlikely(r->rss_hdr.opcode ==
- CPL_TRACE_PKT))
- __skb_pull(skb, ethpad);
-
- ngathered = rx_offload(&adap->tdev, q,
- skb, offload_skbs,
+ /* Preserve the RSS info in csum & priority */
+ skb->csum = rss_hi;
+ skb->priority = rss_lo;
+ ngathered = rx_offload(&adap->tdev, q, skb,
+ offload_skbs,
ngathered);
}
}
@@ -2635,25 +2646,15 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
q->txq[TXQ_ETH].stop_thres = nports *
flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
- if (!is_offload(adapter)) {
-#ifdef USE_RX_PAGE
- q->fl[0].buf_size = RX_PAGE_SIZE;
+#if FL0_PG_CHUNK_SIZE > 0
+ q->fl[0].buf_size = FL0_PG_CHUNK_SIZE;
#else
- q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 +
- sizeof(struct cpl_rx_pkt);
+ q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data);
#endif
- q->fl[1].buf_size = MAX_FRAME_SIZE + 2 +
- sizeof(struct cpl_rx_pkt);
- } else {
-#ifdef USE_RX_PAGE
- q->fl[0].buf_size = RX_PAGE_SIZE;
-#else
- q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE +
- sizeof(struct cpl_rx_data);
-#endif
- q->fl[1].buf_size = (16 * 1024) -
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
- }
+ q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0;
+ q->fl[1].buf_size = is_offload(adapter) ?
+ (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) :
+ MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt);
spin_lock(&adapter->sge.reg_lock);
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index fb485d0a43d..dd3149d94ba 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -847,6 +847,64 @@ static int t3_write_flash(struct adapter *adapter, unsigned int addr,
return 0;
}
+/**
+ * t3_check_tpsram_version - read the tp sram version
+ * @adapter: the adapter
+ *
+ * Reads the protocol sram version from serial eeprom.
+ */
+int t3_check_tpsram_version(struct adapter *adapter)
+{
+ int ret;
+ u32 vers;
+ unsigned int major, minor;
+
+ /* Get version loaded in SRAM */
+ t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
+ ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0,
+ 1, 1, 5, 1);
+ if (ret)
+ return ret;
+
+ vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
+
+ major = G_TP_VERSION_MAJOR(vers);
+ minor = G_TP_VERSION_MINOR(vers);
+
+ if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
+ return 0;
+
+ return -EINVAL;
+}
+
+/**
+ * t3_check_tpsram - check if provided protocol SRAM
+ * is compatible with this driver
+ * @adapter: the adapter
+ * @tp_sram: the firmware image to write
+ * @size: image size
+ *
+ * Checks if an adapter's tp sram is compatible with the driver.
+ * Returns 0 if the versions are compatible, a negative error otherwise.
+ */
+int t3_check_tpsram(struct adapter *adapter, u8 *tp_sram, unsigned int size)
+{
+ u32 csum;
+ unsigned int i;
+ const u32 *p = (const u32 *)tp_sram;
+
+ /* Verify checksum */
+ for (csum = 0, i = 0; i < size / sizeof(csum); i++)
+ csum += ntohl(p[i]);
+ if (csum != 0xffffffff) {
+ CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n",
+ csum);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
enum fw_version_type {
FW_VERSION_N3,
FW_VERSION_T3
@@ -921,7 +979,7 @@ static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
/*
* t3_load_fw - download firmware
* @adapter: the adapter
- * @fw_data: the firrware image to write
+ * @fw_data: the firmware image to write
* @size: image size
*
* Write the supplied firmware image to the card's serial flash.
@@ -2362,7 +2420,7 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
F_MTUENABLE | V_WINDOWSCALEMODE(1) |
- V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
+ V_TIMESTAMPSMODE(0) | V_SACKMODE(1) | V_SACKRX(1));
t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
@@ -2371,16 +2429,18 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
F_IPV6ENABLE | F_NICMODE);
t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
- t3_set_reg_field(adap, A_TP_PARA_REG6,
- adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND,
- 0);
+ t3_set_reg_field(adap, A_TP_PARA_REG6, 0,
+ adap->params.rev > 0 ? F_ENABLEESND :
+ F_T3A_ENABLEESND);
t3_set_reg_field(adap, A_TP_PC_CONFIG,
- F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL,
- F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE |
- F_RXCONGESTIONMODE);
+ F_ENABLEEPCMDAFULL,
+ F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
+ F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0);
-
+ t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
+ t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
+
if (adap->params.rev > 0) {
tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
@@ -2390,9 +2450,10 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
} else
t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
- t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212);
- t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212);
- t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
+ t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
+ t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000);
}
/* Desired TP timer resolution in usec */
@@ -2468,6 +2529,7 @@ int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
val |= F_RXCOALESCEENABLE;
if (psh)
val |= F_RXCOALESCEPSHEN;
+ size = min(MAX_RX_COALESCING_LEN, size);
t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
V_MAXRXDATA(MAX_RX_COALESCING_LEN));
}
@@ -2496,11 +2558,11 @@ static void __devinit init_mtus(unsigned short mtus[])
* it can accomodate max size TCP/IP headers when SACK and timestamps
* are enabled and still have at least 8 bytes of payload.
*/
- mtus[0] = 88;
- mtus[1] = 256;
- mtus[2] = 512;
- mtus[3] = 576;
- mtus[4] = 808;
+ mtus[1] = 88;
+ mtus[1] = 88;
+ mtus[2] = 256;
+ mtus[3] = 512;
+ mtus[4] = 576;
mtus[5] = 1024;
mtus[6] = 1280;
mtus[7] = 1492;
@@ -2682,6 +2744,34 @@ static void ulp_config(struct adapter *adap, const struct tp_params *p)
t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
}
+/**
+ * t3_set_proto_sram - set the contents of the protocol sram
+ * @adapter: the adapter
+ * @data: the protocol image
+ *
+ * Write the contents of the protocol SRAM.
+ */
+int t3_set_proto_sram(struct adapter *adap, u8 *data)
+{
+ int i;
+ u32 *buf = (u32 *)data;
+
+ for (i = 0; i < PROTO_SRAM_LINES; i++) {
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++));
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++));
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++));
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++));
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++));
+
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
+ if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
+ return -EIO;
+ }
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, 0);
+
+ return 0;
+}
+
void t3_config_trace_filter(struct adapter *adapter,
const struct trace_params *tp, int filter_index,
int invert, int enable)
@@ -2802,7 +2892,7 @@ static void init_hw_for_avail_ports(struct adapter *adap, int nports)
t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN |
F_PORT0ACTIVE | F_ENFORCEPKT);
- t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000);
+ t3_write_reg(adap, A_PM1_TX_CFG, 0xffffffff);
} else {
t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
@@ -3097,7 +3187,7 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
else
t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
- t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000);
+ t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
init_hw_for_avail_ports(adapter, adapter->params.nports);
t3_sge_init(adapter, &adapter->params.sge);
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index b112317f033..8eddd23a3a5 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -39,6 +39,6 @@
/* Firmware version */
#define FW_VERSION_MAJOR 4
-#define FW_VERSION_MINOR 0
+#define FW_VERSION_MINOR 1
#define FW_VERSION_MICRO 0
#endif /* __CHELSIO_VERSION_H */