Commit 9af6f26a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull USB fixes from Greg KH:
 "Here are a number of small USB driver fixes for 4.9-rc3.

  There is the usual number of gadget and xhci patches in here to
  resolved reported issues, as well as some usb-serial driver fixes and
  new device ids.

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

* tag 'usb-4.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (26 commits)
  usb: chipidea: host: fix NULL ptr dereference during shutdown
  usb: renesas_usbhs: add wait after initialization for R-Car Gen3
  usb: increase ohci watchdog delay to 275 msec
  usb: musb: Call pm_runtime from musb_gadget_queue
  usb: musb: Fix hardirq-safe hardirq-unsafe lock order error
  usb: ehci-platform: increase EHCI_MAX_RSTS to 4
  usb: ohci-at91: Set RemoteWakeupConnected bit explicitly.
  USB: serial: fix potential NULL-dereference at probe
  xhci: use default USB_RESUME_TIMEOUT when resuming ports.
  xhci: workaround for hosts missing CAS bit
  xhci: add restart quirk for Intel Wildcatpoint PCH
  USB: serial: cp210x: fix tiocmget error handling
  wusb: fix error return code in wusb_prf()
  Revert "Documentation: devicetree: dwc2: Deprecate g-tx-fifo-size"
  Revert "usb: dwc2: gadget: fix TX FIFO size and address initialization"
  Revert "usb: dwc2: gadget: change variable name to more meaningful"
  USB: serial: ftdi_sio: add support for Infineon TriBoard TC2X7
  wusb: Stop using the stack for sg crypto scratch space
  usb: dwc3: Fix size used in dma_free_coherent()
  usb: gadget: f_fs: stop sleeping in ffs_func_eps_disable
  ...
