Loading drivers/net/cxgb3/adapter.h +4 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,7 @@ struct sge_fl { /* SGE per free-buffer list state */ 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 */ unsigned int order; /* order of page allocations */ 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 */ Loading @@ -116,12 +117,15 @@ struct sge_rspq { /* state for an SGE response queue */ unsigned int polling; /* is the queue serviced through NAPI? */ unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */ unsigned int next_holdoff; /* holdoff time for next interrupt */ unsigned int rx_recycle_buf; /* whether recycling occurred within current sop-eop */ struct rsp_desc *desc; /* address of HW response ring */ dma_addr_t phys_addr; /* physical address of the ring */ unsigned int cntxt_id; /* SGE context id for the response q */ spinlock_t lock; /* guards response processing */ struct sk_buff *rx_head; /* offload packet receive queue head */ struct sk_buff *rx_tail; /* offload packet receive queue tail */ struct sk_buff *pg_skb; /* used to build frag list in napi handler */ unsigned long offload_pkts; unsigned long offload_bundles; Loading drivers/net/cxgb3/sge.c +80 −35 Original line number Diff line number Diff line Loading @@ -55,6 +55,9 @@ * directly. */ #define FL0_PG_CHUNK_SIZE 2048 #define FL0_PG_ORDER 0 #define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192) #define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1) #define SGE_RX_DROP_THRES 16 Loading Loading @@ -359,7 +362,7 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) } if (q->pg_chunk.page) { __free_page(q->pg_chunk.page); __free_pages(q->pg_chunk.page, q->order); q->pg_chunk.page = NULL; } } Loading Loading @@ -396,10 +399,11 @@ static inline int add_one_rx_buf(void *va, unsigned int len, return 0; } static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp, unsigned int order) { if (!q->pg_chunk.page) { q->pg_chunk.page = alloc_page(gfp); 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); Loading @@ -408,7 +412,7 @@ static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) sd->pg_chunk = q->pg_chunk; q->pg_chunk.offset += q->buf_size; if (q->pg_chunk.offset == PAGE_SIZE) if (q->pg_chunk.offset == (PAGE_SIZE << order)) q->pg_chunk.page = NULL; else { q->pg_chunk.va += q->buf_size; Loading Loading @@ -439,7 +443,7 @@ static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) int err; if (q->use_pages) { if (unlikely(alloc_pg_chunk(q, sd, gfp))) { if (unlikely(alloc_pg_chunk(q, sd, gfp, q->order))) { nomem: q->alloc_failed++; break; } Loading Loading @@ -484,7 +488,8 @@ nomem: q->alloc_failed++; static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) { refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC); refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC | __GFP_COMP); } /** Loading Loading @@ -759,19 +764,22 @@ static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, * 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 sge_rspq *q, unsigned int len, unsigned int drop_thres) { struct sk_buff *skb = NULL; struct sk_buff *newskb, *skb; 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); 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, pci_unmap_addr(sd, dma_addr), len, PCI_DMA_FROMDEVICE); memcpy(skb->data, sd->pg_chunk.va, len); memcpy(newskb->data, sd->pg_chunk.va, len); pci_dma_sync_single_for_device(adap->pdev, pci_unmap_addr(sd, dma_addr), len, PCI_DMA_FROMDEVICE); Loading @@ -780,14 +788,16 @@ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, recycle: fl->credits--; recycle_rx_buf(adap, fl, fl->cidx); return skb; q->rx_recycle_buf++; return newskb; } if (unlikely(fl->credits <= drop_thres)) if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres))) goto recycle; skb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); if (unlikely(!skb)) { if (!skb) newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); if (unlikely(!newskb)) { if (!drop_thres) return NULL; goto recycle; Loading @@ -795,21 +805,29 @@ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, 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, 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); skb->len = len; skb->data_len = len - SGE_RX_PULL_LEN; skb->truesize += skb->data_len; newskb->len = len; newskb->data_len = len - SGE_RX_PULL_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 += newskb->data_len; fl->credits--; /* * We do not refill FLs here, we let the caller do it to overlap a * prefetch. */ return skb; return newskb; } /** Loading Loading @@ -1966,6 +1984,12 @@ static inline int is_new_response(const struct rsp_desc *r, return (r->intr_gen & F_RSPD_GEN2) == q->gen; } static inline void clear_rspq_bufstate(struct sge_rspq * const q) { q->pg_skb = NULL; q->rx_recycle_buf = 0; } #define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) #define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ Loading Loading @@ -2003,10 +2027,11 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->next_holdoff = q->holdoff_tmr; while (likely(budget_left && is_new_response(r, q))) { int eth, ethpad = 2; int packet_complete, eth, ethpad = 2; struct sk_buff *skb = NULL; u32 len, flags = ntohl(r->flags); __be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val; __be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val; eth = r->rss_hdr.opcode == CPL_RX_PKT; Loading Loading @@ -2044,8 +2069,11 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, #endif __refill_fl(adap, fl); skb = get_packet_pg(adap, fl, G_RSPD_LEN(len), eth ? SGE_RX_DROP_THRES : 0); skb = get_packet_pg(adap, fl, q, G_RSPD_LEN(len), eth ? SGE_RX_DROP_THRES : 0); q->pg_skb = skb; } else skb = get_packet(adap, fl, G_RSPD_LEN(len), eth ? SGE_RX_DROP_THRES : 0); Loading Loading @@ -2079,7 +2107,11 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->credits = 0; } if (likely(skb != NULL)) { packet_complete = flags & (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID | F_RSPD_ASYNC_NOTIF); if (skb != NULL && packet_complete) { if (eth) rx_eth(adap, q, skb, ethpad); else { Loading @@ -2091,6 +2123,9 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, offload_skbs, ngathered); } if (flags & F_RSPD_EOP) clear_rspq_bufstate(q); } --budget_left; } Loading Loading @@ -2706,10 +2741,18 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, #else q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data); #endif q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; #if FL1_PG_CHUNK_SIZE > 0 q->fl[1].buf_size = FL1_PG_CHUNK_SIZE; #else 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); #endif q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0; q->fl[0].order = FL0_PG_ORDER; q->fl[1].order = FL1_PG_ORDER; spin_lock_irq(&adapter->sge.reg_lock); Loading Loading @@ -2760,7 +2803,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->adap = adapter; q->netdev = dev; t3_update_qset_coalesce(q, p); avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL | __GFP_COMP); if (!avail) { CH_ALERT(adapter, "free list queue 0 initialization failed\n"); goto err; Loading @@ -2769,7 +2813,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, CH_WARN(adapter, "free list queue 0 enabled with %d credits\n", avail); avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL | __GFP_COMP); if (avail < q->fl[1].size) CH_WARN(adapter, "free list queue 1 enabled with %d credits\n", avail); Loading Loading
drivers/net/cxgb3/adapter.h +4 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,7 @@ struct sge_fl { /* SGE per free-buffer list state */ 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 */ unsigned int order; /* order of page allocations */ 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 */ Loading @@ -116,12 +117,15 @@ struct sge_rspq { /* state for an SGE response queue */ unsigned int polling; /* is the queue serviced through NAPI? */ unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */ unsigned int next_holdoff; /* holdoff time for next interrupt */ unsigned int rx_recycle_buf; /* whether recycling occurred within current sop-eop */ struct rsp_desc *desc; /* address of HW response ring */ dma_addr_t phys_addr; /* physical address of the ring */ unsigned int cntxt_id; /* SGE context id for the response q */ spinlock_t lock; /* guards response processing */ struct sk_buff *rx_head; /* offload packet receive queue head */ struct sk_buff *rx_tail; /* offload packet receive queue tail */ struct sk_buff *pg_skb; /* used to build frag list in napi handler */ unsigned long offload_pkts; unsigned long offload_bundles; Loading
drivers/net/cxgb3/sge.c +80 −35 Original line number Diff line number Diff line Loading @@ -55,6 +55,9 @@ * directly. */ #define FL0_PG_CHUNK_SIZE 2048 #define FL0_PG_ORDER 0 #define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192) #define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1) #define SGE_RX_DROP_THRES 16 Loading Loading @@ -359,7 +362,7 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) } if (q->pg_chunk.page) { __free_page(q->pg_chunk.page); __free_pages(q->pg_chunk.page, q->order); q->pg_chunk.page = NULL; } } Loading Loading @@ -396,10 +399,11 @@ static inline int add_one_rx_buf(void *va, unsigned int len, return 0; } static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp, unsigned int order) { if (!q->pg_chunk.page) { q->pg_chunk.page = alloc_page(gfp); 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); Loading @@ -408,7 +412,7 @@ static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp) sd->pg_chunk = q->pg_chunk; q->pg_chunk.offset += q->buf_size; if (q->pg_chunk.offset == PAGE_SIZE) if (q->pg_chunk.offset == (PAGE_SIZE << order)) q->pg_chunk.page = NULL; else { q->pg_chunk.va += q->buf_size; Loading Loading @@ -439,7 +443,7 @@ static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) int err; if (q->use_pages) { if (unlikely(alloc_pg_chunk(q, sd, gfp))) { if (unlikely(alloc_pg_chunk(q, sd, gfp, q->order))) { nomem: q->alloc_failed++; break; } Loading Loading @@ -484,7 +488,8 @@ nomem: q->alloc_failed++; static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) { refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC); refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC | __GFP_COMP); } /** Loading Loading @@ -759,19 +764,22 @@ static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, * 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 sge_rspq *q, unsigned int len, unsigned int drop_thres) { struct sk_buff *skb = NULL; struct sk_buff *newskb, *skb; 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); 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, pci_unmap_addr(sd, dma_addr), len, PCI_DMA_FROMDEVICE); memcpy(skb->data, sd->pg_chunk.va, len); memcpy(newskb->data, sd->pg_chunk.va, len); pci_dma_sync_single_for_device(adap->pdev, pci_unmap_addr(sd, dma_addr), len, PCI_DMA_FROMDEVICE); Loading @@ -780,14 +788,16 @@ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, recycle: fl->credits--; recycle_rx_buf(adap, fl, fl->cidx); return skb; q->rx_recycle_buf++; return newskb; } if (unlikely(fl->credits <= drop_thres)) if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres))) goto recycle; skb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); if (unlikely(!skb)) { if (!skb) newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); if (unlikely(!newskb)) { if (!drop_thres) return NULL; goto recycle; Loading @@ -795,21 +805,29 @@ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, 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, 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); skb->len = len; skb->data_len = len - SGE_RX_PULL_LEN; skb->truesize += skb->data_len; newskb->len = len; newskb->data_len = len - SGE_RX_PULL_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 += newskb->data_len; fl->credits--; /* * We do not refill FLs here, we let the caller do it to overlap a * prefetch. */ return skb; return newskb; } /** Loading Loading @@ -1966,6 +1984,12 @@ static inline int is_new_response(const struct rsp_desc *r, return (r->intr_gen & F_RSPD_GEN2) == q->gen; } static inline void clear_rspq_bufstate(struct sge_rspq * const q) { q->pg_skb = NULL; q->rx_recycle_buf = 0; } #define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) #define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ Loading Loading @@ -2003,10 +2027,11 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->next_holdoff = q->holdoff_tmr; while (likely(budget_left && is_new_response(r, q))) { int eth, ethpad = 2; int packet_complete, eth, ethpad = 2; struct sk_buff *skb = NULL; u32 len, flags = ntohl(r->flags); __be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val; __be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val; eth = r->rss_hdr.opcode == CPL_RX_PKT; Loading Loading @@ -2044,8 +2069,11 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, #endif __refill_fl(adap, fl); skb = get_packet_pg(adap, fl, G_RSPD_LEN(len), eth ? SGE_RX_DROP_THRES : 0); skb = get_packet_pg(adap, fl, q, G_RSPD_LEN(len), eth ? SGE_RX_DROP_THRES : 0); q->pg_skb = skb; } else skb = get_packet(adap, fl, G_RSPD_LEN(len), eth ? SGE_RX_DROP_THRES : 0); Loading Loading @@ -2079,7 +2107,11 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->credits = 0; } if (likely(skb != NULL)) { packet_complete = flags & (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID | F_RSPD_ASYNC_NOTIF); if (skb != NULL && packet_complete) { if (eth) rx_eth(adap, q, skb, ethpad); else { Loading @@ -2091,6 +2123,9 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, offload_skbs, ngathered); } if (flags & F_RSPD_EOP) clear_rspq_bufstate(q); } --budget_left; } Loading Loading @@ -2706,10 +2741,18 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, #else q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data); #endif q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; #if FL1_PG_CHUNK_SIZE > 0 q->fl[1].buf_size = FL1_PG_CHUNK_SIZE; #else 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); #endif q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0; q->fl[0].order = FL0_PG_ORDER; q->fl[1].order = FL1_PG_ORDER; spin_lock_irq(&adapter->sge.reg_lock); Loading Loading @@ -2760,7 +2803,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->adap = adapter; q->netdev = dev; t3_update_qset_coalesce(q, p); avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL | __GFP_COMP); if (!avail) { CH_ALERT(adapter, "free list queue 0 initialization failed\n"); goto err; Loading @@ -2769,7 +2813,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, CH_WARN(adapter, "free list queue 0 enabled with %d credits\n", avail); avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL | __GFP_COMP); if (avail < q->fl[1].size) CH_WARN(adapter, "free list queue 1 enabled with %d credits\n", avail); Loading