--- /dev/null
+From: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Subject: net: packet split receive api
+Patch-mainline: No
+References: FATE#303834, bnc#484306
+
+Add some packet-split receive hooks.
+
+For one this allows to do NUMA node affine page allocs. Later on these hooks
+will be extended to do emergency reserve allocations for fragments.
+
+Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Acked-by: Neil Brown <neilb@suse.de>
+Acked-by: Suresh Jayaraman <sjayaraman@suse.de>
+
+bnx2.c part fixed by Jiri Bohac <jbohac@suse.cz> (bnc#484306)
+
+
+
+---
+ drivers/net/bnx2.c | 9 +++------
+ drivers/net/e1000/e1000_main.c | 8 ++------
+ drivers/net/e1000e/netdev.c | 7 ++-----
+ drivers/net/igb/igb_main.c | 9 ++-------
+ drivers/net/ixgbe/ixgbe_main.c | 14 ++++++--------
+ drivers/net/sky2.c | 16 ++++++----------
+ include/linux/skbuff.h | 23 +++++++++++++++++++++++
+ net/core/skbuff.c | 20 ++++++++++++++++++++
+ 8 files changed, 64 insertions(+), 42 deletions(-)
+
+--- a/drivers/net/bnx2.c
++++ b/drivers/net/bnx2.c
+@@ -2476,7 +2476,7 @@ bnx2_alloc_rx_page(struct bnx2 *bp, stru
+ struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
+ struct rx_bd *rxbd =
+ &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
+- struct page *page = alloc_page(GFP_ATOMIC);
++ struct page *page = netdev_alloc_page(bp->dev);
+
+ if (!page)
+ return -ENOMEM;
+@@ -2501,7 +2501,7 @@ bnx2_free_rx_page(struct bnx2 *bp, struc
+ pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+
+- __free_page(page);
++ netdev_free_page(bp->dev, page);
+ rx_pg->page = NULL;
+ }
+
+@@ -2819,7 +2819,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2
+ if (i == pages - 1)
+ frag_len -= 4;
+
+- skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
++ skb_add_rx_frag(skb, i, rx_pg->page, 0, frag_len);
+ rx_pg->page = NULL;
+
+ err = bnx2_alloc_rx_page(bp, rxr,
+@@ -2833,9 +2833,6 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2
+ }
+
+ 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));
+--- a/drivers/net/e1000/e1000_main.c
++++ b/drivers/net/e1000/e1000_main.c
+@@ -4349,12 +4349,8 @@ static bool e1000_clean_rx_irq_ps(struct
+ pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j],
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ ps_page_dma->ps_page_dma[j] = 0;
+- skb_fill_page_desc(skb, j, ps_page->ps_page[j], 0,
+- length);
++ skb_add_rx_frag(skb, j, ps_page->ps_page[j], 0, length);
+ ps_page->ps_page[j] = NULL;
+- skb->len += length;
+- skb->data_len += length;
+- skb->truesize += length;
+ }
+
+ /* strip the ethernet crc, problem is we're using pages now so
+@@ -4553,7 +4549,7 @@ static void e1000_alloc_rx_buffers_ps(st
+ if (j < adapter->rx_ps_pages) {
+ if (likely(!ps_page->ps_page[j])) {
+ ps_page->ps_page[j] =
+- alloc_page(GFP_ATOMIC);
++ netdev_alloc_page(netdev);
+ if (unlikely(!ps_page->ps_page[j])) {
+ adapter->alloc_rx_buff_failed++;
+ goto no_buffers;
+--- a/drivers/net/e1000e/netdev.c
++++ b/drivers/net/e1000e/netdev.c
+@@ -258,7 +258,7 @@ static void e1000_alloc_rx_buffers_ps(st
+ continue;
+ }
+ if (!ps_page->page) {
+- ps_page->page = alloc_page(GFP_ATOMIC);
++ ps_page->page = netdev_alloc_page(netdev);
+ if (!ps_page->page) {
+ adapter->alloc_rx_buff_failed++;
+ goto no_buffers;
+@@ -826,11 +826,8 @@ static bool e1000_clean_rx_irq_ps(struct
+ pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ ps_page->dma = 0;
+- skb_fill_page_desc(skb, j, ps_page->page, 0, length);
++ skb_add_rx_frag(skb, j, ps_page->page, 0, length);
+ ps_page->page = NULL;
+- skb->len += length;
+- skb->data_len += length;
+- skb->truesize += length;
+ }
+
+ /* strip the ethernet crc, problem is we're using pages now so
+--- a/drivers/net/igb/igb_main.c
++++ b/drivers/net/igb/igb_main.c
+@@ -3885,7 +3885,7 @@ static bool igb_clean_rx_irq_adv(struct
+ PAGE_SIZE / 2, PCI_DMA_FROMDEVICE);
+ buffer_info->page_dma = 0;
+
+- skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags++,
++ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags++,
+ buffer_info->page,
+ buffer_info->page_offset,
+ length);
+@@ -3895,11 +3895,6 @@ static bool igb_clean_rx_irq_adv(struct
+ buffer_info->page = NULL;
+ else
+ get_page(buffer_info->page);
+-
+- skb->len += length;
+- skb->data_len += length;
+-
+- skb->truesize += length;
+ }
+ send_up:
+ i++;
+@@ -3993,7 +3988,7 @@ static void igb_alloc_rx_buffers_adv(str
+
+ if (adapter->rx_ps_hdr_size && !buffer_info->page_dma) {
+ if (!buffer_info->page) {
+- buffer_info->page = alloc_page(GFP_ATOMIC);
++ buffer_info->page = netdev_alloc_page(netdev);
+ if (!buffer_info->page) {
+ adapter->alloc_rx_buff_failed++;
+ goto no_buffers;
+--- a/drivers/net/ixgbe/ixgbe_main.c
++++ b/drivers/net/ixgbe/ixgbe_main.c
+@@ -480,6 +480,7 @@ static void ixgbe_alloc_rx_buffers(struc
+ int cleaned_count)
+ {
+ struct pci_dev *pdev = adapter->pdev;
++ struct net_device *netdev = adapter->netdev;
+ union ixgbe_adv_rx_desc *rx_desc;
+ struct ixgbe_rx_buffer *bi;
+ unsigned int i;
+@@ -494,7 +495,7 @@ static void ixgbe_alloc_rx_buffers(struc
+ if (!bi->page_dma &&
+ (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) {
+ if (!bi->page) {
+- bi->page = alloc_page(GFP_ATOMIC);
++ bi->page = netdev_alloc_page(netdev);
+ if (!bi->page) {
+ adapter->alloc_rx_page_failed++;
+ goto no_buffers;
+@@ -628,10 +629,10 @@ static bool ixgbe_clean_rx_irq(struct ix
+ pci_unmap_page(pdev, rx_buffer_info->page_dma,
+ PAGE_SIZE / 2, PCI_DMA_FROMDEVICE);
+ rx_buffer_info->page_dma = 0;
+- skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+- rx_buffer_info->page,
+- rx_buffer_info->page_offset,
+- upper_len);
++ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
++ rx_buffer_info->page,
++ rx_buffer_info->page_offset,
++ upper_len);
+
+ if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) ||
+ (page_count(rx_buffer_info->page) != 1))
+@@ -639,9 +640,6 @@ static bool ixgbe_clean_rx_irq(struct ix
+ else
+ get_page(rx_buffer_info->page);
+
+- skb->len += upper_len;
+- skb->data_len += upper_len;
+- skb->truesize += upper_len;
+ }
+
+ i++;
+--- a/drivers/net/sky2.c
++++ b/drivers/net/sky2.c
+@@ -1272,7 +1272,7 @@ static struct sk_buff *sky2_rx_alloc(str
+ }
+
+ for (i = 0; i < sky2->rx_nfrags; i++) {
+- struct page *page = alloc_page(GFP_ATOMIC);
++ struct page *page = netdev_alloc_page(sky2->netdev);
+
+ if (!page)
+ goto free_partial;
+@@ -2141,8 +2141,8 @@ static struct sk_buff *receive_copy(stru
+ }
+
+ /* Adjust length of skb with fragments to match received data */
+-static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
+- unsigned int length)
++static void skb_put_frags(struct sky2_port *sky2, struct sk_buff *skb,
++ unsigned int hdr_space, unsigned int length)
+ {
+ int i, num_frags;
+ unsigned int size;
+@@ -2159,15 +2159,11 @@ static void skb_put_frags(struct sk_buff
+
+ if (length == 0) {
+ /* don't need this page */
+- __free_page(frag->page);
++ netdev_free_page(sky2->netdev, frag->page);
+ --skb_shinfo(skb)->nr_frags;
+ } else {
+ size = min(length, (unsigned) PAGE_SIZE);
+-
+- frag->size = size;
+- skb->data_len += size;
+- skb->truesize += size;
+- skb->len += size;
++ skb_add_rx_frag(skb, i, frag->page, 0, size);
+ length -= size;
+ }
+ }
+@@ -2194,7 +2190,7 @@ static struct sk_buff *receive_new(struc
+ sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space);
+
+ if (skb_shinfo(skb)->nr_frags)
+- skb_put_frags(skb, hdr_space, length);
++ skb_put_frags(sky2, skb, hdr_space, length);
+ else
+ skb_put(skb, length);
+ return skb;
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -829,6 +829,9 @@ static inline void skb_fill_page_desc(st
+ skb_shinfo(skb)->nr_frags = i + 1;
+ }
+
++extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
++ int off, int size);
++
+ #define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags)
+ #define SKB_FRAG_ASSERT(skb) BUG_ON(skb_shinfo(skb)->frag_list)
+ #define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb))
+@@ -1243,6 +1246,26 @@ static inline struct sk_buff *netdev_all
+ return __netdev_alloc_skb(dev, length, GFP_ATOMIC);
+ }
+
++extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask);
++
++/**
++ * netdev_alloc_page - allocate a page for ps-rx on a specific device
++ * @dev: network device to receive on
++ *
++ * Allocate a new page node local to the specified device.
++ *
++ * %NULL is returned if there is no free memory.
++ */
++static inline struct page *netdev_alloc_page(struct net_device *dev)
++{
++ return __netdev_alloc_page(dev, GFP_ATOMIC);
++}
++
++static inline void netdev_free_page(struct net_device *dev, struct page *page)
++{
++ __free_page(page);
++}
++
+ /**
+ * skb_clone_writable - is the header of a clone writable
+ * @skb: buffer to check
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -259,6 +259,26 @@ struct sk_buff *__netdev_alloc_skb(struc
+ return skb;
+ }
+
++struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask)
++{
++ int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
++ struct page *page;
++
++ page = alloc_pages_node(node, gfp_mask, 0);
++ return page;
++}
++EXPORT_SYMBOL(__netdev_alloc_page);
++
++void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
++ int size)
++{
++ skb_fill_page_desc(skb, i, page, off, size);
++ skb->len += size;
++ skb->data_len += size;
++ skb->truesize += size;
++}
++EXPORT_SYMBOL(skb_add_rx_frag);
++
+ /**
+ * dev_alloc_skb - allocate an skbuff for receiving
+ * @length: length to allocate