aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ntb/ntb_transport.c
diff options
context:
space:
mode:
authorJon Mason <jon.mason@intel.com>2013-09-09 16:39:55 -0400
committerJon Mason <jon.mason@intel.com>2013-11-20 11:57:32 -0500
commitfca4d5188c1123ff63205e35e2c5f551a21d30c4 (patch)
tree736653a1d5d33bd0e7616f2858cb9f54780de021 /drivers/ntb/ntb_transport.c
parent9739047380a4a1a9f3eba4deea2f5978703b4ecb (diff)
NTB: Fix ntb_transport link down race
A WARN_ON is being hit in ntb_qp_link_work due to the NTB transport link being down while the ntb qp link is still active. This is caused by the transport link being brought down prior to the qp link worker thread being terminated. To correct this, shutdown the qp's prior to bringing the transport link down. Also, only call the qp worker thread if it is in interrupt context, otherwise call the function directly. Signed-off-by: Jon Mason <jon.mason@intel.com>
Diffstat (limited to 'drivers/ntb/ntb_transport.c')
-rw-r--r--drivers/ntb/ntb_transport.c43
1 files changed, 28 insertions, 15 deletions
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 12a9e83c008b..7010f23dab18 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -584,11 +584,8 @@ static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size)
584 return 0; 584 return 0;
585} 585}
586 586
587static void ntb_qp_link_cleanup(struct work_struct *work) 587static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp)
588{ 588{
589 struct ntb_transport_qp *qp = container_of(work,
590 struct ntb_transport_qp,
591 link_cleanup);
592 struct ntb_transport *nt = qp->transport; 589 struct ntb_transport *nt = qp->transport;
593 struct pci_dev *pdev = ntb_query_pdev(nt->ndev); 590 struct pci_dev *pdev = ntb_query_pdev(nt->ndev);
594 591
@@ -602,6 +599,16 @@ static void ntb_qp_link_cleanup(struct work_struct *work)
602 599
603 dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num); 600 dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num);
604 qp->qp_link = NTB_LINK_DOWN; 601 qp->qp_link = NTB_LINK_DOWN;
602}
603
604static void ntb_qp_link_cleanup_work(struct work_struct *work)
605{
606 struct ntb_transport_qp *qp = container_of(work,
607 struct ntb_transport_qp,
608 link_cleanup);
609 struct ntb_transport *nt = qp->transport;
610
611 ntb_qp_link_cleanup(qp);
605 612
606 if (nt->transport_link == NTB_LINK_UP) 613 if (nt->transport_link == NTB_LINK_UP)
607 schedule_delayed_work(&qp->link_work, 614 schedule_delayed_work(&qp->link_work,
@@ -613,22 +620,20 @@ static void ntb_qp_link_down(struct ntb_transport_qp *qp)
613 schedule_work(&qp->link_cleanup); 620 schedule_work(&qp->link_cleanup);
614} 621}
615 622
616static void ntb_transport_link_cleanup(struct work_struct *work) 623static void ntb_transport_link_cleanup(struct ntb_transport *nt)
617{ 624{
618 struct ntb_transport *nt = container_of(work, struct ntb_transport,
619 link_cleanup);
620 int i; 625 int i;
621 626
627 /* Pass along the info to any clients */
628 for (i = 0; i < nt->max_qps; i++)
629 if (!test_bit(i, &nt->qp_bitmap))
630 ntb_qp_link_cleanup(&nt->qps[i]);
631
622 if (nt->transport_link == NTB_LINK_DOWN) 632 if (nt->transport_link == NTB_LINK_DOWN)
623 cancel_delayed_work_sync(&nt->link_work); 633 cancel_delayed_work_sync(&nt->link_work);
624 else 634 else
625 nt->transport_link = NTB_LINK_DOWN; 635 nt->transport_link = NTB_LINK_DOWN;
626 636
627 /* Pass along the info to any clients */
628 for (i = 0; i < nt->max_qps; i++)
629 if (!test_bit(i, &nt->qp_bitmap))
630 ntb_qp_link_down(&nt->qps[i]);
631
632 /* The scratchpad registers keep the values if the remote side 637 /* The scratchpad registers keep the values if the remote side
633 * goes down, blast them now to give them a sane value the next 638 * goes down, blast them now to give them a sane value the next
634 * time they are accessed 639 * time they are accessed
@@ -637,6 +642,14 @@ static void ntb_transport_link_cleanup(struct work_struct *work)
637 ntb_write_local_spad(nt->ndev, i, 0); 642 ntb_write_local_spad(nt->ndev, i, 0);
638} 643}
639 644
645static void ntb_transport_link_cleanup_work(struct work_struct *work)
646{
647 struct ntb_transport *nt = container_of(work, struct ntb_transport,
648 link_cleanup);
649
650 ntb_transport_link_cleanup(nt);
651}
652
640static void ntb_transport_event_callback(void *data, enum ntb_hw_event event) 653static void ntb_transport_event_callback(void *data, enum ntb_hw_event event)
641{ 654{
642 struct ntb_transport *nt = data; 655 struct ntb_transport *nt = data;
@@ -880,7 +893,7 @@ static int ntb_transport_init_queue(struct ntb_transport *nt,
880 } 893 }
881 894
882 INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work); 895 INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work);
883 INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup); 896 INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup_work);
884 897
885 spin_lock_init(&qp->ntb_rx_pend_q_lock); 898 spin_lock_init(&qp->ntb_rx_pend_q_lock);
886 spin_lock_init(&qp->ntb_rx_free_q_lock); 899 spin_lock_init(&qp->ntb_rx_free_q_lock);
@@ -936,7 +949,7 @@ int ntb_transport_init(struct pci_dev *pdev)
936 } 949 }
937 950
938 INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work); 951 INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work);
939 INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup); 952 INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work);
940 953
941 rc = ntb_register_event_callback(nt->ndev, 954 rc = ntb_register_event_callback(nt->ndev,
942 ntb_transport_event_callback); 955 ntb_transport_event_callback);
@@ -972,7 +985,7 @@ void ntb_transport_free(void *transport)
972 struct ntb_device *ndev = nt->ndev; 985 struct ntb_device *ndev = nt->ndev;
973 int i; 986 int i;
974 987
975 nt->transport_link = NTB_LINK_DOWN; 988 ntb_transport_link_cleanup(nt);
976 989
977 /* verify that all the qp's are freed */ 990 /* verify that all the qp's are freed */
978 for (i = 0; i < nt->max_qps; i++) { 991 for (i = 0; i < nt->max_qps; i++) {