+bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb,
+ unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
+ u32 ring_idx)
+{
+ int err;
+ u16 prod = ring_idx & 0xffff;
+
+ err = bnx2_alloc_rx_skb(bp, bnapi, prod);
+ if (unlikely(err)) {
+ bnx2_reuse_rx_skb(bp, bnapi, skb, (u16) (ring_idx >> 16), prod);
+ if (hdr_len) {
+ unsigned int raw_len = len + 4;
+ int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
+
+ bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, pages);
+ }
+ return err;
+ }
+
+ skb_reserve(skb, bp->rx_offset);
+ pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
+ PCI_DMA_FROMDEVICE);
+
+ if (hdr_len == 0) {
+ skb_put(skb, len);
+ return 0;
+ } else {
+ unsigned int i, frag_len, frag_size, pages;
+ struct sw_pg *rx_pg;
+ u16 pg_cons = bnapi->rx_pg_cons;
+ u16 pg_prod = bnapi->rx_pg_prod;
+
+ frag_size = len + 4 - hdr_len;
+ pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
+ skb_put(skb, hdr_len);
+
+ for (i = 0; i < pages; i++) {
+ frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
+ if (unlikely(frag_len <= 4)) {
+ unsigned int tail = 4 - frag_len;
+
+ bnapi->rx_pg_cons = pg_cons;
+ bnapi->rx_pg_prod = pg_prod;
+ bnx2_reuse_rx_skb_pages(bp, bnapi, NULL,
+ pages - i);
+ skb->len -= tail;
+ if (i == 0) {
+ skb->tail -= tail;
+ } else {
+ skb_frag_t *frag =
+ &skb_shinfo(skb)->frags[i - 1];
+ frag->size -= tail;
+ skb->data_len -= tail;
+ skb->truesize -= tail;
+ }
+ return 0;
+ }
+ rx_pg = &bp->rx_pg_ring[pg_cons];
+
+ pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping),
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+
+ if (i == pages - 1)
+ frag_len -= 4;
+
+ skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
+ rx_pg->page = NULL;
+
+ err = bnx2_alloc_rx_page(bp, RX_PG_RING_IDX(pg_prod));
+ if (unlikely(err)) {
+ bnapi->rx_pg_cons = pg_cons;
+ bnapi->rx_pg_prod = pg_prod;
+ bnx2_reuse_rx_skb_pages(bp, bnapi, skb,
+ pages - i);
+ return err;
+ }
+
+ frag_size -= frag_len;
+ skb->data_len += frag_len;
+ skb->truesize += frag_len;
+ skb->len += frag_len;
+
+ pg_prod = NEXT_RX_BD(pg_prod);
+ pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
+ }
+ bnapi->rx_pg_prod = pg_prod;
+ bnapi->rx_pg_cons = pg_cons;
+ }
+ return 0;
+}
+
+static inline u16
+bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
+{
+ u16 cons = bnapi->status_blk->status_rx_quick_consumer_index0;
+
+ if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
+ cons++;
+ return cons;
+}
+
+static int
+bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)