USB fixes for 4.14-rc4

Here are a number of USB fixes for 4.14-rc4 to resolved reported issue.
 
 There's a bunch of stuff in here based on the great work Andrey
 Konovalov is doing in fuzzing the USB stack.  Lots of bug fixes when
 dealing with corrupted USB descriptors that we've never seen in "normal"
 operation, but is now ensuring the stack is much more hardened overall.
 
 There's also the usual XHCI and gadget driver fixes as well, and a build
 error fix, and a few other minor things, full details in the shortlog.
 
 All of these have been in linux-next with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWdN/yw8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yl6pQCdGY+nPJhzj9EIeFj5QUpSuS4b1pYAoKrbNn+V
 CMpg4iG1oXUtVL8jBbKa
 =fVpl
 -----END PGP SIGNATURE-----

Merge tag 'usb-4.14-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are a number of USB fixes for 4.14-rc4 to resolved reported
  issues.

  There's a bunch of stuff in here based on the great work Andrey
  Konovalov is doing in fuzzing the USB stack. Lots of bug fixes when
  dealing with corrupted USB descriptors that we've never seen in
  "normal" operation, but is now ensuring the stack is much more
  hardened overall.

  There's also the usual XHCI and gadget driver fixes as well, and a
  build error fix, and a few other minor things, full details in the
  shortlog.

  All of these have been in linux-next with no reported issues"

* tag 'usb-4.14-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (38 commits)
  usb: dwc3: of-simple: Add compatible for Spreadtrum SC9860 platform
  usb: gadget: udc: atmel: set vbus irqflags explicitly
  usb: gadget: ffs: handle I/O completion in-order
  usb: renesas_usbhs: fix usbhsf_fifo_clear() for RX direction
  usb: renesas_usbhs: fix the BCLR setting condition for non-DCP pipe
  usb: gadget: udc: renesas_usb3: Fix return value of usb3_write_pipe()
  usb: gadget: udc: renesas_usb3: fix Pn_RAMMAP.Pn_MPKT value
  usb: gadget: udc: renesas_usb3: fix for no-data control transfer
  USB: dummy-hcd: Fix erroneous synchronization change
  USB: dummy-hcd: fix infinite-loop resubmission bug
  USB: dummy-hcd: fix connection failures (wrong speed)
  USB: cdc-wdm: ignore -EPIPE from GetEncapsulatedResponse
  USB: devio: Don't corrupt user memory
  USB: devio: Prevent integer overflow in proc_do_submiturb()
  USB: g_mass_storage: Fix deadlock when driver is unbound
  USB: gadgetfs: Fix crash caused by inadequate synchronization
  USB: gadgetfs: fix copy_to_user while holding spinlock
  USB: uas: fix bug in handling of alternate settings
  usb-storage: unusual_devs entry to fix write-access regression for Seagate external drives
  usb-storage: fix bogus hardware error messages for ATA pass-thru devices
  ...
This commit is contained in:
Linus Torvalds 2017-10-03 09:25:40 -07:00
commit 887c8ba753
33 changed files with 277 additions and 145 deletions

View File

@ -190,8 +190,10 @@ static void wdm_in_callback(struct urb *urb)
/* /*
* only set a new error if there is no previous error. * only set a new error if there is no previous error.
* Errors are only cleared during read/open * Errors are only cleared during read/open
* Avoid propagating -EPIPE (stall) to userspace since it is
* better handled as an empty read
*/ */
if (desc->rerr == 0) if (desc->rerr == 0 && status != -EPIPE)
desc->rerr = status; desc->rerr = status;
if (length + desc->length > desc->wMaxCommand) { if (length + desc->length > desc->wMaxCommand) {

View File

@ -643,15 +643,23 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
} else if (header->bDescriptorType == } else if (header->bDescriptorType ==
USB_DT_INTERFACE_ASSOCIATION) { USB_DT_INTERFACE_ASSOCIATION) {
struct usb_interface_assoc_descriptor *d;
d = (struct usb_interface_assoc_descriptor *)header;
if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) {
dev_warn(ddev,
"config %d has an invalid interface association descriptor of length %d, skipping\n",
cfgno, d->bLength);
continue;
}
if (iad_num == USB_MAXIADS) { if (iad_num == USB_MAXIADS) {
dev_warn(ddev, "found more Interface " dev_warn(ddev, "found more Interface "
"Association Descriptors " "Association Descriptors "
"than allocated for in " "than allocated for in "
"configuration %d\n", cfgno); "configuration %d\n", cfgno);
} else { } else {
config->intf_assoc[iad_num] = config->intf_assoc[iad_num] = d;
(struct usb_interface_assoc_descriptor
*)header;
iad_num++; iad_num++;
} }
@ -852,7 +860,7 @@ int usb_get_configuration(struct usb_device *dev)
} }
if (dev->quirks & USB_QUIRK_DELAY_INIT) if (dev->quirks & USB_QUIRK_DELAY_INIT)
msleep(100); msleep(200);
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
bigbuffer, length); bigbuffer, length);

View File

@ -140,6 +140,9 @@ module_param(usbfs_memory_mb, uint, 0644);
MODULE_PARM_DESC(usbfs_memory_mb, MODULE_PARM_DESC(usbfs_memory_mb,
"maximum MB allowed for usbfs buffers (0 = no limit)"); "maximum MB allowed for usbfs buffers (0 = no limit)");
/* Hard limit, necessary to avoid arithmetic overflow */
#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000)
static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */ static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */
/* Check whether it's okay to allocate more memory for a transfer */ /* Check whether it's okay to allocate more memory for a transfer */
@ -1460,6 +1463,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
USBDEVFS_URB_ZERO_PACKET | USBDEVFS_URB_ZERO_PACKET |
USBDEVFS_URB_NO_INTERRUPT)) USBDEVFS_URB_NO_INTERRUPT))
return -EINVAL; return -EINVAL;
if ((unsigned int)uurb->buffer_length >= USBFS_XFER_MAX)
return -EINVAL;
if (uurb->buffer_length > 0 && !uurb->buffer) if (uurb->buffer_length > 0 && !uurb->buffer)
return -EINVAL; return -EINVAL;
if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
@ -1571,7 +1576,11 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
totlen += isopkt[u].length; totlen += isopkt[u].length;
} }
u *= sizeof(struct usb_iso_packet_descriptor); u *= sizeof(struct usb_iso_packet_descriptor);
uurb->buffer_length = totlen; if (totlen <= uurb->buffer_length)
uurb->buffer_length = totlen;
else
WARN_ONCE(1, "uurb->buffer_length is too short %d vs %d",
totlen, uurb->buffer_length);
break; break;
default: default:

View File

