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