mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
usb: fixes for v4.11-rc2
dwc3 got a few fixes this time around: Fixed an old bug where a broken endpoint descriptor passed in via userspace through f_fs could prevent dwc3 from working because when calculating max bursts, we could overwrite top 16 bits of a register. Also fixed a bug on dwc3's ep_dequeue implementation which wasn't properly incrementing our TRB dequeue pointer. dwc3 on omap got two fixes: one for system suspend/resume and another added a missing break statement on dwc3_omap_set_mailbox(). Apart from these, we have a set of smaller fixes including memory leak in configfs, build warning fix in atmel udc and a revert of a broken patch that went in during the merge window -----BEGIN PGP SIGNATURE----- iQJRBAABCAA7FiEElLzh7wn96CXwjh2IzL64meEamQYFAljBGmUdHGZlbGlwZS5i YWxiaUBsaW51eC5pbnRlbC5jb20ACgkQzL64meEamQYgPw//YwW3l+zNdc3ACe38 g1DtG/UOuQmYowf7HI3la0np1K8901RfTxm9vt/uHtTGYuHId0Vg6J6Xh6IftByD gPfxyqfSySpfF7Yxsh6SuYWO0NwlBvS4CiBSKS0Fdhahwb9TRwEUqmP5m7rFRj8Z 9A4Rjl0ts62G0DCP8Cj0uB51P6+9v6r11WoLyN7Sb7HHwEw37cbFDtLy2VT4RjJR 3nPS+QQVZvX9CnvN9sMo8YRH1o7ktyioZuXDPkNY9Ge2TQU9RRCUee/hRoQPVNSx XzWPKn8AzqtxkVWjvS7Vo8IvZ5Nce+dHV96VmZG6e90wcT8oWg52+7V1zPB97rp/ mshVmOK2q6Ek6+Vig9ofiqnppS991Be974ph22j1aXtNwD81swAIWJ7YAYA5f8NP 8WmaOhy4//DaTB1z1/Ft+0s8WxxRQweeVBbsIyUw7F2HLRUi7UpBisejg9D9uLpQ o0swPSWmjvJ2IdE68xN/Ov7wziL/xshgwsKr2xkmzHRaAMluMeczbXwdPZ6kv1J9 jt9hAtaYCfRWOpYkaEN/W/QHUSNefgz5axyscZgJIsBofQ/ZFzeRdfLQnYNg2Kgo vF1VfKkAVdnuWEFAWXFKRSEAmbzKBzMrRtJvSdDqqH7mZh1+gxfO8nvmRp008SEM q4oZMVkHQc78HPIbDKuKp33gm4Y= =ywod -----END PGP SIGNATURE----- Merge tag 'fixes-for-v4.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-linus Felipe writes: usb: fixes for v4.11-rc2 dwc3 got a few fixes this time around: Fixed an old bug where a broken endpoint descriptor passed in via userspace through f_fs could prevent dwc3 from working because when calculating max bursts, we could overwrite top 16 bits of a register. Also fixed a bug on dwc3's ep_dequeue implementation which wasn't properly incrementing our TRB dequeue pointer. dwc3 on omap got two fixes: one for system suspend/resume and another added a missing break statement on dwc3_omap_set_mailbox(). Apart from these, we have a set of smaller fixes including memory leak in configfs, build warning fix in atmel udc and a revert of a broken patch that went in during the merge window
This commit is contained in:
commit
88767cc197
@ -250,6 +250,7 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
|
||||
val = dwc3_omap_read_utmi_ctrl(omap);
|
||||
val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG;
|
||||
dwc3_omap_write_utmi_ctrl(omap, val);
|
||||
break;
|
||||
|
||||
case OMAP_DWC3_VBUS_OFF:
|
||||
val = dwc3_omap_read_utmi_ctrl(omap);
|
||||
@ -392,7 +393,7 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap)
|
||||
{
|
||||
u32 reg;
|
||||
struct device_node *node = omap->dev->of_node;
|
||||
int utmi_mode = 0;
|
||||
u32 utmi_mode = 0;
|
||||
|
||||
reg = dwc3_omap_read_utmi_ctrl(omap);
|
||||
|
||||
|
@ -1342,6 +1342,68 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
||||
if (r == req) {
|
||||
/* wait until it is processed */
|
||||
dwc3_stop_active_transfer(dwc, dep->number, true);
|
||||
|
||||
/*
|
||||
* If request was already started, this means we had to
|
||||
* stop the transfer. With that we also need to ignore
|
||||
* all TRBs used by the request, however TRBs can only
|
||||
* be modified after completion of END_TRANSFER
|
||||
* command. So what we do here is that we wait for
|
||||
* END_TRANSFER completion and only after that, we jump
|
||||
* over TRBs by clearing HWO and incrementing dequeue
|
||||
* pointer.
|
||||
*
|
||||
* Note that we have 2 possible types of transfers here:
|
||||
*
|
||||
* i) Linear buffer request
|
||||
* ii) SG-list based request
|
||||
*
|
||||
* SG-list based requests will have r->num_pending_sgs
|
||||
* set to a valid number (> 0). Linear requests,
|
||||
* normally use a single TRB.
|
||||
*
|
||||
* For each of these two cases, if r->unaligned flag is
|
||||
* set, one extra TRB has been used to align transfer
|
||||
* size to wMaxPacketSize.
|
||||
*
|
||||
* All of these cases need to be taken into
|
||||
* consideration so we don't mess up our TRB ring
|
||||
* pointers.
|
||||
*/
|
||||
wait_event_lock_irq(dep->wait_end_transfer,
|
||||
!(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
|
||||
dwc->lock);
|
||||
|
||||
if (!r->trb)
|
||||
goto out1;
|
||||
|
||||
if (r->num_pending_sgs) {
|
||||
struct dwc3_trb *trb;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < r->num_pending_sgs; i++) {
|
||||
trb = r->trb + i;
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
}
|
||||
|
||||
if (r->unaligned) {
|
||||
trb = r->trb + r->num_pending_sgs + 1;
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
}
|
||||
} else {
|
||||
struct dwc3_trb *trb = r->trb;
|
||||
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
|
||||
if (r->unaligned) {
|
||||
trb = r->trb + 1;
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
}
|
||||
}
|
||||
goto out1;
|
||||
}
|
||||
dev_err(dwc->dev, "request %p was not queued to %s\n",
|
||||
@ -1352,6 +1414,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
||||
|
||||
out1:
|
||||
/* giveback the request */
|
||||
dep->queued_requests--;
|
||||
dwc3_gadget_giveback(dep, req, -ECONNRESET);
|
||||
|
||||
out0:
|
||||
@ -2126,12 +2189,12 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
|
||||
return 1;
|
||||
|
||||
count = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
req->remaining += count;
|
||||
|
||||
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
|
||||
return 1;
|
||||
|
||||
if (dep->direction) {
|
||||
if (count) {
|
||||
trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
|
||||
@ -3228,15 +3291,10 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||
|
||||
int dwc3_gadget_suspend(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!dwc->gadget_driver)
|
||||
return 0;
|
||||
|
||||
ret = dwc3_gadget_run_stop(dwc, false, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dwc3_gadget_run_stop(dwc, false, false);
|
||||
dwc3_disconnect_gadget(dwc);
|
||||
__dwc3_gadget_stop(dwc);
|
||||
|
||||
|
@ -28,23 +28,23 @@ struct dwc3;
|
||||
#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget))
|
||||
|
||||
/* DEPCFG parameter 1 */
|
||||
#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0)
|
||||
#define DWC3_DEPCFG_INT_NUM(n) (((n) & 0x1f) << 0)
|
||||
#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
|
||||
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
|
||||
#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
|
||||
#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
|
||||
#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
|
||||
#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16)
|
||||
#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16)
|
||||
#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
|
||||
#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25)
|
||||
#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25)
|
||||
#define DWC3_DEPCFG_BULK_BASED (1 << 30)
|
||||
#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
|
||||
|
||||
/* DEPCFG parameter 0 */
|
||||
#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1)
|
||||
#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3)
|
||||
#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17)
|
||||
#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22)
|
||||
#define DWC3_DEPCFG_EP_TYPE(n) (((n) & 0x3) << 1)
|
||||
#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) (((n) & 0x7ff) << 3)
|
||||
#define DWC3_DEPCFG_FIFO_NUMBER(n) (((n) & 0x1f) << 17)
|
||||
#define DWC3_DEPCFG_BURST_SIZE(n) (((n) & 0xf) << 22)
|
||||
#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
|
||||
/* This applies for core versions earlier than 1.94a */
|
||||
#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
|
||||
|
@ -269,6 +269,7 @@ static ssize_t gadget_dev_desc_UDC_store(struct config_item *item,
|
||||
ret = unregister_gadget(gi);
|
||||
if (ret)
|
||||
goto err;
|
||||
kfree(name);
|
||||
} else {
|
||||
if (gi->composite.gadget_driver.udc_name) {
|
||||
ret = -EBUSY;
|
||||
|
@ -1834,11 +1834,14 @@ static int ffs_func_eps_enable(struct ffs_function *func)
|
||||
spin_lock_irqsave(&func->ffs->eps_lock, flags);
|
||||
while(count--) {
|
||||
struct usb_endpoint_descriptor *ds;
|
||||
struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
|
||||
int needs_comp_desc = false;
|
||||
int desc_idx;
|
||||
|
||||
if (ffs->gadget->speed == USB_SPEED_SUPER)
|
||||
if (ffs->gadget->speed == USB_SPEED_SUPER) {
|
||||
desc_idx = 2;
|
||||
else if (ffs->gadget->speed == USB_SPEED_HIGH)
|
||||
needs_comp_desc = true;
|
||||
} else if (ffs->gadget->speed == USB_SPEED_HIGH)
|
||||
desc_idx = 1;
|
||||
else
|
||||
desc_idx = 0;
|
||||
@ -1855,6 +1858,14 @@ static int ffs_func_eps_enable(struct ffs_function *func)
|
||||
|
||||
ep->ep->driver_data = ep;
|
||||
ep->ep->desc = ds;
|
||||
|
||||
comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds +
|
||||
USB_DT_ENDPOINT_SIZE);
|
||||
ep->ep->maxburst = comp_desc->bMaxBurst + 1;
|
||||
|
||||
if (needs_comp_desc)
|
||||
ep->ep->comp_desc = comp_desc;
|
||||
|
||||
ret = usb_ep_enable(ep->ep);
|
||||
if (likely(!ret)) {
|
||||
epfile->ep = ep;
|
||||
@ -2253,7 +2264,7 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
|
||||
|
||||
if (len < sizeof(*d) ||
|
||||
d->bFirstInterfaceNumber >= ffs->interfaces_count ||
|
||||
d->Reserved1)
|
||||
!d->Reserved1)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
|
||||
if (d->Reserved2[i])
|
||||
|
@ -258,13 +258,6 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
||||
memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req));
|
||||
v4l2_event_queue(&uvc->vdev, &v4l2_event);
|
||||
|
||||
/* Pass additional setup data to userspace */
|
||||
if (uvc->event_setup_out && uvc->event_length) {
|
||||
uvc->control_req->length = uvc->event_length;
|
||||
return usb_ep_queue(uvc->func.config->cdev->gadget->ep0,
|
||||
uvc->control_req, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1782,8 +1782,10 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
|
||||
spin_lock_irq (&dev->lock);
|
||||
value = -EINVAL;
|
||||
if (dev->buf)
|
||||
if (dev->buf) {
|
||||
kfree(kbuf);
|
||||
goto fail;
|
||||
}
|
||||
dev->buf = kbuf;
|
||||
|
||||
/* full or low speed config */
|
||||
|
@ -610,7 +610,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
||||
{
|
||||
struct usba_ep *ep = to_usba_ep(_ep);
|
||||
struct usba_udc *udc = ep->udc;
|
||||
unsigned long flags, ept_cfg, maxpacket;
|
||||
unsigned long flags, maxpacket;
|
||||
unsigned int nr_trans;
|
||||
|
||||
DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
|
||||
@ -630,7 +630,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
||||
ep->is_in = 0;
|
||||
|
||||
DBG(DBG_ERR, "%s: EPT_CFG = 0x%lx (maxpacket = %lu)\n",
|
||||
ep->ep.name, ept_cfg, maxpacket);
|
||||
ep->ep.name, ep->ept_cfg, maxpacket);
|
||||
|
||||
if (usb_endpoint_dir_in(desc)) {
|
||||
ep->is_in = 1;
|
||||
|
@ -1031,6 +1031,8 @@ static int dummy_udc_probe(struct platform_device *pdev)
|
||||
int rc;
|
||||
|
||||
dum = *((void **)dev_get_platdata(&pdev->dev));
|
||||
/* Clear usb_gadget region for new registration to udc-core */
|
||||
memzero_explicit(&dum->gadget, sizeof(struct usb_gadget));
|
||||
dum->gadget.name = gadget_name;
|
||||
dum->gadget.ops = &dummy_ops;
|
||||
dum->gadget.max_speed = USB_SPEED_SUPER;
|
||||
|
@ -1146,15 +1146,15 @@ static int scan_dma_completions(struct net2280_ep *ep)
|
||||
*/
|
||||
while (!list_empty(&ep->queue)) {
|
||||
struct net2280_request *req;
|
||||
u32 tmp;
|
||||
u32 req_dma_count;
|
||||
|
||||
req = list_entry(ep->queue.next,
|
||||
struct net2280_request, queue);
|
||||
if (!req->valid)
|
||||
break;
|
||||
rmb();
|
||||
tmp = le32_to_cpup(&req->td->dmacount);
|
||||
if ((tmp & BIT(VALID_BIT)) != 0)
|
||||
req_dma_count = le32_to_cpup(&req->td->dmacount);
|
||||
if ((req_dma_count & BIT(VALID_BIT)) != 0)
|
||||
break;
|
||||
|
||||
/* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short"
|
||||
@ -1163,40 +1163,41 @@ static int scan_dma_completions(struct net2280_ep *ep)
|
||||
*/
|
||||
if (unlikely(req->td->dmadesc == 0)) {
|
||||
/* paranoia */
|
||||
tmp = readl(&ep->dma->dmacount);
|
||||
if (tmp & DMA_BYTE_COUNT_MASK)
|
||||
u32 const ep_dmacount = readl(&ep->dma->dmacount);
|
||||
|
||||
if (ep_dmacount & DMA_BYTE_COUNT_MASK)
|
||||
break;
|
||||
/* single transfer mode */
|
||||
dma_done(ep, req, tmp, 0);
|
||||
dma_done(ep, req, req_dma_count, 0);
|
||||
num_completed++;
|
||||
break;
|
||||
} else if (!ep->is_in &&
|
||||
(req->req.length % ep->ep.maxpacket) &&
|
||||
!(ep->dev->quirks & PLX_PCIE)) {
|
||||
|
||||
tmp = readl(&ep->regs->ep_stat);
|
||||
u32 const ep_stat = readl(&ep->regs->ep_stat);
|
||||
/* AVOID TROUBLE HERE by not issuing short reads from
|
||||
* your gadget driver. That helps avoids errata 0121,
|
||||
* 0122, and 0124; not all cases trigger the warning.
|
||||
*/
|
||||
if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) {
|
||||
if ((ep_stat & BIT(NAK_OUT_PACKETS)) == 0) {
|
||||
ep_warn(ep->dev, "%s lost packet sync!\n",
|
||||
ep->ep.name);
|
||||
req->req.status = -EOVERFLOW;
|
||||
} else {
|
||||
tmp = readl(&ep->regs->ep_avail);
|
||||
if (tmp) {
|
||||
u32 const ep_avail = readl(&ep->regs->ep_avail);
|
||||
if (ep_avail) {
|
||||
/* fifo gets flushed later */
|
||||
ep->out_overflow = 1;
|
||||
ep_dbg(ep->dev,
|
||||
"%s dma, discard %d len %d\n",
|
||||
ep->ep.name, tmp,
|
||||
ep->ep.name, ep_avail,
|
||||
req->req.length);
|
||||
req->req.status = -EOVERFLOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
dma_done(ep, req, tmp, 0);
|
||||
dma_done(ep, req, req_dma_count, 0);
|
||||
num_completed++;
|
||||
}
|
||||
|
||||
|
@ -2534,9 +2534,10 @@ static int pxa_udc_remove(struct platform_device *_dev)
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
pxa_cleanup_debugfs(udc);
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy);
|
||||
usb_put_phy(udc->transceiver);
|
||||
usb_put_phy(udc->transceiver);
|
||||
}
|
||||
|
||||
udc->transceiver = NULL;
|
||||
the_controller = NULL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user