aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSowmini Varadhan <sowmini.varadhan@oracle.com>2014-10-25 15:12:12 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-25 16:20:15 -0400
commit69088822abe7a09145fc86e1d5dd4996e29abc2d (patch)
tree8a9d646a416fc472c68bc7e9c2c67727547f357a
parent132fb57984e4f4d49c79b2f0749236fe277de1f8 (diff)
sunvnet: NAPIfy sunvnet
Move Rx packet procssing to the NAPI poll callback. Disable VIO interrupt and unconditioanlly go into NAPI context from vnet_event. Note that we want to minimize the number of LDC STOP/START messages sent. Specifically, do not send a STOP message if vnet_walk_rx does not read all the available descriptors because of the NAPI budget limitation. Instead, note the end index as part of port state, and resume from this index when the next poll callback is triggered. Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> Acked-by: Raghuram Kothakota <raghuram.kothakota@oracle.com> Acked-by: Dwight Engen <dwight.engen@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c173
-rw-r--r--drivers/net/ethernet/sun/sunvnet.h6
2 files changed, 135 insertions, 44 deletions
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index 3652afd3ec78..9e048f501f24 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -311,9 +311,7 @@ static int vnet_rx_one(struct vnet_port *port, unsigned int len,
311 311
312 dev->stats.rx_packets++; 312 dev->stats.rx_packets++;
313 dev->stats.rx_bytes += len; 313 dev->stats.rx_bytes += len;
314 314 napi_gro_receive(&port->napi, skb);
315 netif_rx(skb);
316
317 return 0; 315 return 0;
318 316
319out_free_skb: 317out_free_skb:
@@ -430,6 +428,7 @@ static int vnet_walk_rx_one(struct vnet_port *port,
430 struct vio_driver_state *vio = &port->vio; 428 struct vio_driver_state *vio = &port->vio;
431 int err; 429 int err;
432 430
431 BUG_ON(desc == NULL);
433 if (IS_ERR(desc)) 432 if (IS_ERR(desc))
434 return PTR_ERR(desc); 433 return PTR_ERR(desc);
435 434
@@ -456,10 +455,11 @@ static int vnet_walk_rx_one(struct vnet_port *port,
456} 455}
457 456
458static int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr, 457static int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr,
459 u32 start, u32 end) 458 u32 start, u32 end, int *npkts, int budget)
460{ 459{
461 struct vio_driver_state *vio = &port->vio; 460 struct vio_driver_state *vio = &port->vio;
462 int ack_start = -1, ack_end = -1; 461 int ack_start = -1, ack_end = -1;
462 bool send_ack = true;
463 463
464 end = (end == (u32) -1) ? prev_idx(start, dr) : next_idx(end, dr); 464 end = (end == (u32) -1) ? prev_idx(start, dr) : next_idx(end, dr);
465 465
@@ -471,6 +471,7 @@ static int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr,
471 return err; 471 return err;
472 if (err != 0) 472 if (err != 0)
473 break; 473 break;
474 (*npkts)++;
474 if (ack_start == -1) 475 if (ack_start == -1)
475 ack_start = start; 476 ack_start = start;
476 ack_end = start; 477 ack_end = start;
@@ -482,13 +483,26 @@ static int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr,
482 return err; 483 return err;
483 ack_start = -1; 484 ack_start = -1;
484 } 485 }
486 if ((*npkts) >= budget) {
487 send_ack = false;
488 break;
489 }
485 } 490 }
486 if (unlikely(ack_start == -1)) 491 if (unlikely(ack_start == -1))
487 ack_start = ack_end = prev_idx(start, dr); 492 ack_start = ack_end = prev_idx(start, dr);
488 return vnet_send_ack(port, dr, ack_start, ack_end, VIO_DRING_STOPPED); 493 if (send_ack) {
494 port->napi_resume = false;
495 return vnet_send_ack(port, dr, ack_start, ack_end,
496 VIO_DRING_STOPPED);
497 } else {
498 port->napi_resume = true;
499 port->napi_stop_idx = ack_end;
500 return 1;
501 }
489} 502}
490 503
491static int vnet_rx(struct vnet_port *port, void *msgbuf) 504static int vnet_rx(struct vnet_port *port, void *msgbuf, int *npkts,
505 int budget)
492{ 506{
493 struct vio_dring_data *pkt = msgbuf; 507 struct vio_dring_data *pkt = msgbuf;
494 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_RX_RING]; 508 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_RX_RING];
@@ -505,11 +519,13 @@ static int vnet_rx(struct vnet_port *port, void *msgbuf)
505 return 0; 519 return 0;
506 } 520 }
507 521
508 dr->rcv_nxt++; 522 if (!port->napi_resume)
523 dr->rcv_nxt++;
509 524
510 /* XXX Validate pkt->start_idx and pkt->end_idx XXX */ 525 /* XXX Validate pkt->start_idx and pkt->end_idx XXX */
511 526
512 return vnet_walk_rx(port, dr, pkt->start_idx, pkt->end_idx); 527 return vnet_walk_rx(port, dr, pkt->start_idx, pkt->end_idx,
528 npkts, budget);
513} 529}
514 530
515static int idx_is_pending(struct vio_dring_state *dr, u32 end) 531static int idx_is_pending(struct vio_dring_state *dr, u32 end)
@@ -542,9 +558,12 @@ static int vnet_ack(struct vnet_port *port, void *msgbuf)
542 if (unlikely(!idx_is_pending(dr, end))) 558 if (unlikely(!idx_is_pending(dr, end)))
543 return 0; 559 return 0;
544 560
561 vp = port->vp;
562 dev = vp->dev;
545 /* sync for race conditions with vnet_start_xmit() and tell xmit it 563 /* sync for race conditions with vnet_start_xmit() and tell xmit it
546 * is time to send a trigger. 564 * is time to send a trigger.
547 */ 565 */
566 netif_tx_lock(dev);
548 dr->cons = next_idx(end, dr); 567 dr->cons = next_idx(end, dr);
549 desc = vio_dring_entry(dr, dr->cons); 568 desc = vio_dring_entry(dr, dr->cons);
550 if (desc->hdr.state == VIO_DESC_READY && port->start_cons) { 569 if (desc->hdr.state == VIO_DESC_READY && port->start_cons) {
@@ -559,10 +578,8 @@ static int vnet_ack(struct vnet_port *port, void *msgbuf)
559 } else { 578 } else {
560 port->start_cons = true; 579 port->start_cons = true;
561 } 580 }
581 netif_tx_unlock(dev);
562 582
563
564 vp = port->vp;
565 dev = vp->dev;
566 if (unlikely(netif_queue_stopped(dev) && 583 if (unlikely(netif_queue_stopped(dev) &&
567 vnet_tx_dring_avail(dr) >= VNET_TX_WAKEUP_THRESH(dr))) 584 vnet_tx_dring_avail(dr) >= VNET_TX_WAKEUP_THRESH(dr)))
568 return 1; 585 return 1;
@@ -591,9 +608,8 @@ static int handle_mcast(struct vnet_port *port, void *msgbuf)
591 return 0; 608 return 0;
592} 609}
593 610
594static void maybe_tx_wakeup(unsigned long param) 611static void maybe_tx_wakeup(struct vnet *vp)
595{ 612{
596 struct vnet *vp = (struct vnet *)param;
597 struct net_device *dev = vp->dev; 613 struct net_device *dev = vp->dev;
598 614
599 netif_tx_lock(dev); 615 netif_tx_lock(dev);
@@ -617,32 +633,43 @@ static void maybe_tx_wakeup(unsigned long param)
617 netif_tx_unlock(dev); 633 netif_tx_unlock(dev);
618} 634}
619 635
620static void vnet_event(void *arg, int event) 636static inline bool port_is_up(struct vnet_port *vnet)
637{
638 struct vio_driver_state *vio = &vnet->vio;
639
640 return !!(vio->hs_state & VIO_HS_COMPLETE);
641}
642
643static int vnet_event_napi(struct vnet_port *port, int budget)
621{ 644{
622 struct vnet_port *port = arg;
623 struct vio_driver_state *vio = &port->vio; 645 struct vio_driver_state *vio = &port->vio;
624 unsigned long flags;
625 int tx_wakeup, err; 646 int tx_wakeup, err;
647 int npkts = 0;
648 int event = (port->rx_event & LDC_EVENT_RESET);
626 649
627 spin_lock_irqsave(&vio->lock, flags); 650ldc_ctrl:
628
629 if (unlikely(event == LDC_EVENT_RESET || 651 if (unlikely(event == LDC_EVENT_RESET ||
630 event == LDC_EVENT_UP)) { 652 event == LDC_EVENT_UP)) {
631 vio_link_state_change(vio, event); 653 vio_link_state_change(vio, event);
632 spin_unlock_irqrestore(&vio->lock, flags);
633 654
634 if (event == LDC_EVENT_RESET) { 655 if (event == LDC_EVENT_RESET) {
635 port->rmtu = 0; 656 port->rmtu = 0;
636 vio_port_up(vio); 657 vio_port_up(vio);
637 } 658 }
638 return; 659 port->rx_event = 0;
660 return 0;
639 } 661 }
662 /* We may have multiple LDC events in rx_event. Unroll send_events() */
663 event = (port->rx_event & LDC_EVENT_UP);
664 port->rx_event &= ~(LDC_EVENT_RESET|LDC_EVENT_UP);
665 if (event == LDC_EVENT_UP)
666 goto ldc_ctrl;
667 event = port->rx_event;
668 if (!(event & LDC_EVENT_DATA_READY))
669 return 0;
640 670
641 if (unlikely(event != LDC_EVENT_DATA_READY)) { 671 /* we dont expect any other bits than RESET, UP, DATA_READY */
642 pr_warn("Unexpected LDC event %d\n", event); 672 BUG_ON(event != LDC_EVENT_DATA_READY);
643 spin_unlock_irqrestore(&vio->lock, flags);
644 return;
645 }
646 673
647 tx_wakeup = err = 0; 674 tx_wakeup = err = 0;
648 while (1) { 675 while (1) {
@@ -651,6 +678,21 @@ static void vnet_event(void *arg, int event)
651 u64 raw[8]; 678 u64 raw[8];
652 } msgbuf; 679 } msgbuf;
653 680
681 if (port->napi_resume) {
682 struct vio_dring_data *pkt =
683 (struct vio_dring_data *)&msgbuf;
684 struct vio_dring_state *dr =
685 &port->vio.drings[VIO_DRIVER_RX_RING];
686
687 pkt->tag.type = VIO_TYPE_DATA;
688 pkt->tag.stype = VIO_SUBTYPE_INFO;
689 pkt->tag.stype_env = VIO_DRING_DATA;
690 pkt->seq = dr->rcv_nxt;
691 pkt->start_idx = next_idx(port->napi_stop_idx, dr);
692 pkt->end_idx = -1;
693 goto napi_resume;
694 }
695ldc_read:
654 err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf)); 696 err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf));
655 if (unlikely(err < 0)) { 697 if (unlikely(err < 0)) {
656 if (err == -ECONNRESET) 698 if (err == -ECONNRESET)
@@ -667,10 +709,22 @@ static void vnet_event(void *arg, int event)
667 err = vio_validate_sid(vio, &msgbuf.tag); 709 err = vio_validate_sid(vio, &msgbuf.tag);
668 if (err < 0) 710 if (err < 0)
669 break; 711 break;
670 712napi_resume:
671 if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) { 713 if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) {
672 if (msgbuf.tag.stype == VIO_SUBTYPE_INFO) { 714 if (msgbuf.tag.stype == VIO_SUBTYPE_INFO) {
673 err = vnet_rx(port, &msgbuf); 715 if (!port_is_up(port)) {
716 /* failures like handshake_failure()
717 * may have cleaned up dring, but
718 * NAPI polling may bring us here.
719 */
720 err = -ECONNRESET;
721 break;
722 }
723 err = vnet_rx(port, &msgbuf, &npkts, budget);
724 if (npkts >= budget)
725 break;
726 if (npkts == 0 && err != -ECONNRESET)
727 goto ldc_read;
674 } else if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) { 728 } else if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) {
675 err = vnet_ack(port, &msgbuf); 729 err = vnet_ack(port, &msgbuf);
676 if (err > 0) 730 if (err > 0)
@@ -691,15 +745,33 @@ static void vnet_event(void *arg, int event)
691 if (err == -ECONNRESET) 745 if (err == -ECONNRESET)
692 break; 746 break;
693 } 747 }
694 spin_unlock(&vio->lock);
695 /* Kick off a tasklet to wake the queue. We cannot call
696 * maybe_tx_wakeup directly here because we could deadlock on
697 * netif_tx_lock() with dev_watchdog()
698 */
699 if (unlikely(tx_wakeup && err != -ECONNRESET)) 748 if (unlikely(tx_wakeup && err != -ECONNRESET))
700 tasklet_schedule(&port->vp->vnet_tx_wakeup); 749 maybe_tx_wakeup(port->vp);
750 return npkts;
751}
752
753static int vnet_poll(struct napi_struct *napi, int budget)
754{
755 struct vnet_port *port = container_of(napi, struct vnet_port, napi);
756 struct vio_driver_state *vio = &port->vio;
757 int processed = vnet_event_napi(port, budget);
758
759 if (processed < budget) {
760 napi_complete(napi);
761 vio_set_intr(vio->vdev->rx_ino, HV_INTR_ENABLED);
762 }
763 return processed;
764}
765
766static void vnet_event(void *arg, int event)
767{
768 struct vnet_port *port = arg;
769 struct vio_driver_state *vio = &port->vio;
770
771 port->rx_event |= event;
772 vio_set_intr(vio->vdev->rx_ino, HV_INTR_DISABLED);
773 napi_schedule(&port->napi);
701 774
702 local_irq_restore(flags);
703} 775}
704 776
705static int __vnet_tx_trigger(struct vnet_port *port, u32 start) 777static int __vnet_tx_trigger(struct vnet_port *port, u32 start)
@@ -746,13 +818,6 @@ static int __vnet_tx_trigger(struct vnet_port *port, u32 start)
746 return err; 818 return err;
747} 819}
748 820
749static inline bool port_is_up(struct vnet_port *vnet)
750{
751 struct vio_driver_state *vio = &vnet->vio;
752
753 return !!(vio->hs_state & VIO_HS_COMPLETE);
754}
755
756struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb) 821struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb)
757{ 822{
758 unsigned int hash = vnet_hashfn(skb->data); 823 unsigned int hash = vnet_hashfn(skb->data);
@@ -1342,6 +1407,21 @@ err_out:
1342 return err; 1407 return err;
1343} 1408}
1344 1409
1410#ifdef CONFIG_NET_POLL_CONTROLLER
1411static void vnet_poll_controller(struct net_device *dev)
1412{
1413 struct vnet *vp = netdev_priv(dev);
1414 struct vnet_port *port;
1415 unsigned long flags;
1416
1417 spin_lock_irqsave(&vp->lock, flags);
1418 if (!list_empty(&vp->port_list)) {
1419 port = list_entry(vp->port_list.next, struct vnet_port, list);
1420 napi_schedule(&port->napi);
1421 }
1422 spin_unlock_irqrestore(&vp->lock, flags);
1423}
1424#endif
1345static LIST_HEAD(vnet_list); 1425static LIST_HEAD(vnet_list);
1346static DEFINE_MUTEX(vnet_list_mutex); 1426static DEFINE_MUTEX(vnet_list_mutex);
1347 1427
@@ -1354,6 +1434,9 @@ static const struct net_device_ops vnet_ops = {
1354 .ndo_tx_timeout = vnet_tx_timeout, 1434 .ndo_tx_timeout = vnet_tx_timeout,
1355 .ndo_change_mtu = vnet_change_mtu, 1435 .ndo_change_mtu = vnet_change_mtu,
1356 .ndo_start_xmit = vnet_start_xmit, 1436 .ndo_start_xmit = vnet_start_xmit,
1437#ifdef CONFIG_NET_POLL_CONTROLLER
1438 .ndo_poll_controller = vnet_poll_controller,
1439#endif
1357}; 1440};
1358 1441
1359static struct vnet *vnet_new(const u64 *local_mac) 1442static struct vnet *vnet_new(const u64 *local_mac)
@@ -1374,7 +1457,6 @@ static struct vnet *vnet_new(const u64 *local_mac)
1374 vp = netdev_priv(dev); 1457 vp = netdev_priv(dev);
1375 1458
1376 spin_lock_init(&vp->lock); 1459 spin_lock_init(&vp->lock);
1377 tasklet_init(&vp->vnet_tx_wakeup, maybe_tx_wakeup, (unsigned long)vp);
1378 vp->dev = dev; 1460 vp->dev = dev;
1379 1461
1380 INIT_LIST_HEAD(&vp->port_list); 1462 INIT_LIST_HEAD(&vp->port_list);
@@ -1434,7 +1516,6 @@ static void vnet_cleanup(void)
1434 vp = list_first_entry(&vnet_list, struct vnet, list); 1516 vp = list_first_entry(&vnet_list, struct vnet, list);
1435 list_del(&vp->list); 1517 list_del(&vp->list);
1436 dev = vp->dev; 1518 dev = vp->dev;
1437 tasklet_kill(&vp->vnet_tx_wakeup);
1438 /* vio_unregister_driver() should have cleaned up port_list */ 1519 /* vio_unregister_driver() should have cleaned up port_list */
1439 BUG_ON(!list_empty(&vp->port_list)); 1520 BUG_ON(!list_empty(&vp->port_list));
1440 unregister_netdev(dev); 1521 unregister_netdev(dev);
@@ -1536,6 +1617,8 @@ static int vnet_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
1536 if (err) 1617 if (err)
1537 goto err_out_free_port; 1618 goto err_out_free_port;
1538 1619
1620 netif_napi_add(port->vp->dev, &port->napi, vnet_poll, NAPI_POLL_WEIGHT);
1621
1539 err = vnet_port_alloc_tx_bufs(port); 1622 err = vnet_port_alloc_tx_bufs(port);
1540 if (err) 1623 if (err)
1541 goto err_out_free_ldc; 1624 goto err_out_free_ldc;
@@ -1564,6 +1647,7 @@ static int vnet_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
1564 setup_timer(&port->clean_timer, vnet_clean_timer_expire, 1647 setup_timer(&port->clean_timer, vnet_clean_timer_expire,
1565 (unsigned long)port); 1648 (unsigned long)port);
1566 1649
1650 napi_enable(&port->napi);
1567 vio_port_up(&port->vio); 1651 vio_port_up(&port->vio);
1568 1652
1569 mdesc_release(hp); 1653 mdesc_release(hp);
@@ -1571,6 +1655,7 @@ static int vnet_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
1571 return 0; 1655 return 0;
1572 1656
1573err_out_free_ldc: 1657err_out_free_ldc:
1658 netif_napi_del(&port->napi);
1574 vio_ldc_free(&port->vio); 1659 vio_ldc_free(&port->vio);
1575 1660
1576err_out_free_port: 1661err_out_free_port:
@@ -1592,11 +1677,13 @@ static int vnet_port_remove(struct vio_dev *vdev)
1592 del_timer_sync(&port->vio.timer); 1677 del_timer_sync(&port->vio.timer);
1593 del_timer_sync(&port->clean_timer); 1678 del_timer_sync(&port->clean_timer);
1594 1679
1680 napi_disable(&port->napi);
1595 spin_lock_irqsave(&vp->lock, flags); 1681 spin_lock_irqsave(&vp->lock, flags);
1596 list_del(&port->list); 1682 list_del(&port->list);
1597 hlist_del(&port->hash); 1683 hlist_del(&port->hash);
1598 spin_unlock_irqrestore(&vp->lock, flags); 1684 spin_unlock_irqrestore(&vp->lock, flags);
1599 1685
1686 netif_napi_del(&port->napi);
1600 vnet_port_free_tx_bufs(port); 1687 vnet_port_free_tx_bufs(port);
1601 vio_ldc_free(&port->vio); 1688 vio_ldc_free(&port->vio);
1602 1689
diff --git a/drivers/net/ethernet/sun/sunvnet.h b/drivers/net/ethernet/sun/sunvnet.h
index c91104542619..c8a862e471dd 100644
--- a/drivers/net/ethernet/sun/sunvnet.h
+++ b/drivers/net/ethernet/sun/sunvnet.h
@@ -56,6 +56,11 @@ struct vnet_port {
56 struct timer_list clean_timer; 56 struct timer_list clean_timer;
57 57
58 u64 rmtu; 58 u64 rmtu;
59
60 struct napi_struct napi;
61 u32 napi_stop_idx;
62 bool napi_resume;
63 int rx_event;
59}; 64};
60 65
61static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio) 66static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio)
@@ -97,7 +102,6 @@ struct vnet {
97 struct list_head list; 102 struct list_head list;
98 u64 local_mac; 103 u64 local_mac;
99 104
100 struct tasklet_struct vnet_tx_wakeup;
101}; 105};
102 106
103#endif /* _SUNVNET_H */ 107#endif /* _SUNVNET_H */