]>
Commit | Line | Data |
---|---|---|
a7b0967d MT |
1 | From 4baab26129e0540746744232022110dbe9e011e7 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 02/11] 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 093cf3fc46b8..8f6d53a2ed95 100644 | |
358 | --- a/drivers/net/hyperv/netvsc_drv.c | |
359 | +++ b/drivers/net/hyperv/netvsc_drv.c | |
360 | @@ -638,7 +638,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 |