diff options
author | Somnath Kotur <somnath.kotur@broadcom.com> | 2017-08-30 23:57:33 -0400 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2017-09-22 13:57:33 -0400 |
commit | 74828b128115033ff25d4140d732a05a36eaeaf0 (patch) | |
tree | 42e7744de7c5bfb584cee46d2078214c5c264cdd | |
parent | d5917307bb1caa9cb0a915951c57f4cdbacca443 (diff) |
bnxt_re: Remove RTNL lock dependency in bnxt_re_query_port
When there is a NETDEV_UNREGISTER event, bnxt_re driver calls
ib_unregister_device() (RTNL lock held).
ib_unregister_device attempts to flush a worker queue scheduled by
ib_core and that queue might have a pending ib_query_port().
ib_query_port in turn calls bnxt_re_query_port(), which while querying the
link speed using ib_get_eth_speed(), tries to acquire the rtnl_lock() which
was already held by NETDEV_UNREGISTER.
Fixing the issue by removing the link speed query from bnxt_re_query_port()
Now the speed is queried post a successful ib_register_device or whenever
there is a NETDEV_CHANGE event.
Signed-off-by: Somnath Kotur <somnath.kotur@broadcom.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r-- | drivers/infiniband/hw/bnxt_re/bnxt_re.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/bnxt_re/ib_verbs.c | 11 | ||||
-rw-r--r-- | drivers/infiniband/hw/bnxt_re/main.c | 4 |
3 files changed, 9 insertions, 8 deletions
diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index a25f9d240880..ecbac91b2e14 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h | |||
@@ -110,6 +110,8 @@ struct bnxt_re_dev { | |||
110 | 110 | ||
111 | struct delayed_work worker; | 111 | struct delayed_work worker; |
112 | u8 cur_prio_map; | 112 | u8 cur_prio_map; |
113 | u8 active_speed; | ||
114 | u8 active_width; | ||
113 | 115 | ||
114 | /* FP Notification Queue (CQ & SRQ) */ | 116 | /* FP Notification Queue (CQ & SRQ) */ |
115 | struct tasklet_struct nq_task; | 117 | struct tasklet_struct nq_task; |
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 0dbdbe1616ab..7430ef07a0e1 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c | |||
@@ -259,14 +259,9 @@ int bnxt_re_query_port(struct ib_device *ibdev, u8 port_num, | |||
259 | port_attr->sm_sl = 0; | 259 | port_attr->sm_sl = 0; |
260 | port_attr->subnet_timeout = 0; | 260 | port_attr->subnet_timeout = 0; |
261 | port_attr->init_type_reply = 0; | 261 | port_attr->init_type_reply = 0; |
262 | /* call the underlying netdev's ethtool hooks to query speed settings | 262 | port_attr->active_speed = rdev->active_speed; |
263 | * for which we acquire rtnl_lock _only_ if it's registered with | 263 | port_attr->active_width = rdev->active_width; |
264 | * IB stack to avoid race in the NETDEV_UNREG path | 264 | |
265 | */ | ||
266 | if (test_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags)) | ||
267 | if (ib_get_eth_speed(ibdev, port_num, &port_attr->active_speed, | ||
268 | &port_attr->active_width)) | ||
269 | return -EINVAL; | ||
270 | return 0; | 265 | return 0; |
271 | } | 266 | } |
272 | 267 | ||
diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 29c3d7e254af..e7450ea92aa9 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c | |||
@@ -1161,6 +1161,8 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev) | |||
1161 | } | 1161 | } |
1162 | } | 1162 | } |
1163 | set_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags); | 1163 | set_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags); |
1164 | ib_get_eth_speed(&rdev->ibdev, 1, &rdev->active_speed, | ||
1165 | &rdev->active_width); | ||
1164 | bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, IB_EVENT_PORT_ACTIVE); | 1166 | bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, IB_EVENT_PORT_ACTIVE); |
1165 | bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, IB_EVENT_GID_CHANGE); | 1167 | bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, IB_EVENT_GID_CHANGE); |
1166 | 1168 | ||
@@ -1255,6 +1257,8 @@ static void bnxt_re_task(struct work_struct *work) | |||
1255 | else if (netif_carrier_ok(rdev->netdev)) | 1257 | else if (netif_carrier_ok(rdev->netdev)) |
1256 | bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, | 1258 | bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, |
1257 | IB_EVENT_PORT_ACTIVE); | 1259 | IB_EVENT_PORT_ACTIVE); |
1260 | ib_get_eth_speed(&rdev->ibdev, 1, &rdev->active_speed, | ||
1261 | &rdev->active_width); | ||
1258 | break; | 1262 | break; |
1259 | default: | 1263 | default: |
1260 | break; | 1264 | break; |