diff options
author | David S. Miller <davem@davemloft.net> | 2015-02-09 17:03:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-02-09 17:03:59 -0500 |
commit | 46857b57710f7b2088186d4fdd378083799ba6a7 (patch) | |
tree | a39bb7c432f4e36467e61b316050e41ecd408b1f | |
parent | 9dce285b70c157754d753203112cfef22770b1f9 (diff) | |
parent | 35f05dabf95ac3ebc4c15bafd6833f7a3046e66f (diff) |
Merge branch 'mlx4_bond_notify'
Or Gerlitz says:
====================
bonding and mlx4 fixes for the HA/LAG support and mlx4 reset flow
There are two fixes to the boding + mlx4 HA/LAG support from Moni and a patch from Yishai
which does further hardening of the mlx4 reset support for IB kernel ULPs.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/infiniband/hw/mlx4/cq.c | 57 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx4/main.c | 70 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx4/mlx4_ib.h | 9 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx4/qp.c | 59 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx4/srq.c | 8 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 28 | ||||
-rw-r--r-- | include/linux/mlx4/device.h | 2 | ||||
-rw-r--r-- | include/net/bonding.h | 2 |
8 files changed, 210 insertions, 25 deletions
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index a3b70f6c4035..543ecdd8667b 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c | |||
@@ -188,6 +188,8 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector | |||
188 | spin_lock_init(&cq->lock); | 188 | spin_lock_init(&cq->lock); |
189 | cq->resize_buf = NULL; | 189 | cq->resize_buf = NULL; |
190 | cq->resize_umem = NULL; | 190 | cq->resize_umem = NULL; |
191 | INIT_LIST_HEAD(&cq->send_qp_list); | ||
192 | INIT_LIST_HEAD(&cq->recv_qp_list); | ||
191 | 193 | ||
192 | if (context) { | 194 | if (context) { |
193 | struct mlx4_ib_create_cq ucmd; | 195 | struct mlx4_ib_create_cq ucmd; |
@@ -594,6 +596,55 @@ static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct | |||
594 | return 0; | 596 | return 0; |
595 | } | 597 | } |
596 | 598 | ||
599 | static void mlx4_ib_qp_sw_comp(struct mlx4_ib_qp *qp, int num_entries, | ||
600 | struct ib_wc *wc, int *npolled, int is_send) | ||
601 | { | ||
602 | struct mlx4_ib_wq *wq; | ||
603 | unsigned cur; | ||
604 | int i; | ||
605 | |||
606 | wq = is_send ? &qp->sq : &qp->rq; | ||
607 | cur = wq->head - wq->tail; | ||
608 | |||
609 | if (cur == 0) | ||
610 | return; | ||
611 | |||
612 | for (i = 0; i < cur && *npolled < num_entries; i++) { | ||
613 | wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; | ||
614 | wc->status = IB_WC_WR_FLUSH_ERR; | ||
615 | wc->vendor_err = MLX4_CQE_SYNDROME_WR_FLUSH_ERR; | ||
616 | wq->tail++; | ||
617 | (*npolled)++; | ||
618 | wc->qp = &qp->ibqp; | ||
619 | wc++; | ||
620 | } | ||
621 | } | ||
622 | |||
623 | static void mlx4_ib_poll_sw_comp(struct mlx4_ib_cq *cq, int num_entries, | ||
624 | struct ib_wc *wc, int *npolled) | ||
625 | { | ||
626 | struct mlx4_ib_qp *qp; | ||
627 | |||
628 | *npolled = 0; | ||
629 | /* Find uncompleted WQEs belonging to that cq and retrun | ||
630 | * simulated FLUSH_ERR completions | ||
631 | */ | ||
632 | list_for_each_entry(qp, &cq->send_qp_list, cq_send_list) { | ||
633 | mlx4_ib_qp_sw_comp(qp, num_entries, wc, npolled, 1); | ||
634 | if (*npolled >= num_entries) | ||
635 | goto out; | ||
636 | } | ||
637 | |||
638 | list_for_each_entry(qp, &cq->recv_qp_list, cq_recv_list) { | ||
639 | mlx4_ib_qp_sw_comp(qp, num_entries, wc + *npolled, npolled, 0); | ||
640 | if (*npolled >= num_entries) | ||
641 | goto out; | ||
642 | } | ||
643 | |||
644 | out: | ||
645 | return; | ||
646 | } | ||
647 | |||
597 | static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, | 648 | static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, |
598 | struct mlx4_ib_qp **cur_qp, | 649 | struct mlx4_ib_qp **cur_qp, |
599 | struct ib_wc *wc) | 650 | struct ib_wc *wc) |
@@ -836,8 +887,13 @@ int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) | |||
836 | unsigned long flags; | 887 | unsigned long flags; |
837 | int npolled; | 888 | int npolled; |
838 | int err = 0; | 889 | int err = 0; |
890 | struct mlx4_ib_dev *mdev = to_mdev(cq->ibcq.device); | ||
839 | 891 | ||
840 | spin_lock_irqsave(&cq->lock, flags); | 892 | spin_lock_irqsave(&cq->lock, flags); |
893 | if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { | ||
894 | mlx4_ib_poll_sw_comp(cq, num_entries, wc, &npolled); | ||
895 | goto out; | ||
896 | } | ||
841 | 897 | ||
842 | for (npolled = 0; npolled < num_entries; ++npolled) { | 898 | for (npolled = 0; npolled < num_entries; ++npolled) { |
843 | err = mlx4_ib_poll_one(cq, &cur_qp, wc + npolled); | 899 | err = mlx4_ib_poll_one(cq, &cur_qp, wc + npolled); |
@@ -847,6 +903,7 @@ int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) | |||
847 | 903 | ||
848 | mlx4_cq_set_ci(&cq->mcq); | 904 | mlx4_cq_set_ci(&cq->mcq); |
849 | 905 | ||
906 | out: | ||
850 | spin_unlock_irqrestore(&cq->lock, flags); | 907 | spin_unlock_irqrestore(&cq->lock, flags); |
851 | 908 | ||
852 | if (err == 0 || err == -EAGAIN) | 909 | if (err == 0 || err == -EAGAIN) |
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 2ed5b996b2f4..eb8e215f1613 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c | |||
@@ -1186,6 +1186,9 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp, | |||
1186 | goto err_create_flow; | 1186 | goto err_create_flow; |
1187 | i++; | 1187 | i++; |
1188 | if (is_bonded) { | 1188 | if (is_bonded) { |
1189 | /* Application always sees one port so the mirror rule | ||
1190 | * must be on port #2 | ||
1191 | */ | ||
1189 | flow_attr->port = 2; | 1192 | flow_attr->port = 2; |
1190 | err = __mlx4_ib_create_flow(qp, flow_attr, | 1193 | err = __mlx4_ib_create_flow(qp, flow_attr, |
1191 | domain, type[j], | 1194 | domain, type[j], |
@@ -1286,7 +1289,8 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | |||
1286 | 1289 | ||
1287 | reg_id.mirror = 0; | 1290 | reg_id.mirror = 0; |
1288 | if (mlx4_is_bonded(dev)) { | 1291 | if (mlx4_is_bonded(dev)) { |
1289 | err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, 2, | 1292 | err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, |
1293 | (mqp->port == 1) ? 2 : 1, | ||
1290 | !!(mqp->flags & | 1294 | !!(mqp->flags & |
1291 | MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), | 1295 | MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), |
1292 | prot, ®_id.mirror); | 1296 | prot, ®_id.mirror); |
@@ -2304,6 +2308,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) | |||
2304 | 2308 | ||
2305 | spin_lock_init(&ibdev->sm_lock); | 2309 | spin_lock_init(&ibdev->sm_lock); |
2306 | mutex_init(&ibdev->cap_mask_mutex); | 2310 | mutex_init(&ibdev->cap_mask_mutex); |
2311 | INIT_LIST_HEAD(&ibdev->qp_list); | ||
2312 | spin_lock_init(&ibdev->reset_flow_resource_lock); | ||
2307 | 2313 | ||
2308 | if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED && | 2314 | if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED && |
2309 | ib_num_ports) { | 2315 | ib_num_ports) { |
@@ -2618,6 +2624,67 @@ out: | |||
2618 | return; | 2624 | return; |
2619 | } | 2625 | } |
2620 | 2626 | ||
2627 | static void mlx4_ib_handle_catas_error(struct mlx4_ib_dev *ibdev) | ||
2628 | { | ||
2629 | struct mlx4_ib_qp *mqp; | ||
2630 | unsigned long flags_qp; | ||
2631 | unsigned long flags_cq; | ||
2632 | struct mlx4_ib_cq *send_mcq, *recv_mcq; | ||
2633 | struct list_head cq_notify_list; | ||
2634 | struct mlx4_cq *mcq; | ||
2635 | unsigned long flags; | ||
2636 | |||
2637 | pr_warn("mlx4_ib_handle_catas_error was started\n"); | ||
2638 | INIT_LIST_HEAD(&cq_notify_list); | ||
2639 | |||
2640 | /* Go over qp list reside on that ibdev, sync with create/destroy qp.*/ | ||
2641 | spin_lock_irqsave(&ibdev->reset_flow_resource_lock, flags); | ||
2642 | |||
2643 | list_for_each_entry(mqp, &ibdev->qp_list, qps_list) { | ||
2644 | spin_lock_irqsave(&mqp->sq.lock, flags_qp); | ||
2645 | if (mqp->sq.tail != mqp->sq.head) { | ||
2646 | send_mcq = to_mcq(mqp->ibqp.send_cq); | ||
2647 | spin_lock_irqsave(&send_mcq->lock, flags_cq); | ||
2648 | if (send_mcq->mcq.comp && | ||
2649 | mqp->ibqp.send_cq->comp_handler) { | ||
2650 | if (!send_mcq->mcq.reset_notify_added) { | ||
2651 | send_mcq->mcq.reset_notify_added = 1; | ||
2652 | list_add_tail(&send_mcq->mcq.reset_notify, | ||
2653 | &cq_notify_list); | ||
2654 | } | ||
2655 | } | ||
2656 | spin_unlock_irqrestore(&send_mcq->lock, flags_cq); | ||
2657 | } | ||
2658 | spin_unlock_irqrestore(&mqp->sq.lock, flags_qp); | ||
2659 | /* Now, handle the QP's receive queue */ | ||
2660 | spin_lock_irqsave(&mqp->rq.lock, flags_qp); | ||
2661 | /* no handling is needed for SRQ */ | ||
2662 | if (!mqp->ibqp.srq) { | ||
2663 | if (mqp->rq.tail != mqp->rq.head) { | ||
2664 | recv_mcq = to_mcq(mqp->ibqp.recv_cq); | ||
2665 | spin_lock_irqsave(&recv_mcq->lock, flags_cq); | ||
2666 | if (recv_mcq->mcq.comp && | ||
2667 | mqp->ibqp.recv_cq->comp_handler) { | ||
2668 | if (!recv_mcq->mcq.reset_notify_added) { | ||
2669 | recv_mcq->mcq.reset_notify_added = 1; | ||
2670 | list_add_tail(&recv_mcq->mcq.reset_notify, | ||
2671 | &cq_notify_list); | ||
2672 | } | ||
2673 | } | ||
2674 | spin_unlock_irqrestore(&recv_mcq->lock, | ||
2675 | flags_cq); | ||
2676 | } | ||
2677 | } | ||
2678 | spin_unlock_irqrestore(&mqp->rq.lock, flags_qp); | ||
2679 | } | ||
2680 | |||
2681 | list_for_each_entry(mcq, &cq_notify_list, reset_notify) { | ||
2682 | mcq->comp(mcq); | ||
2683 | } | ||
2684 | spin_unlock_irqrestore(&ibdev->reset_flow_resource_lock, flags); | ||
2685 | pr_warn("mlx4_ib_handle_catas_error ended\n"); | ||
2686 | } | ||
2687 | |||
2621 | static void handle_bonded_port_state_event(struct work_struct *work) | 2688 | static void handle_bonded_port_state_event(struct work_struct *work) |
2622 | { | 2689 | { |
2623 | struct ib_event_work *ew = | 2690 | struct ib_event_work *ew = |
@@ -2697,6 +2764,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, | |||
2697 | case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: | 2764 | case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: |
2698 | ibdev->ib_active = false; | 2765 | ibdev->ib_active = false; |
2699 | ibev.event = IB_EVENT_DEVICE_FATAL; | 2766 | ibev.event = IB_EVENT_DEVICE_FATAL; |
2767 | mlx4_ib_handle_catas_error(ibdev); | ||
2700 | break; | 2768 | break; |
2701 | 2769 | ||
2702 | case MLX4_DEV_EVENT_PORT_MGMT_CHANGE: | 2770 | case MLX4_DEV_EVENT_PORT_MGMT_CHANGE: |
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 721540c9163d..f829fd935b79 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h | |||
@@ -110,6 +110,9 @@ struct mlx4_ib_cq { | |||
110 | struct mutex resize_mutex; | 110 | struct mutex resize_mutex; |
111 | struct ib_umem *umem; | 111 | struct ib_umem *umem; |
112 | struct ib_umem *resize_umem; | 112 | struct ib_umem *resize_umem; |
113 | /* List of qps that it serves.*/ | ||
114 | struct list_head send_qp_list; | ||
115 | struct list_head recv_qp_list; | ||
113 | }; | 116 | }; |
114 | 117 | ||
115 | struct mlx4_ib_mr { | 118 | struct mlx4_ib_mr { |
@@ -300,6 +303,9 @@ struct mlx4_ib_qp { | |||
300 | struct mlx4_roce_smac_vlan_info pri; | 303 | struct mlx4_roce_smac_vlan_info pri; |
301 | struct mlx4_roce_smac_vlan_info alt; | 304 | struct mlx4_roce_smac_vlan_info alt; |
302 | u64 reg_id; | 305 | u64 reg_id; |
306 | struct list_head qps_list; | ||
307 | struct list_head cq_recv_list; | ||
308 | struct list_head cq_send_list; | ||
303 | }; | 309 | }; |
304 | 310 | ||
305 | struct mlx4_ib_srq { | 311 | struct mlx4_ib_srq { |
@@ -535,6 +541,9 @@ struct mlx4_ib_dev { | |||
535 | /* lock when destroying qp1_proxy and getting netdev events */ | 541 | /* lock when destroying qp1_proxy and getting netdev events */ |
536 | struct mutex qp1_proxy_lock[MLX4_MAX_PORTS]; | 542 | struct mutex qp1_proxy_lock[MLX4_MAX_PORTS]; |
537 | u8 bond_next_port; | 543 | u8 bond_next_port; |
544 | /* protect resources needed as part of reset flow */ | ||
545 | spinlock_t reset_flow_resource_lock; | ||
546 | struct list_head qp_list; | ||
538 | }; | 547 | }; |
539 | 548 | ||
540 | struct ib_event_work { | 549 | struct ib_event_work { |
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 792f9dc86ada..dfc6ca128a7e 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c | |||
@@ -46,6 +46,11 @@ | |||
46 | #include "mlx4_ib.h" | 46 | #include "mlx4_ib.h" |
47 | #include "user.h" | 47 | #include "user.h" |
48 | 48 | ||
49 | static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, | ||
50 | struct mlx4_ib_cq *recv_cq); | ||
51 | static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, | ||
52 | struct mlx4_ib_cq *recv_cq); | ||
53 | |||
49 | enum { | 54 | enum { |
50 | MLX4_IB_ACK_REQ_FREQ = 8, | 55 | MLX4_IB_ACK_REQ_FREQ = 8, |
51 | }; | 56 | }; |
@@ -618,6 +623,8 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, | |||
618 | struct mlx4_ib_sqp *sqp; | 623 | struct mlx4_ib_sqp *sqp; |
619 | struct mlx4_ib_qp *qp; | 624 | struct mlx4_ib_qp *qp; |
620 | enum mlx4_ib_qp_type qp_type = (enum mlx4_ib_qp_type) init_attr->qp_type; | 625 | enum mlx4_ib_qp_type qp_type = (enum mlx4_ib_qp_type) init_attr->qp_type; |
626 | struct mlx4_ib_cq *mcq; | ||
627 | unsigned long flags; | ||
621 | 628 | ||
622 | /* When tunneling special qps, we use a plain UD qp */ | 629 | /* When tunneling special qps, we use a plain UD qp */ |
623 | if (sqpn) { | 630 | if (sqpn) { |
@@ -828,6 +835,24 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, | |||
828 | qp->mqp.event = mlx4_ib_qp_event; | 835 | qp->mqp.event = mlx4_ib_qp_event; |
829 | if (!*caller_qp) | 836 | if (!*caller_qp) |
830 | *caller_qp = qp; | 837 | *caller_qp = qp; |
838 | |||
839 | spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); | ||
840 | mlx4_ib_lock_cqs(to_mcq(init_attr->send_cq), | ||
841 | to_mcq(init_attr->recv_cq)); | ||
842 | /* Maintain device to QPs access, needed for further handling | ||
843 | * via reset flow | ||
844 | */ | ||
845 | list_add_tail(&qp->qps_list, &dev->qp_list); | ||
846 | /* Maintain CQ to QPs access, needed for further handling | ||
847 | * via reset flow | ||
848 | */ | ||
849 | mcq = to_mcq(init_attr->send_cq); | ||
850 | list_add_tail(&qp->cq_send_list, &mcq->send_qp_list); | ||
851 | mcq = to_mcq(init_attr->recv_cq); | ||
852 | list_add_tail(&qp->cq_recv_list, &mcq->recv_qp_list); | ||
853 | mlx4_ib_unlock_cqs(to_mcq(init_attr->send_cq), | ||
854 | to_mcq(init_attr->recv_cq)); | ||
855 | spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); | ||
831 | return 0; | 856 | return 0; |
832 | 857 | ||
833 | err_qpn: | 858 | err_qpn: |
@@ -886,13 +911,13 @@ static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv | |||
886 | __acquires(&send_cq->lock) __acquires(&recv_cq->lock) | 911 | __acquires(&send_cq->lock) __acquires(&recv_cq->lock) |
887 | { | 912 | { |
888 | if (send_cq == recv_cq) { | 913 | if (send_cq == recv_cq) { |
889 | spin_lock_irq(&send_cq->lock); | 914 | spin_lock(&send_cq->lock); |
890 | __acquire(&recv_cq->lock); | 915 | __acquire(&recv_cq->lock); |
891 | } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { | 916 | } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { |
892 | spin_lock_irq(&send_cq->lock); | 917 | spin_lock(&send_cq->lock); |
893 | spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); | 918 | spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); |
894 | } else { | 919 | } else { |
895 | spin_lock_irq(&recv_cq->lock); | 920 | spin_lock(&recv_cq->lock); |
896 | spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING); | 921 | spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING); |
897 | } | 922 | } |
898 | } | 923 | } |
@@ -902,13 +927,13 @@ static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *re | |||
902 | { | 927 | { |
903 | if (send_cq == recv_cq) { | 928 | if (send_cq == recv_cq) { |
904 | __release(&recv_cq->lock); | 929 | __release(&recv_cq->lock); |
905 | spin_unlock_irq(&send_cq->lock); | 930 | spin_unlock(&send_cq->lock); |
906 | } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { | 931 | } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { |
907 | spin_unlock(&recv_cq->lock); | 932 | spin_unlock(&recv_cq->lock); |
908 | spin_unlock_irq(&send_cq->lock); | 933 | spin_unlock(&send_cq->lock); |
909 | } else { | 934 | } else { |
910 | spin_unlock(&send_cq->lock); | 935 | spin_unlock(&send_cq->lock); |
911 | spin_unlock_irq(&recv_cq->lock); | 936 | spin_unlock(&recv_cq->lock); |
912 | } | 937 | } |
913 | } | 938 | } |
914 | 939 | ||
@@ -953,6 +978,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, | |||
953 | int is_user) | 978 | int is_user) |
954 | { | 979 | { |
955 | struct mlx4_ib_cq *send_cq, *recv_cq; | 980 | struct mlx4_ib_cq *send_cq, *recv_cq; |
981 | unsigned long flags; | ||
956 | 982 | ||
957 | if (qp->state != IB_QPS_RESET) { | 983 | if (qp->state != IB_QPS_RESET) { |
958 | if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state), | 984 | if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state), |
@@ -984,8 +1010,13 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, | |||
984 | 1010 | ||
985 | get_cqs(qp, &send_cq, &recv_cq); | 1011 | get_cqs(qp, &send_cq, &recv_cq); |
986 | 1012 | ||
1013 | spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); | ||
987 | mlx4_ib_lock_cqs(send_cq, recv_cq); | 1014 | mlx4_ib_lock_cqs(send_cq, recv_cq); |
988 | 1015 | ||
1016 | /* del from lists under both locks above to protect reset flow paths */ | ||
1017 | list_del(&qp->qps_list); | ||
1018 | list_del(&qp->cq_send_list); | ||
1019 | list_del(&qp->cq_recv_list); | ||
989 | if (!is_user) { | 1020 | if (!is_user) { |
990 | __mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, | 1021 | __mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, |
991 | qp->ibqp.srq ? to_msrq(qp->ibqp.srq): NULL); | 1022 | qp->ibqp.srq ? to_msrq(qp->ibqp.srq): NULL); |
@@ -996,6 +1027,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, | |||
996 | mlx4_qp_remove(dev->dev, &qp->mqp); | 1027 | mlx4_qp_remove(dev->dev, &qp->mqp); |
997 | 1028 | ||
998 | mlx4_ib_unlock_cqs(send_cq, recv_cq); | 1029 | mlx4_ib_unlock_cqs(send_cq, recv_cq); |
1030 | spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); | ||
999 | 1031 | ||
1000 | mlx4_qp_free(dev->dev, &qp->mqp); | 1032 | mlx4_qp_free(dev->dev, &qp->mqp); |
1001 | 1033 | ||
@@ -2618,8 +2650,15 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
2618 | __be32 uninitialized_var(lso_hdr_sz); | 2650 | __be32 uninitialized_var(lso_hdr_sz); |
2619 | __be32 blh; | 2651 | __be32 blh; |
2620 | int i; | 2652 | int i; |
2653 | struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); | ||
2621 | 2654 | ||
2622 | spin_lock_irqsave(&qp->sq.lock, flags); | 2655 | spin_lock_irqsave(&qp->sq.lock, flags); |
2656 | if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { | ||
2657 | err = -EIO; | ||
2658 | *bad_wr = wr; | ||
2659 | nreq = 0; | ||
2660 | goto out; | ||
2661 | } | ||
2623 | 2662 | ||
2624 | ind = qp->sq_next_wqe; | 2663 | ind = qp->sq_next_wqe; |
2625 | 2664 | ||
@@ -2917,10 +2956,18 @@ int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
2917 | int ind; | 2956 | int ind; |
2918 | int max_gs; | 2957 | int max_gs; |
2919 | int i; | 2958 | int i; |
2959 | struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); | ||
2920 | 2960 | ||
2921 | max_gs = qp->rq.max_gs; | 2961 | max_gs = qp->rq.max_gs; |
2922 | spin_lock_irqsave(&qp->rq.lock, flags); | 2962 | spin_lock_irqsave(&qp->rq.lock, flags); |
2923 | 2963 | ||
2964 | if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { | ||
2965 | err = -EIO; | ||
2966 | *bad_wr = wr; | ||
2967 | nreq = 0; | ||
2968 | goto out; | ||
2969 | } | ||
2970 | |||
2924 | ind = qp->rq.head & (qp->rq.wqe_cnt - 1); | 2971 | ind = qp->rq.head & (qp->rq.wqe_cnt - 1); |
2925 | 2972 | ||
2926 | for (nreq = 0; wr; ++nreq, wr = wr->next) { | 2973 | for (nreq = 0; wr; ++nreq, wr = wr->next) { |
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index 62d9285300af..dce5dfe3a70e 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c | |||
@@ -316,8 +316,15 @@ int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, | |||
316 | int err = 0; | 316 | int err = 0; |
317 | int nreq; | 317 | int nreq; |
318 | int i; | 318 | int i; |
319 | struct mlx4_ib_dev *mdev = to_mdev(ibsrq->device); | ||
319 | 320 | ||
320 | spin_lock_irqsave(&srq->lock, flags); | 321 | spin_lock_irqsave(&srq->lock, flags); |
322 | if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { | ||
323 | err = -EIO; | ||
324 | *bad_wr = wr; | ||
325 | nreq = 0; | ||
326 | goto out; | ||
327 | } | ||
321 | 328 | ||
322 | for (nreq = 0; wr; ++nreq, wr = wr->next) { | 329 | for (nreq = 0; wr; ++nreq, wr = wr->next) { |
323 | if (unlikely(wr->num_sge > srq->msrq.max_gs)) { | 330 | if (unlikely(wr->num_sge > srq->msrq.max_gs)) { |
@@ -362,6 +369,7 @@ int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, | |||
362 | 369 | ||
363 | *srq->db.db = cpu_to_be32(srq->wqe_ctr); | 370 | *srq->db.db = cpu_to_be32(srq->wqe_ctr); |
364 | } | 371 | } |
372 | out: | ||
365 | 373 | ||
366 | spin_unlock_irqrestore(&srq->lock, flags); | 374 | spin_unlock_irqrestore(&srq->lock, flags); |
367 | 375 | ||
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 679ef00d6b16..b979c265fc51 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -1196,18 +1196,11 @@ static void bond_fill_ifslave(struct slave *slave, struct ifslave *info) | |||
1196 | info->link_failure_count = slave->link_failure_count; | 1196 | info->link_failure_count = slave->link_failure_count; |
1197 | } | 1197 | } |
1198 | 1198 | ||
1199 | static void bond_netdev_notify(struct slave *slave, struct net_device *dev) | 1199 | static void bond_netdev_notify(struct net_device *dev, |
1200 | struct netdev_bonding_info *info) | ||
1200 | { | 1201 | { |
1201 | struct bonding *bond = slave->bond; | ||
1202 | struct netdev_bonding_info bonding_info; | ||
1203 | |||
1204 | rtnl_lock(); | 1202 | rtnl_lock(); |
1205 | /* make sure that slave is still valid */ | 1203 | netdev_bonding_info_change(dev, info); |
1206 | if (dev->priv_flags & IFF_BONDING) { | ||
1207 | bond_fill_ifslave(slave, &bonding_info.slave); | ||
1208 | bond_fill_ifbond(bond, &bonding_info.master); | ||
1209 | netdev_bonding_info_change(slave->dev, &bonding_info); | ||
1210 | } | ||
1211 | rtnl_unlock(); | 1204 | rtnl_unlock(); |
1212 | } | 1205 | } |
1213 | 1206 | ||
@@ -1216,25 +1209,26 @@ static void bond_netdev_notify_work(struct work_struct *_work) | |||
1216 | struct netdev_notify_work *w = | 1209 | struct netdev_notify_work *w = |
1217 | container_of(_work, struct netdev_notify_work, work.work); | 1210 | container_of(_work, struct netdev_notify_work, work.work); |
1218 | 1211 | ||
1219 | bond_netdev_notify(w->slave, w->dev); | 1212 | bond_netdev_notify(w->dev, &w->bonding_info); |
1220 | dev_put(w->dev); | 1213 | dev_put(w->dev); |
1214 | kfree(w); | ||
1221 | } | 1215 | } |
1222 | 1216 | ||
1223 | void bond_queue_slave_event(struct slave *slave) | 1217 | void bond_queue_slave_event(struct slave *slave) |
1224 | { | 1218 | { |
1219 | struct bonding *bond = slave->bond; | ||
1225 | struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC); | 1220 | struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC); |
1226 | 1221 | ||
1227 | if (!nnw) | 1222 | if (!nnw) |
1228 | return; | 1223 | return; |
1229 | 1224 | ||
1230 | INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work); | 1225 | dev_hold(slave->dev); |
1231 | nnw->slave = slave; | ||
1232 | nnw->dev = slave->dev; | 1226 | nnw->dev = slave->dev; |
1227 | bond_fill_ifslave(slave, &nnw->bonding_info.slave); | ||
1228 | bond_fill_ifbond(bond, &nnw->bonding_info.master); | ||
1229 | INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work); | ||
1233 | 1230 | ||
1234 | if (queue_delayed_work(slave->bond->wq, &nnw->work, 0)) | 1231 | queue_delayed_work(slave->bond->wq, &nnw->work, 0); |
1235 | dev_hold(slave->dev); | ||
1236 | else | ||
1237 | kfree(nnw); | ||
1238 | } | 1232 | } |
1239 | 1233 | ||
1240 | /* enslave device <slave> to bond device <master> */ | 1234 | /* enslave device <slave> to bond device <master> */ |
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index c116cb02475c..e4ebff7e9d02 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h | |||
@@ -689,6 +689,8 @@ struct mlx4_cq { | |||
689 | void (*comp)(struct mlx4_cq *); | 689 | void (*comp)(struct mlx4_cq *); |
690 | void *priv; | 690 | void *priv; |
691 | } tasklet_ctx; | 691 | } tasklet_ctx; |
692 | int reset_notify_added; | ||
693 | struct list_head reset_notify; | ||
692 | }; | 694 | }; |
693 | 695 | ||
694 | struct mlx4_qp { | 696 | struct mlx4_qp { |
diff --git a/include/net/bonding.h b/include/net/bonding.h index 4e17095ad46a..fda6feeb6c1f 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h | |||
@@ -152,8 +152,8 @@ struct bond_parm_tbl { | |||
152 | 152 | ||
153 | struct netdev_notify_work { | 153 | struct netdev_notify_work { |
154 | struct delayed_work work; | 154 | struct delayed_work work; |
155 | struct slave *slave; | ||
156 | struct net_device *dev; | 155 | struct net_device *dev; |
156 | struct netdev_bonding_info bonding_info; | ||
157 | }; | 157 | }; |
158 | 158 | ||
159 | struct slave { | 159 | struct slave { |