mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 20:48:49 +08:00
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>
This commit is contained in:
parent
6e6581e0a9
commit
a899575191
@ -683,12 +683,9 @@ static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface)
|
||||
wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */
|
||||
wa->usb_iface = usb_get_intf(iface);
|
||||
wusbhc->dev = dev;
|
||||
wusbhc->uwb_rc = uwb_rc_get_by_grandpa(iface->dev.parent);
|
||||
if (wusbhc->uwb_rc == NULL) {
|
||||
result = -ENODEV;
|
||||
dev_err(dev, "Cannot get associated UWB Host Controller\n");
|
||||
goto error_rc_get;
|
||||
}
|
||||
/* defer getting the uwb_rc handle until it is needed since it
|
||||
* may not have been registered by the hwa_rc driver yet. */
|
||||
wusbhc->uwb_rc = NULL;
|
||||
result = wa_fill_descr(wa); /* Get the device descriptor */
|
||||
if (result < 0)
|
||||
goto error_fill_descriptor;
|
||||
@ -731,8 +728,6 @@ error_wusbhc_create:
|
||||
/* WA Descr fill allocs no resources */
|
||||
error_security_create:
|
||||
error_fill_descriptor:
|
||||
uwb_rc_put(wusbhc->uwb_rc);
|
||||
error_rc_get:
|
||||
usb_put_intf(iface);
|
||||
usb_put_dev(usb_dev);
|
||||
return result;
|
||||
|
@ -195,6 +195,7 @@ int wusbhc_start(struct wusbhc *wusbhc)
|
||||
struct device *dev = wusbhc->dev;
|
||||
|
||||
WARN_ON(wusbhc->wuie_host_info != NULL);
|
||||
BUG_ON(wusbhc->uwb_rc == NULL);
|
||||
|
||||
result = wusbhc_rsv_establish(wusbhc);
|
||||
if (result < 0) {
|
||||
@ -276,12 +277,38 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
|
||||
}
|
||||
wusbhc->chid = *chid;
|
||||
}
|
||||
|
||||
/* register with UWB if we haven't already since we are about to start
|
||||
the radio. */
|
||||
if ((chid) && (wusbhc->uwb_rc == NULL)) {
|
||||
wusbhc->uwb_rc = uwb_rc_get_by_grandpa(wusbhc->dev->parent);
|
||||
if (wusbhc->uwb_rc == NULL) {
|
||||
result = -ENODEV;
|
||||
dev_err(wusbhc->dev, "Cannot get associated UWB Host Controller\n");
|
||||
goto error_rc_get;
|
||||
}
|
||||
|
||||
result = wusbhc_pal_register(wusbhc);
|
||||
if (result < 0) {
|
||||
dev_err(wusbhc->dev, "Cannot register as a UWB PAL\n");
|
||||
goto error_pal_register;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&wusbhc->mutex);
|
||||
|
||||
if (chid)
|
||||
result = uwb_radio_start(&wusbhc->pal);
|
||||
else
|
||||
uwb_radio_stop(&wusbhc->pal);
|
||||
|
||||
return result;
|
||||
|
||||
error_pal_register:
|
||||
uwb_rc_put(wusbhc->uwb_rc);
|
||||
wusbhc->uwb_rc = NULL;
|
||||
error_rc_get:
|
||||
mutex_unlock(&wusbhc->mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wusbhc_chid_set);
|
||||
|
@ -45,10 +45,11 @@ int wusbhc_pal_register(struct wusbhc *wusbhc)
|
||||
}
|
||||
|
||||
/**
|
||||
* wusbhc_pal_register - unregister the WUSB HC as a UWB PAL
|
||||
* wusbhc_pal_unregister - unregister the WUSB HC as a UWB PAL
|
||||
* @wusbhc: the WUSB HC
|
||||
*/
|
||||
void wusbhc_pal_unregister(struct wusbhc *wusbhc)
|
||||
{
|
||||
uwb_pal_unregister(&wusbhc->pal);
|
||||
if (wusbhc->uwb_rc)
|
||||
uwb_pal_unregister(&wusbhc->pal);
|
||||
}
|
||||
|
@ -80,6 +80,9 @@ int wusbhc_rsv_establish(struct wusbhc *wusbhc)
|
||||
struct uwb_dev_addr bcid;
|
||||
int ret;
|
||||
|
||||
if (rc == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc);
|
||||
if (rsv == NULL)
|
||||
return -ENOMEM;
|
||||
|
@ -325,13 +325,7 @@ int wusbhc_b_create(struct wusbhc *wusbhc)
|
||||
goto error_create_attr_group;
|
||||
}
|
||||
|
||||
result = wusbhc_pal_register(wusbhc);
|
||||
if (result < 0)
|
||||
goto error_pal_register;
|
||||
return 0;
|
||||
|
||||
error_pal_register:
|
||||
sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
|
||||
error_create_attr_group:
|
||||
return result;
|
||||
}
|
||||
@ -457,7 +451,8 @@ EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);
|
||||
*/
|
||||
void wusbhc_reset_all(struct wusbhc *wusbhc)
|
||||
{
|
||||
uwb_rc_reset_all(wusbhc->uwb_rc);
|
||||
if (wusbhc->uwb_rc)
|
||||
uwb_rc_reset_all(wusbhc->uwb_rc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wusbhc_reset_all);
|
||||
|
||||
|
@ -44,10 +44,12 @@ int uwb_pal_register(struct uwb_pal *pal)
|
||||
int ret;
|
||||
|
||||
if (pal->device) {
|
||||
/* create a link to the uwb_rc in the PAL device's directory. */
|
||||
ret = sysfs_create_link(&pal->device->kobj,
|
||||
&rc->uwb_dev.dev.kobj, "uwb_rc");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* create a link to the PAL in the UWB device's directory. */
|
||||
ret = sysfs_create_link(&rc->uwb_dev.dev.kobj,
|
||||
&pal->device->kobj, pal->name);
|
||||
if (ret < 0) {
|
||||
|
@ -55,7 +55,8 @@ static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc)
|
||||
|
||||
static inline void __uwb_rc_put(struct uwb_rc *rc)
|
||||
{
|
||||
uwb_dev_put(&rc->uwb_dev);
|
||||
if (rc)
|
||||
uwb_dev_put(&rc->uwb_dev);
|
||||
}
|
||||
|
||||
extern int uwb_rc_reset(struct uwb_rc *rc);
|
||||
|
Loading…
Reference in New Issue
Block a user