aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ntb/hw
diff options
context:
space:
mode:
authorJoey Zhang <joey.zhang@microchip.com>2019-06-06 03:09:44 -0400
committerJon Mason <jdmason@kudzu.us>2019-06-13 08:59:31 -0400
commita944ccc3b0aedb7f3a24b8c90624fe182e8a8851 (patch)
tree4cc6839b608a51033798208a44e88da21e3df2f5 /drivers/ntb/hw
parentf0f43e766bdb314b3816ac891fb18cea5de4123d (diff)
ntb_hw_switchtec: Fix setup MW with failure bug
Switchtec does not support setting multiple MWs simultaneously. The driver takes a hardware lock to ensure that two peers are not doing this simultaneously and it fails if someone else takes the lock. In most cases, this is fine as clients only setup the MWs once on one side of the link. However, there's a race condition when a re-initialization is caused by a link event. The driver will re-setup the shared memory window asynchronously and this races with the client setting up it's memory windows on the link up event. To fix this we ensure do the entire initialization in a work queue and signal the client once it's done. Signed-off-by: Joey Zhang <joey.zhang@microchip.com> Signed-off-by: Wesley Sheng <wesley.sheng@microchip.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
Diffstat (limited to 'drivers/ntb/hw')
-rw-r--r--drivers/ntb/hw/mscc/ntb_hw_switchtec.c66
1 files changed, 39 insertions, 27 deletions
diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
index a26e3d0cf457..7e3e16c04eef 100644
--- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
+++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c
@@ -95,7 +95,8 @@ struct switchtec_ntb {
95 bool link_is_up; 95 bool link_is_up;
96 enum ntb_speed link_speed; 96 enum ntb_speed link_speed;
97 enum ntb_width link_width; 97 enum ntb_width link_width;
98 struct work_struct link_reinit_work; 98 struct work_struct check_link_status_work;
99 bool link_force_down;
99}; 100};
100 101
101static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) 102static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb)
@@ -494,33 +495,11 @@ enum switchtec_msg {
494 495
495static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev); 496static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev);
496 497
497static void link_reinit_work(struct work_struct *work) 498static void switchtec_ntb_link_status_update(struct switchtec_ntb *sndev)
498{
499 struct switchtec_ntb *sndev;
500
501 sndev = container_of(work, struct switchtec_ntb, link_reinit_work);
502
503 switchtec_ntb_reinit_peer(sndev);
504}
505
506static void switchtec_ntb_check_link(struct switchtec_ntb *sndev,
507 enum switchtec_msg msg)
508{ 499{
509 int link_sta; 500 int link_sta;
510 int old = sndev->link_is_up; 501 int old = sndev->link_is_up;
511 502
512 if (msg == MSG_LINK_FORCE_DOWN) {
513 schedule_work(&sndev->link_reinit_work);
514
515 if (sndev->link_is_up) {
516 sndev->link_is_up = 0;
517 ntb_link_event(&sndev->ntb);
518 dev_info(&sndev->stdev->dev, "ntb link forced down\n");
519 }
520
521 return;
522 }
523
524 link_sta = sndev->self_shared->link_sta; 503 link_sta = sndev->self_shared->link_sta;
525 if (link_sta) { 504 if (link_sta) {
526 u64 peer = ioread64(&sndev->peer_shared->magic); 505 u64 peer = ioread64(&sndev->peer_shared->magic);
@@ -545,6 +524,38 @@ static void switchtec_ntb_check_link(struct switchtec_ntb *sndev,
545 } 524 }
546} 525}
547 526
527static void check_link_status_work(struct work_struct *work)
528{
529 struct switchtec_ntb *sndev;
530
531 sndev = container_of(work, struct switchtec_ntb,
532 check_link_status_work);
533
534 if (sndev->link_force_down) {
535 sndev->link_force_down = false;
536 switchtec_ntb_reinit_peer(sndev);
537
538 if (sndev->link_is_up) {
539 sndev->link_is_up = 0;
540 ntb_link_event(&sndev->ntb);
541 dev_info(&sndev->stdev->dev, "ntb link forced down\n");
542 }
543
544 return;
545 }
546
547 switchtec_ntb_link_status_update(sndev);
548}
549
550static void switchtec_ntb_check_link(struct switchtec_ntb *sndev,
551 enum switchtec_msg msg)
552{
553 if (msg == MSG_LINK_FORCE_DOWN)
554 sndev->link_force_down = true;
555
556 schedule_work(&sndev->check_link_status_work);
557}
558
548static void switchtec_ntb_link_notification(struct switchtec_dev *stdev) 559static void switchtec_ntb_link_notification(struct switchtec_dev *stdev)
549{ 560{
550 struct switchtec_ntb *sndev = stdev->sndev; 561 struct switchtec_ntb *sndev = stdev->sndev;
@@ -577,7 +588,7 @@ static int switchtec_ntb_link_enable(struct ntb_dev *ntb,
577 sndev->self_shared->link_sta = 1; 588 sndev->self_shared->link_sta = 1;
578 switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); 589 switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP);
579 590
580 switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); 591 switchtec_ntb_link_status_update(sndev);
581 592
582 return 0; 593 return 0;
583} 594}
@@ -591,7 +602,7 @@ static int switchtec_ntb_link_disable(struct ntb_dev *ntb)
591 sndev->self_shared->link_sta = 0; 602 sndev->self_shared->link_sta = 0;
592 switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN); 603 switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN);
593 604
594 switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); 605 switchtec_ntb_link_status_update(sndev);
595 606
596 return 0; 607 return 0;
597} 608}
@@ -844,7 +855,8 @@ static int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev)
844 sndev->ntb.topo = NTB_TOPO_SWITCH; 855 sndev->ntb.topo = NTB_TOPO_SWITCH;
845 sndev->ntb.ops = &switchtec_ntb_ops; 856 sndev->ntb.ops = &switchtec_ntb_ops;
846 857
847 INIT_WORK(&sndev->link_reinit_work, link_reinit_work); 858 INIT_WORK(&sndev->check_link_status_work, check_link_status_work);
859 sndev->link_force_down = false;
848 860
849 sndev->self_partition = sndev->stdev->partition; 861 sndev->self_partition = sndev->stdev->partition;
850 862