]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/linux/0017-hyperv-Remove-recv_pkt_list-and-lock.patch
util-linux: update rootfile (armv5tel)
[ipfire-2.x.git] / src / patches / linux / 0017-hyperv-Remove-recv_pkt_list-and-lock.patch
1 From d6bf5567c1438b4f3b1bcff1a1525ddb1754df19 Mon Sep 17 00:00:00 2001
2 From: Haiyang Zhang <haiyangz@microsoft.com>
3 Date: Mon, 21 Apr 2014 14:54:43 -0700
4 Subject: [PATCH 17/25] hyperv: Remove recv_pkt_list and lock
5
6 Removed recv_pkt_list and lock, and updated related code, so that
7 the locking overhead is reduced especially when multiple channels
8 are in use.
9
10 The recv_pkt_list isn't actually necessary because the packets are
11 processed sequentially in each channel. It has been replaced by a
12 local variable, and the related lock for this list is also removed.
13 The is_data_pkt field is not used in receive path, so its assignment
14 is cleaned up.
15
16 Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
17 Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
18 Signed-off-by: David S. Miller <davem@davemloft.net>
19 ---
20 drivers/net/hyperv/hyperv_net.h | 33 --------
21 drivers/net/hyperv/netvsc.c | 174 +++-----------------------------------
22 drivers/net/hyperv/netvsc_drv.c | 2 +-
23 drivers/net/hyperv/rndis_filter.c | 2 -
24 4 files changed, 13 insertions(+), 198 deletions(-)
25
26 diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
27 index 57eb3f906d64..a1af0f7711e2 100644
28 --- a/drivers/net/hyperv/hyperv_net.h
29 +++ b/drivers/net/hyperv/hyperv_net.h
30 @@ -119,27 +119,14 @@ struct ndis_recv_scale_param { /* NDIS_RECEIVE_SCALE_PARAMETERS */
31 };
32
33 /* Fwd declaration */
34 -struct hv_netvsc_packet;
35 struct ndis_tcp_ip_checksum_info;
36
37 -/* Represent the xfer page packet which contains 1 or more netvsc packet */
38 -struct xferpage_packet {
39 - struct list_head list_ent;
40 - u32 status;
41 -
42 - /* # of netvsc packets this xfer packet contains */
43 - u32 count;
44 -
45 - struct vmbus_channel *channel;
46 -};
47 -
48 /*
49 * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame
50 * within the RNDIS
51 */
52 struct hv_netvsc_packet {
53 /* Bookkeeping stuff */
54 - struct list_head list_ent;
55 u32 status;
56
57 struct hv_device *device;
58 @@ -149,19 +136,8 @@ struct hv_netvsc_packet {
59 u16 q_idx;
60 struct vmbus_channel *channel;
61
62 - /*
63 - * Valid only for receives when we break a xfer page packet
64 - * into multiple netvsc packets
65 - */
66 - struct xferpage_packet *xfer_page_pkt;
67 -
68 union {
69 struct {
70 - u64 recv_completion_tid;
71 - void *recv_completion_ctx;
72 - void (*recv_completion)(void *context);
73 - } recv;
74 - struct {
75 u64 send_completion_tid;
76 void *send_completion_ctx;
77 void (*send_completion)(void *context);
78 @@ -613,9 +589,6 @@ struct nvsp_message {
79
80 #define NETVSC_RECEIVE_BUFFER_ID 0xcafe
81
82 -/* Preallocated receive packets */
83 -#define NETVSC_RECEIVE_PACKETLIST_COUNT 256
84 -
85 #define NETVSC_PACKET_SIZE 2048
86
87 #define VRSS_SEND_TAB_SIZE 16
88 @@ -630,12 +603,6 @@ struct netvsc_device {
89 wait_queue_head_t wait_drain;
90 bool start_remove;
91 bool destroy;
92 - /*
93 - * List of free preallocated hv_netvsc_packet to represent receive
94 - * packet
95 - */
96 - struct list_head recv_pkt_list;
97 - spinlock_t recv_pkt_list_lock;
98
99 /* Receive buffer allocated by us but manages by NetVSP */
100 void *recv_buf;
101 diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
102 index e7e77f12bc38..b10334773b32 100644
103 --- a/drivers/net/hyperv/netvsc.c
104 +++ b/drivers/net/hyperv/netvsc.c
105 @@ -387,7 +387,6 @@ static void netvsc_disconnect_vsp(struct netvsc_device *net_device)
106 int netvsc_device_remove(struct hv_device *device)
107 {
108 struct netvsc_device *net_device;
109 - struct hv_netvsc_packet *netvsc_packet, *pos;
110 unsigned long flags;
111
112 net_device = hv_get_drvdata(device);
113 @@ -416,12 +415,6 @@ int netvsc_device_remove(struct hv_device *device)
114 vmbus_close(device->channel);
115
116 /* Release all resources */
117 - list_for_each_entry_safe(netvsc_packet, pos,
118 - &net_device->recv_pkt_list, list_ent) {
119 - list_del(&netvsc_packet->list_ent);
120 - kfree(netvsc_packet);
121 - }
122 -
123 if (net_device->sub_cb_buf)
124 vfree(net_device->sub_cb_buf);
125
126 @@ -641,62 +634,6 @@ retry_send_cmplt:
127 }
128 }
129
130 -/* Send a receive completion packet to RNDIS device (ie NetVsp) */
131 -static void netvsc_receive_completion(void *context)
132 -{
133 - struct hv_netvsc_packet *packet = context;
134 - struct hv_device *device = packet->device;
135 - struct vmbus_channel *channel;
136 - struct netvsc_device *net_device;
137 - u64 transaction_id = 0;
138 - bool fsend_receive_comp = false;
139 - unsigned long flags;
140 - struct net_device *ndev;
141 - u32 status = NVSP_STAT_NONE;
142 -
143 - /*
144 - * Even though it seems logical to do a GetOutboundNetDevice() here to
145 - * send out receive completion, we are using GetInboundNetDevice()
146 - * since we may have disable outbound traffic already.
147 - */
148 - net_device = get_inbound_net_device(device);
149 - if (!net_device)
150 - return;
151 - ndev = net_device->ndev;
152 -
153 - /* Overloading use of the lock. */
154 - spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
155 -
156 - if (packet->status != NVSP_STAT_SUCCESS)
157 - packet->xfer_page_pkt->status = NVSP_STAT_FAIL;
158 -
159 - packet->xfer_page_pkt->count--;
160 -
161 - /*
162 - * Last one in the line that represent 1 xfer page packet.
163 - * Return the xfer page packet itself to the freelist
164 - */
165 - if (packet->xfer_page_pkt->count == 0) {
166 - fsend_receive_comp = true;
167 - channel = packet->xfer_page_pkt->channel;
168 - transaction_id = packet->completion.recv.recv_completion_tid;
169 - status = packet->xfer_page_pkt->status;
170 - list_add_tail(&packet->xfer_page_pkt->list_ent,
171 - &net_device->recv_pkt_list);
172 -
173 - }
174 -
175 - /* Put the packet back */
176 - list_add_tail(&packet->list_ent, &net_device->recv_pkt_list);
177 - spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
178 -
179 - /* Send a receive completion for the xfer page packet */
180 - if (fsend_receive_comp)
181 - netvsc_send_recv_completion(device, channel, net_device,
182 - transaction_id, status);
183 -
184 -}
185 -
186 static void netvsc_receive(struct netvsc_device *net_device,
187 struct vmbus_channel *channel,
188 struct hv_device *device,
189 @@ -704,16 +641,13 @@ static void netvsc_receive(struct netvsc_device *net_device,
190 {
191 struct vmtransfer_page_packet_header *vmxferpage_packet;
192 struct nvsp_message *nvsp_packet;
193 - struct hv_netvsc_packet *netvsc_packet = NULL;
194 - /* struct netvsc_driver *netvscDriver; */
195 - struct xferpage_packet *xferpage_packet = NULL;
196 + struct hv_netvsc_packet nv_pkt;
197 + struct hv_netvsc_packet *netvsc_packet = &nv_pkt;
198 + u32 status = NVSP_STAT_SUCCESS;
199 int i;
200 int count = 0;
201 - unsigned long flags;
202 struct net_device *ndev;
203
204 - LIST_HEAD(listHead);
205 -
206 ndev = net_device->ndev;
207
208 /*
209 @@ -746,78 +680,14 @@ static void netvsc_receive(struct netvsc_device *net_device,
210 return;
211 }
212
213 - /*
214 - * Grab free packets (range count + 1) to represent this xfer
215 - * page packet. +1 to represent the xfer page packet itself.
216 - * We grab it here so that we know exactly how many we can
217 - * fulfil
218 - */
219 - spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
220 - while (!list_empty(&net_device->recv_pkt_list)) {
221 - list_move_tail(net_device->recv_pkt_list.next, &listHead);
222 - if (++count == vmxferpage_packet->range_cnt + 1)
223 - break;
224 - }
225 - spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
226 -
227 - /*
228 - * We need at least 2 netvsc pkts (1 to represent the xfer
229 - * page and at least 1 for the range) i.e. we can handled
230 - * some of the xfer page packet ranges...
231 - */
232 - if (count < 2) {
233 - netdev_err(ndev, "Got only %d netvsc pkt...needed "
234 - "%d pkts. Dropping this xfer page packet completely!\n",
235 - count, vmxferpage_packet->range_cnt + 1);
236 -
237 - /* Return it to the freelist */
238 - spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
239 - for (i = count; i != 0; i--) {
240 - list_move_tail(listHead.next,
241 - &net_device->recv_pkt_list);
242 - }
243 - spin_unlock_irqrestore(&net_device->recv_pkt_list_lock,
244 - flags);
245 -
246 - netvsc_send_recv_completion(device, channel, net_device,
247 - vmxferpage_packet->d.trans_id,
248 - NVSP_STAT_FAIL);
249 -
250 - return;
251 - }
252 -
253 - /* Remove the 1st packet to represent the xfer page packet itself */
254 - xferpage_packet = (struct xferpage_packet *)listHead.next;
255 - list_del(&xferpage_packet->list_ent);
256 - xferpage_packet->status = NVSP_STAT_SUCCESS;
257 - xferpage_packet->channel = channel;
258 -
259 - /* This is how much we can satisfy */
260 - xferpage_packet->count = count - 1;
261 -
262 - if (xferpage_packet->count != vmxferpage_packet->range_cnt) {
263 - netdev_err(ndev, "Needed %d netvsc pkts to satisfy "
264 - "this xfer page...got %d\n",
265 - vmxferpage_packet->range_cnt, xferpage_packet->count);
266 - }
267 + count = vmxferpage_packet->range_cnt;
268 + netvsc_packet->device = device;
269 + netvsc_packet->channel = channel;
270
271 /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
272 - for (i = 0; i < (count - 1); i++) {
273 - netvsc_packet = (struct hv_netvsc_packet *)listHead.next;
274 - list_del(&netvsc_packet->list_ent);
275 -
276 + for (i = 0; i < count; i++) {
277 /* Initialize the netvsc packet */
278 netvsc_packet->status = NVSP_STAT_SUCCESS;
279 - netvsc_packet->xfer_page_pkt = xferpage_packet;
280 - netvsc_packet->completion.recv.recv_completion =
281 - netvsc_receive_completion;
282 - netvsc_packet->completion.recv.recv_completion_ctx =
283 - netvsc_packet;
284 - netvsc_packet->device = device;
285 - /* Save this so that we can send it back */
286 - netvsc_packet->completion.recv.recv_completion_tid =
287 - vmxferpage_packet->d.trans_id;
288 -
289 netvsc_packet->data = (void *)((unsigned long)net_device->
290 recv_buf + vmxferpage_packet->ranges[i].byte_offset);
291 netvsc_packet->total_data_buflen =
292 @@ -826,10 +696,12 @@ static void netvsc_receive(struct netvsc_device *net_device,
293 /* Pass it to the upper layer */
294 rndis_filter_receive(device, netvsc_packet);
295
296 - netvsc_receive_completion(netvsc_packet->
297 - completion.recv.recv_completion_ctx);
298 + if (netvsc_packet->status != NVSP_STAT_SUCCESS)
299 + status = NVSP_STAT_FAIL;
300 }
301
302 + netvsc_send_recv_completion(device, channel, net_device,
303 + vmxferpage_packet->d.trans_id, status);
304 }
305
306
307 @@ -956,11 +828,9 @@ void netvsc_channel_cb(void *context)
308 int netvsc_device_add(struct hv_device *device, void *additional_info)
309 {
310 int ret = 0;
311 - int i;
312 int ring_size =
313 ((struct netvsc_device_info *)additional_info)->ring_size;
314 struct netvsc_device *net_device;
315 - struct hv_netvsc_packet *packet, *pos;
316 struct net_device *ndev;
317
318 net_device = alloc_net_device(device);
319 @@ -981,18 +851,6 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
320 ndev = net_device->ndev;
321
322 /* Initialize the NetVSC channel extension */
323 - spin_lock_init(&net_device->recv_pkt_list_lock);
324 -
325 - INIT_LIST_HEAD(&net_device->recv_pkt_list);
326 -
327 - for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
328 - packet = kzalloc(sizeof(struct hv_netvsc_packet), GFP_KERNEL);
329 - if (!packet)
330 - break;
331 -
332 - list_add_tail(&packet->list_ent,
333 - &net_device->recv_pkt_list);
334 - }
335 init_completion(&net_device->channel_init_wait);
336
337 set_per_channel_state(device->channel, net_device->cb_buffer);
338 @@ -1028,16 +886,8 @@ close:
339
340 cleanup:
341
342 - if (net_device) {
343 - list_for_each_entry_safe(packet, pos,
344 - &net_device->recv_pkt_list,
345 - list_ent) {
346 - list_del(&packet->list_ent);
347 - kfree(packet);
348 - }
349 -
350 + if (net_device)
351 kfree(net_device);
352 - }
353
354 return ret;
355 }
356 diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
357 index e486dbd33f61..6cc4db064fec 100644
358 --- a/drivers/net/hyperv/netvsc_drv.c
359 +++ b/drivers/net/hyperv/netvsc_drv.c
360 @@ -643,7 +643,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
361 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
362 packet->vlan_tci);
363
364 - skb_record_rx_queue(skb, packet->xfer_page_pkt->channel->
365 + skb_record_rx_queue(skb, packet->channel->
366 offermsg.offer.sub_channel_index %
367 net->real_num_rx_queues);
368
369 diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
370 index d92cfbe43410..48f5a0fbd674 100644
371 --- a/drivers/net/hyperv/rndis_filter.c
372 +++ b/drivers/net/hyperv/rndis_filter.c
373 @@ -401,8 +401,6 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
374 pkt->total_data_buflen = rndis_pkt->data_len;
375 pkt->data = (void *)((unsigned long)pkt->data + data_offset);
376
377 - pkt->is_data_pkt = true;
378 -
379 vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
380 if (vlan) {
381 pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
382 --
383 2.4.3
384