xref: /openbmc/linux/net/core/gro_cells.c (revision 1c2dd16a)
1 #include <linux/skbuff.h>
2 #include <linux/slab.h>
3 #include <linux/netdevice.h>
4 #include <net/gro_cells.h>
5 
6 struct gro_cell {
7 	struct sk_buff_head	napi_skbs;
8 	struct napi_struct	napi;
9 };
10 
11 int gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb)
12 {
13 	struct net_device *dev = skb->dev;
14 	struct gro_cell *cell;
15 
16 	if (!gcells->cells || skb_cloned(skb) || netif_elide_gro(dev))
17 		return netif_rx(skb);
18 
19 	cell = this_cpu_ptr(gcells->cells);
20 
21 	if (skb_queue_len(&cell->napi_skbs) > netdev_max_backlog) {
22 		atomic_long_inc(&dev->rx_dropped);
23 		kfree_skb(skb);
24 		return NET_RX_DROP;
25 	}
26 
27 	__skb_queue_tail(&cell->napi_skbs, skb);
28 	if (skb_queue_len(&cell->napi_skbs) == 1)
29 		napi_schedule(&cell->napi);
30 	return NET_RX_SUCCESS;
31 }
32 EXPORT_SYMBOL(gro_cells_receive);
33 
34 /* called under BH context */
35 static int gro_cell_poll(struct napi_struct *napi, int budget)
36 {
37 	struct gro_cell *cell = container_of(napi, struct gro_cell, napi);
38 	struct sk_buff *skb;
39 	int work_done = 0;
40 
41 	while (work_done < budget) {
42 		skb = __skb_dequeue(&cell->napi_skbs);
43 		if (!skb)
44 			break;
45 		napi_gro_receive(napi, skb);
46 		work_done++;
47 	}
48 
49 	if (work_done < budget)
50 		napi_complete_done(napi, work_done);
51 	return work_done;
52 }
53 
54 int gro_cells_init(struct gro_cells *gcells, struct net_device *dev)
55 {
56 	int i;
57 
58 	gcells->cells = alloc_percpu(struct gro_cell);
59 	if (!gcells->cells)
60 		return -ENOMEM;
61 
62 	for_each_possible_cpu(i) {
63 		struct gro_cell *cell = per_cpu_ptr(gcells->cells, i);
64 
65 		__skb_queue_head_init(&cell->napi_skbs);
66 
67 		set_bit(NAPI_STATE_NO_BUSY_POLL, &cell->napi.state);
68 
69 		netif_napi_add(dev, &cell->napi, gro_cell_poll,
70 			       NAPI_POLL_WEIGHT);
71 		napi_enable(&cell->napi);
72 	}
73 	return 0;
74 }
75 EXPORT_SYMBOL(gro_cells_init);
76 
77 void gro_cells_destroy(struct gro_cells *gcells)
78 {
79 	int i;
80 
81 	if (!gcells->cells)
82 		return;
83 	for_each_possible_cpu(i) {
84 		struct gro_cell *cell = per_cpu_ptr(gcells->cells, i);
85 
86 		netif_napi_del(&cell->napi);
87 		__skb_queue_purge(&cell->napi_skbs);
88 	}
89 	free_percpu(gcells->cells);
90 	gcells->cells = NULL;
91 }
92 EXPORT_SYMBOL(gro_cells_destroy);
93