xref: /openbmc/linux/include/net/gro_cells.h (revision 88340160)
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;
1188340160SMartin KaFai Lau };
12c9e6bc64SEric Dumazet 
13c9e6bc64SEric Dumazet struct gro_cells {
1488340160SMartin KaFai Lau 	struct gro_cell __percpu	*cells;
15c9e6bc64SEric Dumazet };
16c9e6bc64SEric Dumazet 
17c9e6bc64SEric Dumazet static inline void gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb)
18c9e6bc64SEric Dumazet {
1988340160SMartin KaFai Lau 	struct gro_cell *cell;
20c9e6bc64SEric Dumazet 	struct net_device *dev = skb->dev;
21c9e6bc64SEric Dumazet 
2288340160SMartin KaFai Lau 	if (!gcells->cells || skb_cloned(skb) || !(dev->features & NETIF_F_GRO)) {
23c9e6bc64SEric Dumazet 		netif_rx(skb);
24c9e6bc64SEric Dumazet 		return;
25c9e6bc64SEric Dumazet 	}
26c9e6bc64SEric Dumazet 
2788340160SMartin KaFai Lau 	cell = this_cpu_ptr(gcells->cells);
28c9e6bc64SEric Dumazet 
29c9e6bc64SEric Dumazet 	if (skb_queue_len(&cell->napi_skbs) > netdev_max_backlog) {
30c9e6bc64SEric Dumazet 		atomic_long_inc(&dev->rx_dropped);
31c9e6bc64SEric Dumazet 		kfree_skb(skb);
32c9e6bc64SEric Dumazet 		return;
33c9e6bc64SEric Dumazet 	}
34c9e6bc64SEric Dumazet 
35f8e8f97cSEric Dumazet 	/* We run in BH context */
36f8e8f97cSEric Dumazet 	spin_lock(&cell->napi_skbs.lock);
37c9e6bc64SEric Dumazet 
38c9e6bc64SEric Dumazet 	__skb_queue_tail(&cell->napi_skbs, skb);
39c9e6bc64SEric Dumazet 	if (skb_queue_len(&cell->napi_skbs) == 1)
40c9e6bc64SEric Dumazet 		napi_schedule(&cell->napi);
41c9e6bc64SEric Dumazet 
42f8e8f97cSEric Dumazet 	spin_unlock(&cell->napi_skbs.lock);
43c9e6bc64SEric Dumazet }
44c9e6bc64SEric Dumazet 
45f8e8f97cSEric Dumazet /* called unser BH context */
46c9e6bc64SEric Dumazet static inline int gro_cell_poll(struct napi_struct *napi, int budget)
47c9e6bc64SEric Dumazet {
48c9e6bc64SEric Dumazet 	struct gro_cell *cell = container_of(napi, struct gro_cell, napi);
49c9e6bc64SEric Dumazet 	struct sk_buff *skb;
50c9e6bc64SEric Dumazet 	int work_done = 0;
51c9e6bc64SEric Dumazet 
52f8e8f97cSEric Dumazet 	spin_lock(&cell->napi_skbs.lock);
53c9e6bc64SEric Dumazet 	while (work_done < budget) {
54f8e8f97cSEric Dumazet 		skb = __skb_dequeue(&cell->napi_skbs);
55c9e6bc64SEric Dumazet 		if (!skb)
56c9e6bc64SEric Dumazet 			break;
57f8e8f97cSEric Dumazet 		spin_unlock(&cell->napi_skbs.lock);
58c9e6bc64SEric Dumazet 		napi_gro_receive(napi, skb);
59c9e6bc64SEric Dumazet 		work_done++;
60f8e8f97cSEric Dumazet 		spin_lock(&cell->napi_skbs.lock);
61c9e6bc64SEric Dumazet 	}
62c9e6bc64SEric Dumazet 
63c9e6bc64SEric Dumazet 	if (work_done < budget)
64c9e6bc64SEric Dumazet 		napi_complete(napi);
65f8e8f97cSEric Dumazet 	spin_unlock(&cell->napi_skbs.lock);
66c9e6bc64SEric Dumazet 	return work_done;
67c9e6bc64SEric Dumazet }
68c9e6bc64SEric Dumazet 
69c9e6bc64SEric Dumazet static inline int gro_cells_init(struct gro_cells *gcells, struct net_device *dev)
70c9e6bc64SEric Dumazet {
71c9e6bc64SEric Dumazet 	int i;
72c9e6bc64SEric Dumazet 
7388340160SMartin KaFai Lau 	gcells->cells = alloc_percpu(struct gro_cell);
74c9e6bc64SEric Dumazet 	if (!gcells->cells)
75c9e6bc64SEric Dumazet 		return -ENOMEM;
76c9e6bc64SEric Dumazet 
7788340160SMartin KaFai Lau 	for_each_possible_cpu(i) {
7888340160SMartin KaFai Lau 		struct gro_cell *cell = per_cpu_ptr(gcells->cells, i);
79c9e6bc64SEric Dumazet 
80c9e6bc64SEric Dumazet 		skb_queue_head_init(&cell->napi_skbs);
81c9e6bc64SEric Dumazet 		netif_napi_add(dev, &cell->napi, gro_cell_poll, 64);
82c9e6bc64SEric Dumazet 		napi_enable(&cell->napi);
83c9e6bc64SEric Dumazet 	}
84c9e6bc64SEric Dumazet 	return 0;
85c9e6bc64SEric Dumazet }
86c9e6bc64SEric Dumazet 
87c9e6bc64SEric Dumazet static inline void gro_cells_destroy(struct gro_cells *gcells)
88c9e6bc64SEric Dumazet {
89c9e6bc64SEric Dumazet 	int i;
90c9e6bc64SEric Dumazet 
9188340160SMartin KaFai Lau 	if (!gcells->cells)
92c9e6bc64SEric Dumazet 		return;
9388340160SMartin KaFai Lau 	for_each_possible_cpu(i) {
9488340160SMartin KaFai Lau 		struct gro_cell *cell = per_cpu_ptr(gcells->cells, i);
95c9e6bc64SEric Dumazet 		netif_napi_del(&cell->napi);
96c9e6bc64SEric Dumazet 		skb_queue_purge(&cell->napi_skbs);
97c9e6bc64SEric Dumazet 	}
9888340160SMartin KaFai Lau 	free_percpu(gcells->cells);
99c9e6bc64SEric Dumazet 	gcells->cells = NULL;
100c9e6bc64SEric Dumazet }
101c9e6bc64SEric Dumazet 
102c9e6bc64SEric Dumazet #endif
103