@ -4838,7 +4838,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
goto loop; goto loop;
if (udev->quirks & USB_QUIRK_DELAY_INIT) if (udev->quirks & USB_QUIRK_DELAY_INIT)
msleep(1000); msleep(2000);
/* consecutive bus-powered hubs aren't reliable; they can /* consecutive bus-powered hubs aren't reliable; they can
* violate the voltage drop budget. if the new child has * violate the voltage drop budget. if the new child has

View File

@ -2069,6 +2069,10 @@ int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
elength = 1; elength = 1;
goto next_desc; goto next_desc;
} }
if ((buflen < elength) || (elength < 3)) {
dev_err(&intf->dev, "invalid descriptor buffer length\n");
break;
}
if (buffer[1] != USB_DT_CS_INTERFACE) { if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n"); dev_err(&intf->dev, "skipping garbage\n");
goto next_desc; goto next_desc;

View File

@ -177,6 +177,7 @@ static const struct of_device_id of_dwc3_simple_match[] = {
{ .compatible = "rockchip,rk3399-dwc3" }, { .compatible = "rockchip,rk3399-dwc3" },
{ .compatible = "xlnx,zynqmp-dwc3" }, { .compatible = "xlnx,zynqmp-dwc3" },
{ .compatible = "cavium,octeon-7130-usb-uctl" }, { .compatible = "cavium,octeon-7130-usb-uctl" },
{ .compatible = "sprd,sc9860-dwc3" },
{ /* Sentinel */ } { /* Sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, of_dwc3_simple_match); MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);

View File

@ -990,6 +990,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
DWC3_TRBCTL_CONTROL_DATA, DWC3_TRBCTL_CONTROL_DATA,
true); true);
req->trb = &dwc->ep0_trb[dep->trb_enqueue - 1];
/* Now prepare one extra TRB to align transfer size */ /* Now prepare one extra TRB to align transfer size */
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
maxpacket - rem, maxpacket - rem,
@ -1015,6 +1017,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
DWC3_TRBCTL_CONTROL_DATA, DWC3_TRBCTL_CONTROL_DATA,
true); true);
req->trb = &dwc->ep0_trb[dep->trb_enqueue - 1];
/* Now prepare one extra TRB to align transfer size */ /* Now prepare one extra TRB to align transfer size */
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
0, DWC3_TRBCTL_CONTROL_DATA, 0, DWC3_TRBCTL_CONTROL_DATA,
@ -1029,6 +1033,9 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
dwc3_ep0_prepare_one_trb(dep, req->request.dma, dwc3_ep0_prepare_one_trb(dep, req->request.dma,
req->request.length, DWC3_TRBCTL_CONTROL_DATA, req->request.length, DWC3_TRBCTL_CONTROL_DATA,
false); false);
req->trb = &dwc->ep0_trb[dep->trb_enqueue];
ret = dwc3_ep0_start_trans(dep); ret = dwc3_ep0_start_trans(dep);
} }

View File

@ -46,7 +46,8 @@
static void ffs_data_get(struct ffs_data *ffs); static void ffs_data_get(struct ffs_data *ffs);
static void ffs_data_put(struct ffs_data *ffs); static void ffs_data_put(struct ffs_data *ffs);
/* Creates new ffs_data object. */ /* Creates new ffs_data object. */
static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc)); static struct ffs_data *__must_check ffs_data_new(const char *dev_name)
__attribute__((malloc));
/* Opened counter handling. */ /* Opened counter handling. */
static void ffs_data_opened(struct ffs_data *ffs); static void ffs_data_opened(struct ffs_data *ffs);
@ -780,11 +781,12 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
struct usb_request *req) struct usb_request *req)
{ {
struct ffs_io_data *io_data = req->context; struct ffs_io_data *io_data = req->context;
struct ffs_data *ffs = io_data->ffs;
ENTER(); ENTER();
INIT_WORK(&io_data->work, ffs_user_copy_worker); INIT_WORK(&io_data->work, ffs_user_copy_worker);
schedule_work(&io_data->work); queue_work(ffs->io_completion_wq, &io_data->work);
} }
static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile) static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile)
@ -1500,7 +1502,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return ERR_PTR(ret); return ERR_PTR(ret);
ffs = ffs_data_new(); ffs = ffs_data_new(dev_name);
if (unlikely(!ffs)) if (unlikely(!ffs))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ffs->file_perms = data.perms; ffs->file_perms = data.perms;
@ -1610,6 +1612,7 @@ static void ffs_data_put(struct ffs_data *ffs)
BUG_ON(waitqueue_active(&ffs->ev.waitq) || BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
waitqueue_active(&ffs->ep0req_completion.wait) || waitqueue_active(&ffs->ep0req_completion.wait) ||
waitqueue_active(&ffs->wait)); waitqueue_active(&ffs->wait));
destroy_workqueue(ffs->io_completion_wq);
kfree(ffs->dev_name); kfree(ffs->dev_name);
kfree(ffs); kfree(ffs);
} }
@ -1642,7 +1645,7 @@ static void ffs_data_closed(struct ffs_data *ffs)
ffs_data_put(ffs); ffs_data_put(ffs);
} }
static struct ffs_data *ffs_data_new(void) static struct ffs_data *ffs_data_new(const char *dev_name)
{ {
struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL); struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
if (unlikely(!ffs)) if (unlikely(!ffs))
@ -1650,6 +1653,12 @@ static struct ffs_data *ffs_data_new(void)
ENTER(); ENTER();
ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
if (!ffs->io_completion_wq) {
kfree(ffs);
return NULL;
}
refcount_set(&ffs->ref, 1); refcount_set(&ffs->ref, 1);
atomic_set(&ffs->opened, 0); atomic_set(&ffs->opened, 0);
ffs->state = FFS_READ_DESCRIPTORS; ffs->state = FFS_READ_DESCRIPTORS;

View File

@ -307,8 +307,6 @@ struct fsg_common {
struct completion thread_notifier; struct completion thread_notifier;
struct task_struct *thread_task; struct task_struct *thread_task;
/* Callback functions. */
const struct fsg_operations *ops;
/* Gadget's private data. */ /* Gadget's private data. */
void *private_data; void *private_data;
@ -2438,6 +2436,7 @@ static void handle_exception(struct fsg_common *common)
static int fsg_main_thread(void *common_) static int fsg_main_thread(void *common_)
{ {
struct fsg_common *common = common_; struct fsg_common *common = common_;
int i;
/* /*
* Allow the thread to be killed by a signal, but set the signal mask * Allow the thread to be killed by a signal, but set the signal mask
@ -2476,21 +2475,16 @@ static int fsg_main_thread(void *common_)
common->thread_task = NULL; common->thread_task = NULL;
spin_unlock_irq(&common->lock); spin_unlock_irq(&common->lock);
if (!common->ops || !common->ops->thread_exits /* Eject media from all LUNs */
|| common->ops->thread_exits(common) < 0) {
int i;
down_write(&common->filesem); down_write(&common->filesem);
for (i = 0; i < ARRAY_SIZE(common->luns); i++) { for (i = 0; i < ARRAY_SIZE(common->luns); i++) {
struct fsg_lun *curlun = common->luns[i]; struct fsg_lun *curlun = common->luns[i];
if (!curlun || !fsg_lun_is_open(curlun))
continue;
if (curlun && fsg_lun_is_open(curlun))
fsg_lun_close(curlun); fsg_lun_close(curlun);
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
}
up_write(&common->filesem);
} }
up_write(&common->filesem);
/* Let fsg_unbind() know the thread has exited */ /* Let fsg_unbind() know the thread has exited */
complete_and_exit(&common->thread_notifier, 0); complete_and_exit(&common->thread_notifier, 0);
@ -2681,13 +2675,6 @@ void fsg_common_remove_luns(struct fsg_common *common)
} }
EXPORT_SYMBOL_GPL(fsg_common_remove_luns); EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
void fsg_common_set_ops(struct fsg_common *common,
const struct fsg_operations *ops)
{
common->ops = ops;
}
EXPORT_SYMBOL_GPL(fsg_common_set_ops);
void fsg_common_free_buffers(struct fsg_common *common) void fsg_common_free_buffers(struct fsg_common *common)
{ {
_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);

View File

@ -60,17 +60,6 @@ struct fsg_module_parameters {
struct fsg_common; struct fsg_common;
/* FSF callback functions */ /* FSF callback functions */
struct fsg_operations {
/*
* Callback function to call when thread exits. If no
* callback is set or it returns value lower then zero MSF
* will force eject all LUNs it operates on (including those
* marked as non-removable or with prevent_medium_removal flag
* set).
*/
int (*thread_exits)(struct fsg_common *common);
};
struct fsg_lun_opts { struct fsg_lun_opts {
struct config_group group; struct config_group group;
struct fsg_lun *lun; struct fsg_lun *lun;
@ -142,9 +131,6 @@ void fsg_common_remove_lun(struct fsg_lun *lun);
void fsg_common_remove_luns(struct fsg_common *common); void fsg_common_remove_luns(struct fsg_common *common);
void fsg_common_set_ops(struct fsg_common *common,
const struct fsg_operations *ops);
int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
unsigned int id, const char *name, unsigned int id, const char *name,
const char **name_pfx); const char **name_pfx);

View File

@ -555,6 +555,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
size_t size; /* Amount of data in a TX request. */ size_t size; /* Amount of data in a TX request. */
size_t bytes_copied = 0; size_t bytes_copied = 0;
struct usb_request *req; struct usb_request *req;
int value;
DBG(dev, "printer_write trying to send %d bytes\n", (int)len); DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
@ -634,7 +635,11 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
return -EAGAIN; return -EAGAIN;
} }
if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) { /* here, we unlock, and only unlock, to avoid deadlock. */
spin_unlock(&dev->lock);
value = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
spin_lock(&dev->lock);
if (value) {
list_add(&req->list, &dev->tx_reqs); list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->lock_printer_io); mutex_unlock(&dev->lock_printer_io);

View File

@ -279,6 +279,7 @@ struct ffs_data {
} file_perms; } file_perms;
struct eventfd_ctx *ffs_eventfd; struct eventfd_ctx *ffs_eventfd;
struct workqueue_struct *io_completion_wq;
bool no_disconnect; bool no_disconnect;
struct work_struct reset_work; struct work_struct reset_work;

