xref: /openbmc/linux/include/net/gro_cells.h (revision f8e8f97c)
1c9e6bc64SEric Dumazet #ifndef _NET_GRO_CELLS_H
2c9e6bc64SEric Dumazet #define _NET_GRO_CELLS_H
3c9e6bc64SEric Dumazet 
4c9e6bc64SEric Dumazet #include <linux/skbuff.h>
5c9e6bc64SEric Dumazet #include <linux/slab.h>
6c9e6bc64SEric Dumazet #include <linux/netdevice.h>
7c9e6bc64SEric Dumazet 
8c9e6bc64SEric Dumazet struct gro_cell {
9c9e6bc64SEric Dumazet 	struct sk_buff_head	napi_skbs;
10c9e6bc64SEric Dumazet 	struct napi_struct	napi;
11c9e6bc64SEric Dumazet } ____cacheline_aligned_in_smp;
12c9e6bc64SEric Dumazet 
13c9e6bc64SEric Dumazet struct gro_cells {
14c9e6bc64SEric Dumazet 	unsigned int		gro_cells_mask;
15c9e6bc64SEric Dumazet 	struct gro_cell		*cells;
16c9e6bc64SEric Dumazet };
17c9e6bc64SEric Dumazet 
18c9e6bc64SEric Dumazet static inline void gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb)
19c9e6bc64SEric Dumazet {
20c9e6bc64SEric Dumazet 	struct gro_cell *cell = gcells->cells;
21c9e6bc64SEric Dumazet 	struct net_device *dev = skb->dev;
22c9e6bc64SEric Dumazet 
23c9e6bc64SEric Dumazet 	if (!cell || skb_cloned(skb) || !(dev->features & NETIF_F_GRO)) {
24c9e6bc64SEric Dumazet 		netif_rx(skb);
25c9e6bc64SEric Dumazet 		return;
26c9e6bc64SEric Dumazet 	}
27c9e6bc64SEric Dumazet 
28c9e6bc64SEric Dumazet 	if (skb_rx_queue_recorded(skb))
29c9e6bc64SEric Dumazet 		cell += skb_get_rx_queue(skb) & gcells->gro_cells_mask;
30c9e6bc64SEric Dumazet 
31c9e6bc64SEric Dumazet 	if (skb_queue_len(&cell->napi_skbs) > netdev_max_backlog) {
32c9e6bc64SEric Dumazet 		atomic_long_inc(&dev->rx_dropped);
33c9e6bc64SEric Dumazet 		kfree_skb(skb);
34c9e6bc64SEric Dumazet 		return;
35c9e6bc64SEric Dumazet 	}
36c9e6bc64SEric Dumazet 
37f8e8f97cSEric Dumazet 	/* We run in BH context */
38f8e8f97cSEric Dumazet 	spin_lock(&cell->napi_skbs.lock);
39c9e6bc64SEric Dumazet 
40c9e6bc64SEric Dumazet 	__skb_queue_tail(&cell->napi_skbs, skb);
41c9e6bc64SEric Dumazet 	if (skb_queue_len(&cell->napi_skbs) == 1)
42c9e6bc64SEric Dumazet 		napi_schedule(&cell->napi);
43c9e6bc64SEric Dumazet 
44f8e8f97cSEric Dumazet 	spin_unlock(&cell->napi_skbs.lock);
45c9e6bc64SEric Dumazet }
46c9e6bc64SEric Dumazet 
47f8e8f97cSEric Dumazet /* called unser BH context */
48c9e6bc64SEric Dumazet static inline int gro_cell_poll(struct napi_struct *napi, int budget)
49c9e6bc64SEric Dumazet {
50c9e6bc64SEric Dumazet 	struct gro_cell *cell = container_of(napi, struct gro_cell, napi);
51c9e6bc64SEric Dumazet 	struct sk_buff *skb;
52c9e6bc64SEric Dumazet 	int work_done = 0;
53c9e6bc64SEric Dumazet 
54f8e8f97cSEric Dumazet 	spin_lock(&cell->napi_skbs.lock);
55c9e6bc64SEric Dumazet 	while (work_done < budget) {
56f8e8f97cSEric Dumazet 		skb = __skb_dequeue(&cell->napi_skbs);
57c9e6bc64SEric Dumazet 		if (!skb)
58c9e6bc64SEric Dumazet 			break;
59f8e8f97cSEric Dumazet 		spin_unlock(&cell->napi_skbs.lock);
60c9e6bc64SEric Dumazet 		napi_gro_receive(napi, skb);
61c9e6bc64SEric Dumazet 		work_done++;
62f8e8f97cSEric Dumazet 		spin_lock(&cell->napi_skbs.lock);
63c9e6bc64SEric Dumazet 	}
64c9e6bc64SEric Dumazet 
65c9e6bc64SEric Dumazet 	if (work_done < budget)
66c9e6bc64SEric Dumazet 		napi_complete(napi);
67f8e8f97cSEric Dumazet 	spin_unlock(&cell->napi_skbs.lock);
68c9e6bc64SEric Dumazet 	return work_done;
69c9e6bc64SEric Dumazet }
70c9e6bc64SEric Dumazet 
71c9e6bc64SEric Dumazet static inline int gro_cells_init(struct gro_cells *gcells, struct net_device *dev)
72c9e6bc64SEric Dumazet {
73c9e6bc64SEric Dumazet 	int i;
74c9e6bc64SEric Dumazet 
75c9e6bc64SEric Dumazet 	gcells->gro_cells_mask = roundup_pow_of_two(netif_get_num_default_rss_queues()) - 1;
76c9e6bc64SEric Dumazet 	gcells->cells = kcalloc(sizeof(struct gro_cell),
77c9e6bc64SEric Dumazet 				gcells->gro_cells_mask + 1,
78c9e6bc64SEric Dumazet 				GFP_KERNEL);
79c9e6bc64SEric Dumazet 	if (!gcells->cells)
80c9e6bc64SEric Dumazet 		return -ENOMEM;
81c9e6bc64SEric Dumazet 
82c9e6bc64SEric Dumazet 	for (i = 0; i <= gcells->gro_cells_mask; i++) {
83c9e6bc64SEric Dumazet 		struct gro_cell *cell = gcells->cells + i;
84c9e6bc64SEric Dumazet 
85c9e6bc64SEric Dumazet 		skb_queue_head_init(&cell->napi_skbs);
86c9e6bc64SEric Dumazet 		netif_napi_add(dev, &cell->napi, gro_cell_poll, 64);
87c9e6bc64SEric Dumazet 		napi_enable(&cell->napi);
88c9e6bc64SEric Dumazet 	}
89c9e6bc64SEric Dumazet 	return 0;
90c9e6bc64SEric Dumazet }
91c9e6bc64SEric Dumazet 
92c9e6bc64SEric Dumazet static inline void gro_cells_destroy(struct gro_cells *gcells)
93c9e6bc64SEric Dumazet {
94c9e6bc64SEric Dumazet 	struct gro_cell *cell = gcells->cells;
95c9e6bc64SEric Dumazet 	int i;
96c9e6bc64SEric Dumazet 
97c9e6bc64SEric Dumazet 	if (!cell)
98c9e6bc64SEric Dumazet 		return;
99c9e6bc64SEric Dumazet 	for (i = 0; i <= gcells->gro_cells_mask; i++,cell++) {
100c9e6bc64SEric Dumazet 		netif_napi_del(&cell->napi);
101c9e6bc64SEric Dumazet 		skb_queue_purge(&cell->napi_skbs);
102c9e6bc64SEric Dumazet 	}
103c9e6bc64SEric Dumazet 	kfree(gcells->cells);
104c9e6bc64SEric Dumazet 	gcells->cells = NULL;
105c9e6bc64SEric Dumazet }
106c9e6bc64SEric Dumazet 
107c9e6bc64SEric Dumazet #endif
108