aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSteve Wise <swise@opengridcomputing.com>2008-11-12 13:16:47 -0500
committerRoland Dreier <rolandd@cisco.com>2008-11-12 13:16:47 -0500
commitb3e123cf65baadc0cc30a843fd48cfd6a4b2e1ca (patch)
treed18868ac64c78daeab54d11e3853cf544aaf506d /drivers
parentaf2b0a1ec37c61513d83d2d123658b4ef69d2ce9 (diff)
RDMA/cxgb3: Fix deadlock in iw_cxgb3 (hang when configuring interface)
When the iw_cxgb3 module's cxgb3_client "add" func gets called by the cxgb3 module, the iwarp driver ends up calling the ethtool ops get_drvinfo function in cxgb3 to get the fw version and other info. Currently the iwarp driver grabs the rtnl lock around this down call to serialize. As of 2.6.27 or so, things changed such that the rtnl lock is held around the call to the netdev driver open function. Also the cxgb3_client "add" function doesn't get called if the device is down. So, if you load cxgb3, then load iw_cxgb3, then ifconfig up the device, the iw_cxgb3 add func gets called with the rtnl_lock held. If you load cxgb3, ifconfig up the device, then load iw_cxgb3, the add func gets called without the rtnl_lock held. The former causes the deadlock, the latter does not. In addition, there are iw_cxgb3 sysfs handlers that also can call down into cxgb3 to gather the fw and hw versions. These can be called concurrently on different processors and at any time. Thus we need to push this serialization down in the cxgb3 driver get_drvinfo func. The fix is to remove rtnl lock usage, and use a per-device lock in cxgb3. Signed-off-by: Steve Wise <swise@opengridcomputing.com> Acked-by: Divy Le Ray <divy@chelsio.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c6
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c2
2 files changed, 2 insertions, 6 deletions
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index ecff98043589..160ef482712d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -1102,9 +1102,7 @@ static u64 fw_vers_string_to_u64(struct iwch_dev *iwch_dev)
1102 char *cp, *next; 1102 char *cp, *next;
1103 unsigned fw_maj, fw_min, fw_mic; 1103 unsigned fw_maj, fw_min, fw_mic;
1104 1104
1105 rtnl_lock();
1106 lldev->ethtool_ops->get_drvinfo(lldev, &info); 1105 lldev->ethtool_ops->get_drvinfo(lldev, &info);
1107 rtnl_unlock();
1108 1106
1109 next = info.fw_version + 1; 1107 next = info.fw_version + 1;
1110 cp = strsep(&next, "."); 1108 cp = strsep(&next, ".");
@@ -1192,9 +1190,7 @@ static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr, ch
1192 struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev; 1190 struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev;
1193 1191
1194 PDBG("%s dev 0x%p\n", __func__, dev); 1192 PDBG("%s dev 0x%p\n", __func__, dev);
1195 rtnl_lock();
1196 lldev->ethtool_ops->get_drvinfo(lldev, &info); 1193 lldev->ethtool_ops->get_drvinfo(lldev, &info);
1197 rtnl_unlock();
1198 return sprintf(buf, "%s\n", info.fw_version); 1194 return sprintf(buf, "%s\n", info.fw_version);
1199} 1195}
1200 1196
@@ -1207,9 +1203,7 @@ static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
1207 struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev; 1203 struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev;
1208 1204
1209 PDBG("%s dev 0x%p\n", __func__, dev); 1205 PDBG("%s dev 0x%p\n", __func__, dev);
1210 rtnl_lock();
1211 lldev->ethtool_ops->get_drvinfo(lldev, &info); 1206 lldev->ethtool_ops->get_drvinfo(lldev, &info);
1212 rtnl_unlock();
1213 return sprintf(buf, "%s\n", info.driver); 1207 return sprintf(buf, "%s\n", info.driver);
1214} 1208}
1215 1209
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 1ace41a13ac3..5e663ccda4d4 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -1307,8 +1307,10 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
1307 u32 fw_vers = 0; 1307 u32 fw_vers = 0;
1308 u32 tp_vers = 0; 1308 u32 tp_vers = 0;
1309 1309
1310 spin_lock(&adapter->stats_lock);
1310 t3_get_fw_version(adapter, &fw_vers); 1311 t3_get_fw_version(adapter, &fw_vers);
1311 t3_get_tp_version(adapter, &tp_vers); 1312 t3_get_tp_version(adapter, &tp_vers);
1313 spin_unlock(&adapter->stats_lock);
1312 1314
1313 strcpy(info->driver, DRV_NAME); 1315 strcpy(info->driver, DRV_NAME);
1314 strcpy(info->version, DRV_VERSION); 1316 strcpy(info->version, DRV_VERSION);