View File

@ -28,7 +28,7 @@
#include <linux/aio.h> #include <linux/aio.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/refcount.h> #include <linux/refcount.h>
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
@ -116,6 +116,7 @@ enum ep0_state {
struct dev_data { struct dev_data {
spinlock_t lock; spinlock_t lock;
refcount_t count; refcount_t count;
int udc_usage;
enum ep0_state state; /* P: lock */ enum ep0_state state; /* P: lock */
struct usb_gadgetfs_event event [N_EVENT]; struct usb_gadgetfs_event event [N_EVENT];
unsigned ev_next; unsigned ev_next;
@ -513,9 +514,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
INIT_WORK(&priv->work, ep_user_copy_worker); INIT_WORK(&priv->work, ep_user_copy_worker);
schedule_work(&priv->work); schedule_work(&priv->work);
} }
spin_unlock(&epdata->dev->lock);
usb_ep_free_request(ep, req); usb_ep_free_request(ep, req);
spin_unlock(&epdata->dev->lock);
put_ep(epdata); put_ep(epdata);
} }
@ -939,9 +940,11 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
struct usb_request *req = dev->req; struct usb_request *req = dev->req;
if ((retval = setup_req (ep, req, 0)) == 0) { if ((retval = setup_req (ep, req, 0)) == 0) {
++dev->udc_usage;
spin_unlock_irq (&dev->lock); spin_unlock_irq (&dev->lock);
retval = usb_ep_queue (ep, req, GFP_KERNEL); retval = usb_ep_queue (ep, req, GFP_KERNEL);
spin_lock_irq (&dev->lock); spin_lock_irq (&dev->lock);
--dev->udc_usage;
} }
dev->state = STATE_DEV_CONNECTED; dev->state = STATE_DEV_CONNECTED;
@ -983,11 +986,14 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
retval = -EIO; retval = -EIO;
else { else {
len = min (len, (size_t)dev->req->actual); len = min (len, (size_t)dev->req->actual);
// FIXME don't call this with the spinlock held ... ++dev->udc_usage;
spin_unlock_irq(&dev->lock);
if (copy_to_user (buf, dev->req->buf, len)) if (copy_to_user (buf, dev->req->buf, len))
retval = -EFAULT; retval = -EFAULT;
else else
retval = len; retval = len;
spin_lock_irq(&dev->lock);
--dev->udc_usage;
clean_req (dev->gadget->ep0, dev->req); clean_req (dev->gadget->ep0, dev->req);
/* NOTE userspace can't yet choose to stall */ /* NOTE userspace can't yet choose to stall */
} }
@ -1131,6 +1137,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
retval = setup_req (dev->gadget->ep0, dev->req, len); retval = setup_req (dev->gadget->ep0, dev->req, len);
if (retval == 0) { if (retval == 0) {
dev->state = STATE_DEV_CONNECTED; dev->state = STATE_DEV_CONNECTED;
++dev->udc_usage;
spin_unlock_irq (&dev->lock); spin_unlock_irq (&dev->lock);
if (copy_from_user (dev->req->buf, buf, len)) if (copy_from_user (dev->req->buf, buf, len))
retval = -EFAULT; retval = -EFAULT;
@ -1142,6 +1149,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
GFP_KERNEL); GFP_KERNEL);
} }
spin_lock_irq(&dev->lock); spin_lock_irq(&dev->lock);
--dev->udc_usage;
if (retval < 0) { if (retval < 0) {
clean_req (dev->gadget->ep0, dev->req); clean_req (dev->gadget->ep0, dev->req);
} else } else
@ -1243,9 +1251,21 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
struct usb_gadget *gadget = dev->gadget; struct usb_gadget *gadget = dev->gadget;
long ret = -ENOTTY; long ret = -ENOTTY;
if (gadget->ops->ioctl) spin_lock_irq(&dev->lock);
if (dev->state == STATE_DEV_OPENED ||
dev->state == STATE_DEV_UNBOUND) {
/* Not bound to a UDC */
} else if (gadget->ops->ioctl) {
++dev->udc_usage;
spin_unlock_irq(&dev->lock);
ret = gadget->ops->ioctl (gadget, code, value); ret = gadget->ops->ioctl (gadget, code, value);
spin_lock_irq(&dev->lock);
--dev->udc_usage;
}
spin_unlock_irq(&dev->lock);
return ret; return ret;
} }
@ -1463,10 +1483,12 @@ delegate:
if (value < 0) if (value < 0)
break; break;
++dev->udc_usage;
spin_unlock (&dev->lock); spin_unlock (&dev->lock);
value = usb_ep_queue (gadget->ep0, dev->req, value = usb_ep_queue (gadget->ep0, dev->req,
GFP_KERNEL); GFP_KERNEL);
spin_lock (&dev->lock); spin_lock (&dev->lock);
--dev->udc_usage;
if (value < 0) { if (value < 0) {
clean_req (gadget->ep0, dev->req); clean_req (gadget->ep0, dev->req);
break; break;
@ -1490,8 +1512,12 @@ delegate:
req->length = value; req->length = value;
req->zero = value < w_length; req->zero = value < w_length;
++dev->udc_usage;
spin_unlock (&dev->lock); spin_unlock (&dev->lock);
value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL); value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL);
spin_lock(&dev->lock);
--dev->udc_usage;
spin_unlock(&dev->lock);
if (value < 0) { if (value < 0) {
DBG (dev, "ep_queue --> %d\n", value); DBG (dev, "ep_queue --> %d\n", value);
req->status = 0; req->status = 0;
@ -1518,21 +1544,24 @@ static void destroy_ep_files (struct dev_data *dev)
/* break link to FS */ /* break link to FS */
ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles); ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
list_del_init (&ep->epfiles); list_del_init (&ep->epfiles);
spin_unlock_irq (&dev->lock);
dentry = ep->dentry; dentry = ep->dentry;
ep->dentry = NULL; ep->dentry = NULL;
parent = d_inode(dentry->d_parent); parent = d_inode(dentry->d_parent);
/* break link to controller */ /* break link to controller */
mutex_lock(&ep->lock);
if (ep->state == STATE_EP_ENABLED) if (ep->state == STATE_EP_ENABLED)
(void) usb_ep_disable (ep->ep); (void) usb_ep_disable (ep->ep);
ep->state = STATE_EP_UNBOUND; ep->state = STATE_EP_UNBOUND;
usb_ep_free_request (ep->ep, ep->req); usb_ep_free_request (ep->ep, ep->req);
ep->ep = NULL; ep->ep = NULL;
mutex_unlock(&ep->lock);
wake_up (&ep->wait); wake_up (&ep->wait);
put_ep (ep); put_ep (ep);
spin_unlock_irq (&dev->lock);
/* break link to dcache */ /* break link to dcache */
inode_lock(parent); inode_lock(parent);
d_delete (dentry); d_delete (dentry);
@ -1603,6 +1632,11 @@ gadgetfs_unbind (struct usb_gadget *gadget)
spin_lock_irq (&dev->lock); spin_lock_irq (&dev->lock);
dev->state = STATE_DEV_UNBOUND; dev->state = STATE_DEV_UNBOUND;
while (dev->udc_usage > 0) {
spin_unlock_irq(&dev->lock);
usleep_range(1000, 2000);
spin_lock_irq(&dev->lock);
}
spin_unlock_irq (&dev->lock); spin_unlock_irq (&dev->lock);
destroy_ep_files (dev); destroy_ep_files (dev);

View File

@ -107,15 +107,6 @@ static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data); FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
static unsigned long msg_registered;
static void msg_cleanup(void);
static int msg_thread_exits(struct fsg_common *common)
{
msg_cleanup();
return 0;
}
static int msg_do_config(struct usb_configuration *c) static int msg_do_config(struct usb_configuration *c)
{ {
struct fsg_opts *opts; struct fsg_opts *opts;
@ -154,9 +145,6 @@ static struct usb_configuration msg_config_driver = {
static int msg_bind(struct usb_composite_dev *cdev) static int msg_bind(struct usb_composite_dev *cdev)
{ {
static const struct fsg_operations ops = {
.thread_exits = msg_thread_exits,
};
struct fsg_opts *opts; struct fsg_opts *opts;
struct fsg_config config; struct fsg_config config;
int status; int status;
@ -173,8 +161,6 @@ static int msg_bind(struct usb_composite_dev *cdev)
if (status) if (status)
goto fail; goto fail;
fsg_common_set_ops(opts->common, &ops);
status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
if (status) if (status)
goto fail_set_cdev; goto fail_set_cdev;
@ -256,18 +242,12 @@ MODULE_LICENSE("GPL");
static int __init msg_init(void) static int __init msg_init(void)
{ {
int ret; return usb_composite_probe(&msg_driver);
ret = usb_composite_probe(&msg_driver);
set_bit(0, &msg_registered);
return ret;
} }
module_init(msg_init); module_init(msg_init);
static void msg_cleanup(void) static void __exit msg_cleanup(void)
{ {
if (test_and_clear_bit(0, &msg_registered)) usb_composite_unregister(&msg_driver);
usb_composite_unregister(&msg_driver);
} }
module_exit(msg_cleanup); module_exit(msg_cleanup);

View File

@ -273,6 +273,7 @@ config USB_SNP_CORE
config USB_SNP_UDC_PLAT config USB_SNP_UDC_PLAT
tristate "Synopsys USB 2.0 Device controller" tristate "Synopsys USB 2.0 Device controller"
depends on USB_GADGET && OF && HAS_DMA depends on USB_GADGET && OF && HAS_DMA
depends on EXTCON || EXTCON=n
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
select USB_SNP_CORE select USB_SNP_CORE
default ARCH_BCM_IPROC default ARCH_BCM_IPROC

View File

@ -29,6 +29,8 @@
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include "atmel_usba_udc.h" #include "atmel_usba_udc.h"
#define USBA_VBUS_IRQFLAGS (IRQF_ONESHOT \
| IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)
#ifdef CONFIG_USB_GADGET_DEBUG_FS #ifdef CONFIG_USB_GADGET_DEBUG_FS
#include <linux/debugfs.h> #include <linux/debugfs.h>
@ -2361,7 +2363,7 @@ static int usba_udc_probe(struct platform_device *pdev)
IRQ_NOAUTOEN); IRQ_NOAUTOEN);
ret = devm_request_threaded_irq(&pdev->dev, ret = devm_request_threaded_irq(&pdev->dev,
gpio_to_irq(udc->vbus_pin), NULL, gpio_to_irq(udc->vbus_pin), NULL,
usba_vbus_irq_thread, IRQF_ONESHOT, usba_vbus_irq_thread, USBA_VBUS_IRQFLAGS,
"atmel_usba_udc", udc); "atmel_usba_udc", udc);
if (ret) { if (ret) {
udc->vbus_pin = -ENODEV; udc->vbus_pin = -ENODEV;

View File

@ -1320,8 +1320,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
udc->dev.driver = &driver->driver; udc->dev.driver = &driver->driver;
udc->gadget->dev.driver = &driver->driver; udc->gadget->dev.driver = &driver->driver;
if (driver->max_speed < udc->gadget->max_speed) usb_gadget_udc_set_speed(udc, driver->max_speed);
usb_gadget_udc_set_speed(udc, driver->max_speed);
ret = driver->bind(udc->gadget, driver); ret = driver->bind(udc->gadget, driver);
if (ret) if (ret)

View File

@ -237,6 +237,8 @@ struct dummy_hcd {
struct usb_device *udev; struct usb_device *udev;
struct list_head urbp_list; struct list_head urbp_list;
struct urbp *next_frame_urbp;
u32 stream_en_ep; u32 stream_en_ep;
u8 num_stream[30 / 2]; u8 num_stream[30 / 2];
@ -253,11 +255,13 @@ struct dummy {
*/ */
struct dummy_ep ep[DUMMY_ENDPOINTS]; struct dummy_ep ep[DUMMY_ENDPOINTS];
int address; int address;
int callback_usage;
struct usb_gadget gadget; struct usb_gadget gadget;
struct usb_gadget_driver *driver; struct usb_gadget_driver *driver;
struct dummy_request fifo_req; struct dummy_request fifo_req;
u8 fifo_buf[FIFO_SIZE]; u8 fifo_buf[FIFO_SIZE];
u16 devstatus; u16 devstatus;
unsigned ints_enabled:1;
unsigned udc_suspended:1; unsigned udc_suspended:1;
unsigned pullup:1; unsigned pullup:1;
@ -375,11 +379,10 @@ static void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
USB_PORT_STAT_CONNECTION) == 0) USB_PORT_STAT_CONNECTION) == 0)
dum_hcd->port_status |= dum_hcd->port_status |=
(USB_PORT_STAT_C_CONNECTION << 16); (USB_PORT_STAT_C_CONNECTION << 16);
if ((dum_hcd->port_status & if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) &&
USB_PORT_STAT_ENABLE) == 1 && (dum_hcd->port_status &
(dum_hcd->port_status & USB_PORT_STAT_LINK_STATE) == USB_SS_PORT_LS_U0 &&
USB_SS_PORT_LS_U0) == 1 && dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
dum_hcd->active = 1; dum_hcd->active = 1;
} }
} else { } else {
@ -440,18 +443,27 @@ static void set_link_state(struct dummy_hcd *dum_hcd)
(~dum_hcd->old_status) & dum_hcd->port_status; (~dum_hcd->old_status) & dum_hcd->port_status;
/* Report reset and disconnect events to the driver */ /* Report reset and disconnect events to the driver */
if (dum->driver && (disconnect || reset)) { if (dum->ints_enabled && (disconnect || reset)) {
stop_activity(dum); stop_activity(dum);
++dum->callback_usage;
spin_unlock(&dum->lock);
if (reset) if (reset)
usb_gadget_udc_reset(&dum->gadget, dum->driver); usb_gadget_udc_reset(&dum->gadget, dum->driver);
else else
dum->driver->disconnect(&dum->gadget); dum->driver->disconnect(&dum->gadget);
spin_lock(&dum->lock);
--dum->callback_usage;
} }
} else if (dum_hcd->active != dum_hcd->old_active) { } else if (dum_hcd->active != dum_hcd->old_active &&
dum->ints_enabled) {
++dum->callback_usage;
spin_unlock(&dum->lock);
if (dum_hcd->old_active && dum->driver->suspend) if (dum_hcd->old_active && dum->driver->suspend)
dum->driver->suspend(&dum->gadget); dum->driver->suspend(&dum->gadget);
else if (!dum_hcd->old_active && dum->driver->resume) else if (!dum_hcd->old_active && dum->driver->resume)
dum->driver->resume(&dum->gadget); dum->driver->resume(&dum->gadget);
spin_lock(&dum->lock);
--dum->callback_usage;
} }
dum_hcd->old_status = dum_hcd->port_status; dum_hcd->old_status = dum_hcd->port_status;
@ -972,8 +984,11 @@ static int dummy_udc_start(struct usb_gadget *g,
* can't enumerate without help from the driver we're binding. * can't enumerate without help from the driver we're binding.
*/ */
spin_lock_irq(&dum->lock);
dum->devstatus = 0; dum->devstatus = 0;
dum->driver = driver; dum->driver = driver;
dum->ints_enabled = 1;
spin_unlock_irq(&dum->lock);
return 0; return 0;
} }
@ -984,6 +999,16 @@ static int dummy_udc_stop(struct usb_gadget *g)
struct dummy *dum = dum_hcd->dum; struct dummy *dum = dum_hcd->dum;
spin_lock_irq(&dum->lock); spin_lock_irq(&dum->lock);
dum->ints_enabled = 0;
stop_activity(dum);
/* emulate synchronize_irq(): wait for callbacks to finish */
while (dum->callback_usage > 0) {
spin_unlock_irq(&dum->lock);
usleep_range(1000, 2000);
spin_lock_irq(&dum->lock);
}
dum->driver = NULL; dum->driver = NULL;
spin_unlock_irq(&dum->lock); spin_unlock_irq(&dum->lock);
@ -1037,7 +1062,12 @@ static int dummy_udc_probe(struct platform_device *pdev)
memzero_explicit(&dum->gadget, sizeof(struct usb_gadget)); memzero_explicit(&dum->gadget, sizeof(struct usb_gadget));
dum->gadget.name = gadget_name; dum->gadget.name = gadget_name;
dum->gadget.ops = &dummy_ops; dum->gadget.ops = &dummy_ops;
dum->gadget.max_speed = USB_SPEED_SUPER; if (mod_data.is_super_speed)
dum->gadget.max_speed = USB_SPEED_SUPER;
else if (mod_data.is_high_speed)
dum->gadget.max_speed = USB_SPEED_HIGH;
else
dum->gadget.max_speed = USB_SPEED_FULL;
dum->gadget.dev.parent = &pdev->dev; dum->gadget.dev.parent = &pdev->dev;
init_dummy_udc_hw(dum); init_dummy_udc_hw(dum);
@ -1246,6 +1276,8 @@ static int dummy_urb_enqueue(
list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list); list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
urb->hcpriv = urbp; urb->hcpriv = urbp;
if (!dum_hcd->next_frame_urbp)
dum_hcd->next_frame_urbp = urbp;
if (usb_pipetype(urb->pipe) == PIPE_CONTROL) if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
urb->error_count = 1; /* mark as a new urb */ urb->error_count = 1; /* mark as a new urb */
@ -1521,6 +1553,8 @@ static struct dummy_ep *find_endpoint(struct dummy *dum, u8 address)
if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ? if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
dum->ss_hcd : dum->hs_hcd))) dum->ss_hcd : dum->hs_hcd)))
return NULL; return NULL;
if (!dum->ints_enabled)
return NULL;
if ((address & ~USB_DIR_IN) == 0) if ((address & ~USB_DIR_IN) == 0)
return &dum->ep[0]; return &dum->ep[0];
for (i = 1; i < DUMMY_ENDPOINTS; i++) { for (i = 1; i < DUMMY_ENDPOINTS; i++) {
@ -1762,6 +1796,7 @@ static void dummy_timer(unsigned long _dum_hcd)
spin_unlock_irqrestore(&dum->lock, flags); spin_unlock_irqrestore(&dum->lock, flags);
return; return;
} }
dum_hcd->next_frame_urbp = NULL;
for (i = 0; i < DUMMY_ENDPOINTS; i++) { for (i = 0; i < DUMMY_ENDPOINTS; i++) {
if (!ep_info[i].name) if (!ep_info[i].name)
@ -1778,6 +1813,10 @@ restart:
int type; int type;
int status = -EINPROGRESS; int status = -EINPROGRESS;
/* stop when we reach URBs queued after the timer interrupt */
if (urbp == dum_hcd->next_frame_urbp)
break;
urb = urbp->urb; urb = urbp->urb;
if (urb->unlinked) if (urb->unlinked)
goto return_urb; goto return_urb;
@ -1857,10 +1896,12 @@ restart:
* until setup() returns; no reentrancy issues etc. * until setup() returns; no reentrancy issues etc.
*/ */
if (value > 0) { if (value > 0) {
++dum->callback_usage;
spin_unlock(&dum->lock); spin_unlock(&dum->lock);
value = dum->driver->setup(&dum->gadget, value = dum->driver->setup(&dum->gadget,
&setup); &setup);
spin_lock(&dum->lock); spin_lock(&dum->lock);
--dum->callback_usage;
if (value >= 0) { if (value >= 0) {
/* no delays (max 64KB data stage) */ /* no delays (max 64KB data stage) */
@ -2561,8 +2602,6 @@ static struct hc_driver dummy_hcd = {
.product_desc = "Dummy host controller", .product_desc = "Dummy host controller",
.hcd_priv_size = sizeof(struct dummy_hcd), .hcd_priv_size = sizeof(struct dummy_hcd),
.flags = HCD_USB3 | HCD_SHARED,
.reset = dummy_setup, .reset = dummy_setup,
.start = dummy_start, .start = dummy_start,
.stop = dummy_stop, .stop = dummy_stop,
@ -2591,8 +2630,12 @@ static int dummy_hcd_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
dum = *((void **)dev_get_platdata(&pdev->dev)); dum = *((void **)dev_get_platdata(&pdev->dev));
if (!mod_data.is_super_speed) if (mod_data.is_super_speed)
dummy_hcd.flags = HCD_USB3 | HCD_SHARED;
else if (mod_data.is_high_speed)
dummy_hcd.flags = HCD_USB2; dummy_hcd.flags = HCD_USB2;
else
dummy_hcd.flags = HCD_USB11;
hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
if (!hs_hcd) if (!hs_hcd)
return -ENOMEM; return -ENOMEM;

View File

@ -1038,7 +1038,7 @@ static int usb3_write_pipe(struct renesas_usb3_ep *usb3_ep,
usb3_ep->ep.maxpacket); usb3_ep->ep.maxpacket);
u8 *buf = usb3_req->req.buf + usb3_req->req.actual; u8 *buf = usb3_req->req.buf + usb3_req->req.actual;
u32 tmp = 0; u32 tmp = 0;
bool is_last; bool is_last = !len ? true : false;
if (usb3_wait_pipe_status(usb3_ep, PX_STA_BUFSTS) < 0) if (usb3_wait_pipe_status(usb3_ep, PX_STA_BUFSTS) < 0)
return -EBUSY; return -EBUSY;
@ -1059,7 +1059,8 @@ static int usb3_write_pipe(struct renesas_usb3_ep *usb3_ep,
usb3_write(usb3, tmp, fifo_reg); usb3_write(usb3, tmp, fifo_reg);
} }
is_last = usb3_is_transfer_complete(usb3_ep, usb3_req); if (!is_last)
is_last = usb3_is_transfer_complete(usb3_ep, usb3_req);
/* Send the data */ /* Send the data */
usb3_set_px_con_send(usb3_ep, len, is_last); usb3_set_px_con_send(usb3_ep, len, is_last);
@ -1150,7 +1151,8 @@ static void usb3_start_pipe0(struct renesas_usb3_ep *usb3_ep,
usb3_set_p0_con_for_ctrl_read_data(usb3); usb3_set_p0_con_for_ctrl_read_data(usb3);
} else { } else {
usb3_clear_bit(usb3, P0_MOD_DIR, USB3_P0_MOD); usb3_clear_bit(usb3, P0_MOD_DIR, USB3_P0_MOD);
usb3_set_p0_con_for_ctrl_write_data(usb3); if (usb3_req->req.length)
usb3_set_p0_con_for_ctrl_write_data(usb3);
} }
usb3_p0_xfer(usb3_ep, usb3_req); usb3_p0_xfer(usb3_ep, usb3_req);
@ -2053,7 +2055,16 @@ static u32 usb3_calc_ramarea(int ram_size)
static u32 usb3_calc_rammap_val(struct renesas_usb3_ep *usb3_ep, static u32 usb3_calc_rammap_val(struct renesas_usb3_ep *usb3_ep,
const struct usb_endpoint_descriptor *desc) const struct usb_endpoint_descriptor *desc)
{ {
return usb3_ep->rammap_val | PN_RAMMAP_MPKT(usb_endpoint_maxp(desc)); int i;
const u32 max_packet_array[] = {8, 16, 32, 64, 512};
u32 mpkt = PN_RAMMAP_MPKT(1024);
for (i = 0; i < ARRAY_SIZE(max_packet_array); i++) {
if (usb_endpoint_maxp(desc) <= max_packet_array[i])
mpkt = PN_RAMMAP_MPKT(max_packet_array[i]);
}
return usb3_ep->rammap_val | mpkt;
} }
static int usb3_enable_pipe_n(struct renesas_usb3_ep *usb3_ep, static int usb3_enable_pipe_n(struct renesas_usb3_ep *usb3_ep,

View File

@ -447,7 +447,7 @@ static int usb_asmedia_wait_write(struct pci_dev *pdev)
if ((value & ASMT_CONTROL_WRITE_BIT) == 0) if ((value & ASMT_CONTROL_WRITE_BIT) == 0)
return 0; return 0;
usleep_range(40, 60); udelay(50);
} }
dev_warn(&pdev->dev, "%s: check_write_ready timeout", __func__); dev_warn(&pdev->dev, "%s: check_write_ready timeout", __func__);
@ -1022,7 +1022,7 @@ EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
* *
* Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS. * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS.
* It signals to the BIOS that the OS wants control of the host controller, * It signals to the BIOS that the OS wants control of the host controller,
* and then waits 5 seconds for the BIOS to hand over control. * and then waits 1 second for the BIOS to hand over control.
* If we timeout, assume the BIOS is broken and take control anyway. * If we timeout, assume the BIOS is broken and take control anyway.
*/ */
static void quirk_usb_handoff_xhci(struct pci_dev *pdev) static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
@ -1069,9 +1069,9 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
if (val & XHCI_HC_BIOS_OWNED) { if (val & XHCI_HC_BIOS_OWNED) {
writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset); writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
/* Wait for 5 seconds with 10 microsecond polling interval */ /* Wait for 1 second with 10 microsecond polling interval */
timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED, timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
0, 5000, 10); 0, 1000000, 10);
/* Assume a buggy BIOS and take HC ownership anyway */ /* Assume a buggy BIOS and take HC ownership anyway */
if (timeout) { if (timeout) {
@ -1100,7 +1100,7 @@ hc_init:
* operational or runtime registers. Wait 5 seconds and no more. * operational or runtime registers. Wait 5 seconds and no more.
*/ */
timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0, timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
5000, 10); 5000000, 10);
/* Assume a buggy HC and start HC initialization anyway */ /* Assume a buggy HC and start HC initialization anyway */
if (timeout) { if (timeout) {
val = readl(op_reg_base + XHCI_STS_OFFSET); val = readl(op_reg_base + XHCI_STS_OFFSET);

View File

@ -112,7 +112,7 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
/* If PSI table exists, add the custom speed attributes from it */ /* If PSI table exists, add the custom speed attributes from it */
if (usb3_1 && xhci->usb3_rhub.psi_count) { if (usb3_1 && xhci->usb3_rhub.psi_count) {
u32 ssp_cap_base, bm_attrib, psi; u32 ssp_cap_base, bm_attrib, psi, psi_mant, psi_exp;
int offset; int offset;
ssp_cap_base = USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; ssp_cap_base = USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
@ -139,6 +139,15 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
for (i = 0; i < xhci->usb3_rhub.psi_count; i++) { for (i = 0; i < xhci->usb3_rhub.psi_count; i++) {
psi = xhci->usb3_rhub.psi[i]; psi = xhci->usb3_rhub.psi[i];
psi &= ~USB_SSP_SUBLINK_SPEED_RSVD; psi &= ~USB_SSP_SUBLINK_SPEED_RSVD;
psi_exp = XHCI_EXT_PORT_PSIE(psi);
psi_mant = XHCI_EXT_PORT_PSIM(psi);
/* Shift to Gbps and set SSP Link BIT(14) if 10Gpbs */
for (; psi_exp < 3; psi_exp++)
psi_mant /= 1000;
if (psi_mant >= 10)
psi |= BIT(14);
if ((psi & PLT_MASK) == PLT_SYM) { if ((psi & PLT_MASK) == PLT_SYM) {
/* Symmetric, create SSA RX and TX from one PSI entry */ /* Symmetric, create SSA RX and TX from one PSI entry */
put_unaligned_le32(psi, &buf[offset]); put_unaligned_le32(psi, &buf[offset]);
@ -1506,9 +1515,6 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
t2 |= PORT_WKOC_E | PORT_WKCONN_E; t2 |= PORT_WKOC_E | PORT_WKCONN_E;
t2 &= ~PORT_WKDISC_E; t2 &= ~PORT_WKDISC_E;
} }
if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) &&
(hcd->speed < HCD_USB3))
t2 &= ~PORT_WAKE_BITS;
} else } else
t2 &= ~PORT_WAKE_BITS; t2 &= ~PORT_WAKE_BITS;

View File

@ -54,11 +54,6 @@
#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 #define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0 #define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
#define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb
#define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc
#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142 #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142
static const char hcd_name[] = "xhci_hcd"; static const char hcd_name[] = "xhci_hcd";
@ -142,13 +137,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_AMD) if (pdev->vendor == PCI_VENDOR_ID_AMD)
xhci->quirks |= XHCI_TRUST_TX_LENGTH; xhci->quirks |= XHCI_TRUST_TX_LENGTH;
if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) ||
(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) ||
(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1)))
xhci->quirks |= XHCI_U2_DISABLE_WAKE;
if (pdev->vendor == PCI_VENDOR_ID_INTEL) { if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_LPM_SUPPORT;
xhci->quirks |= XHCI_INTEL_HOST; xhci->quirks |= XHCI_INTEL_HOST;

View File

@ -178,14 +178,18 @@ static int xhci_plat_probe(struct platform_device *pdev)
* 2. xhci_plat is child of a device from firmware (dwc3-plat) * 2. xhci_plat is child of a device from firmware (dwc3-plat)
* 3. xhci_plat is grandchild of a pci device (dwc3-pci) * 3. xhci_plat is grandchild of a pci device (dwc3-pci)
*/ */
sysdev = &pdev->dev; for (sysdev = &pdev->dev; sysdev; sysdev = sysdev->parent) {
if (sysdev->parent && !sysdev->of_node && sysdev->parent->of_node) if (is_of_node(sysdev->fwnode) ||
sysdev = sysdev->parent; is_acpi_device_node(sysdev->fwnode))
break;
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
else if (sysdev->parent && sysdev->parent->parent && else if (sysdev->bus == &pci_bus_type)
sysdev->parent->parent->bus == &pci_bus_type) break;
sysdev = sysdev->parent->parent;
#endif #endif
}
if (!sysdev)
sysdev = &pdev->dev;
/* Try to set 64-bit DMA first */ /* Try to set 64-bit DMA first */
if (WARN_ON(!sysdev->dma_mask)) if (WARN_ON(!sysdev->dma_mask))

View File

@ -1703,7 +1703,8 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
if (xhci->quirks & XHCI_MTK_HOST) { if (xhci->quirks & XHCI_MTK_HOST) {
ret = xhci_mtk_add_ep_quirk(hcd, udev, ep); ret = xhci_mtk_add_ep_quirk(hcd, udev, ep);
if (ret < 0) { if (ret < 0) {
xhci_free_endpoint_ring(xhci, virt_dev, ep_index); xhci_ring_free(xhci, virt_dev->eps[ep_index].new_ring);
virt_dev->eps[ep_index].new_ring = NULL;
return ret; return ret;
} }
} }

View File

@ -735,6 +735,8 @@ struct xhci_ep_ctx {
#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK) #define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK)
/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */ /* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */
#define EP_HAS_LSA (1 << 15) #define EP_HAS_LSA (1 << 15)
/* hosts with LEC=1 use bits 31:24 as ESIT high bits. */
#define CTX_TO_MAX_ESIT_PAYLOAD_HI(p) (((p) >> 24) & 0xff)
/* ep_info2 bitmasks */ /* ep_info2 bitmasks */
/* /*
@ -1681,7 +1683,7 @@ struct xhci_bus_state {
static inline unsigned int hcd_index(struct usb_hcd *hcd) static inline unsigned int hcd_index(struct usb_hcd *hcd)
{ {
if (hcd->speed == HCD_USB3) if (hcd->speed >= HCD_USB3)
return 0; return 0;
else else
return 1; return 1;
@ -1826,7 +1828,7 @@ struct xhci_hcd {
/* For controller with a broken Port Disable implementation */ /* For controller with a broken Port Disable implementation */
#define XHCI_BROKEN_PORT_PED (1 << 25) #define XHCI_BROKEN_PORT_PED (1 << 25)
#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26) #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
#define XHCI_U2_DISABLE_WAKE (1 << 27) /* Reserved. It was XHCI_U2_DISABLE_WAKE */
#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28) #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
unsigned int num_active_eps; unsigned int num_active_eps;
@ -2540,8 +2542,8 @@ static inline const char *xhci_decode_ep_context(u32 info, u32 info2, u64 deq,
u8 lsa; u8 lsa;
u8 hid; u8 hid;
esit = EP_MAX_ESIT_PAYLOAD_HI(info) << 16 | esit = CTX_TO_MAX_ESIT_PAYLOAD_HI(info) << 16 |
EP_MAX_ESIT_PAYLOAD_LO(tx_info); CTX_TO_MAX_ESIT_PAYLOAD(tx_info);
ep_state = info & EP_STATE_MASK; ep_state = info & EP_STATE_MASK;
max_pstr = info & EP_MAXPSTREAMS_MASK; max_pstr = info & EP_MAXPSTREAMS_MASK;

View File

@ -282,11 +282,26 @@ static void usbhsf_fifo_clear(struct usbhs_pipe *pipe,
struct usbhs_fifo *fifo) struct usbhs_fifo *fifo)
{ {
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
int ret = 0;
if (!usbhs_pipe_is_dcp(pipe)) if (!usbhs_pipe_is_dcp(pipe)) {
usbhsf_fifo_barrier(priv, fifo); /*
* This driver checks the pipe condition first to avoid -EBUSY
* from usbhsf_fifo_barrier() with about 10 msec delay in
* the interrupt handler if the pipe is RX direction and empty.
*/
if (usbhs_pipe_is_dir_in(pipe))
ret = usbhs_pipe_is_accessible(pipe);
if (!ret)
ret = usbhsf_fifo_barrier(priv, fifo);
}
usbhs_write(priv, fifo->ctr, BCLR); /*
* if non-DCP pipe, this driver should set BCLR when
* usbhsf_fifo_barrier() returns 0.
*/
if (!ret)
usbhs_write(priv, fifo->ctr, BCLR);
} }
static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv, static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv,

View File

@ -834,13 +834,25 @@ Retry_Sense:
if (result == USB_STOR_TRANSPORT_GOOD) { if (result == USB_STOR_TRANSPORT_GOOD) {
srb->result = SAM_STAT_GOOD; srb->result = SAM_STAT_GOOD;
srb->sense_buffer[0] = 0x0; srb->sense_buffer[0] = 0x0;
}
/*
* ATA-passthru commands use sense data to report
* the command completion status, and often devices
* return Check Condition status when nothing is
* wrong.
*/
else if (srb->cmnd[0] == ATA_16 ||
srb->cmnd[0] == ATA_12) {
/* leave the data alone */
}
/* /*
* If there was a problem, report an unspecified * If there was a problem, report an unspecified
* hardware error to prevent the higher layers from * hardware error to prevent the higher layers from
* entering an infinite retry loop. * entering an infinite retry loop.
*/ */
} else { else {
srb->result = DID_ERROR << 16; srb->result = DID_ERROR << 16;
if ((sshdr.response_code & 0x72) == 0x72) if ((sshdr.response_code & 0x72) == 0x72)
srb->sense_buffer[1] = HARDWARE_ERROR; srb->sense_buffer[1] = HARDWARE_ERROR;

View File

@ -9,7 +9,8 @@ static int uas_is_interface(struct usb_host_interface *intf)
intf->desc.bInterfaceProtocol == USB_PR_UAS); intf->desc.bInterfaceProtocol == USB_PR_UAS);
} }
static int uas_find_uas_alt_setting(struct usb_interface *intf) static struct usb_host_interface *uas_find_uas_alt_setting(
struct usb_interface *intf)
{ {
int i; int i;
@ -17,10 +18,10 @@ static int uas_find_uas_alt_setting(struct usb_interface *intf)
struct usb_host_interface *alt = &intf->altsetting[i]; struct usb_host_interface *alt = &intf->altsetting[i];
if (uas_is_interface(alt)) if (uas_is_interface(alt))
return alt->desc.bAlternateSetting; return alt;
} }
return -ENODEV; return NULL;
} }
static int uas_find_endpoints(struct usb_host_interface *alt, static int uas_find_endpoints(struct usb_host_interface *alt,
@ -58,14 +59,14 @@ static int uas_use_uas_driver(struct usb_interface *intf,
struct usb_device *udev = interface_to_usbdev(intf); struct usb_device *udev = interface_to_usbdev(intf);
struct usb_hcd *hcd = bus_to_hcd(udev->bus); struct usb_hcd *hcd = bus_to_hcd(udev->bus);
unsigned long flags = id->driver_info; unsigned long flags = id->driver_info;
int r, alt; struct usb_host_interface *alt;
int r;
alt = uas_find_uas_alt_setting(intf); alt = uas_find_uas_alt_setting(intf);
if (alt < 0) if (!alt)
return 0; return 0;
r = uas_find_endpoints(&intf->altsetting[alt], eps); r = uas_find_endpoints(alt, eps);
if (r < 0) if (r < 0)
return 0; return 0;

View File

@ -873,14 +873,14 @@ MODULE_DEVICE_TABLE(usb, uas_usb_ids);
static int uas_switch_interface(struct usb_device *udev, static int uas_switch_interface(struct usb_device *udev,
struct usb_interface *intf) struct usb_interface *intf)
{ {
int alt; struct usb_host_interface *alt;
alt = uas_find_uas_alt_setting(intf); alt = uas_find_uas_alt_setting(intf);
if (alt < 0) if (!alt)
return alt; return -ENODEV;
return usb_set_interface(udev, return usb_set_interface(udev, alt->desc.bInterfaceNumber,
intf->altsetting[0].desc.bInterfaceNumber, alt); alt->desc.bAlternateSetting);
} }
static int uas_configure_endpoints(struct uas_dev_info *devinfo) static int uas_configure_endpoints(struct uas_dev_info *devinfo)

View File

@ -1459,6 +1459,13 @@ UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000,
USB_SC_DEVICE, USB_PR_DEVICE, NULL, USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_SANE_SENSE ), US_FL_SANE_SENSE ),
/* Reported by Kris Lindgren <kris.lindgren@gmail.com> */
UNUSUAL_DEV( 0x0bc2, 0x3332, 0x0000, 0x9999,
"Seagate",
"External",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_WP_DETECT ),
UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999, UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999,
"Maxtor", "Maxtor",
"USB to SATA", "USB to SATA",

View File

@ -825,6 +825,8 @@ static int hwarc_probe(struct usb_interface *iface,
if (iface->cur_altsetting->desc.bNumEndpoints < 1) if (iface->cur_altsetting->desc.bNumEndpoints < 1)
return -ENODEV; return -ENODEV;
if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc))
return -ENODEV;
result = -ENOMEM; result = -ENOMEM;
uwb_rc = uwb_rc_alloc(); uwb_rc = uwb_rc_alloc();

