aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Pugliese <thomas.pugliese@gmail.com>2013-06-24 15:26:35 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-06-24 19:20:43 -0400
commita899575191ba85a71401f2c8f36bec7b14487043 (patch)
tree74070049b20ec44cf625db68ac62751e4b33cab0
parent6e6581e0a94758a4e69fab82407d39312eeff5c4 (diff)
USB: HWA: fix device probe failure
This patch fixes a race condition that caused the HWA_HC interface probe function to occasionally fail. The HWA_HC would attempt to register itself with the HWA_RC by searching for a uwb_rc class device with the same parent device ptr. If the probe function for the HWA_RC interface had yet to run, the uwb_rc class device would not have been created causing the look up to fail and the HWA_HC probe function to return an error causing the device to be unusable. The fix is for the HWA to delay registering with the HWA_RC until receiving the command from userspace to start the wireless channel. It is the responsibility of userspace to ensure that the uwb_rc class device has been created before starting the HWA channel. Signed-off-by: Thomas Pugliese <thomas.pugliese@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/hwa-hc.c11
-rw-r--r--drivers/usb/wusbcore/mmc.c27
-rw-r--r--drivers/usb/wusbcore/pal.c5
-rw-r--r--drivers/usb/wusbcore/reservation.c3
-rw-r--r--drivers/usb/wusbcore/wusbhc.c9
-rw-r--r--drivers/uwb/pal.c2
-rw-r--r--drivers/uwb/uwb-internal.h3
7 files changed, 42 insertions, 18 deletions
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
index 4af750ecfe8f..483990c716aa 100644
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -683,12 +683,9 @@ static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface)
683 wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */ 683 wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */
684 wa->usb_iface = usb_get_intf(iface); 684 wa->usb_iface = usb_get_intf(iface);
685 wusbhc->dev = dev; 685 wusbhc->dev = dev;
686 wusbhc->uwb_rc = uwb_rc_get_by_grandpa(iface->dev.parent); 686 /* defer getting the uwb_rc handle until it is needed since it
687 if (wusbhc->uwb_rc == NULL) { 687 * may not have been registered by the hwa_rc driver yet. */
688 result = -ENODEV; 688 wusbhc->uwb_rc = NULL;
689 dev_err(dev, "Cannot get associated UWB Host Controller\n");
690 goto error_rc_get;
691 }
692 result = wa_fill_descr(wa); /* Get the device descriptor */ 689 result = wa_fill_descr(wa); /* Get the device descriptor */
693 if (result < 0) 690 if (result < 0)
694 goto error_fill_descriptor; 691 goto error_fill_descriptor;
@@ -731,8 +728,6 @@ error_wusbhc_create:
731 /* WA Descr fill allocs no resources */ 728 /* WA Descr fill allocs no resources */
732error_security_create: 729error_security_create:
733error_fill_descriptor: 730error_fill_descriptor:
734 uwb_rc_put(wusbhc->uwb_rc);
735error_rc_get:
736 usb_put_intf(iface); 731 usb_put_intf(iface);
737 usb_put_dev(usb_dev); 732 usb_put_dev(usb_dev);
738 return result; 733 return result;
diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c
index 021467f86d9e..b71760c8d3ad 100644
--- a/drivers/usb/wusbcore/mmc.c
+++ b/drivers/usb/wusbcore/mmc.c
@@ -195,6 +195,7 @@ int wusbhc_start(struct wusbhc *wusbhc)
195 struct device *dev = wusbhc->dev; 195 struct device *dev = wusbhc->dev;
196 196
197 WARN_ON(wusbhc->wuie_host_info != NULL); 197 WARN_ON(wusbhc->wuie_host_info != NULL);
198 BUG_ON(wusbhc->uwb_rc == NULL);
198 199
199 result = wusbhc_rsv_establish(wusbhc); 200 result = wusbhc_rsv_establish(wusbhc);
200 if (result < 0) { 201 if (result < 0) {
@@ -276,12 +277,38 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
276 } 277 }
277 wusbhc->chid = *chid; 278 wusbhc->chid = *chid;
278 } 279 }
280
281 /* register with UWB if we haven't already since we are about to start
282 the radio. */
283 if ((chid) && (wusbhc->uwb_rc == NULL)) {
284 wusbhc->uwb_rc = uwb_rc_get_by_grandpa(wusbhc->dev->parent);
285 if (wusbhc->uwb_rc == NULL) {
286 result = -ENODEV;
287 dev_err(wusbhc->dev, "Cannot get associated UWB Host Controller\n");
288 goto error_rc_get;
289 }
290
291 result = wusbhc_pal_register(wusbhc);
292 if (result < 0) {
293 dev_err(wusbhc->dev, "Cannot register as a UWB PAL\n");
294 goto error_pal_register;
295 }
296 }
279 mutex_unlock(&wusbhc->mutex); 297 mutex_unlock(&wusbhc->mutex);
280 298
281 if (chid) 299 if (chid)
282 result = uwb_radio_start(&wusbhc->pal); 300 result = uwb_radio_start(&wusbhc->pal);
283 else 301 else
284 uwb_radio_stop(&wusbhc->pal); 302 uwb_radio_stop(&wusbhc->pal);
303
304 return result;
305
306error_pal_register:
307 uwb_rc_put(wusbhc->uwb_rc);
308 wusbhc->uwb_rc = NULL;
309error_rc_get:
310 mutex_unlock(&wusbhc->mutex);
311
285 return result; 312 return result;
286} 313}
287EXPORT_SYMBOL_GPL(wusbhc_chid_set); 314EXPORT_SYMBOL_GPL(wusbhc_chid_set);
diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c
index d0b172c5ecc7..59e100c2eb50 100644
--- a/drivers/usb/wusbcore/pal.c
+++ b/drivers/usb/wusbcore/pal.c
@@ -45,10 +45,11 @@ int wusbhc_pal_register(struct wusbhc *wusbhc)
45} 45}
46 46
47/** 47/**
48 * wusbhc_pal_register - unregister the WUSB HC as a UWB PAL 48 * wusbhc_pal_unregister - unregister the WUSB HC as a UWB PAL
49 * @wusbhc: the WUSB HC 49 * @wusbhc: the WUSB HC
50 */ 50 */
51void wusbhc_pal_unregister(struct wusbhc *wusbhc) 51void wusbhc_pal_unregister(struct wusbhc *wusbhc)
52{ 52{
53 uwb_pal_unregister(&wusbhc->pal); 53 if (wusbhc->uwb_rc)
54 uwb_pal_unregister(&wusbhc->pal);
54} 55}
diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c
index 6f4fafdc2401..ead79f793927 100644
--- a/drivers/usb/wusbcore/reservation.c
+++ b/drivers/usb/wusbcore/reservation.c
@@ -80,6 +80,9 @@ int wusbhc_rsv_establish(struct wusbhc *wusbhc)
80 struct uwb_dev_addr bcid; 80 struct uwb_dev_addr bcid;
81 int ret; 81 int ret;
82 82
83 if (rc == NULL)
84 return -ENODEV;
85
83 rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc); 86 rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc);
84 if (rsv == NULL) 87 if (rsv == NULL)
85 return -ENOMEM; 88 return -ENOMEM;
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c
index e712af3e46c2..742c607d1fa3 100644
--- a/drivers/usb/wusbcore/wusbhc.c
+++ b/drivers/usb/wusbcore/wusbhc.c
@@ -325,13 +325,7 @@ int wusbhc_b_create(struct wusbhc *wusbhc)
325 goto error_create_attr_group; 325 goto error_create_attr_group;
326 } 326 }
327 327
328 result = wusbhc_pal_register(wusbhc);
329 if (result < 0)
330 goto error_pal_register;
331 return 0; 328 return 0;
332
333error_pal_register:
334 sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
335error_create_attr_group: 329error_create_attr_group:
336 return result; 330 return result;
337} 331}
@@ -457,7 +451,8 @@ EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);
457 */ 451 */
458void wusbhc_reset_all(struct wusbhc *wusbhc) 452void wusbhc_reset_all(struct wusbhc *wusbhc)
459{ 453{
460 uwb_rc_reset_all(wusbhc->uwb_rc); 454 if (wusbhc->uwb_rc)
455 uwb_rc_reset_all(wusbhc->uwb_rc);
461} 456}
462EXPORT_SYMBOL_GPL(wusbhc_reset_all); 457EXPORT_SYMBOL_GPL(wusbhc_reset_all);
463 458
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
index 8ee7d90a8c68..690577d2a35b 100644
--- a/drivers/uwb/pal.c
+++ b/drivers/uwb/pal.c
@@ -44,10 +44,12 @@ int uwb_pal_register(struct uwb_pal *pal)
44 int ret; 44 int ret;
45 45
46 if (pal->device) { 46 if (pal->device) {
47 /* create a link to the uwb_rc in the PAL device's directory. */
47 ret = sysfs_create_link(&pal->device->kobj, 48 ret = sysfs_create_link(&pal->device->kobj,
48 &rc->uwb_dev.dev.kobj, "uwb_rc"); 49 &rc->uwb_dev.dev.kobj, "uwb_rc");
49 if (ret < 0) 50 if (ret < 0)
50 return ret; 51 return ret;
52 /* create a link to the PAL in the UWB device's directory. */
51 ret = sysfs_create_link(&rc->uwb_dev.dev.kobj, 53 ret = sysfs_create_link(&rc->uwb_dev.dev.kobj,
52 &pal->device->kobj, pal->name); 54 &pal->device->kobj, pal->name);
53 if (ret < 0) { 55 if (ret < 0) {
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h
index a7494bf10081..9a103b100f1e 100644
--- a/drivers/uwb/uwb-internal.h
+++ b/drivers/uwb/uwb-internal.h
@@ -55,7 +55,8 @@ static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc)
55 55
56static inline void __uwb_rc_put(struct uwb_rc *rc) 56static inline void __uwb_rc_put(struct uwb_rc *rc)
57{ 57{
58 uwb_dev_put(&rc->uwb_dev); 58 if (rc)
59 uwb_dev_put(&rc->uwb_dev);
59} 60}
60 61
61extern int uwb_rc_reset(struct uwb_rc *rc); 62extern int uwb_rc_reset(struct uwb_rc *rc);