diff options
| author | Ralf Baechle <ralf@linux-mips.org> | 2014-06-04 16:53:02 -0400 |
|---|---|---|
| committer | Ralf Baechle <ralf@linux-mips.org> | 2014-06-04 16:53:02 -0400 |
| commit | f8647b506d7116a1a3accd8d618184096e85f50b (patch) | |
| tree | f10bc7201fda2a36c035548a0ea62210ad57adb6 /drivers/net/xen-netback | |
| parent | 1d421ca9d7edbac1eb118631ee039d50ab54771e (diff) | |
| parent | f7a89f1b8eb598ac5da61c9795b3d847baa73d12 (diff) | |
Merge branch '3.15-fixes' into mips-for-linux-next
Diffstat (limited to 'drivers/net/xen-netback')
| -rw-r--r-- | drivers/net/xen-netback/common.h | 2 | ||||
| -rw-r--r-- | drivers/net/xen-netback/interface.c | 30 | ||||
| -rw-r--r-- | drivers/net/xen-netback/netback.c | 102 |
3 files changed, 86 insertions, 48 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 630a3fcf65bc..0d4a285cbd7e 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h | |||
| @@ -226,7 +226,7 @@ int xenvif_map_frontend_rings(struct xenvif *vif, | |||
| 226 | grant_ref_t rx_ring_ref); | 226 | grant_ref_t rx_ring_ref); |
| 227 | 227 | ||
| 228 | /* Check for SKBs from frontend and schedule backend processing */ | 228 | /* Check for SKBs from frontend and schedule backend processing */ |
| 229 | void xenvif_check_rx_xenvif(struct xenvif *vif); | 229 | void xenvif_napi_schedule_or_enable_events(struct xenvif *vif); |
| 230 | 230 | ||
| 231 | /* Prevent the device from generating any further traffic. */ | 231 | /* Prevent the device from generating any further traffic. */ |
| 232 | void xenvif_carrier_off(struct xenvif *vif); | 232 | void xenvif_carrier_off(struct xenvif *vif); |
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index ef05c5c49d41..20e9defa1060 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c | |||
| @@ -75,32 +75,8 @@ static int xenvif_poll(struct napi_struct *napi, int budget) | |||
| 75 | work_done = xenvif_tx_action(vif, budget); | 75 | work_done = xenvif_tx_action(vif, budget); |
| 76 | 76 | ||
| 77 | if (work_done < budget) { | 77 | if (work_done < budget) { |
| 78 | int more_to_do = 0; | 78 | napi_complete(napi); |
| 79 | unsigned long flags; | 79 | xenvif_napi_schedule_or_enable_events(vif); |
| 80 | |||
| 81 | /* It is necessary to disable IRQ before calling | ||
| 82 | * RING_HAS_UNCONSUMED_REQUESTS. Otherwise we might | ||
| 83 | * lose event from the frontend. | ||
| 84 | * | ||
| 85 | * Consider: | ||
| 86 | * RING_HAS_UNCONSUMED_REQUESTS | ||
| 87 | * <frontend generates event to trigger napi_schedule> | ||
| 88 | * __napi_complete | ||
| 89 | * | ||
| 90 | * This handler is still in scheduled state so the | ||
| 91 | * event has no effect at all. After __napi_complete | ||
| 92 | * this handler is descheduled and cannot get | ||
| 93 | * scheduled again. We lose event in this case and the ring | ||
| 94 | * will be completely stalled. | ||
| 95 | */ | ||
| 96 | |||
| 97 | local_irq_save(flags); | ||
| 98 | |||
| 99 | RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do); | ||
| 100 | if (!more_to_do) | ||
| 101 | __napi_complete(napi); | ||
| 102 | |||
| 103 | local_irq_restore(flags); | ||
| 104 | } | 80 | } |
| 105 | 81 | ||
| 106 | return work_done; | 82 | return work_done; |
| @@ -194,7 +170,7 @@ static void xenvif_up(struct xenvif *vif) | |||
| 194 | enable_irq(vif->tx_irq); | 170 | enable_irq(vif->tx_irq); |
| 195 | if (vif->tx_irq != vif->rx_irq) | 171 | if (vif->tx_irq != vif->rx_irq) |
| 196 | enable_irq(vif->rx_irq); | 172 | enable_irq(vif->rx_irq); |
| 197 | xenvif_check_rx_xenvif(vif); | 173 | xenvif_napi_schedule_or_enable_events(vif); |
| 198 | } | 174 | } |
| 199 | 175 | ||
| 200 | static void xenvif_down(struct xenvif *vif) | 176 | static void xenvif_down(struct xenvif *vif) |
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 76665405c5aa..7367208ee8cd 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
| @@ -104,7 +104,7 @@ static inline unsigned long idx_to_kaddr(struct xenvif *vif, | |||
| 104 | 104 | ||
| 105 | /* Find the containing VIF's structure from a pointer in pending_tx_info array | 105 | /* Find the containing VIF's structure from a pointer in pending_tx_info array |
| 106 | */ | 106 | */ |
| 107 | static inline struct xenvif* ubuf_to_vif(struct ubuf_info *ubuf) | 107 | static inline struct xenvif *ubuf_to_vif(const struct ubuf_info *ubuf) |
| 108 | { | 108 | { |
| 109 | u16 pending_idx = ubuf->desc; | 109 | u16 pending_idx = ubuf->desc; |
| 110 | struct pending_tx_info *temp = | 110 | struct pending_tx_info *temp = |
| @@ -323,6 +323,35 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, | |||
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | /* | 325 | /* |
| 326 | * Find the grant ref for a given frag in a chain of struct ubuf_info's | ||
| 327 | * skb: the skb itself | ||
| 328 | * i: the frag's number | ||
| 329 | * ubuf: a pointer to an element in the chain. It should not be NULL | ||
| 330 | * | ||
| 331 | * Returns a pointer to the element in the chain where the page were found. If | ||
| 332 | * not found, returns NULL. | ||
| 333 | * See the definition of callback_struct in common.h for more details about | ||
| 334 | * the chain. | ||
| 335 | */ | ||
| 336 | static const struct ubuf_info *xenvif_find_gref(const struct sk_buff *const skb, | ||
| 337 | const int i, | ||
| 338 | const struct ubuf_info *ubuf) | ||
| 339 | { | ||
| 340 | struct xenvif *foreign_vif = ubuf_to_vif(ubuf); | ||
| 341 | |||
| 342 | do { | ||
| 343 | u16 pending_idx = ubuf->desc; | ||
| 344 | |||
| 345 | if (skb_shinfo(skb)->frags[i].page.p == | ||
| 346 | foreign_vif->mmap_pages[pending_idx]) | ||
| 347 | break; | ||
| 348 | ubuf = (struct ubuf_info *) ubuf->ctx; | ||
| 349 | } while (ubuf); | ||
| 350 | |||
| 351 | return ubuf; | ||
| 352 | } | ||
| 353 | |||
| 354 | /* | ||
| 326 | * Prepare an SKB to be transmitted to the frontend. | 355 | * Prepare an SKB to be transmitted to the frontend. |
| 327 | * | 356 | * |
| 328 | * This function is responsible for allocating grant operations, meta | 357 | * This function is responsible for allocating grant operations, meta |
| @@ -346,9 +375,8 @@ static int xenvif_gop_skb(struct sk_buff *skb, | |||
| 346 | int head = 1; | 375 | int head = 1; |
| 347 | int old_meta_prod; | 376 | int old_meta_prod; |
| 348 | int gso_type; | 377 | int gso_type; |
| 349 | struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg; | 378 | const struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg; |
| 350 | grant_ref_t foreign_grefs[MAX_SKB_FRAGS]; | 379 | const struct ubuf_info *const head_ubuf = ubuf; |
| 351 | struct xenvif *foreign_vif = NULL; | ||
| 352 | 380 | ||
| 353 | old_meta_prod = npo->meta_prod; | 381 | old_meta_prod = npo->meta_prod; |
| 354 | 382 | ||
| @@ -386,19 +414,6 @@ static int xenvif_gop_skb(struct sk_buff *skb, | |||
| 386 | npo->copy_off = 0; | 414 | npo->copy_off = 0; |
| 387 | npo->copy_gref = req->gref; | 415 | npo->copy_gref = req->gref; |
| 388 | 416 | ||
| 389 | if ((skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) && | ||
| 390 | (ubuf->callback == &xenvif_zerocopy_callback)) { | ||
| 391 | int i = 0; | ||
| 392 | foreign_vif = ubuf_to_vif(ubuf); | ||
| 393 | |||
| 394 | do { | ||
| 395 | u16 pending_idx = ubuf->desc; | ||
| 396 | foreign_grefs[i++] = | ||
| 397 | foreign_vif->pending_tx_info[pending_idx].req.gref; | ||
| 398 | ubuf = (struct ubuf_info *) ubuf->ctx; | ||
| 399 | } while (ubuf); | ||
| 400 | } | ||
| 401 | |||
| 402 | data = skb->data; | 417 | data = skb->data; |
| 403 | while (data < skb_tail_pointer(skb)) { | 418 | while (data < skb_tail_pointer(skb)) { |
| 404 | unsigned int offset = offset_in_page(data); | 419 | unsigned int offset = offset_in_page(data); |
| @@ -415,13 +430,60 @@ static int xenvif_gop_skb(struct sk_buff *skb, | |||
| 415 | } | 430 | } |
| 416 | 431 | ||
| 417 | for (i = 0; i < nr_frags; i++) { | 432 | for (i = 0; i < nr_frags; i++) { |
| 433 | /* This variable also signals whether foreign_gref has a real | ||
| 434 | * value or not. | ||
| 435 | */ | ||
| 436 | struct xenvif *foreign_vif = NULL; | ||
| 437 | grant_ref_t foreign_gref; | ||
| 438 | |||
| 439 | if ((skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) && | ||
| 440 | (ubuf->callback == &xenvif_zerocopy_callback)) { | ||
| 441 | const struct ubuf_info *const startpoint = ubuf; | ||
| 442 | |||
| 443 | /* Ideally ubuf points to the chain element which | ||
| 444 | * belongs to this frag. Or if frags were removed from | ||
| 445 | * the beginning, then shortly before it. | ||
| 446 | */ | ||
| 447 | ubuf = xenvif_find_gref(skb, i, ubuf); | ||
| 448 | |||
| 449 | /* Try again from the beginning of the list, if we | ||
| 450 | * haven't tried from there. This only makes sense in | ||
| 451 | * the unlikely event of reordering the original frags. | ||
| 452 | * For injected local pages it's an unnecessary second | ||
| 453 | * run. | ||
| 454 | */ | ||
| 455 | if (unlikely(!ubuf) && startpoint != head_ubuf) | ||
| 456 | ubuf = xenvif_find_gref(skb, i, head_ubuf); | ||
| 457 | |||
| 458 | if (likely(ubuf)) { | ||
| 459 | u16 pending_idx = ubuf->desc; | ||
| 460 | |||
| 461 | foreign_vif = ubuf_to_vif(ubuf); | ||
| 462 | foreign_gref = foreign_vif->pending_tx_info[pending_idx].req.gref; | ||
| 463 | /* Just a safety measure. If this was the last | ||
| 464 | * element on the list, the for loop will | ||
| 465 | * iterate again if a local page were added to | ||
| 466 | * the end. Using head_ubuf here prevents the | ||
| 467 | * second search on the chain. Or the original | ||
| 468 | * frags changed order, but that's less likely. | ||
| 469 | * In any way, ubuf shouldn't be NULL. | ||
| 470 | */ | ||
| 471 | ubuf = ubuf->ctx ? | ||
| 472 | (struct ubuf_info *) ubuf->ctx : | ||
| 473 | head_ubuf; | ||
| 474 | } else | ||
| 475 | /* This frag was a local page, added to the | ||
| 476 | * array after the skb left netback. | ||
| 477 | */ | ||
| 478 | ubuf = head_ubuf; | ||
| 479 | } | ||
| 418 | xenvif_gop_frag_copy(vif, skb, npo, | 480 | xenvif_gop_frag_copy(vif, skb, npo, |
| 419 | skb_frag_page(&skb_shinfo(skb)->frags[i]), | 481 | skb_frag_page(&skb_shinfo(skb)->frags[i]), |
| 420 | skb_frag_size(&skb_shinfo(skb)->frags[i]), | 482 | skb_frag_size(&skb_shinfo(skb)->frags[i]), |
| 421 | skb_shinfo(skb)->frags[i].page_offset, | 483 | skb_shinfo(skb)->frags[i].page_offset, |
| 422 | &head, | 484 | &head, |
| 423 | foreign_vif, | 485 | foreign_vif, |
| 424 | foreign_grefs[i]); | 486 | foreign_vif ? foreign_gref : UINT_MAX); |
| 425 | } | 487 | } |
| 426 | 488 | ||
| 427 | return npo->meta_prod - old_meta_prod; | 489 | return npo->meta_prod - old_meta_prod; |
| @@ -654,7 +716,7 @@ done: | |||
| 654 | notify_remote_via_irq(vif->rx_irq); | 716 | notify_remote_via_irq(vif->rx_irq); |
| 655 | } | 717 | } |
| 656 | 718 | ||
| 657 | void xenvif_check_rx_xenvif(struct xenvif *vif) | 719 | void xenvif_napi_schedule_or_enable_events(struct xenvif *vif) |
| 658 | { | 720 | { |
| 659 | int more_to_do; | 721 | int more_to_do; |
| 660 | 722 | ||
| @@ -688,7 +750,7 @@ static void tx_credit_callback(unsigned long data) | |||
| 688 | { | 750 | { |
| 689 | struct xenvif *vif = (struct xenvif *)data; | 751 | struct xenvif *vif = (struct xenvif *)data; |
| 690 | tx_add_credit(vif); | 752 | tx_add_credit(vif); |
| 691 | xenvif_check_rx_xenvif(vif); | 753 | xenvif_napi_schedule_or_enable_events(vif); |
| 692 | } | 754 | } |
| 693 | 755 | ||
| 694 | static void xenvif_tx_err(struct xenvif *vif, | 756 | static void xenvif_tx_err(struct xenvif *vif, |
