diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c index 7401b9dbfd37..a9fcdd8418ab 100644 --- a/sys/dev/usb/usb_subr.c +++ b/sys/dev/usb/usb_subr.c @@ -708,12 +708,19 @@ usbd_set_config_index(struct usbd_device *dev, int index, int msg) usb_bos_descriptor_t *bdp = NULL; usbd_status err; int i, ifcidx, nifc, len, selfpowered, power; + struct lwp *l; + if ((l = atomic_cas_ptr(&dev->ud_configlock, NULL, curlwp)) != NULL) { + panic("bus %u device %u: concurrent %s by lwp %u [%s]", + dev->ud_bus->ub_busnum, dev->ud_addr, __func__, + l->l_lid, l->l_name ? l->l_name : l->l_proc->p_comm); + } if (index >= dev->ud_ddesc.bNumConfigurations && index != USB_UNCONFIG_INDEX) { /* panic? */ printf("usbd_set_config_index: illegal index\n"); + atomic_store_relaxed(&dev->ud_configlock, NULL); return USBD_INVAL; } @@ -739,6 +746,9 @@ usbd_set_config_index(struct usbd_device *dev, int index, int msg) dev->ud_config = USB_UNCONFIG_NO; } + KASSERT(dev->ud_config == USB_UNCONFIG_NO); + KASSERT(dev->ud_ifaces == NULL); + if (index == USB_UNCONFIG_INDEX) { /* We are unconfiguring the device, so leave unallocated. */ DPRINTF("set config 0", 0, 0, 0, 0); @@ -747,6 +757,7 @@ usbd_set_config_index(struct usbd_device *dev, int index, int msg) DPRINTF("setting config=0 failed, err = %jd", err, 0, 0, 0); } + atomic_store_relaxed(&dev->ud_configlock, NULL); return err; } @@ -754,11 +765,13 @@ usbd_set_config_index(struct usbd_device *dev, int index, int msg) err = usbd_get_config_desc(dev, index, &cd); if (err) { DPRINTF("get_config_desc=%jd", err, 0, 0, 0); + atomic_store_relaxed(&dev->ud_configlock, NULL); return err; } len = UGETW(cd.wTotalLength); if (len < USB_CONFIG_DESCRIPTOR_SIZE) { DPRINTF("empty short descriptor", 0, 0, 0, 0); + atomic_store_relaxed(&dev->ud_configlock, NULL); return USBD_INVAL; } cdp = kmem_alloc(len, KM_SLEEP); @@ -929,6 +942,7 @@ usbd_set_config_index(struct usbd_device *dev, int index, int msg) } } + atomic_store_relaxed(&dev->ud_configlock, NULL); return USBD_NORMAL_COMPLETION; bad: @@ -942,6 +956,7 @@ bad: kmem_free(bdp, UGETW(bdp->wTotalLength)); dev->ud_bdesc = NULL; } + atomic_store_relaxed(&dev->ud_configlock, NULL); return err; } @@ -1455,6 +1470,7 @@ usbd_new_device(device_t parent, struct usbd_bus *bus, int depth, int speed, dev->ud_quirks = &usbd_no_quirk; dev->ud_addr = USB_START_ADDR; + dev->ud_config = USB_UNCONFIG_NO; dev->ud_ddesc.bMaxPacketSize = 0; dev->ud_depth = depth; dev->ud_powersrc = up; diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h index 2ff3cbe6cfbd..c0a427eeea13 100644 --- a/sys/dev/usb/usbdivar.h +++ b/sys/dev/usb/usbdivar.h @@ -228,6 +228,8 @@ struct usbd_device { char *ud_serial; /* serial number, can be NULL */ char *ud_vendor; /* vendor string, can be NULL */ char *ud_product; /* product string can be NULL */ + + struct lwp *ud_configlock; }; struct usbd_interface {