diff options
| author | Hans Petter Selasky <hselasky@FreeBSD.org> | 2016-09-12 10:23:24 +0000 |
|---|---|---|
| committer | Hans Petter Selasky <hselasky@FreeBSD.org> | 2016-09-12 10:23:24 +0000 |
| commit | 2bb33dd7772af050018cc070d814ca817fa006ff (patch) | |
| tree | 866d143f38922cc516f9cec0a40348f9f03b1b38 | |
| parent | 02a0b99cd08756fba07393b2f6abe9d96dffb733 (diff) | |
Notes
| -rw-r--r-- | sys/dev/usb/template/usb_template.c | 4 | ||||
| -rw-r--r-- | sys/dev/usb/usb_device.c | 44 | ||||
| -rw-r--r-- | sys/dev/usb/usb_device.h | 5 | ||||
| -rw-r--r-- | sys/dev/usb/usb_generic.c | 11 | ||||
| -rw-r--r-- | sys/dev/usb/usb_request.c | 15 | ||||
| -rw-r--r-- | sys/dev/usb/usb_transfer.c | 4 | ||||
| -rw-r--r-- | sys/dev/usb/usb_util.c | 4 | ||||
| -rw-r--r-- | sys/sys/param.h | 2 |
8 files changed, 61 insertions, 28 deletions
diff --git a/sys/dev/usb/template/usb_template.c b/sys/dev/usb/template/usb_template.c index ce48b3fe7c5c..805fb8ffe103 100644 --- a/sys/dev/usb/template/usb_template.c +++ b/sys/dev/usb/template/usb_template.c @@ -1240,7 +1240,7 @@ usb_temp_setup(struct usb_device *udev, return (0); /* Protect scratch area */ - do_unlock = usbd_enum_lock(udev); + do_unlock = usbd_ctrl_lock(udev); uts = udev->scratch.temp_setup; @@ -1319,7 +1319,7 @@ done: if (error) usb_temp_unsetup(udev); if (do_unlock) - usbd_enum_unlock(udev); + usbd_ctrl_unlock(udev); return (error); } diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 638aef41c9ea..de30122b37a7 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -1550,6 +1550,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, /* initialise our SX-lock */ sx_init_flags(&udev->enum_sx, "USB config SX lock", SX_DUPOK); sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", SX_NOWITNESS); + sx_init_flags(&udev->ctrl_sx, "USB control transfer SX lock", SX_DUPOK); cv_init(&udev->ctrlreq_cv, "WCTRL"); cv_init(&udev->ref_cv, "UGONE"); @@ -1735,7 +1736,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, */ /* Protect scratch area */ - do_unlock = usbd_enum_lock(udev); + do_unlock = usbd_ctrl_lock(udev); scratch_ptr = udev->scratch.data; @@ -1786,7 +1787,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, } if (do_unlock) - usbd_enum_unlock(udev); + usbd_ctrl_unlock(udev); /* assume 100mA bus powered for now. Changed when configured. */ udev->power = USB_MIN_POWER; @@ -2148,6 +2149,7 @@ usb_free_device(struct usb_device *udev, uint8_t flag) sx_destroy(&udev->enum_sx); sx_destroy(&udev->sr_sx); + sx_destroy(&udev->ctrl_sx); cv_destroy(&udev->ctrlreq_cv); cv_destroy(&udev->ref_cv); @@ -2311,7 +2313,7 @@ usbd_set_device_strings(struct usb_device *udev) uint8_t do_unlock; /* Protect scratch area */ - do_unlock = usbd_enum_lock(udev); + do_unlock = usbd_ctrl_lock(udev); temp_ptr = (char *)udev->scratch.data; temp_size = sizeof(udev->scratch.data); @@ -2371,7 +2373,7 @@ usbd_set_device_strings(struct usb_device *udev) } if (do_unlock) - usbd_enum_unlock(udev); + usbd_ctrl_unlock(udev); } /* @@ -2853,6 +2855,40 @@ usbd_enum_is_locked(struct usb_device *udev) } /* + * The following function is used to serialize access to USB control + * transfers and the USB scratch area. If the lock is already grabbed + * this function returns zero. Else a value of one is returned. + */ +uint8_t +usbd_ctrl_lock(struct usb_device *udev) +{ + if (sx_xlocked(&udev->ctrl_sx)) + return (0); + sx_xlock(&udev->ctrl_sx); + + /* + * We need to allow suspend and resume at this point, else the + * control transfer will timeout if the device is suspended! + */ + if (usbd_enum_is_locked(udev)) + usbd_sr_unlock(udev); + return (1); +} + +void +usbd_ctrl_unlock(struct usb_device *udev) +{ + sx_xunlock(&udev->ctrl_sx); + + /* + * Restore the suspend and resume lock after we have unlocked + * the USB control transfer lock to avoid LOR: + */ + if (usbd_enum_is_locked(udev)) + usbd_sr_lock(udev); +} + +/* * The following function is used to set the per-interface specific * plug and play information. The string referred to by the pnpinfo * argument can safely be freed after calling this function. The diff --git a/sys/dev/usb/usb_device.h b/sys/dev/usb/usb_device.h index b4ff58f225ff..063ea2dc1a35 100644 --- a/sys/dev/usb/usb_device.h +++ b/sys/dev/usb/usb_device.h @@ -162,7 +162,7 @@ struct usb_temp_setup { /* * The scratch area for USB devices. Access to this structure is - * protected by the enumeration SX lock. + * protected by the control SX lock. */ union usb_device_scratch { struct usb_hw_ep_scratch hw_ep_scratch[1]; @@ -183,6 +183,7 @@ struct usb_device { struct usb_udev_msg cs_msg[2]; struct sx enum_sx; struct sx sr_sx; + struct sx ctrl_sx; struct mtx device_mtx; struct cv ctrlreq_cv; struct cv ref_cv; @@ -309,6 +310,8 @@ uint8_t usbd_enum_lock_sig(struct usb_device *); void usbd_enum_unlock(struct usb_device *); void usbd_sr_lock(struct usb_device *); void usbd_sr_unlock(struct usb_device *); +uint8_t usbd_ctrl_lock(struct usb_device *); +void usbd_ctrl_unlock(struct usb_device *); uint8_t usbd_enum_is_locked(struct usb_device *); #if USB_HAVE_TT_SUPPORT diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c index dc796dc09a99..f5014f61b667 100644 --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -706,16 +706,16 @@ ugen_get_cdesc(struct usb_fifo *f, struct usb_gen_descriptor *ugd) return (error); } -/* - * This function is called having the enumeration SX locked which - * protects the scratch area used. - */ static int ugen_get_sdesc(struct usb_fifo *f, struct usb_gen_descriptor *ugd) { void *ptr; uint16_t size; int error; + uint8_t do_unlock; + + /* Protect scratch area */ + do_unlock = usbd_ctrl_lock(f->udev); ptr = f->udev->scratch.data; size = sizeof(f->udev->scratch.data); @@ -736,6 +736,9 @@ ugen_get_sdesc(struct usb_fifo *f, struct usb_gen_descriptor *ugd) error = copyout(ptr, ugd->ugd_data, size); } + if (do_unlock) + usbd_ctrl_unlock(f->udev); + return (error); } diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c index 5574795de190..982835a906b9 100644 --- a/sys/dev/usb/usb_request.c +++ b/sys/dev/usb/usb_request.c @@ -453,16 +453,9 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, } /* - * Grab the USB device enumeration SX-lock serialization is - * achieved when multiple threads are involved: + * Serialize access to this function: */ - do_unlock = usbd_enum_lock(udev); - - /* - * We need to allow suspend and resume at this point, else the - * control transfer will timeout if the device is suspended! - */ - usbd_sr_unlock(udev); + do_unlock = usbd_ctrl_lock(udev); hr_func = usbd_get_hr_func(udev); @@ -706,10 +699,8 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, USB_XFER_UNLOCK(xfer); done: - usbd_sr_lock(udev); - if (do_unlock) - usbd_enum_unlock(udev); + usbd_ctrl_unlock(udev); if ((mtx != NULL) && (mtx != &Giant)) mtx_lock(mtx); diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index 3fe4ff4c1c17..4ec6ecdc4ef2 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -872,7 +872,7 @@ usbd_transfer_setup(struct usb_device *udev, return (error); /* Protect scratch area */ - do_unlock = usbd_enum_lock(udev); + do_unlock = usbd_ctrl_lock(udev); refcount = 0; info = NULL; @@ -1170,7 +1170,7 @@ done: error = parm->err; if (do_unlock) - usbd_enum_unlock(udev); + usbd_ctrl_unlock(udev); return (error); } diff --git a/sys/dev/usb/usb_util.c b/sys/dev/usb/usb_util.c index 1aeb9461c366..7aa45b9a49b8 100644 --- a/sys/dev/usb/usb_util.c +++ b/sys/dev/usb/usb_util.c @@ -119,7 +119,7 @@ device_set_usb_desc(device_t dev) } /* Protect scratch area */ - do_unlock = usbd_enum_lock(udev); + do_unlock = usbd_ctrl_lock(udev); temp_p = (char *)udev->scratch.data; @@ -136,7 +136,7 @@ device_set_usb_desc(device_t dev) } if (do_unlock) - usbd_enum_unlock(udev); + usbd_ctrl_unlock(udev); device_set_desc_copy(dev, temp_p); device_printf(dev, "<%s> on %s\n", temp_p, diff --git a/sys/sys/param.h b/sys/sys/param.h index ac3a8e9a97b7..e5460391c8f0 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 804508 /* Master, propagated to newvers */ +#define __FreeBSD_version 804509 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, |
