diff options
author | David Vrabel <david.vrabel@citrix.com> | 2016-10-04 05:29:14 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-10-06 20:37:35 -0400 |
commit | eb1723a29b9a75dd787510a39096a68dba6cc200 (patch) | |
tree | 7f6c52ddcb5b98accb591c01b94def17d100007e | |
parent | fedbc8c132bcf836358103195d8b6df6c03d9daf (diff) |
xen-netback: refactor guest rx
Refactor the to-guest (rx) path to:
1. Push responses for completed skbs earlier, reducing latency.
2. Reduce the per-queue memory overhead by greatly reducing the
maximum number of grant copy ops in each hypercall (from 4352 to
64). Each struct xenvif_queue is now only 44 kB instead of 220 kB.
3. Make the code more maintainable.
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
[re-based]
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/xen-netback/common.h | 23 | ||||
-rw-r--r-- | drivers/net/xen-netback/rx.c | 576 |
2 files changed, 215 insertions, 384 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 0ba59106b1a5..7d12a388afc6 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h | |||
@@ -91,13 +91,6 @@ struct xenvif_rx_meta { | |||
91 | */ | 91 | */ |
92 | #define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1) | 92 | #define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1) |
93 | 93 | ||
94 | /* It's possible for an skb to have a maximal number of frags | ||
95 | * but still be less than MAX_BUFFER_OFFSET in size. Thus the | ||
96 | * worst-case number of copy operations is MAX_XEN_SKB_FRAGS per | ||
97 | * ring slot. | ||
98 | */ | ||
99 | #define MAX_GRANT_COPY_OPS (MAX_XEN_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE) | ||
100 | |||
101 | #define NETBACK_INVALID_HANDLE -1 | 94 | #define NETBACK_INVALID_HANDLE -1 |
102 | 95 | ||
103 | /* To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating | 96 | /* To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating |
@@ -133,6 +126,14 @@ struct xenvif_stats { | |||
133 | unsigned long tx_frag_overflow; | 126 | unsigned long tx_frag_overflow; |
134 | }; | 127 | }; |
135 | 128 | ||
129 | #define COPY_BATCH_SIZE 64 | ||
130 | |||
131 | struct xenvif_copy_state { | ||
132 | struct gnttab_copy op[COPY_BATCH_SIZE]; | ||
133 | RING_IDX idx[COPY_BATCH_SIZE]; | ||
134 | unsigned int num; | ||
135 | }; | ||
136 | |||
136 | struct xenvif_queue { /* Per-queue data for xenvif */ | 137 | struct xenvif_queue { /* Per-queue data for xenvif */ |
137 | unsigned int id; /* Queue ID, 0-based */ | 138 | unsigned int id; /* Queue ID, 0-based */ |
138 | char name[QUEUE_NAME_SIZE]; /* DEVNAME-qN */ | 139 | char name[QUEUE_NAME_SIZE]; /* DEVNAME-qN */ |
@@ -189,12 +190,7 @@ struct xenvif_queue { /* Per-queue data for xenvif */ | |||
189 | unsigned long last_rx_time; | 190 | unsigned long last_rx_time; |
190 | bool stalled; | 191 | bool stalled; |
191 | 192 | ||
192 | struct gnttab_copy grant_copy_op[MAX_GRANT_COPY_OPS]; | 193 | struct xenvif_copy_state rx_copy; |
193 | |||
194 | /* We create one meta structure per ring request we consume, so | ||
195 | * the maximum number is the same as the ring size. | ||
196 | */ | ||
197 | struct xenvif_rx_meta meta[XEN_NETIF_RX_RING_SIZE]; | ||
198 | 194 | ||
199 | /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */ | 195 | /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */ |
200 | unsigned long credit_bytes; | 196 | unsigned long credit_bytes; |
@@ -358,6 +354,7 @@ int xenvif_dealloc_kthread(void *data); | |||
358 | 354 | ||
359 | irqreturn_t xenvif_ctrl_irq_fn(int irq, void *data); | 355 | irqreturn_t xenvif_ctrl_irq_fn(int irq, void *data); |
360 | 356 | ||
357 | void xenvif_rx_action(struct xenvif_queue *queue); | ||
361 | void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb); | 358 | void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb); |
362 | 359 | ||
363 | void xenvif_carrier_on(struct xenvif *vif); | 360 | void xenvif_carrier_on(struct xenvif *vif); |
diff --git a/drivers/net/xen-netback/rx.c b/drivers/net/xen-netback/rx.c index 6bd7d6e84b8e..b0ce4c6e9b21 100644 --- a/drivers/net/xen-netback/rx.c +++ b/drivers/net/xen-netback/rx.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
27 | * IN THE SOFTWARE. | 27 | * IN THE SOFTWARE. |
28 | */ | 28 | */ |
29 | |||
30 | #include "common.h" | 29 | #include "common.h" |
31 | 30 | ||
32 | #include <linux/kthread.h> | 31 | #include <linux/kthread.h> |
@@ -137,464 +136,299 @@ static void xenvif_rx_queue_drop_expired(struct xenvif_queue *queue) | |||
137 | } | 136 | } |
138 | } | 137 | } |
139 | 138 | ||
140 | struct netrx_pending_operations { | 139 | static void xenvif_rx_copy_flush(struct xenvif_queue *queue) |
141 | unsigned int copy_prod, copy_cons; | ||
142 | unsigned int meta_prod, meta_cons; | ||
143 | struct gnttab_copy *copy; | ||
144 | struct xenvif_rx_meta *meta; | ||
145 | int copy_off; | ||
146 | grant_ref_t copy_gref; | ||
147 | }; | ||
148 | |||
149 | static struct xenvif_rx_meta *get_next_rx_buffer( | ||
150 | struct xenvif_queue *queue, | ||
151 | struct netrx_pending_operations *npo) | ||
152 | { | 140 | { |
153 | struct xenvif_rx_meta *meta; | 141 | unsigned int i; |
154 | struct xen_netif_rx_request req; | ||
155 | 142 | ||
156 | RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req); | 143 | gnttab_batch_copy(queue->rx_copy.op, queue->rx_copy.num); |
157 | 144 | ||
158 | meta = npo->meta + npo->meta_prod++; | 145 | for (i = 0; i < queue->rx_copy.num; i++) { |
159 | meta->gso_type = XEN_NETIF_GSO_TYPE_NONE; | 146 | struct gnttab_copy *op; |
160 | meta->gso_size = 0; | ||
161 | meta->size = 0; | ||
162 | meta->id = req.id; | ||
163 | 147 | ||
164 | npo->copy_off = 0; | 148 | op = &queue->rx_copy.op[i]; |
165 | npo->copy_gref = req.gref; | ||
166 | 149 | ||
167 | return meta; | 150 | /* If the copy failed, overwrite the status field in |
168 | } | 151 | * the corresponding response. |
152 | */ | ||
153 | if (unlikely(op->status != GNTST_okay)) { | ||
154 | struct xen_netif_rx_response *rsp; | ||
169 | 155 | ||
170 | struct gop_frag_copy { | 156 | rsp = RING_GET_RESPONSE(&queue->rx, |
171 | struct xenvif_queue *queue; | 157 | queue->rx_copy.idx[i]); |
172 | struct netrx_pending_operations *npo; | 158 | rsp->status = op->status; |
173 | struct xenvif_rx_meta *meta; | 159 | } |
174 | int head; | 160 | } |
175 | int gso_type; | ||
176 | int protocol; | ||
177 | int hash_present; | ||
178 | 161 | ||
179 | struct page *page; | 162 | queue->rx_copy.num = 0; |
180 | }; | 163 | } |
181 | 164 | ||
182 | static void xenvif_setup_copy_gop(unsigned long gfn, | 165 | static void xenvif_rx_copy_add(struct xenvif_queue *queue, |
183 | unsigned int offset, | 166 | struct xen_netif_rx_request *req, |
184 | unsigned int *len, | 167 | unsigned int offset, void *data, size_t len) |
185 | struct gop_frag_copy *info) | ||
186 | { | 168 | { |
187 | struct gnttab_copy *copy_gop; | 169 | struct gnttab_copy *op; |
170 | struct page *page; | ||
188 | struct xen_page_foreign *foreign; | 171 | struct xen_page_foreign *foreign; |
189 | /* Convenient aliases */ | ||
190 | struct xenvif_queue *queue = info->queue; | ||
191 | struct netrx_pending_operations *npo = info->npo; | ||
192 | struct page *page = info->page; | ||
193 | 172 | ||
194 | WARN_ON(npo->copy_off > MAX_BUFFER_OFFSET); | 173 | if (queue->rx_copy.num == COPY_BATCH_SIZE) |
174 | xenvif_rx_copy_flush(queue); | ||
195 | 175 | ||
196 | if (npo->copy_off == MAX_BUFFER_OFFSET) | 176 | op = &queue->rx_copy.op[queue->rx_copy.num]; |
197 | info->meta = get_next_rx_buffer(queue, npo); | ||
198 | 177 | ||
199 | if (npo->copy_off + *len > MAX_BUFFER_OFFSET) | 178 | page = virt_to_page(data); |
200 | *len = MAX_BUFFER_OFFSET - npo->copy_off; | ||
201 | 179 | ||
202 | copy_gop = npo->copy + npo->copy_prod++; | 180 | op->flags = GNTCOPY_dest_gref; |
203 | copy_gop->flags = GNTCOPY_dest_gref; | ||
204 | copy_gop->len = *len; | ||
205 | 181 | ||
206 | foreign = xen_page_foreign(page); | 182 | foreign = xen_page_foreign(page); |
207 | if (foreign) { | 183 | if (foreign) { |
208 | copy_gop->source.domid = foreign->domid; | 184 | op->source.domid = foreign->domid; |
209 | copy_gop->source.u.ref = foreign->gref; | 185 | op->source.u.ref = foreign->gref; |
210 | copy_gop->flags |= GNTCOPY_source_gref; | 186 | op->flags |= GNTCOPY_source_gref; |
211 | } else { | 187 | } else { |
212 | copy_gop->source.domid = DOMID_SELF; | 188 | op->source.u.gmfn = virt_to_gfn(data); |
213 | copy_gop->source.u.gmfn = gfn; | 189 | op->source.domid = DOMID_SELF; |
214 | } | 190 | } |
215 | copy_gop->source.offset = offset; | ||
216 | 191 | ||
217 | copy_gop->dest.domid = queue->vif->domid; | 192 | op->source.offset = xen_offset_in_page(data); |
218 | copy_gop->dest.offset = npo->copy_off; | 193 | op->dest.u.ref = req->gref; |
219 | copy_gop->dest.u.ref = npo->copy_gref; | 194 | op->dest.domid = queue->vif->domid; |
195 | op->dest.offset = offset; | ||
196 | op->len = len; | ||
220 | 197 | ||
221 | npo->copy_off += *len; | 198 | queue->rx_copy.idx[queue->rx_copy.num] = queue->rx.req_cons; |
222 | info->meta->size += *len; | 199 | queue->rx_copy.num++; |
223 | |||
224 | if (!info->head) | ||
225 | return; | ||
226 | |||
227 | /* Leave a gap for the GSO descriptor. */ | ||
228 | if ((1 << info->gso_type) & queue->vif->gso_mask) | ||
229 | queue->rx.req_cons++; | ||
230 | |||
231 | /* Leave a gap for the hash extra segment. */ | ||
232 | if (info->hash_present) | ||
233 | queue->rx.req_cons++; | ||
234 | |||
235 | info->head = 0; /* There must be something in this buffer now */ | ||
236 | } | 200 | } |
237 | 201 | ||
238 | static void xenvif_gop_frag_copy_grant(unsigned long gfn, | 202 | static unsigned int xenvif_gso_type(struct sk_buff *skb) |
239 | unsigned int offset, | ||
240 | unsigned int len, | ||
241 | void *data) | ||
242 | { | 203 | { |
243 | unsigned int bytes; | ||
244 | |||
245 | while (len) { | ||
246 | bytes = len; | ||
247 | xenvif_setup_copy_gop(gfn, offset, &bytes, data); | ||
248 | offset += bytes; | ||
249 | len -= bytes; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | /* Set up the grant operations for this fragment. If it's a flipping | ||
254 | * interface, we also set up the unmap request from here. | ||
255 | */ | ||
256 | static void xenvif_gop_frag_copy(struct xenvif_queue *queue, | ||
257 | struct sk_buff *skb, | ||
258 | struct netrx_pending_operations *npo, | ||
259 | struct page *page, unsigned long size, | ||
260 | unsigned long offset, int *head) | ||
261 | { | ||
262 | struct gop_frag_copy info = { | ||
263 | .queue = queue, | ||
264 | .npo = npo, | ||
265 | .head = *head, | ||
266 | .gso_type = XEN_NETIF_GSO_TYPE_NONE, | ||
267 | /* xenvif_set_skb_hash() will have either set a s/w | ||
268 | * hash or cleared the hash depending on | ||
269 | * whether the the frontend wants a hash for this skb. | ||
270 | */ | ||
271 | .hash_present = skb->sw_hash, | ||
272 | }; | ||
273 | unsigned long bytes; | ||
274 | |||
275 | if (skb_is_gso(skb)) { | 204 | if (skb_is_gso(skb)) { |
276 | if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) | 205 | if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) |
277 | info.gso_type = XEN_NETIF_GSO_TYPE_TCPV4; | 206 | return XEN_NETIF_GSO_TYPE_TCPV4; |
278 | else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) | 207 | else |
279 | info.gso_type = XEN_NETIF_GSO_TYPE_TCPV6; | 208 | return XEN_NETIF_GSO_TYPE_TCPV6; |
280 | } | 209 | } |
210 | return XEN_NETIF_GSO_TYPE_NONE; | ||
211 | } | ||
281 | 212 | ||
282 | /* Data must not cross a page boundary. */ | 213 | struct xenvif_pkt_state { |
283 | WARN_ON(size + offset > (PAGE_SIZE << compound_order(page))); | 214 | struct sk_buff *skb; |
215 | size_t remaining_len; | ||
216 | int frag; /* frag == -1 => skb->head */ | ||
217 | unsigned int frag_offset; | ||
218 | struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; | ||
219 | unsigned int extra_count; | ||
220 | unsigned int slot; | ||
221 | }; | ||
284 | 222 | ||
285 | info.meta = npo->meta + npo->meta_prod - 1; | 223 | static void xenvif_rx_next_skb(struct xenvif_queue *queue, |
224 | struct xenvif_pkt_state *pkt) | ||
225 | { | ||
226 | struct sk_buff *skb; | ||
227 | unsigned int gso_type; | ||
286 | 228 | ||
287 | /* Skip unused frames from start of page */ | 229 | skb = xenvif_rx_dequeue(queue); |
288 | page += offset >> PAGE_SHIFT; | ||
289 | offset &= ~PAGE_MASK; | ||
290 | 230 | ||
291 | while (size > 0) { | 231 | queue->stats.tx_bytes += skb->len; |
292 | WARN_ON(offset >= PAGE_SIZE); | 232 | queue->stats.tx_packets++; |
293 | 233 | ||
294 | bytes = PAGE_SIZE - offset; | 234 | /* Reset packet state. */ |
295 | if (bytes > size) | 235 | memset(pkt, 0, sizeof(struct xenvif_pkt_state)); |
296 | bytes = size; | ||
297 | 236 | ||
298 | info.page = page; | 237 | pkt->skb = skb; |
299 | gnttab_foreach_grant_in_range(page, offset, bytes, | 238 | pkt->remaining_len = skb->len; |
300 | xenvif_gop_frag_copy_grant, | 239 | pkt->frag = -1; |
301 | &info); | ||
302 | size -= bytes; | ||
303 | offset = 0; | ||
304 | 240 | ||
305 | /* Next page */ | 241 | gso_type = xenvif_gso_type(skb); |
306 | if (size) { | 242 | if ((1 << gso_type) & queue->vif->gso_mask) { |
307 | WARN_ON(!PageCompound(page)); | 243 | struct xen_netif_extra_info *extra; |
308 | page++; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | *head = info.head; | ||
313 | } | ||
314 | 244 | ||
315 | /* Prepare an SKB to be transmitted to the frontend. | 245 | extra = &pkt->extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; |
316 | * | ||
317 | * This function is responsible for allocating grant operations, meta | ||
318 | * structures, etc. | ||
319 | * | ||
320 | * It returns the number of meta structures consumed. The number of | ||
321 | * ring slots used is always equal to the number of meta slots used | ||
322 | * plus the number of GSO descriptors used. Currently, we use either | ||
323 | * zero GSO descriptors (for non-GSO packets) or one descriptor (for | ||
324 | * frontend-side LRO). | ||
325 | */ | ||
326 | static int xenvif_gop_skb(struct sk_buff *skb, | ||
327 | struct netrx_pending_operations *npo, | ||
328 | struct xenvif_queue *queue) | ||
329 | { | ||
330 | struct xenvif *vif = netdev_priv(skb->dev); | ||
331 | int nr_frags = skb_shinfo(skb)->nr_frags; | ||
332 | int i; | ||
333 | struct xen_netif_rx_request req; | ||
334 | struct xenvif_rx_meta *meta; | ||
335 | unsigned char *data; | ||
336 | int head = 1; | ||
337 | int old_meta_prod; | ||
338 | int gso_type; | ||
339 | |||
340 | old_meta_prod = npo->meta_prod; | ||
341 | |||
342 | gso_type = XEN_NETIF_GSO_TYPE_NONE; | ||
343 | if (skb_is_gso(skb)) { | ||
344 | if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) | ||
345 | gso_type = XEN_NETIF_GSO_TYPE_TCPV4; | ||
346 | else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) | ||
347 | gso_type = XEN_NETIF_GSO_TYPE_TCPV6; | ||
348 | } | ||
349 | 246 | ||
350 | RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req); | 247 | extra->u.gso.type = gso_type; |
351 | meta = npo->meta + npo->meta_prod++; | 248 | extra->u.gso.size = skb_shinfo(skb)->gso_size; |
249 | extra->u.gso.pad = 0; | ||
250 | extra->u.gso.features = 0; | ||
251 | extra->type = XEN_NETIF_EXTRA_TYPE_GSO; | ||
252 | extra->flags = 0; | ||
352 | 253 | ||
353 | if ((1 << gso_type) & vif->gso_mask) { | 254 | pkt->extra_count++; |
354 | meta->gso_type = gso_type; | ||
355 | meta->gso_size = skb_shinfo(skb)->gso_size; | ||
356 | } else { | ||
357 | meta->gso_type = XEN_NETIF_GSO_TYPE_NONE; | ||
358 | meta->gso_size = 0; | ||
359 | } | 255 | } |
360 | 256 | ||
361 | meta->size = 0; | 257 | if (skb->sw_hash) { |
362 | meta->id = req.id; | 258 | struct xen_netif_extra_info *extra; |
363 | npo->copy_off = 0; | ||
364 | npo->copy_gref = req.gref; | ||
365 | 259 | ||
366 | data = skb->data; | 260 | extra = &pkt->extras[XEN_NETIF_EXTRA_TYPE_HASH - 1]; |
367 | while (data < skb_tail_pointer(skb)) { | ||
368 | unsigned int offset = offset_in_page(data); | ||
369 | unsigned int len = PAGE_SIZE - offset; | ||
370 | 261 | ||
371 | if (data + len > skb_tail_pointer(skb)) | 262 | extra->u.hash.algorithm = |
372 | len = skb_tail_pointer(skb) - data; | 263 | XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ; |
373 | 264 | ||
374 | xenvif_gop_frag_copy(queue, skb, npo, | 265 | if (skb->l4_hash) |
375 | virt_to_page(data), len, offset, &head); | 266 | extra->u.hash.type = |
376 | data += len; | 267 | skb->protocol == htons(ETH_P_IP) ? |
377 | } | 268 | _XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP : |
269 | _XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP; | ||
270 | else | ||
271 | extra->u.hash.type = | ||
272 | skb->protocol == htons(ETH_P_IP) ? | ||
273 | _XEN_NETIF_CTRL_HASH_TYPE_IPV4 : | ||
274 | _XEN_NETIF_CTRL_HASH_TYPE_IPV6; | ||
378 | 275 | ||
379 | for (i = 0; i < nr_frags; i++) { | 276 | *(uint32_t *)extra->u.hash.value = skb_get_hash_raw(skb); |
380 | xenvif_gop_frag_copy(queue, skb, npo, | ||
381 | skb_frag_page(&skb_shinfo(skb)->frags[i]), | ||
382 | skb_frag_size(&skb_shinfo(skb)->frags[i]), | ||
383 | skb_shinfo(skb)->frags[i].page_offset, | ||
384 | &head); | ||
385 | } | ||
386 | 277 | ||
387 | return npo->meta_prod - old_meta_prod; | 278 | extra->type = XEN_NETIF_EXTRA_TYPE_HASH; |
388 | } | 279 | extra->flags = 0; |
389 | 280 | ||
390 | /* This is a twin to xenvif_gop_skb. Assume that xenvif_gop_skb was | 281 | pkt->extra_count++; |
391 | * used to set up the operations on the top of | ||
392 | * netrx_pending_operations, which have since been done. Check that | ||
393 | * they didn't give any errors and advance over them. | ||
394 | */ | ||
395 | static int xenvif_check_gop(struct xenvif *vif, int nr_meta_slots, | ||
396 | struct netrx_pending_operations *npo) | ||
397 | { | ||
398 | struct gnttab_copy *copy_op; | ||
399 | int status = XEN_NETIF_RSP_OKAY; | ||
400 | int i; | ||
401 | |||
402 | for (i = 0; i < nr_meta_slots; i++) { | ||
403 | copy_op = npo->copy + npo->copy_cons++; | ||
404 | if (copy_op->status != GNTST_okay) { | ||
405 | netdev_dbg(vif->dev, | ||
406 | "Bad status %d from copy to DOM%d.\n", | ||
407 | copy_op->status, vif->domid); | ||
408 | status = XEN_NETIF_RSP_ERROR; | ||
409 | } | ||
410 | } | 282 | } |
411 | |||
412 | return status; | ||
413 | } | 283 | } |
414 | 284 | ||
415 | static struct xen_netif_rx_response *make_rx_response( | 285 | static void xenvif_rx_complete(struct xenvif_queue *queue, |
416 | struct xenvif_queue *queue, u16 id, s8 st, u16 offset, u16 size, | 286 | struct xenvif_pkt_state *pkt) |
417 | u16 flags) | ||
418 | { | 287 | { |
419 | RING_IDX i = queue->rx.rsp_prod_pvt; | 288 | int notify; |
420 | struct xen_netif_rx_response *resp; | ||
421 | 289 | ||
422 | resp = RING_GET_RESPONSE(&queue->rx, i); | 290 | /* Complete any outstanding copy ops for this skb. */ |
423 | resp->offset = offset; | 291 | xenvif_rx_copy_flush(queue); |
424 | resp->flags = flags; | ||
425 | resp->id = id; | ||
426 | resp->status = (s16)size; | ||
427 | if (st < 0) | ||
428 | resp->status = (s16)st; | ||
429 | 292 | ||
430 | queue->rx.rsp_prod_pvt = ++i; | 293 | /* Push responses and notify. */ |
294 | queue->rx.rsp_prod_pvt = queue->rx.req_cons; | ||
295 | RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->rx, notify); | ||
296 | if (notify) | ||
297 | notify_remote_via_irq(queue->rx_irq); | ||
431 | 298 | ||
432 | return resp; | 299 | dev_kfree_skb(pkt->skb); |
433 | } | 300 | } |
434 | 301 | ||
435 | static void xenvif_add_frag_responses(struct xenvif_queue *queue, | 302 | static void xenvif_rx_next_chunk(struct xenvif_queue *queue, |
436 | int status, | 303 | struct xenvif_pkt_state *pkt, |
437 | struct xenvif_rx_meta *meta, | 304 | unsigned int offset, void **data, |
438 | int nr_meta_slots) | 305 | size_t *len) |
439 | { | 306 | { |
440 | int i; | 307 | struct sk_buff *skb = pkt->skb; |
441 | unsigned long offset; | 308 | void *frag_data; |
309 | size_t frag_len, chunk_len; | ||
442 | 310 | ||
443 | /* No fragments used */ | 311 | if (pkt->frag == -1) { |
444 | if (nr_meta_slots <= 1) | 312 | frag_data = skb->data; |
445 | return; | 313 | frag_len = skb_headlen(skb); |
446 | 314 | } else { | |
447 | nr_meta_slots--; | 315 | skb_frag_t *frag = &skb_shinfo(skb)->frags[pkt->frag]; |
448 | |||
449 | for (i = 0; i < nr_meta_slots; i++) { | ||
450 | int flags; | ||
451 | |||
452 | if (i == nr_meta_slots - 1) | ||
453 | flags = 0; | ||
454 | else | ||
455 | flags = XEN_NETRXF_more_data; | ||
456 | 316 | ||
457 | offset = 0; | 317 | frag_data = skb_frag_address(frag); |
458 | make_rx_response(queue, meta[i].id, status, offset, | 318 | frag_len = skb_frag_size(frag); |
459 | meta[i].size, flags); | ||
460 | } | 319 | } |
461 | } | ||
462 | |||
463 | static void xenvif_rx_action(struct xenvif_queue *queue) | ||
464 | { | ||
465 | struct xenvif *vif = queue->vif; | ||
466 | s8 status; | ||
467 | u16 flags; | ||
468 | struct xen_netif_rx_response *resp; | ||
469 | struct sk_buff_head rxq; | ||
470 | struct sk_buff *skb; | ||
471 | LIST_HEAD(notify); | ||
472 | int ret; | ||
473 | unsigned long offset; | ||
474 | bool need_to_notify = false; | ||
475 | 320 | ||
476 | struct netrx_pending_operations npo = { | 321 | frag_data += pkt->frag_offset; |
477 | .copy = queue->grant_copy_op, | 322 | frag_len -= pkt->frag_offset; |
478 | .meta = queue->meta, | ||
479 | }; | ||
480 | 323 | ||
481 | skb_queue_head_init(&rxq); | 324 | chunk_len = min(frag_len, XEN_PAGE_SIZE - offset); |
325 | chunk_len = min(chunk_len, | ||
326 | XEN_PAGE_SIZE - xen_offset_in_page(frag_data)); | ||
482 | 327 | ||
483 | while (xenvif_rx_ring_slots_available(queue) && | 328 | pkt->frag_offset += chunk_len; |
484 | (skb = xenvif_rx_dequeue(queue)) != NULL) { | ||
485 | queue->last_rx_time = jiffies; | ||
486 | 329 | ||
487 | XENVIF_RX_CB(skb)->meta_slots_used = | 330 | /* Advance to next frag? */ |
488 | xenvif_gop_skb(skb, &npo, queue); | 331 | if (frag_len == chunk_len) { |
489 | 332 | pkt->frag++; | |
490 | __skb_queue_tail(&rxq, skb); | 333 | pkt->frag_offset = 0; |
491 | } | 334 | } |
492 | 335 | ||
493 | WARN_ON(npo.meta_prod > ARRAY_SIZE(queue->meta)); | 336 | *data = frag_data; |
337 | *len = chunk_len; | ||
338 | } | ||
339 | |||
340 | static void xenvif_rx_data_slot(struct xenvif_queue *queue, | ||
341 | struct xenvif_pkt_state *pkt, | ||
342 | struct xen_netif_rx_request *req, | ||
343 | struct xen_netif_rx_response *rsp) | ||
344 | { | ||
345 | unsigned int offset = 0; | ||
346 | unsigned int flags; | ||
494 | 347 | ||
495 | if (!npo.copy_prod) | 348 | do { |
496 | goto done; | 349 | size_t len; |
350 | void *data; | ||
497 | 351 | ||
498 | WARN_ON(npo.copy_prod > MAX_GRANT_COPY_OPS); | 352 | xenvif_rx_next_chunk(queue, pkt, offset, &data, &len); |
499 | gnttab_batch_copy(queue->grant_copy_op, npo.copy_prod); | 353 | xenvif_rx_copy_add(queue, req, offset, data, len); |
500 | 354 | ||
501 | while ((skb = __skb_dequeue(&rxq)) != NULL) { | 355 | offset += len; |
502 | struct xen_netif_extra_info *extra = NULL; | 356 | pkt->remaining_len -= len; |
503 | 357 | ||
504 | queue->stats.tx_bytes += skb->len; | 358 | } while (offset < XEN_PAGE_SIZE && pkt->remaining_len > 0); |
505 | queue->stats.tx_packets++; | ||
506 | 359 | ||
507 | status = xenvif_check_gop(vif, | 360 | if (pkt->remaining_len > 0) |
508 | XENVIF_RX_CB(skb)->meta_slots_used, | 361 | flags = XEN_NETRXF_more_data; |
509 | &npo); | 362 | else |
363 | flags = 0; | ||
510 | 364 | ||
511 | if (XENVIF_RX_CB(skb)->meta_slots_used == 1) | 365 | if (pkt->slot == 0) { |
512 | flags = 0; | 366 | struct sk_buff *skb = pkt->skb; |
513 | else | ||
514 | flags = XEN_NETRXF_more_data; | ||
515 | 367 | ||
516 | if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */ | 368 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
517 | flags |= XEN_NETRXF_csum_blank | | 369 | flags |= XEN_NETRXF_csum_blank | |
518 | XEN_NETRXF_data_validated; | 370 | XEN_NETRXF_data_validated; |
519 | else if (skb->ip_summed == CHECKSUM_UNNECESSARY) | 371 | else if (skb->ip_summed == CHECKSUM_UNNECESSARY) |
520 | /* remote but checksummed. */ | ||
521 | flags |= XEN_NETRXF_data_validated; | 372 | flags |= XEN_NETRXF_data_validated; |
522 | 373 | ||
523 | offset = 0; | 374 | if (pkt->extra_count != 0) |
524 | resp = make_rx_response(queue, queue->meta[npo.meta_cons].id, | 375 | flags |= XEN_NETRXF_extra_info; |
525 | status, offset, | 376 | } |
526 | queue->meta[npo.meta_cons].size, | ||
527 | flags); | ||
528 | 377 | ||
529 | if ((1 << queue->meta[npo.meta_cons].gso_type) & | 378 | rsp->offset = 0; |
530 | vif->gso_mask) { | 379 | rsp->flags = flags; |
531 | extra = (struct xen_netif_extra_info *) | 380 | rsp->id = req->id; |
532 | RING_GET_RESPONSE(&queue->rx, | 381 | rsp->status = (s16)offset; |
533 | queue->rx.rsp_prod_pvt++); | 382 | } |
534 | 383 | ||
535 | resp->flags |= XEN_NETRXF_extra_info; | 384 | static void xenvif_rx_extra_slot(struct xenvif_queue *queue, |
385 | struct xenvif_pkt_state *pkt, | ||
386 | struct xen_netif_rx_request *req, | ||
387 | struct xen_netif_rx_response *rsp) | ||
388 | { | ||
389 | struct xen_netif_extra_info *extra = (void *)rsp; | ||
390 | unsigned int i; | ||
536 | 391 | ||
537 | extra->u.gso.type = queue->meta[npo.meta_cons].gso_type; | 392 | pkt->extra_count--; |
538 | extra->u.gso.size = queue->meta[npo.meta_cons].gso_size; | ||
539 | extra->u.gso.pad = 0; | ||
540 | extra->u.gso.features = 0; | ||
541 | 393 | ||
542 | extra->type = XEN_NETIF_EXTRA_TYPE_GSO; | 394 | for (i = 0; i < ARRAY_SIZE(pkt->extras); i++) { |
543 | extra->flags = 0; | 395 | if (pkt->extras[i].type) { |
544 | } | 396 | *extra = pkt->extras[i]; |
545 | 397 | ||
546 | if (skb->sw_hash) { | 398 | if (pkt->extra_count != 0) |
547 | /* Since the skb got here via xenvif_select_queue() | ||
548 | * we know that the hash has been re-calculated | ||
549 | * according to a configuration set by the frontend | ||
550 | * and therefore we know that it is legitimate to | ||
551 | * pass it to the frontend. | ||
552 | */ | ||
553 | if (resp->flags & XEN_NETRXF_extra_info) | ||
554 | extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE; | 399 | extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE; |
555 | else | 400 | |
556 | resp->flags |= XEN_NETRXF_extra_info; | 401 | pkt->extras[i].type = 0; |
557 | 402 | return; | |
558 | extra = (struct xen_netif_extra_info *) | ||
559 | RING_GET_RESPONSE(&queue->rx, | ||
560 | queue->rx.rsp_prod_pvt++); | ||
561 | |||
562 | extra->u.hash.algorithm = | ||
563 | XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ; | ||
564 | |||
565 | if (skb->l4_hash) | ||
566 | extra->u.hash.type = | ||
567 | skb->protocol == htons(ETH_P_IP) ? | ||
568 | _XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP : | ||
569 | _XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP; | ||
570 | else | ||
571 | extra->u.hash.type = | ||
572 | skb->protocol == htons(ETH_P_IP) ? | ||
573 | _XEN_NETIF_CTRL_HASH_TYPE_IPV4 : | ||
574 | _XEN_NETIF_CTRL_HASH_TYPE_IPV6; | ||
575 | |||
576 | *(uint32_t *)extra->u.hash.value = | ||
577 | skb_get_hash_raw(skb); | ||
578 | |||
579 | extra->type = XEN_NETIF_EXTRA_TYPE_HASH; | ||
580 | extra->flags = 0; | ||
581 | } | 403 | } |
404 | } | ||
405 | BUG(); | ||
406 | } | ||
582 | 407 | ||
583 | xenvif_add_frag_responses(queue, status, | 408 | void xenvif_rx_action(struct xenvif_queue *queue) |
584 | queue->meta + npo.meta_cons + 1, | 409 | { |
585 | XENVIF_RX_CB(skb)->meta_slots_used); | 410 | struct xenvif_pkt_state pkt; |
586 | 411 | ||
587 | RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->rx, ret); | 412 | xenvif_rx_next_skb(queue, &pkt); |
588 | 413 | ||
589 | need_to_notify |= !!ret; | 414 | do { |
415 | struct xen_netif_rx_request *req; | ||
416 | struct xen_netif_rx_response *rsp; | ||
590 | 417 | ||
591 | npo.meta_cons += XENVIF_RX_CB(skb)->meta_slots_used; | 418 | req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons); |
592 | dev_kfree_skb(skb); | 419 | rsp = RING_GET_RESPONSE(&queue->rx, queue->rx.req_cons); |
593 | } | ||
594 | 420 | ||
595 | done: | 421 | /* Extras must go after the first data slot */ |
596 | if (need_to_notify) | 422 | if (pkt.slot != 0 && pkt.extra_count != 0) |
597 | notify_remote_via_irq(queue->rx_irq); | 423 | xenvif_rx_extra_slot(queue, &pkt, req, rsp); |
424 | else | ||
425 | xenvif_rx_data_slot(queue, &pkt, req, rsp); | ||
426 | |||
427 | queue->rx.req_cons++; | ||
428 | pkt.slot++; | ||
429 | } while (pkt.remaining_len > 0 || pkt.extra_count != 0); | ||
430 | |||
431 | xenvif_rx_complete(queue, &pkt); | ||
598 | } | 432 | } |
599 | 433 | ||
600 | static bool xenvif_rx_queue_stalled(struct xenvif_queue *queue) | 434 | static bool xenvif_rx_queue_stalled(struct xenvif_queue *queue) |