View File

@ -302,18 +302,22 @@ static int uwbd(void *param)
/** Start the UWB daemon */ /** Start the UWB daemon */
void uwbd_start(struct uwb_rc *rc) void uwbd_start(struct uwb_rc *rc)
{ {
rc->uwbd.task = kthread_run(uwbd, rc, "uwbd"); struct task_struct *task = kthread_run(uwbd, rc, "uwbd");
if (rc->uwbd.task == NULL) if (IS_ERR(task)) {
rc->uwbd.task = NULL;
printk(KERN_ERR "UWB: Cannot start management daemon; " printk(KERN_ERR "UWB: Cannot start management daemon; "
"UWB won't work\n"); "UWB won't work\n");
else } else {
rc->uwbd.task = task;
rc->uwbd.pid = rc->uwbd.task->pid; rc->uwbd.pid = rc->uwbd.task->pid;
}
} }
/* Stop the UWB daemon and free any unprocessed events */ /* Stop the UWB daemon and free any unprocessed events */
void uwbd_stop(struct uwb_rc *rc) void uwbd_stop(struct uwb_rc *rc)
{ {
kthread_stop(rc->uwbd.task); if (rc->uwbd.task)
kthread_stop(rc->uwbd.task);
uwbd_flush(rc); uwbd_flush(rc);
} }

View File

@ -780,6 +780,7 @@ struct usb_interface_assoc_descriptor {
__u8 iFunction; __u8 iFunction;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/