parents c067affc c1aa6772
...@@ -28,10 +28,7 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties ...@@ -28,10 +28,7 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties
- g-use-dma: enable dma usage in gadget driver. - g-use-dma: enable dma usage in gadget driver.
- g-rx-fifo-size: size of rx fifo size in gadget mode. - g-rx-fifo-size: size of rx fifo size in gadget mode.
- g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode. - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
Deprecated properties:
- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0)
in gadget mode.
Example: Example:
......
...@@ -188,6 +188,8 @@ static void host_stop(struct ci_hdrc *ci) ...@@ -188,6 +188,8 @@ static void host_stop(struct ci_hdrc *ci)
if (hcd) { if (hcd) {
usb_remove_hcd(hcd); usb_remove_hcd(hcd);
ci->role = CI_ROLE_END;
synchronize_irq(ci->irq);
usb_put_hcd(hcd); usb_put_hcd(hcd);
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci) && if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci) &&
(ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON)) (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON))
......
...@@ -463,9 +463,18 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) ...@@ -463,9 +463,18 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
*/ */
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
{ {
bool ret;
switch (hsotg->dr_mode) { switch (hsotg->dr_mode) {
case USB_DR_MODE_HOST: case USB_DR_MODE_HOST:
dwc2_force_mode(hsotg, true); ret = dwc2_force_mode(hsotg, true);
/*
* NOTE: This is required for some rockchip soc based
* platforms on their host-only dwc2.
*/
if (!ret)
msleep(50);
break; break;
case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_PERIPHERAL:
dwc2_force_mode(hsotg, false); dwc2_force_mode(hsotg, false);
......
...@@ -259,6 +259,13 @@ enum dwc2_lx_state { ...@@ -259,6 +259,13 @@ enum dwc2_lx_state {
DWC2_L3, /* Off state */ DWC2_L3, /* Off state */
}; };
/*
* Gadget periodic tx fifo sizes as used by legacy driver
* EP0 is not included
*/
#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
768, 0, 0, 0, 0, 0, 0, 0}
/* Gadget ep0 states */ /* Gadget ep0 states */
enum dwc2_ep0_state { enum dwc2_ep0_state {
DWC2_EP0_SETUP, DWC2_EP0_SETUP,
......
...@@ -186,10 +186,9 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, ...@@ -186,10 +186,9 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg,
*/ */
static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
{ {
unsigned int fifo; unsigned int ep;
unsigned int addr; unsigned int addr;
int timeout; int timeout;
u32 dptxfsizn;
u32 val; u32 val;
/* Reset fifo map if not correctly cleared during previous session */ /* Reset fifo map if not correctly cleared during previous session */
...@@ -217,16 +216,16 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) ...@@ -217,16 +216,16 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
* them to endpoints dynamically according to maxpacket size value of * them to endpoints dynamically according to maxpacket size value of
* given endpoint. * given endpoint.
*/ */
for (fifo = 1; fifo < MAX_EPS_CHANNELS; fifo++) { for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) {
dptxfsizn = dwc2_readl(hsotg->regs + DPTXFSIZN(fifo)); if (!hsotg->g_tx_fifo_sz[ep])
continue;
val = (dptxfsizn & FIFOSIZE_DEPTH_MASK) | addr; val = addr;
addr += dptxfsizn >> FIFOSIZE_DEPTH_SHIFT; val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT;
WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem,
if (addr > hsotg->fifo_mem) "insufficient fifo memory");
break; addr += hsotg->g_tx_fifo_sz[ep];
dwc2_writel(val, hsotg->regs + DPTXFSIZN(fifo)); dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep));
} }
/* /*
...@@ -3807,10 +3806,36 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) ...@@ -3807,10 +3806,36 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg)
static void dwc2_hsotg_of_probe(struct dwc2_hsotg *hsotg) static void dwc2_hsotg_of_probe(struct dwc2_hsotg *hsotg)
{ {
struct device_node *np = hsotg->dev->of_node; struct device_node *np = hsotg->dev->of_node;
u32 len = 0;
u32 i = 0;
/* Enable dma if requested in device tree */ /* Enable dma if requested in device tree */
hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma"); hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma");
/*
* Register TX periodic fifo size per endpoint.
* EP0 is excluded since it has no fifo configuration.
*/
if (!of_find_property(np, "g-tx-fifo-size", &len))
goto rx_fifo;
len /= sizeof(u32);
/* Read tx fifo sizes other than ep0 */
if (of_property_read_u32_array(np, "g-tx-fifo-size",
&hsotg->g_tx_fifo_sz[1], len))
goto rx_fifo;
/* Add ep0 */
len++;
/* Make remaining TX fifos unavailable */
if (len < MAX_EPS_CHANNELS) {
for (i = len; i < MAX_EPS_CHANNELS; i++)
hsotg->g_tx_fifo_sz[i] = 0;
}
rx_fifo:
/* Register RX fifo size */ /* Register RX fifo size */
of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz); of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz);
...@@ -3832,10 +3857,13 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) ...@@ -3832,10 +3857,13 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
struct device *dev = hsotg->dev; struct device *dev = hsotg->dev;
int epnum; int epnum;
int ret; int ret;
int i;
u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE;
/* Initialize to legacy fifo configuration values */ /* Initialize to legacy fifo configuration values */
hsotg->g_rx_fifo_sz = 2048; hsotg->g_rx_fifo_sz = 2048;
hsotg->g_np_g_tx_fifo_sz = 1024; hsotg->g_np_g_tx_fifo_sz = 1024;
memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo));
/* Device tree specific probe */ /* Device tree specific probe */
dwc2_hsotg_of_probe(hsotg); dwc2_hsotg_of_probe(hsotg);
...@@ -3853,6 +3881,9 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) ...@@ -3853,6 +3881,9 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n",
hsotg->g_np_g_tx_fifo_sz); hsotg->g_np_g_tx_fifo_sz);
dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz); dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz);
for (i = 0; i < MAX_EPS_CHANNELS; i++)
dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i,
hsotg->g_tx_fifo_sz[i]);
hsotg->gadget.max_speed = USB_SPEED_HIGH; hsotg->gadget.max_speed = USB_SPEED_HIGH;
hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; hsotg->gadget.ops = &dwc2_hsotg_gadget_ops;
......
...@@ -783,6 +783,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, ...@@ -783,6 +783,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
req->trb = trb; req->trb = trb;
req->trb_dma = dwc3_trb_dma_offset(dep, trb); req->trb_dma = dwc3_trb_dma_offset(dep, trb);
req->first_trb_index = dep->trb_enqueue; req->first_trb_index = dep->trb_enqueue;
dep->queued_requests++;
} }
dwc3_ep_inc_enq(dep); dwc3_ep_inc_enq(dep);
...@@ -833,8 +834,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, ...@@ -833,8 +834,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
trb->ctrl |= DWC3_TRB_CTRL_HWO; trb->ctrl |= DWC3_TRB_CTRL_HWO;
dep->queued_requests++;
trace_dwc3_prepare_trb(dep, trb); trace_dwc3_prepare_trb(dep, trb);
} }
...@@ -1074,9 +1073,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) ...@@ -1074,9 +1073,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
list_add_tail(&req->list, &dep->pending_list); list_add_tail(&req->list, &dep->pending_list);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && /*
dep->flags & DWC3_EP_PENDING_REQUEST) { * NOTICE: Isochronous endpoints should NEVER be prestarted. We must
if (list_empty(&dep->started_list)) { * wait for a XferNotReady event so we will know what's the current
* (micro-)frame number.
*
* Without this trick, we are very, very likely gonna get Bus Expiry
* errors which will force us issue EndTransfer command.
*/
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
if ((dep->flags & DWC3_EP_PENDING_REQUEST) &&
list_empty(&dep->started_list)) {
dwc3_stop_active_transfer(dwc, dep->number, true); dwc3_stop_active_transfer(dwc, dep->number, true);
dep->flags = DWC3_EP_ENABLED; dep->flags = DWC3_EP_ENABLED;
} }
...@@ -1861,8 +1868,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, ...@@ -1861,8 +1868,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
unsigned int s_pkt = 0; unsigned int s_pkt = 0;
unsigned int trb_status; unsigned int trb_status;
dep->queued_requests--;
dwc3_ep_inc_deq(dep); dwc3_ep_inc_deq(dep);
if (req->trb == trb)
dep->queued_requests--;
trace_dwc3_complete_trb(dep, trb); trace_dwc3_complete_trb(dep, trb);
/* /*
...@@ -2980,7 +2990,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) ...@@ -2980,7 +2990,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
kfree(dwc->setup_buf); kfree(dwc->setup_buf);
err2: err2:
dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2,
dwc->ep0_trb, dwc->ep0_trb_addr); dwc->ep0_trb, dwc->ep0_trb_addr);
err1: err1:
...@@ -3005,7 +3015,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) ...@@ -3005,7 +3015,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
kfree(dwc->setup_buf); kfree(dwc->setup_buf);
kfree(dwc->zlp_buf); kfree(dwc->zlp_buf);
dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2,
dwc->ep0_trb, dwc->ep0_trb_addr); dwc->ep0_trb, dwc->ep0_trb_addr);
dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
......
...@@ -136,8 +136,60 @@ struct ffs_epfile { ...@@ -136,8 +136,60 @@ struct ffs_epfile {
/* /*
* Buffer for holding data from partial reads which may happen since * Buffer for holding data from partial reads which may happen since
* we’re rounding user read requests to a multiple of a max packet size. * we’re rounding user read requests to a multiple of a max packet size.
*
* The pointer is initialised with NULL value and may be set by
* __ffs_epfile_read_data function to point to a temporary buffer.
*
* In normal operation, calls to __ffs_epfile_read_buffered will consume
* data from said buffer and eventually free it. Importantly, while the
* function is using the buffer, it sets the pointer to NULL. This is
* all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered
* can never run concurrently (they are synchronised by epfile->mutex)
* so the latter will not assign a new value to the pointer.
*
* Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is
* valid) and sets the pointer to READ_BUFFER_DROP value. This special
* value is crux of the synchronisation between ffs_func_eps_disable and
* __ffs_epfile_read_data.
*
* Once __ffs_epfile_read_data is about to finish it will try to set the
* pointer back to its old value (as described above), but seeing as the
* pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free
* the buffer.
*
* == State transitions ==
*
* • ptr == NULL: (initial state)
* ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP
* ◦ __ffs_epfile_read_buffered: nop
* ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf
* ◦ reading finishes: n/a, not in ‘and reading’ state
* • ptr == DROP:
* ◦ __ffs_epfile_read_buffer_free: nop
* ◦ __ffs_epfile_read_buffered: go to ptr == NULL
* ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop
* ◦ reading finishes: n/a, not in ‘and reading’ state
* • ptr == buf:
* ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP
* ◦ __ffs_epfile_read_buffered: go to ptr == NULL and reading
* ◦ __ffs_epfile_read_data: n/a, __ffs_epfile_read_buffered
* is always called first
* ◦ reading finishes: n/a, not in ‘and reading’ state
* • ptr == NULL and reading:
* ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading
* ◦ __ffs_epfile_read_buffered: n/a, mutex is held
* ◦ __ffs_epfile_read_data: n/a, mutex is held
* ◦ reading finishes and …
* … all data read: free buf, go to ptr == NULL
* … otherwise: go to ptr == buf and reading
* • ptr == DROP and reading:
* ◦ __ffs_epfile_read_buffer_free: nop
* ◦ __ffs_epfile_read_buffered: n/a, mutex is held
* ◦ __ffs_epfile_read_data: n/a, mutex is held
* ◦ reading finishes: free buf, go to ptr == DROP
*/ */
struct ffs_buffer *read_buffer; /* P: epfile->mutex */ struct ffs_buffer *read_buffer;
#define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN))
char name[5]; char name[5];
...@@ -736,25 +788,47 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, ...@@ -736,25 +788,47 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
schedule_work(&io_data->work); schedule_work(&io_data->work);
} }
static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile)
{
/*
* See comment in struct ffs_epfile for full read_buffer pointer
* synchronisation story.
*/
struct ffs_buffer *buf = xchg(&epfile->read_buffer, READ_BUFFER_DROP);
if (buf && buf != READ_BUFFER_DROP)
kfree(buf);
}
/* Assumes epfile->mutex is held. */ /* Assumes epfile->mutex is held. */
static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile, static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile,
struct iov_iter *iter) struct iov_iter *iter)
{ {
struct ffs_buffer *buf = epfile->read_buffer; /*
* Null out epfile->read_buffer so ffs_func_eps_disable does not free
* the buffer while we are using it. See comment in struct ffs_epfile
* for full read_buffer pointer synchronisation story.
*/
struct ffs_buffer *buf = xchg(&epfile->read_buffer, NULL);
ssize_t ret; ssize_t ret;
if (!buf) if (!buf || buf == READ_BUFFER_DROP)
return 0; return 0;
ret = copy_to_iter(buf->data, buf->length, iter); ret = copy_to_iter(buf->data, buf->length, iter);
if (buf->length == ret) { if (buf->length == ret) {
kfree(buf); kfree(buf);
epfile->read_buffer = NULL; return ret;
} else if (unlikely(iov_iter_count(iter))) { }
if (unlikely(iov_iter_count(iter))) {
ret = -EFAULT; ret = -EFAULT;
} else { } else {
buf->length -= ret; buf->length -= ret;
buf->data += ret; buf->data += ret;
} }
if (cmpxchg(&epfile->read_buffer, NULL, buf))
kfree(buf);
return ret; return ret;
} }
...@@ -783,7 +857,15 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, ...@@ -783,7 +857,15 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
buf->length = data_len; buf->length = data_len;
buf->data = buf->storage; buf->data = buf->storage;
memcpy(buf->storage, data + ret, data_len); memcpy(buf->storage, data + ret, data_len);
epfile->read_buffer = buf;
/*
* At this point read_buffer is NULL or READ_BUFFER_DROP (if
* ffs_func_eps_disable has been called in the meanwhile). See comment
* in struct ffs_epfile for full read_buffer pointer synchronisation
* story.
*/
if (unlikely(cmpxchg(&epfile->read_buffer, NULL, buf)))
kfree(buf);
return ret; return ret;
} }
...@@ -1097,8 +1179,7 @@ ffs_epfile_release(struct inode *inode, struct file *file) ...@@ -1097,8 +1179,7 @@ ffs_epfile_release(struct inode *inode, struct file *file)
ENTER(); ENTER();
kfree(epfile->read_buffer); __ffs_epfile_read_buffer_free(epfile);
epfile->read_buffer = NULL;
ffs_data_closed(epfile->ffs); ffs_data_closed(epfile->ffs);
return 0; return 0;
...@@ -1724,24 +1805,20 @@ static void ffs_func_eps_disable(struct ffs_function *func) ...@@ -1724,24 +1805,20 @@ static void ffs_func_eps_disable(struct ffs_function *func)
unsigned count = func->ffs->eps_count; unsigned count = func->ffs->eps_count;
unsigned long flags; unsigned long flags;
do {
if (epfile)
mutex_lock(&epfile->mutex);
spin_lock_irqsave(&func->ffs->eps_lock, flags); spin_lock_irqsave(&func->ffs->eps_lock, flags);
do {
/* pending requests get nuked */ /* pending requests get nuked */
if (likely(ep->ep)) if (likely(ep->ep))
usb_ep_disable(ep->ep); usb_ep_disable(ep->ep);
++ep; ++ep;
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
if (epfile) { if (epfile) {
epfile->ep = NULL; epfile->ep = NULL;
kfree(epfile->read_buffer); __ffs_epfile_read_buffer_free(epfile);
epfile->read_buffer = NULL;
mutex_unlock(&epfile->mutex);
++epfile; ++epfile;
} }
} while (--count); } while (--count);
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
} }
static int ffs_func_eps_enable(struct ffs_function *func) static int ffs_func_eps_enable(struct ffs_function *func)
......
...@@ -590,8 +590,9 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, ...@@ -590,8 +590,9 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
/* throttle high/super speed IRQ rate back slightly */ /* throttle high/super speed IRQ rate back slightly */
if (gadget_is_dualspeed(dev->gadget)) if (gadget_is_dualspeed(dev->gadget))
req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH || req->no_interrupt = (((dev->gadget->speed == USB_SPEED_HIGH ||
dev->gadget->speed == USB_SPEED_SUPER) dev->gadget->speed == USB_SPEED_SUPER)) &&
!list_empty(&dev->tx_reqs))
? ((atomic_read(&dev->tx_qlen) % dev->qmult) != 0) ? ((atomic_read(&dev->tx_qlen) % dev->qmult) != 0)
: 0; : 0;
......
...@@ -1978,7 +1978,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ...@@ -1978,7 +1978,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret); dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret);
goto err; goto err;
} }
ep->ep.name = name; ep->ep.name = kasprintf(GFP_KERNEL, "ep%d", ep->index);
ep->ep_regs = udc->regs + USBA_EPT_BASE(i); ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
ep->dma_regs = udc->regs + USBA_DMA_BASE(i); ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
#define DRIVER_DESC "EHCI generic platform driver" #define DRIVER_DESC "EHCI generic platform driver"
#define EHCI_MAX_CLKS 4 #define EHCI_MAX_CLKS 4
#define EHCI_MAX_RSTS 3 #define EHCI_MAX_RSTS 4
#define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv) #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
struct ehci_platform_priv { struct ehci_platform_priv {
......
...@@ -221,6 +221,12 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, ...@@ -221,6 +221,12 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
ohci->num_ports = board->ports; ohci->num_ports = board->ports;
at91_start_hc(pdev); at91_start_hc(pdev);
/*
* The RemoteWakeupConnected bit has to be set explicitly
* before calling ohci_run. The reset value of this bit is 0.
*/
ohci->hc_control = OHCI_CTRL_RWC;
retval = usb_add_hcd(hcd, irq, IRQF_SHARED); retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval == 0) { if (retval == 0) {
device_wakeup_enable(hcd->self.controller); device_wakeup_enable(hcd->self.controller);
...@@ -677,9 +683,6 @@ ohci_hcd_at91_drv_suspend(struct device *dev) ...@@ -677,9 +683,6 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
* REVISIT: some boards will be able to turn VBUS off... * REVISIT: some boards will be able to turn VBUS off...
*/ */
if (!ohci_at91->wakeup) { if (!ohci_at91->wakeup) {
ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
ohci->hc_control &= OHCI_CTRL_RWC;
ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
ohci->rh_state = OHCI_RH_HALTED; ohci->rh_state = OHCI_RH_HALTED;
/* flush the writes */ /* flush the writes */
......
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
static const char hcd_name [] = "ohci_hcd"; static const char hcd_name [] = "ohci_hcd";
#define STATECHANGE_DELAY msecs_to_jiffies(300) #define STATECHANGE_DELAY msecs_to_jiffies(300)
#define IO_WATCHDOG_DELAY msecs_to_jiffies(250) #define IO_WATCHDOG_DELAY msecs_to_jiffies(275)
#include "ohci.h" #include "ohci.h"
#include "pci-quirks.h" #include "pci-quirks.h"
......
...@@ -1166,7 +1166,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -1166,7 +1166,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_set_link_state(xhci, port_array, wIndex, xhci_set_link_state(xhci, port_array, wIndex,
XDEV_RESUME); XDEV_RESUME);
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
msleep(20); msleep(USB_RESUME_TIMEOUT);
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
xhci_set_link_state(xhci, port_array, wIndex, xhci_set_link_state(xhci, port_array, wIndex,
XDEV_U0); XDEV_U0);
...@@ -1355,6 +1355,35 @@ int xhci_bus_suspend(struct usb_hcd *hcd) ...@@ -1355,6 +1355,35 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
return 0; return 0;
} }
/*
* Workaround for missing Cold Attach Status (CAS) if device re-plugged in S3.
* warm reset a USB3 device stuck in polling or compliance mode after resume.
* See Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8
*/
static bool xhci_port_missing_cas_quirk(int port_index,
__le32 __iomem **port_array)
{
u32 portsc;
portsc = readl(port_array[port_index]);
/* if any of these are set we are not stuck */
if (portsc & (PORT_CONNECT | PORT_CAS))
return false;
if (((portsc & PORT_PLS_MASK) != XDEV_POLLING) &&
((portsc & PORT_PLS_MASK) != XDEV_COMP_MODE))
return false;
/* clear wakeup/change bits, and do a warm port reset */
portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
portsc |= PORT_WR;
writel(portsc, port_array[port_index]);
/* flush write */
readl(port_array[port_index]);
return true;
}
int xhci_bus_resume(struct usb_hcd *hcd) int xhci_bus_resume(struct usb_hcd *hcd)
{ {
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
...@@ -1392,6 +1421,14 @@ int xhci_bus_resume(struct usb_hcd *hcd) ...@@ -1392,6 +1421,14 @@ int xhci_bus_resume(struct usb_hcd *hcd)
u32 temp; u32 temp;
temp = readl(port_array[port_index]); temp = readl(port_array[port_index]);
/* warm reset CAS limited ports stuck in polling/compliance */
if ((xhci->quirks & XHCI_MISSING_CAS) &&
(hcd->speed >= HCD_USB3) &&
xhci_port_missing_cas_quirk(port_index, port_array)) {
xhci_dbg(xhci, "reset stuck port %d\n", port_index);
continue;
}
if (DEV_SUPERSPEED_ANY(temp)) if (DEV_SUPERSPEED_ANY(temp))
temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
else else
...@@ -1410,7 +1447,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) ...@@ -1410,7 +1447,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
if (need_usb2_u3_exit) { if (need_usb2_u3_exit) {
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
msleep(20); msleep(USB_RESUME_TIMEOUT);
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
} }
......
...@@ -45,11 +45,13 @@ ...@@ -45,11 +45,13 @@
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI 0x9cb1
#define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5 #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f
#define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8 #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8
#define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8 #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8
#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
static const char hcd_name[] = "xhci_hcd"; static const char hcd_name[] = "xhci_hcd";
...@@ -153,7 +155,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) ...@@ -153,7 +155,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_SPURIOUS_REBOOT; xhci->quirks |= XHCI_SPURIOUS_REBOOT;
} }
if (pdev->vendor == PCI_VENDOR_ID_INTEL && if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) { (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI)) {
xhci->quirks |= XHCI_SPURIOUS_REBOOT; xhci->quirks |= XHCI_SPURIOUS_REBOOT;
xhci->quirks |= XHCI_SPURIOUS_WAKEUP; xhci->quirks |= XHCI_SPURIOUS_WAKEUP;
} }
...@@ -169,6 +172,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) ...@@ -169,6 +172,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
xhci->quirks |= XHCI_SSIC_PORT_UNUSED; xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
} }
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI))
xhci->quirks |= XHCI_MISSING_CAS;
if (pdev->vendor == PCI_VENDOR_ID_ETRON && if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
pdev->device == PCI_DEVICE_ID_EJ168) { pdev->device == PCI_DEVICE_ID_EJ168) {
xhci->quirks |= XHCI_RESET_ON_RESUME; xhci->quirks |= XHCI_RESET_ON_RESUME;
......
...@@ -314,6 +314,8 @@ struct xhci_op_regs { ...@@ -314,6 +314,8 @@ struct xhci_op_regs {
#define XDEV_U2 (0x2 << 5) #define XDEV_U2 (0x2 << 5)
#define XDEV_U3 (0x3 << 5) #define XDEV_U3 (0x3 << 5)
#define XDEV_INACTIVE (0x6 << 5) #define XDEV_INACTIVE (0x6 << 5)
#define XDEV_POLLING (0x7 << 5)
#define XDEV_COMP_MODE (0xa << 5)
#define XDEV_RESUME (0xf << 5) #define XDEV_RESUME (0xf << 5)
/* true: port has power (see HCC_PPC) */ /* true: port has power (see HCC_PPC) */
#define PORT_POWER (1 << 9) #define PORT_POWER (1 << 9)
...@@ -1653,6 +1655,7 @@ struct xhci_hcd { ...@@ -1653,6 +1655,7 @@ struct xhci_hcd {
#define XHCI_MTK_HOST (1 << 21) #define XHCI_MTK_HOST (1 << 21)
#define XHCI_SSIC_PORT_UNUSED (1 << 22) #define XHCI_SSIC_PORT_UNUSED (1 << 22)
#define XHCI_NO_64BIT_SUPPORT (1 << 23) #define XHCI_NO_64BIT_SUPPORT (1 << 23)
#define XHCI_MISSING_CAS (1 << 24)
unsigned int num_active_eps; unsigned int num_active_eps;
unsigned int limit_active_eps; unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */ /* There are two roothubs to keep track of bus suspend info for */
......
...@@ -1255,6 +1255,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, ...@@ -1255,6 +1255,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
map_dma_buffer(request, musb, musb_ep); map_dma_buffer(request, musb, musb_ep);
pm_runtime_get_sync(musb->controller);
spin_lock_irqsave(&musb->lock, lockflags); spin_lock_irqsave(&musb->lock, lockflags);
/* don't queue if the ep is down */ /* don't queue if the ep is down */
...@@ -1275,6 +1276,9 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, ...@@ -1275,6 +1276,9 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
unlock: unlock:
spin_unlock_irqrestore(&musb->lock, lockflags); spin_unlock_irqrestore(&musb->lock, lockflags);
pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(musb->controller);
return status; return status;
} }
......
...@@ -287,6 +287,7 @@ static int omap2430_musb_init(struct musb *musb) ...@@ -287,6 +287,7 @@ static int omap2430_musb_init(struct musb *musb)
} }
musb->isr = omap2430_musb_interrupt; musb->isr = omap2430_musb_interrupt;
phy_init(musb->phy); phy_init(musb->phy);
phy_power_on(musb->phy);
l = musb_readl(musb->mregs, OTG_INTERFSEL); l = musb_readl(musb->mregs, OTG_INTERFSEL);
...@@ -323,8 +324,6 @@ static void omap2430_musb_enable(struct musb *musb) ...@@ -323,8 +324,6 @@ static void omap2430_musb_enable(struct musb *musb)
struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
struct omap_musb_board_data *data = pdata->board_data; struct omap_musb_board_data *data = pdata->board_data;
if (!WARN_ON(!musb->phy))
phy_power_on(musb->phy);
switch (glue->status) { switch (glue->status) {
...@@ -361,9 +360,6 @@ static void omap2430_musb_disable(struct musb *musb) ...@@ -361,9 +360,6 @@ static void omap2430_musb_disable(struct musb *musb)
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct omap2430_glue *glue = dev_get_drvdata(dev->parent); struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
if (!WARN_ON(!musb->phy))
phy_power_off(musb->phy);
if (glue->status != MUSB_UNKNOWN) if (glue->status != MUSB_UNKNOWN)
omap_control_usb_set_mode(glue->control_otghs, omap_control_usb_set_mode(glue->control_otghs,
USB_MODE_DISCONNECT); USB_MODE_DISCONNECT);
...@@ -375,6 +371,7 @@ static int omap2430_musb_exit(struct musb *musb) ...@@ -375,6 +371,7 @@ static int omap2430_musb_exit(struct musb *musb)
struct omap2430_glue *glue = dev_get_drvdata(dev->parent); struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
omap2430_low_level_exit(musb); omap2430_low_level_exit(musb);
phy_power_off(musb->phy);
phy_exit(musb->phy); phy_exit(musb->phy);
musb->phy = NULL; musb->phy = NULL;
cancel_work_sync(&glue->omap_musb_mailbox_work); cancel_work_sync(&glue->omap_musb_mailbox_work);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* *
*/ */
#include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include "common.h" #include "common.h"
#include "rcar3.h" #include "rcar3.h"
...@@ -35,10 +36,13 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, ...@@ -35,10 +36,13 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG); usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG);
if (enable) if (enable) {
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
else /* The controller on R-Car Gen3 needs to wait up to 45 usec */
udelay(45);
} else {
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0); usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0);
}
return 0; return 0;
} }
......
...@@ -1077,7 +1077,9 @@ static int cp210x_tiocmget(struct tty_struct *tty) ...@@ -1077,7 +1077,9 @@ static int cp210x_tiocmget(struct tty_struct *tty)
u8 control; u8 control;
int result; int result;
cp210x_read_u8_reg(port, CP210X_GET_MDMSTS, &control); result = cp210x_read_u8_reg(port, CP210X_GET_MDMSTS, &control);
if (result)
return result;
result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
|((control & CONTROL_RTS) ? TIOCM_RTS : 0) |((control & CONTROL_RTS) ? TIOCM_RTS : 0)
......
...@@ -986,7 +986,8 @@ static const struct usb_device_id id_table_combined[] = { ...@@ -986,7 +986,8 @@ static const struct usb_device_id id_table_combined[] = {
/* ekey Devices */ /* ekey Devices */
{ USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) },
/* Infineon Devices */ /* Infineon Devices */
{ USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC1798_PID, 1) },
{ USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC2X7_PID, 1) },
/* GE Healthcare devices */ /* GE Healthcare devices */
{ USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) }, { USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) },
/* Active Research (Actisense) devices */ /* Active Research (Actisense) devices */
......
...@@ -627,7 +627,8 @@ ...@@ -627,7 +627,8 @@
* Infineon Technologies * Infineon Technologies
*/ */
#define INFINEON_VID 0x058b #define INFINEON_VID 0x058b
#define INFINEON_TRIBOARD_PID 0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */ #define INFINEON_TRIBOARD_TC1798_PID 0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */
#define INFINEON_TRIBOARD_TC2X7_PID 0x0043 /* DAS JTAG TriBoard TC2X7 V1.0 */
/* /*
* Acton Research Corp. * Acton Research Corp.
......
...@@ -1078,6 +1078,7 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -1078,6 +1078,7 @@ static int usb_serial_probe(struct usb_interface *interface,
serial->disconnected = 0; serial->disconnected = 0;
if (num_ports > 0)
usb_serial_console_init(serial->port[0]->minor); usb_serial_console_init(serial->port[0]->minor);
exit: exit:
module_put(type->driver.owner); module_put(type->driver.owner);
......
...@@ -133,6 +133,13 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2, ...@@ -133,6 +133,13 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
bo[itr] = bi1[itr] ^ bi2[itr]; bo[itr] = bi1[itr] ^ bi2[itr];
} }
/* Scratch space for MAC calculations. */
struct wusb_mac_scratch {
struct aes_ccm_b0 b0;
struct aes_ccm_b1 b1;
struct aes_ccm_a ax;
};
/* /*
* CC-MAC function WUSB1.0[6.5] * CC-MAC function WUSB1.0[6.5]
* *
...@@ -197,16 +204,15 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2, ...@@ -197,16 +204,15 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
* what sg[4] is for. Maybe there is a smarter way to do this. * what sg[4] is for. Maybe there is a smarter way to do this.
*/ */
static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
struct crypto_cipher *tfm_aes, void *mic, struct crypto_cipher *tfm_aes,
struct wusb_mac_scratch *scratch,
void *mic,
const struct aes_ccm_nonce *n, const struct aes_ccm_nonce *n,
const struct aes_ccm_label *a, const void *b, const struct aes_ccm_label *a, const void *b,
size_t blen) size_t blen)
{ {
int result = 0; int result = 0;
SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc); SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc);
struct aes_ccm_b0 b0;
struct aes_ccm_b1 b1;
struct aes_ccm_a ax;
struct scatterlist sg[4], sg_dst; struct scatterlist sg[4], sg_dst;
void *dst_buf; void *dst_buf;
size_t dst_size; size_t dst_size;
...@@ -218,16 +224,17 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, ...@@ -218,16 +224,17 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
* These checks should be compile time optimized out * These checks should be compile time optimized out
* ensure @a fills b1's mac_header and following fields * ensure @a fills b1's mac_header and following fields
*/ */
WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la)); WARN_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block)); WARN_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block)); WARN_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block)); WARN_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
result = -ENOMEM; result = -ENOMEM;
zero_padding = blen % sizeof(struct aes_ccm_block); zero_padding = blen % sizeof(struct aes_ccm_block);
if (zero_padding) if (zero_padding)
zero_padding = sizeof(struct aes_ccm_block) - zero_padding; zero_padding = sizeof(struct aes_ccm_block) - zero_padding;
dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding; dst_size = blen + sizeof(scratch->b0) + sizeof(scratch->b1) +
zero_padding;
dst_buf = kzalloc(dst_size, GFP_KERNEL); dst_buf = kzalloc(dst_size, GFP_KERNEL);
if (!dst_buf) if (!dst_buf)
goto error_dst_buf; goto error_dst_buf;
...@@ -235,9 +242,9 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, ...@@ -235,9 +242,9 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
memset(iv, 0, sizeof(iv)); memset(iv, 0, sizeof(iv));
/* Setup B0 */ /* Setup B0 */
b0.flags = 0x59; /* Format B0 */ scratch->b0.flags = 0x59; /* Format B0 */
b0.ccm_nonce = *n; scratch->b0.ccm_nonce = *n;
b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */ scratch->b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */
/* Setup B1 /* Setup B1
* *
...@@ -246,12 +253,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, ...@@ -246,12 +253,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
* 14'--after clarification, it means to use A's contents * 14'--after clarification, it means to use A's contents
* for MAC Header, EO, sec reserved and padding. * for MAC Header, EO, sec reserved and padding.
*/ */
b1.la = cpu_to_be16(blen + 14); scratch->b1.la = cpu_to_be16(blen + 14);
memcpy(&b1.mac_header, a, sizeof(*a)); memcpy(&scratch->b1.mac_header, a, sizeof(*a));
sg_init_table(sg, ARRAY_SIZE(sg)); sg_init_table(sg, ARRAY_SIZE(sg));
sg_set_buf(&sg[0], &b0, sizeof(b0)); sg_set_buf(&sg[0], &scratch->b0, sizeof(scratch->b0));
sg_set_buf(&sg[1], &b1, sizeof(b1)); sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1));
sg_set_buf(&sg[2], b, blen); sg_set_buf(&sg[2], b, blen);
/* 0 if well behaved :) */ /* 0 if well behaved :) */
sg_set_buf(&sg[3], bzero, zero_padding); sg_set_buf(&sg[3], bzero, zero_padding);
...@@ -276,11 +283,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, ...@@ -276,11 +283,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
* POS Crypto API: size is assumed to be AES's block size. * POS Crypto API: size is assumed to be AES's block size.
* Thanks for documenting it -- tip taken from airo.c * Thanks for documenting it -- tip taken from airo.c
*/ */
ax.flags = 0x01; /* as per WUSB 1.0 spec */ scratch->ax.flags = 0x01; /* as per WUSB 1.0 spec */
ax.ccm_nonce = *n; scratch->ax.ccm_nonce = *n;
ax.counter = 0; scratch->ax.counter = 0;
crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax); crypto_cipher_encrypt_one(tfm_aes, (void *)&scratch->ax,
bytewise_xor(mic, &ax, iv, 8); (void *)&scratch->ax);
bytewise_xor(mic, &scratch->ax, iv, 8);
result = 8; result = 8;
error_cbc_crypt: error_cbc_crypt:
kfree(dst_buf); kfree(dst_buf);
...@@ -303,6 +311,7 @@ ssize_t wusb_prf(void *out, size_t out_size, ...@@ -303,6 +311,7 @@ ssize_t wusb_prf(void *out, size_t out_size,
struct aes_ccm_nonce n = *_n; struct aes_ccm_nonce n = *_n;
struct crypto_skcipher *tfm_cbc; struct crypto_skcipher *tfm_cbc;
struct crypto_cipher *tfm_aes; struct crypto_cipher *tfm_aes;
struct wusb_mac_scratch *scratch;
u64 sfn = 0; u64 sfn = 0;
__le64 sfn_le; __le64 sfn_le;
...@@ -329,17 +338,25 @@ ssize_t wusb_prf(void *out, size_t out_size, ...@@ -329,17 +338,25 @@ ssize_t wusb_prf(void *out, size_t out_size,
printk(KERN_ERR "E: can't set AES key: %d\n", (int)result); printk(KERN_ERR "E: can't set AES key: %d\n", (int)result);
goto error_setkey_aes; goto error_setkey_aes;
} }
scratch = kmalloc(sizeof(*scratch), GFP_KERNEL);
if (!scratch) {
result = -ENOMEM;
goto error_alloc_scratch;
}
for (bitr = 0; bitr < (len + 63) / 64; bitr++) { for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
sfn_le = cpu_to_le64(sfn++); sfn_le = cpu_to_le64(sfn++);
memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */ memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
result = wusb_ccm_mac(tfm_cbc, tfm_aes, out + bytes, result = wusb_ccm_mac(tfm_cbc, tfm_aes, scratch, out + bytes,
&n, a, b, blen); &n, a, b, blen);
if (result < 0) if (result < 0)
goto error_ccm_mac; goto error_ccm_mac;
bytes += result; bytes += result;
} }
result = bytes; result = bytes;
kfree(scratch);
error_alloc_scratch:
error_ccm_mac: error_ccm_mac:
error_setkey_aes: error_setkey_aes:
crypto_free_cipher(tfm_aes); crypto_free_cipher(tfm_aes);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment