diff options
Diffstat (limited to 'drivers/net/cxgb3')
-rw-r--r-- | drivers/net/cxgb3/adapter.h | 38 | ||||
-rw-r--r-- | drivers/net/cxgb3/common.h | 28 | ||||
-rw-r--r-- | drivers/net/cxgb3/cxgb3_main.c | 48 | ||||
-rw-r--r-- | drivers/net/cxgb3/regs.h | 11 | ||||
-rw-r--r-- | drivers/net/cxgb3/sge.c | 423 | ||||
-rw-r--r-- | drivers/net/cxgb3/t3_hw.c | 128 | ||||
-rw-r--r-- | drivers/net/cxgb3/version.h | 2 | ||||
-rw-r--r-- | drivers/net/cxgb3/xgmac.c | 8 |
8 files changed, 432 insertions, 254 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..6fd1e524183 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -43,6 +43,7 @@ #include <linux/proc_fs.h> #include <linux/rtnetlink.h> #include <linux/firmware.h> +#include <linux/log2.h> #include <asm/uaccess.h> #include "common.h" @@ -1818,8 +1819,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) return -EBUSY; if (copy_from_user(&m, useraddr, sizeof(m))) return -EFAULT; - if (!m.rx_pg_sz || (m.rx_pg_sz & (m.rx_pg_sz - 1)) || - !m.tx_pg_sz || (m.tx_pg_sz & (m.tx_pg_sz - 1))) + if (!is_power_of_2(m.rx_pg_sz) || + !is_power_of_2(m.tx_pg_sz)) return -EINVAL; /* not power of 2 */ if (!(m.rx_pg_sz & 0x14000)) return -EINVAL; /* not 16KB or 64KB */ @@ -2088,6 +2089,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 +2474,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..eb508bf8022 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 3 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index b261be147e7..c302b1a30cb 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -335,11 +335,11 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) hwm = min(hwm, MAC_RXFIFO_SIZE - 8192); lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4); - v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); if (adap->params.rev == T3_REV_B2 && (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { disable_exact_filters(mac); - t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + mac->offset, + v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset); + t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset, F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST); /* drain rx FIFO */ @@ -347,11 +347,12 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + mac->offset, 1 << 31, 1, 20, 5)) { - t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); + t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); enable_exact_filters(mac); return -EIO; } t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); + t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); enable_exact_filters(mac); } else t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); @@ -362,6 +363,7 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) */ hwm = rx_fifo_hwm(mtu); lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4); + v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); v |= V_RXFIFOPAUSELWM(lwm / 8); if (G_RXFIFOPAUSEHWM(v)) |