Commit 2dd0d98d authored by Linus Torvalds's avatar Linus Torvalds

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

Pull USB / Thunderbolt fixes from Greg KH:
 "Here are some USB fixes for 6.4-rc3, as well as a driver core fix that
  resolves a memory leak that shows up in USB devices easier than other
  subsystems.

  Included in here are:

   - driver core memory leak as reported and tested by syzbot and
     developers

   - dwc3 driver fixes for reported problems

   - xhci driver fixes for reported problems

   - USB gadget driver reverts to resolve regressions

   - usbtmc driver fix for syzbot reported problem

   - thunderbolt driver fixes for reported issues

   - other small USB fixes

  All of these, except for the driver core fix, have been in linux-next
  with no reported problems. The driver core fix was tested and verified
  to solve the issue by syzbot and the original reporter"

* tag 'usb-6.4-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  driver core: class: properly reference count class_dev_iter()
  xhci: Fix incorrect tracking of free space on transfer rings
  xhci-pci: Only run d3cold avoidance quirk for s2idle
  usb-storage: fix deadlock when a scsi command timeouts more than once
  usb: dwc3: fix a test for error in dwc3_core_init()
  usb: typec: tps6598x: Fix fault at module removal
  usb: gadget: u_ether: Fix host MAC address case
  usb: typec: altmodes/displayport: fix pin_assignment_show
  Revert "usb: gadget: udc: core: Invoke usb_gadget_connect only when started"
  Revert "usb: gadget: udc: core: Prevent redundant calls to pullup"
  usb: gadget: drop superfluous ':' in doc string
  usb: dwc3: debugfs: Resume dwc3 before accessing registers
  USB: UHCI: adjust zhaoxin UHCI controllers OverCurrent bit value
  usb: dwc3: fix gadget mode suspend interrupt handler issue
  usb: dwc3: gadget: Improve dwc3_gadget_suspend() and dwc3_gadget_resume()
  USB: usbtmc: Fix direction for 0-length ioctl control messages
  thunderbolt: Clear registers properly when auto clear isn't in use
parents 98be58a6 ddaf098e
...@@ -320,6 +320,7 @@ void class_dev_iter_init(struct class_dev_iter *iter, const struct class *class, ...@@ -320,6 +320,7 @@ void class_dev_iter_init(struct class_dev_iter *iter, const struct class *class,
start_knode = &start->p->knode_class; start_knode = &start->p->knode_class;
klist_iter_init_node(&sp->klist_devices, &iter->ki, start_knode); klist_iter_init_node(&sp->klist_devices, &iter->ki, start_knode);
iter->type = type; iter->type = type;
iter->sp = sp;
} }
EXPORT_SYMBOL_GPL(class_dev_iter_init); EXPORT_SYMBOL_GPL(class_dev_iter_init);
...@@ -361,6 +362,7 @@ EXPORT_SYMBOL_GPL(class_dev_iter_next); ...@@ -361,6 +362,7 @@ EXPORT_SYMBOL_GPL(class_dev_iter_next);
void class_dev_iter_exit(struct class_dev_iter *iter) void class_dev_iter_exit(struct class_dev_iter *iter)
{ {
klist_iter_exit(&iter->ki); klist_iter_exit(&iter->ki);
subsys_put(iter->sp);
} }
EXPORT_SYMBOL_GPL(class_dev_iter_exit); EXPORT_SYMBOL_GPL(class_dev_iter_exit);
......
...@@ -54,6 +54,21 @@ static int ring_interrupt_index(const struct tb_ring *ring) ...@@ -54,6 +54,21 @@ static int ring_interrupt_index(const struct tb_ring *ring)
return bit; return bit;
} }
static void nhi_mask_interrupt(struct tb_nhi *nhi, int mask, int ring)
{
if (nhi->quirks & QUIRK_AUTO_CLEAR_INT)
return;
iowrite32(mask, nhi->iobase + REG_RING_INTERRUPT_MASK_CLEAR_BASE + ring);
}
static void nhi_clear_interrupt(struct tb_nhi *nhi, int ring)
{
if (nhi->quirks & QUIRK_AUTO_CLEAR_INT)
ioread32(nhi->iobase + REG_RING_NOTIFY_BASE + ring);
else
iowrite32(~0, nhi->iobase + REG_RING_INT_CLEAR + ring);
}
/* /*
* ring_interrupt_active() - activate/deactivate interrupts for a single ring * ring_interrupt_active() - activate/deactivate interrupts for a single ring
* *
...@@ -61,8 +76,8 @@ static int ring_interrupt_index(const struct tb_ring *ring) ...@@ -61,8 +76,8 @@ static int ring_interrupt_index(const struct tb_ring *ring)
*/ */
static void ring_interrupt_active(struct tb_ring *ring, bool active) static void ring_interrupt_active(struct tb_ring *ring, bool active)
{ {
int reg = REG_RING_INTERRUPT_BASE + int index = ring_interrupt_index(ring) / 32 * 4;
ring_interrupt_index(ring) / 32 * 4; int reg = REG_RING_INTERRUPT_BASE + index;
int interrupt_bit = ring_interrupt_index(ring) & 31; int interrupt_bit = ring_interrupt_index(ring) & 31;
int mask = 1 << interrupt_bit; int mask = 1 << interrupt_bit;
u32 old, new; u32 old, new;
...@@ -123,7 +138,11 @@ static void ring_interrupt_active(struct tb_ring *ring, bool active) ...@@ -123,7 +138,11 @@ static void ring_interrupt_active(struct tb_ring *ring, bool active)
"interrupt for %s %d is already %s\n", "interrupt for %s %d is already %s\n",
RING_TYPE(ring), ring->hop, RING_TYPE(ring), ring->hop,
active ? "enabled" : "disabled"); active ? "enabled" : "disabled");
iowrite32(new, ring->nhi->iobase + reg);
if (active)
iowrite32(new, ring->nhi->iobase + reg);
else
nhi_mask_interrupt(ring->nhi, mask, index);
} }
/* /*
...@@ -136,11 +155,11 @@ static void nhi_disable_interrupts(struct tb_nhi *nhi) ...@@ -136,11 +155,11 @@ static void nhi_disable_interrupts(struct tb_nhi *nhi)
int i = 0; int i = 0;
/* disable interrupts */ /* disable interrupts */
for (i = 0; i < RING_INTERRUPT_REG_COUNT(nhi); i++) for (i = 0; i < RING_INTERRUPT_REG_COUNT(nhi); i++)
iowrite32(0, nhi->iobase + REG_RING_INTERRUPT_BASE + 4 * i); nhi_mask_interrupt(nhi, ~0, 4 * i);
/* clear interrupt status bits */ /* clear interrupt status bits */
for (i = 0; i < RING_NOTIFY_REG_COUNT(nhi); i++) for (i = 0; i < RING_NOTIFY_REG_COUNT(nhi); i++)
ioread32(nhi->iobase + REG_RING_NOTIFY_BASE + 4 * i); nhi_clear_interrupt(nhi, 4 * i);
} }
/* ring helper methods */ /* ring helper methods */
......
...@@ -93,6 +93,8 @@ struct ring_desc { ...@@ -93,6 +93,8 @@ struct ring_desc {
#define REG_RING_INTERRUPT_BASE 0x38200 #define REG_RING_INTERRUPT_BASE 0x38200
#define RING_INTERRUPT_REG_COUNT(nhi) ((31 + 2 * nhi->hop_count) / 32) #define RING_INTERRUPT_REG_COUNT(nhi) ((31 + 2 * nhi->hop_count) / 32)
#define REG_RING_INTERRUPT_MASK_CLEAR_BASE 0x38208
#define REG_INT_THROTTLING_RATE 0x38c00 #define REG_INT_THROTTLING_RATE 0x38c00
/* Interrupt Vector Allocation */ /* Interrupt Vector Allocation */
......
...@@ -1928,6 +1928,8 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, ...@@ -1928,6 +1928,8 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
if (request.req.wLength > USBTMC_BUFSIZE) if (request.req.wLength > USBTMC_BUFSIZE)
return -EMSGSIZE; return -EMSGSIZE;
if (request.req.wLength == 0) /* Length-0 requests are never IN */
request.req.bRequestType &= ~USB_DIR_IN;
is_in = request.req.bRequestType & USB_DIR_IN; is_in = request.req.bRequestType & USB_DIR_IN;
......
...@@ -1137,7 +1137,7 @@ static int dwc3_core_init(struct dwc3 *dwc) ...@@ -1137,7 +1137,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_set_incr_burst_type(dwc); dwc3_set_incr_burst_type(dwc);
dwc3_phy_power_on(dwc); ret = dwc3_phy_power_on(dwc);
if (ret) if (ret)
goto err_exit_phy; goto err_exit_phy;
......
...@@ -1116,6 +1116,7 @@ struct dwc3_scratchpad_array { ...@@ -1116,6 +1116,7 @@ struct dwc3_scratchpad_array {
* @dis_metastability_quirk: set to disable metastability quirk. * @dis_metastability_quirk: set to disable metastability quirk.
* @dis_split_quirk: set to disable split boundary. * @dis_split_quirk: set to disable split boundary.
* @wakeup_configured: set if the device is configured for remote wakeup. * @wakeup_configured: set if the device is configured for remote wakeup.
* @suspended: set to track suspend event due to U3/L2.
* @imod_interval: set the interrupt moderation interval in 250ns * @imod_interval: set the interrupt moderation interval in 250ns
* increments or 0 to disable. * increments or 0 to disable.
* @max_cfg_eps: current max number of IN eps used across all USB configs. * @max_cfg_eps: current max number of IN eps used across all USB configs.
...@@ -1332,6 +1333,7 @@ struct dwc3 { ...@@ -1332,6 +1333,7 @@ struct dwc3 {
unsigned dis_split_quirk:1; unsigned dis_split_quirk:1;
unsigned async_callbacks:1; unsigned async_callbacks:1;
unsigned wakeup_configured:1; unsigned wakeup_configured:1;
unsigned suspended:1;
u16 imod_interval; u16 imod_interval;
......
...@@ -332,6 +332,11 @@ static int dwc3_lsp_show(struct seq_file *s, void *unused) ...@@ -332,6 +332,11 @@ static int dwc3_lsp_show(struct seq_file *s, void *unused)
unsigned int current_mode; unsigned int current_mode;
unsigned long flags; unsigned long flags;
u32 reg; u32 reg;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GSTS); reg = dwc3_readl(dwc->regs, DWC3_GSTS);
...@@ -350,6 +355,8 @@ static int dwc3_lsp_show(struct seq_file *s, void *unused) ...@@ -350,6 +355,8 @@ static int dwc3_lsp_show(struct seq_file *s, void *unused)
} }
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -395,6 +402,11 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) ...@@ -395,6 +402,11 @@ static int dwc3_mode_show(struct seq_file *s, void *unused)
struct dwc3 *dwc = s->private; struct dwc3 *dwc = s->private;
unsigned long flags; unsigned long flags;
u32 reg; u32 reg;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg = dwc3_readl(dwc->regs, DWC3_GCTL);
...@@ -414,6 +426,8 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) ...@@ -414,6 +426,8 @@ static int dwc3_mode_show(struct seq_file *s, void *unused)
seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg)); seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
} }
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -463,6 +477,11 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused) ...@@ -463,6 +477,11 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused)
struct dwc3 *dwc = s->private; struct dwc3 *dwc = s->private;
unsigned long flags; unsigned long flags;
u32 reg; u32 reg;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg = dwc3_readl(dwc->regs, DWC3_DCTL);
...@@ -493,6 +512,8 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused) ...@@ -493,6 +512,8 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused)
seq_printf(s, "UNKNOWN %d\n", reg); seq_printf(s, "UNKNOWN %d\n", reg);
} }
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -509,6 +530,7 @@ static ssize_t dwc3_testmode_write(struct file *file, ...@@ -509,6 +530,7 @@ static ssize_t dwc3_testmode_write(struct file *file,
unsigned long flags; unsigned long flags;
u32 testmode = 0; u32 testmode = 0;
char buf[32]; char buf[32];
int ret;
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT; return -EFAULT;
...@@ -526,10 +548,16 @@ static ssize_t dwc3_testmode_write(struct file *file, ...@@ -526,10 +548,16 @@ static ssize_t dwc3_testmode_write(struct file *file,
else else
testmode = 0; testmode = 0;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_set_test_mode(dwc, testmode); dwc3_gadget_set_test_mode(dwc, testmode);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return count; return count;
} }
...@@ -548,12 +576,18 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) ...@@ -548,12 +576,18 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
enum dwc3_link_state state; enum dwc3_link_state state;
u32 reg; u32 reg;
u8 speed; u8 speed;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GSTS); reg = dwc3_readl(dwc->regs, DWC3_GSTS);
if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) {
seq_puts(s, "Not available\n"); seq_puts(s, "Not available\n");
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -566,6 +600,8 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) ...@@ -566,6 +600,8 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
dwc3_gadget_hs_link_string(state)); dwc3_gadget_hs_link_string(state));
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -584,6 +620,7 @@ static ssize_t dwc3_link_state_write(struct file *file, ...@@ -584,6 +620,7 @@ static ssize_t dwc3_link_state_write(struct file *file,
char buf[32]; char buf[32];
u32 reg; u32 reg;
u8 speed; u8 speed;
int ret;
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT; return -EFAULT;
...@@ -603,10 +640,15 @@ static ssize_t dwc3_link_state_write(struct file *file, ...@@ -603,10 +640,15 @@ static ssize_t dwc3_link_state_write(struct file *file,
else else
return -EINVAL; return -EINVAL;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GSTS); reg = dwc3_readl(dwc->regs, DWC3_GSTS);
if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) {
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return -EINVAL; return -EINVAL;
} }
...@@ -616,12 +658,15 @@ static ssize_t dwc3_link_state_write(struct file *file, ...@@ -616,12 +658,15 @@ static ssize_t dwc3_link_state_write(struct file *file,
if (speed < DWC3_DSTS_SUPERSPEED && if (speed < DWC3_DSTS_SUPERSPEED &&
state != DWC3_LINK_STATE_RECOV) { state != DWC3_LINK_STATE_RECOV) {
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return -EINVAL; return -EINVAL;
} }
dwc3_gadget_set_link_state(dwc, state); dwc3_gadget_set_link_state(dwc, state);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return count; return count;
} }
...@@ -645,6 +690,11 @@ static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused) ...@@ -645,6 +690,11 @@ static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused)
unsigned long flags; unsigned long flags;
u32 mdwidth; u32 mdwidth;
u32 val; u32 val;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_TXFIFO); val = dwc3_core_fifo_space(dep, DWC3_TXFIFO);
...@@ -657,6 +707,8 @@ static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused) ...@@ -657,6 +707,8 @@ static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused)
seq_printf(s, "%u\n", val); seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -667,6 +719,11 @@ static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused) ...@@ -667,6 +719,11 @@ static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused)
unsigned long flags; unsigned long flags;
u32 mdwidth; u32 mdwidth;
u32 val; u32 val;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXFIFO); val = dwc3_core_fifo_space(dep, DWC3_RXFIFO);
...@@ -679,6 +736,8 @@ static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused) ...@@ -679,6 +736,8 @@ static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused)
seq_printf(s, "%u\n", val); seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -688,12 +747,19 @@ static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused) ...@@ -688,12 +747,19 @@ static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused)
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
unsigned long flags; unsigned long flags;
u32 val; u32 val;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_TXREQQ); val = dwc3_core_fifo_space(dep, DWC3_TXREQQ);
seq_printf(s, "%u\n", val); seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -703,12 +769,19 @@ static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused) ...@@ -703,12 +769,19 @@ static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused)
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
unsigned long flags; unsigned long flags;
u32 val; u32 val;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXREQQ); val = dwc3_core_fifo_space(dep, DWC3_RXREQQ);
seq_printf(s, "%u\n", val); seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -718,12 +791,19 @@ static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused) ...@@ -718,12 +791,19 @@ static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused)
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
unsigned long flags; unsigned long flags;
u32 val; u32 val;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ); val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ);
seq_printf(s, "%u\n", val); seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -733,12 +813,19 @@ static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused) ...@@ -733,12 +813,19 @@ static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused)
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
unsigned long flags; unsigned long flags;
u32 val; u32 val;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ); val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ);
seq_printf(s, "%u\n", val); seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -748,12 +835,19 @@ static int dwc3_event_queue_show(struct seq_file *s, void *unused) ...@@ -748,12 +835,19 @@ static int dwc3_event_queue_show(struct seq_file *s, void *unused)
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
unsigned long flags; unsigned long flags;
u32 val; u32 val;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_EVENTQ); val = dwc3_core_fifo_space(dep, DWC3_EVENTQ);
seq_printf(s, "%u\n", val); seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -798,6 +892,11 @@ static int dwc3_trb_ring_show(struct seq_file *s, void *unused) ...@@ -798,6 +892,11 @@ static int dwc3_trb_ring_show(struct seq_file *s, void *unused)
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
unsigned long flags; unsigned long flags;
int i; int i;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
if (dep->number <= 1) { if (dep->number <= 1) {
...@@ -827,6 +926,8 @@ static int dwc3_trb_ring_show(struct seq_file *s, void *unused) ...@@ -827,6 +926,8 @@ static int dwc3_trb_ring_show(struct seq_file *s, void *unused)
out: out:
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -839,6 +940,11 @@ static int dwc3_ep_info_register_show(struct seq_file *s, void *unused) ...@@ -839,6 +940,11 @@ static int dwc3_ep_info_register_show(struct seq_file *s, void *unused)
u32 lower_32_bits; u32 lower_32_bits;
u32 upper_32_bits; u32 upper_32_bits;
u32 reg; u32 reg;
int ret;
ret = pm_runtime_resume_and_get(dwc->dev);
if (ret < 0)
return ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
reg = DWC3_GDBGLSPMUX_EPSELECT(dep->number); reg = DWC3_GDBGLSPMUX_EPSELECT(dep->number);
...@@ -851,6 +957,8 @@ static int dwc3_ep_info_register_show(struct seq_file *s, void *unused) ...@@ -851,6 +957,8 @@ static int dwc3_ep_info_register_show(struct seq_file *s, void *unused)
seq_printf(s, "0x%016llx\n", ep_info); seq_printf(s, "0x%016llx\n", ep_info);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return 0; return 0;
} }
...@@ -910,6 +1018,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc) ...@@ -910,6 +1018,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
dwc->regset->regs = dwc3_regs; dwc->regset->regs = dwc3_regs;
dwc->regset->nregs = ARRAY_SIZE(dwc3_regs); dwc->regset->nregs = ARRAY_SIZE(dwc3_regs);
dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START; dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;
dwc->regset->dev = dwc->dev;
root = debugfs_create_dir(dev_name(dwc->dev), usb_debug_root); root = debugfs_create_dir(dev_name(dwc->dev), usb_debug_root);
dwc->debug_root = root; dwc->debug_root = root;
......
...@@ -2440,6 +2440,7 @@ static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id) ...@@ -2440,6 +2440,7 @@ static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id)
return -EINVAL; return -EINVAL;
} }
dwc3_resume_gadget(dwc); dwc3_resume_gadget(dwc);
dwc->suspended = false;
dwc->link_state = DWC3_LINK_STATE_U0; dwc->link_state = DWC3_LINK_STATE_U0;
} }
...@@ -2699,6 +2700,21 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) ...@@ -2699,6 +2700,21 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
return ret; return ret;
} }
static int dwc3_gadget_soft_connect(struct dwc3 *dwc)
{
/*
* In the Synopsys DWC_usb31 1.90a programming guide section
* 4.1.9, it specifies that for a reconnect after a
* device-initiated disconnect requires a core soft reset
* (DCTL.CSftRst) before enabling the run/stop bit.
*/
dwc3_core_soft_reset(dwc);
dwc3_event_buffers_setup(dwc);
__dwc3_gadget_start(dwc);
return dwc3_gadget_run_stop(dwc, true);
}
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
{ {
struct dwc3 *dwc = gadget_to_dwc(g); struct dwc3 *dwc = gadget_to_dwc(g);
...@@ -2737,21 +2753,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) ...@@ -2737,21 +2753,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
synchronize_irq(dwc->irq_gadget); synchronize_irq(dwc->irq_gadget);
if (!is_on) { if (!is_on)
ret = dwc3_gadget_soft_disconnect(dwc); ret = dwc3_gadget_soft_disconnect(dwc);
} else { else
/* ret = dwc3_gadget_soft_connect(dwc);
* In the Synopsys DWC_usb31 1.90a programming guide section
* 4.1.9, it specifies that for a reconnect after a
* device-initiated disconnect requires a core soft reset
* (DCTL.CSftRst) before enabling the run/stop bit.
*/
dwc3_core_soft_reset(dwc);
dwc3_event_buffers_setup(dwc);
__dwc3_gadget_start(dwc);
ret = dwc3_gadget_run_stop(dwc, true);
}
pm_runtime_put(dwc->dev); pm_runtime_put(dwc->dev);
...@@ -3938,6 +3943,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) ...@@ -3938,6 +3943,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
{ {
int reg; int reg;
dwc->suspended = false;
dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RX_DET); dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RX_DET);
reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg = dwc3_readl(dwc->regs, DWC3_DCTL);
...@@ -3962,6 +3969,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) ...@@ -3962,6 +3969,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
{ {
u32 reg; u32 reg;
dwc->suspended = false;
/* /*
* Ideally, dwc3_reset_gadget() would trigger the function * Ideally, dwc3_reset_gadget() would trigger the function
* drivers to stop any active transfers through ep disable. * drivers to stop any active transfers through ep disable.
...@@ -4180,6 +4189,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) ...@@ -4180,6 +4189,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, unsigned int evtinfo) static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, unsigned int evtinfo)
{ {
dwc->suspended = false;
/* /*
* TODO take core out of low power mode when that's * TODO take core out of low power mode when that's
* implemented. * implemented.
...@@ -4277,6 +4288,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, ...@@ -4277,6 +4288,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
if (dwc->gadget->wakeup_armed) { if (dwc->gadget->wakeup_armed) {
dwc3_gadget_enable_linksts_evts(dwc, false); dwc3_gadget_enable_linksts_evts(dwc, false);
dwc3_resume_gadget(dwc); dwc3_resume_gadget(dwc);
dwc->suspended = false;
} }
break; break;
case DWC3_LINK_STATE_U1: case DWC3_LINK_STATE_U1:
...@@ -4303,8 +4315,10 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc, ...@@ -4303,8 +4315,10 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
{ {
enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
if (dwc->link_state != next && next == DWC3_LINK_STATE_U3) if (!dwc->suspended && next == DWC3_LINK_STATE_U3) {
dwc->suspended = true;
dwc3_suspend_gadget(dwc); dwc3_suspend_gadget(dwc);
}
dwc->link_state = next; dwc->link_state = next;
} }
...@@ -4655,42 +4669,39 @@ void dwc3_gadget_exit(struct dwc3 *dwc) ...@@ -4655,42 +4669,39 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
int dwc3_gadget_suspend(struct dwc3 *dwc) int dwc3_gadget_suspend(struct dwc3 *dwc)
{ {
unsigned long flags; unsigned long flags;
int ret;
if (!dwc->gadget_driver) if (!dwc->gadget_driver)
return 0; return 0;
dwc3_gadget_run_stop(dwc, false); ret = dwc3_gadget_soft_disconnect(dwc);
if (ret)
goto err;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
dwc3_disconnect_gadget(dwc); dwc3_disconnect_gadget(dwc);
__dwc3_gadget_stop(dwc);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
return 0; return 0;
err:
/*
* Attempt to reset the controller's state. Likely no
* communication can be established until the host
* performs a port reset.
*/
if (dwc->softconnect)
dwc3_gadget_soft_connect(dwc);
return ret;
} }
int dwc3_gadget_resume(struct dwc3 *dwc) int dwc3_gadget_resume(struct dwc3 *dwc)
{ {
int ret;
if (!dwc->gadget_driver || !dwc->softconnect) if (!dwc->gadget_driver || !dwc->softconnect)
return 0; return 0;
ret = __dwc3_gadget_start(dwc); return dwc3_gadget_soft_connect(dwc);
if (ret < 0)
goto err0;
ret = dwc3_gadget_run_stop(dwc, true);
if (ret < 0)
goto err1;
return 0;
err1:
__dwc3_gadget_stop(dwc);
err0:
return ret;
} }
void dwc3_gadget_process_pending_events(struct dwc3 *dwc) void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/string_helpers.h>
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
#include "u_ether.h" #include "u_ether.h"
...@@ -965,6 +966,8 @@ int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len) ...@@ -965,6 +966,8 @@ int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len)
dev = netdev_priv(net); dev = netdev_priv(net);
snprintf(host_addr, len, "%pm", dev->host_mac); snprintf(host_addr, len, "%pm", dev->host_mac);
string_upper(host_addr, host_addr);
return strlen(host_addr); return strlen(host_addr);
} }
EXPORT_SYMBOL_GPL(gether_get_host_addr_cdc); EXPORT_SYMBOL_GPL(gether_get_host_addr_cdc);
......
...@@ -37,10 +37,6 @@ static const struct bus_type gadget_bus_type; ...@@ -37,10 +37,6 @@ static const struct bus_type gadget_bus_type;
* @vbus: for udcs who care about vbus status, this value is real vbus status; * @vbus: for udcs who care about vbus status, this value is real vbus status;
* for udcs who do not care about vbus status, this value is always true * for udcs who do not care about vbus status, this value is always true
* @started: the UDC's started state. True if the UDC had started. * @started: the UDC's started state. True if the UDC had started.
* @connect_lock: protects udc->vbus, udc->started, gadget->connect, gadget->deactivate related
* functions. usb_gadget_connect_locked, usb_gadget_disconnect_locked,
* usb_udc_connect_control_locked, usb_gadget_udc_start_locked, usb_gadget_udc_stop_locked are
* called with this lock held.
* *
* This represents the internal data structure which is used by the UDC-class * This represents the internal data structure which is used by the UDC-class
* to hold information about udc driver and gadget together. * to hold information about udc driver and gadget together.
...@@ -52,7 +48,6 @@ struct usb_udc { ...@@ -52,7 +48,6 @@ struct usb_udc {
struct list_head list; struct list_head list;
bool vbus; bool vbus;
bool started; bool started;
struct mutex connect_lock;
}; };
static struct class *udc_class; static struct class *udc_class;
...@@ -692,9 +687,17 @@ int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) ...@@ -692,9 +687,17 @@ int usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
} }
EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect);
/* Internal version of usb_gadget_connect needs to be called with connect_lock held. */ /**
static int usb_gadget_connect_locked(struct usb_gadget *gadget) * usb_gadget_connect - software-controlled connect to USB host
__must_hold(&gadget->udc->connect_lock) * @gadget:the peripheral being connected
*
* Enables the D+ (or potentially D-) pullup. The host will start
* enumerating this gadget when the pullup is active and a VBUS session
* is active (the link is powered).
*
* Returns zero on success, else negative errno.
*/
int usb_gadget_connect(struct usb_gadget *gadget)
{ {
int ret = 0; int ret = 0;
...@@ -703,15 +706,10 @@ static int usb_gadget_connect_locked(struct usb_gadget *gadget) ...@@ -703,15 +706,10 @@ static int usb_gadget_connect_locked(struct usb_gadget *gadget)
goto out; goto out;
} }
if (gadget->connected) if (gadget->deactivated) {
goto out;
if (gadget->deactivated || !gadget->udc->started) {
/* /*
* If gadget is deactivated we only save new state. * If gadget is deactivated we only save new state.
* Gadget will be connected automatically after activation. * Gadget will be connected automatically after activation.
*
* udc first needs to be started before gadget can be pulled up.
*/ */
gadget->connected = true; gadget->connected = true;
goto out; goto out;
...@@ -726,32 +724,22 @@ static int usb_gadget_connect_locked(struct usb_gadget *gadget) ...@@ -726,32 +724,22 @@ static int usb_gadget_connect_locked(struct usb_gadget *gadget)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(usb_gadget_connect);
/** /**
* usb_gadget_connect - software-controlled connect to USB host * usb_gadget_disconnect - software-controlled disconnect from USB host
* @gadget:the peripheral being connected * @gadget:the peripheral being disconnected
* *
* Enables the D+ (or potentially D-) pullup. The host will start * Disables the D+ (or potentially D-) pullup, which the host may see
* enumerating this gadget when the pullup is active and a VBUS session * as a disconnect (when a VBUS session is active). Not all systems
* is active (the link is powered). * support software pullup controls.
*
* Following a successful disconnect, invoke the ->disconnect() callback
* for the current gadget driver so that UDC drivers don't need to.
* *
* Returns zero on success, else negative errno. * Returns zero on success, else negative errno.
*/ */
int usb_gadget_connect(struct usb_gadget *gadget) int usb_gadget_disconnect(struct usb_gadget *gadget)
{
int ret;
mutex_lock(&gadget->udc->connect_lock);
ret = usb_gadget_connect_locked(gadget);
mutex_unlock(&gadget->udc->connect_lock);
return ret;
}
EXPORT_SYMBOL_GPL(usb_gadget_connect);
/* Internal version of usb_gadget_disconnect needs to be called with connect_lock held. */
static int usb_gadget_disconnect_locked(struct usb_gadget *gadget)
__must_hold(&gadget->udc->connect_lock)
{ {
int ret = 0; int ret = 0;
...@@ -763,12 +751,10 @@ static int usb_gadget_disconnect_locked(struct usb_gadget *gadget) ...@@ -763,12 +751,10 @@ static int usb_gadget_disconnect_locked(struct usb_gadget *gadget)
if (!gadget->connected) if (!gadget->connected)
goto out; goto out;
if (gadget->deactivated || !gadget->udc->started) { if (gadget->deactivated) {
/* /*
* If gadget is deactivated we only save new state. * If gadget is deactivated we only save new state.
* Gadget will stay disconnected after activation. * Gadget will stay disconnected after activation.
*
* udc should have been started before gadget being pulled down.
*/ */
gadget->connected = false; gadget->connected = false;
goto out; goto out;
...@@ -788,30 +774,6 @@ static int usb_gadget_disconnect_locked(struct usb_gadget *gadget) ...@@ -788,30 +774,6 @@ static int usb_gadget_disconnect_locked(struct usb_gadget *gadget)
return ret; return ret;
} }
/**
* usb_gadget_disconnect - software-controlled disconnect from USB host
* @gadget:the peripheral being disconnected
*
* Disables the D+ (or potentially D-) pullup, which the host may see
* as a disconnect (when a VBUS session is active). Not all systems
* support software pullup controls.
*
* Following a successful disconnect, invoke the ->disconnect() callback
* for the current gadget driver so that UDC drivers don't need to.
*
* Returns zero on success, else negative errno.
*/
int usb_gadget_disconnect(struct usb_gadget *gadget)
{
int ret;
mutex_lock(&gadget->udc->connect_lock);
ret = usb_gadget_disconnect_locked(gadget);
mutex_unlock(&gadget->udc->connect_lock);
return ret;
}
EXPORT_SYMBOL_GPL(usb_gadget_disconnect); EXPORT_SYMBOL_GPL(usb_gadget_disconnect);
/** /**
...@@ -832,11 +794,10 @@ int usb_gadget_deactivate(struct usb_gadget *gadget) ...@@ -832,11 +794,10 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
if (gadget->deactivated) if (gadget->deactivated)
goto out; goto out;
mutex_lock(&gadget->udc->connect_lock);
if (gadget->connected) { if (gadget->connected) {
ret = usb_gadget_disconnect_locked(gadget); ret = usb_gadget_disconnect(gadget);
if (ret) if (ret)
goto unlock; goto out;
/* /*
* If gadget was being connected before deactivation, we want * If gadget was being connected before deactivation, we want
...@@ -846,8 +807,6 @@ int usb_gadget_deactivate(struct usb_gadget *gadget) ...@@ -846,8 +807,6 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
} }
gadget->deactivated = true; gadget->deactivated = true;
unlock:
mutex_unlock(&gadget->udc->connect_lock);
out: out:
trace_usb_gadget_deactivate(gadget, ret); trace_usb_gadget_deactivate(gadget, ret);
...@@ -871,7 +830,6 @@ int usb_gadget_activate(struct usb_gadget *gadget) ...@@ -871,7 +830,6 @@ int usb_gadget_activate(struct usb_gadget *gadget)
if (!gadget->deactivated) if (!gadget->deactivated)
goto out; goto out;
mutex_lock(&gadget->udc->connect_lock);
gadget->deactivated = false; gadget->deactivated = false;
/* /*
...@@ -879,8 +837,7 @@ int usb_gadget_activate(struct usb_gadget *gadget) ...@@ -879,8 +837,7 @@ int usb_gadget_activate(struct usb_gadget *gadget)
* while it was being deactivated, we call usb_gadget_connect(). * while it was being deactivated, we call usb_gadget_connect().
*/ */
if (gadget->connected) if (gadget->connected)
ret = usb_gadget_connect_locked(gadget); ret = usb_gadget_connect(gadget);
mutex_unlock(&gadget->udc->connect_lock);
out: out:
trace_usb_gadget_activate(gadget, ret); trace_usb_gadget_activate(gadget, ret);
...@@ -1121,13 +1078,12 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state); ...@@ -1121,13 +1078,12 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state);
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Acquire connect_lock before calling this function. */ static void usb_udc_connect_control(struct usb_udc *udc)
static void usb_udc_connect_control_locked(struct usb_udc *udc) __must_hold(&udc->connect_lock)
{ {
if (udc->vbus && udc->started) if (udc->vbus)
usb_gadget_connect_locked(udc->gadget); usb_gadget_connect(udc->gadget);
else else
usb_gadget_disconnect_locked(udc->gadget); usb_gadget_disconnect(udc->gadget);
} }
/** /**
...@@ -1143,12 +1099,10 @@ void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status) ...@@ -1143,12 +1099,10 @@ void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
{ {
struct usb_udc *udc = gadget->udc; struct usb_udc *udc = gadget->udc;
mutex_lock(&udc->connect_lock);
if (udc) { if (udc) {
udc->vbus = status; udc->vbus = status;
usb_udc_connect_control_locked(udc); usb_udc_connect_control(udc);
} }
mutex_unlock(&udc->connect_lock);
} }
EXPORT_SYMBOL_GPL(usb_udc_vbus_handler); EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
...@@ -1170,7 +1124,7 @@ void usb_gadget_udc_reset(struct usb_gadget *gadget, ...@@ -1170,7 +1124,7 @@ void usb_gadget_udc_reset(struct usb_gadget *gadget,
EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
/** /**
* usb_gadget_udc_start_locked - tells usb device controller to start up * usb_gadget_udc_start - tells usb device controller to start up
* @udc: The UDC to be started * @udc: The UDC to be started
* *
* This call is issued by the UDC Class driver when it's about * This call is issued by the UDC Class driver when it's about
...@@ -1181,11 +1135,8 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); ...@@ -1181,11 +1135,8 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
* necessary to have it powered on. * necessary to have it powered on.
* *
* Returns zero on success, else negative errno. * Returns zero on success, else negative errno.
*
* Caller should acquire connect_lock before invoking this function.
*/ */
static inline int usb_gadget_udc_start_locked(struct usb_udc *udc) static inline int usb_gadget_udc_start(struct usb_udc *udc)
__must_hold(&udc->connect_lock)
{ {
int ret; int ret;
...@@ -1202,7 +1153,7 @@ static inline int usb_gadget_udc_start_locked(struct usb_udc *udc) ...@@ -1202,7 +1153,7 @@ static inline int usb_gadget_udc_start_locked(struct usb_udc *udc)
} }
/** /**
* usb_gadget_udc_stop_locked - tells usb device controller we don't need it anymore * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
* @udc: The UDC to be stopped * @udc: The UDC to be stopped
* *
* This call is issued by the UDC Class driver after calling * This call is issued by the UDC Class driver after calling
...@@ -1211,11 +1162,8 @@ static inline int usb_gadget_udc_start_locked(struct usb_udc *udc) ...@@ -1211,11 +1162,8 @@ static inline int usb_gadget_udc_start_locked(struct usb_udc *udc)
* The details are implementation specific, but it can go as * The details are implementation specific, but it can go as
* far as powering off UDC completely and disable its data * far as powering off UDC completely and disable its data
* line pullups. * line pullups.
*
* Caller should acquire connect lock before invoking this function.
*/ */
static inline void usb_gadget_udc_stop_locked(struct usb_udc *udc) static inline void usb_gadget_udc_stop(struct usb_udc *udc)
__must_hold(&udc->connect_lock)
{ {
if (!udc->started) { if (!udc->started) {
dev_err(&udc->dev, "UDC had already stopped\n"); dev_err(&udc->dev, "UDC had already stopped\n");
...@@ -1374,7 +1322,6 @@ int usb_add_gadget(struct usb_gadget *gadget) ...@@ -1374,7 +1322,6 @@ int usb_add_gadget(struct usb_gadget *gadget)
udc->gadget = gadget; udc->gadget = gadget;
gadget->udc = udc; gadget->udc = udc;
mutex_init(&udc->connect_lock);
udc->started = false; udc->started = false;
...@@ -1576,15 +1523,11 @@ static int gadget_bind_driver(struct device *dev) ...@@ -1576,15 +1523,11 @@ static int gadget_bind_driver(struct device *dev)
if (ret) if (ret)
goto err_bind; goto err_bind;
mutex_lock(&udc->connect_lock); ret = usb_gadget_udc_start(udc);
ret = usb_gadget_udc_start_locked(udc); if (ret)
if (ret) {
mutex_unlock(&udc->connect_lock);
goto err_start; goto err_start;
}
usb_gadget_enable_async_callbacks(udc); usb_gadget_enable_async_callbacks(udc);
usb_udc_connect_control_locked(udc); usb_udc_connect_control(udc);
mutex_unlock(&udc->connect_lock);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
return 0; return 0;
...@@ -1615,14 +1558,12 @@ static void gadget_unbind_driver(struct device *dev) ...@@ -1615,14 +1558,12 @@ static void gadget_unbind_driver(struct device *dev)
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
mutex_lock(&udc->connect_lock); usb_gadget_disconnect(gadget);
usb_gadget_disconnect_locked(gadget);
usb_gadget_disable_async_callbacks(udc); usb_gadget_disable_async_callbacks(udc);
if (gadget->irq) if (gadget->irq)
synchronize_irq(gadget->irq); synchronize_irq(gadget->irq);
udc->driver->unbind(gadget); udc->driver->unbind(gadget);
usb_gadget_udc_stop_locked(udc); usb_gadget_udc_stop(udc);
mutex_unlock(&udc->connect_lock);
mutex_lock(&udc_lock); mutex_lock(&udc_lock);
driver->is_bound = false; driver->is_bound = false;
...@@ -1708,15 +1649,11 @@ static ssize_t soft_connect_store(struct device *dev, ...@@ -1708,15 +1649,11 @@ static ssize_t soft_connect_store(struct device *dev,
} }
if (sysfs_streq(buf, "connect")) { if (sysfs_streq(buf, "connect")) {
mutex_lock(&udc->connect_lock); usb_gadget_udc_start(udc);
usb_gadget_udc_start_locked(udc); usb_gadget_connect(udc->gadget);
usb_gadget_connect_locked(udc->gadget);
mutex_unlock(&udc->connect_lock);
} else if (sysfs_streq(buf, "disconnect")) { } else if (sysfs_streq(buf, "disconnect")) {
mutex_lock(&udc->connect_lock); usb_gadget_disconnect(udc->gadget);
usb_gadget_disconnect_locked(udc->gadget); usb_gadget_udc_stop(udc);
usb_gadget_udc_stop_locked(udc);
mutex_unlock(&udc->connect_lock);
} else { } else {
dev_err(dev, "unsupported command '%s'\n", buf); dev_err(dev, "unsupported command '%s'\n", buf);
ret = -EINVAL; ret = -EINVAL;
......
...@@ -119,11 +119,13 @@ static int uhci_pci_init(struct usb_hcd *hcd) ...@@ -119,11 +119,13 @@ static int uhci_pci_init(struct usb_hcd *hcd)
uhci->rh_numports = uhci_count_ports(hcd); uhci->rh_numports = uhci_count_ports(hcd);
/* Intel controllers report the OverCurrent bit active on. /*
* VIA controllers report it active off, so we'll adjust the * Intel controllers report the OverCurrent bit active on. VIA
* bit value. (It's not standardized in the UHCI spec.) * and ZHAOXIN controllers report it active off, so we'll adjust
* the bit value. (It's not standardized in the UHCI spec.)
*/ */
if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA) if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA ||
to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_ZHAOXIN)
uhci->oc_low = 1; uhci->oc_low = 1;
/* HP's server management chip requires a longer port reset delay. */ /* HP's server management chip requires a longer port reset delay. */
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/suspend.h>
#include "xhci.h" #include "xhci.h"
#include "xhci-trace.h" #include "xhci-trace.h"
...@@ -387,7 +388,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) ...@@ -387,7 +388,7 @@ 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 &&
pdev->device == PCI_DEVICE_ID_AMD_RENOIR_XHCI) pdev->device == PCI_DEVICE_ID_AMD_RENOIR_XHCI)
xhci->quirks |= XHCI_BROKEN_D3COLD; xhci->quirks |= XHCI_BROKEN_D3COLD_S2I;
if (pdev->vendor == PCI_VENDOR_ID_INTEL) { if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_LPM_SUPPORT;
...@@ -801,9 +802,16 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) ...@@ -801,9 +802,16 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
* Systems with the TI redriver that loses port status change events * Systems with the TI redriver that loses port status change events
* need to have the registers polled during D3, so avoid D3cold. * need to have the registers polled during D3, so avoid D3cold.
*/ */
if (xhci->quirks & (XHCI_COMP_MODE_QUIRK | XHCI_BROKEN_D3COLD)) if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
pci_d3cold_disable(pdev); pci_d3cold_disable(pdev);
#ifdef CONFIG_SUSPEND
/* d3cold is broken, but only when s2idle is used */
if (pm_suspend_target_state == PM_SUSPEND_TO_IDLE &&
xhci->quirks & (XHCI_BROKEN_D3COLD_S2I))
pci_d3cold_disable(pdev);
#endif
if (xhci->quirks & XHCI_PME_STUCK_QUIRK) if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
xhci_pme_quirk(hcd); xhci_pme_quirk(hcd);
......
...@@ -276,6 +276,26 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, ...@@ -276,6 +276,26 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
trace_xhci_inc_enq(ring); trace_xhci_inc_enq(ring);
} }
static int xhci_num_trbs_to(struct xhci_segment *start_seg, union xhci_trb *start,
struct xhci_segment *end_seg, union xhci_trb *end,
unsigned int num_segs)
{
union xhci_trb *last_on_seg;
int num = 0;
int i = 0;
do {
if (start_seg == end_seg && end >= start)
return num + (end - start);
last_on_seg = &start_seg->trbs[TRBS_PER_SEGMENT - 1];
num += last_on_seg - start;
start_seg = start_seg->next;
start = start_seg->trbs;
} while (i++ <= num_segs);
return -EINVAL;
}
/* /*
* Check to see if there's room to enqueue num_trbs on the ring and make sure * Check to see if there's room to enqueue num_trbs on the ring and make sure
* enqueue pointer will not advance into dequeue segment. See rules above. * enqueue pointer will not advance into dequeue segment. See rules above.
...@@ -2140,6 +2160,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, ...@@ -2140,6 +2160,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
u32 trb_comp_code) u32 trb_comp_code)
{ {
struct xhci_ep_ctx *ep_ctx; struct xhci_ep_ctx *ep_ctx;
int trbs_freed;
ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index); ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index);
...@@ -2209,9 +2230,15 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, ...@@ -2209,9 +2230,15 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
} }
/* Update ring dequeue pointer */ /* Update ring dequeue pointer */
trbs_freed = xhci_num_trbs_to(ep_ring->deq_seg, ep_ring->dequeue,
td->last_trb_seg, td->last_trb,
ep_ring->num_segs);
if (trbs_freed < 0)
xhci_dbg(xhci, "Failed to count freed trbs at TD finish\n");
else
ep_ring->num_trbs_free += trbs_freed;
ep_ring->dequeue = td->last_trb; ep_ring->dequeue = td->last_trb;
ep_ring->deq_seg = td->last_trb_seg; ep_ring->deq_seg = td->last_trb_seg;
ep_ring->num_trbs_free += td->num_trbs - 1;
inc_deq(xhci, ep_ring); inc_deq(xhci, ep_ring);
return xhci_td_cleanup(xhci, td, ep_ring, td->status); return xhci_td_cleanup(xhci, td, ep_ring, td->status);
......
...@@ -1901,7 +1901,7 @@ struct xhci_hcd { ...@@ -1901,7 +1901,7 @@ struct xhci_hcd {
#define XHCI_DISABLE_SPARSE BIT_ULL(38) #define XHCI_DISABLE_SPARSE BIT_ULL(38)
#define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39) #define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39)
#define XHCI_NO_SOFT_RETRY BIT_ULL(40) #define XHCI_NO_SOFT_RETRY BIT_ULL(40)
#define XHCI_BROKEN_D3COLD BIT_ULL(41) #define XHCI_BROKEN_D3COLD_S2I BIT_ULL(41)
#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42) #define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42)
#define XHCI_SUSPEND_RESUME_CLKS BIT_ULL(43) #define XHCI_SUSPEND_RESUME_CLKS BIT_ULL(43)
#define XHCI_RESET_TO_DEFAULT BIT_ULL(44) #define XHCI_RESET_TO_DEFAULT BIT_ULL(44)
......
...@@ -406,22 +406,25 @@ static DEF_SCSI_QCMD(queuecommand) ...@@ -406,22 +406,25 @@ static DEF_SCSI_QCMD(queuecommand)
***********************************************************************/ ***********************************************************************/
/* Command timeout and abort */ /* Command timeout and abort */
static int command_abort(struct scsi_cmnd *srb) static int command_abort_matching(struct us_data *us, struct scsi_cmnd *srb_match)
{ {
struct us_data *us = host_to_us(srb->device->host);
usb_stor_dbg(us, "%s called\n", __func__);
/* /*
* us->srb together with the TIMED_OUT, RESETTING, and ABORTING * us->srb together with the TIMED_OUT, RESETTING, and ABORTING
* bits are protected by the host lock. * bits are protected by the host lock.
*/ */
scsi_lock(us_to_host(us)); scsi_lock(us_to_host(us));
/* Is this command still active? */ /* is there any active pending command to abort ? */
if (us->srb != srb) { if (!us->srb) {
scsi_unlock(us_to_host(us)); scsi_unlock(us_to_host(us));
usb_stor_dbg(us, "-- nothing to abort\n"); usb_stor_dbg(us, "-- nothing to abort\n");
return SUCCESS;
}
/* Does the command match the passed srb if any ? */
if (srb_match && us->srb != srb_match) {
scsi_unlock(us_to_host(us));
usb_stor_dbg(us, "-- pending command mismatch\n");
return FAILED; return FAILED;
} }
...@@ -444,6 +447,14 @@ static int command_abort(struct scsi_cmnd *srb) ...@@ -444,6 +447,14 @@ static int command_abort(struct scsi_cmnd *srb)
return SUCCESS; return SUCCESS;
} }
static int command_abort(struct scsi_cmnd *srb)
{
struct us_data *us = host_to_us(srb->device->host);
usb_stor_dbg(us, "%s called\n", __func__);
return command_abort_matching(us, srb);
}
/* /*
* This invokes the transport reset mechanism to reset the state of the * This invokes the transport reset mechanism to reset the state of the
* device * device
...@@ -455,6 +466,9 @@ static int device_reset(struct scsi_cmnd *srb) ...@@ -455,6 +466,9 @@ static int device_reset(struct scsi_cmnd *srb)
usb_stor_dbg(us, "%s called\n", __func__); usb_stor_dbg(us, "%s called\n", __func__);
/* abort any pending command before reset */
command_abort_matching(us, NULL);
/* lock the device pointers and do the reset */ /* lock the device pointers and do the reset */
mutex_lock(&(us->dev_mutex)); mutex_lock(&(us->dev_mutex));
result = us->transport_reset(us); result = us->transport_reset(us);
......
...@@ -516,6 +516,10 @@ static ssize_t pin_assignment_show(struct device *dev, ...@@ -516,6 +516,10 @@ static ssize_t pin_assignment_show(struct device *dev,
mutex_unlock(&dp->lock); mutex_unlock(&dp->lock);
/* get_current_pin_assignments can return 0 when no matching pin assignments are found */
if (len == 0)
len++;
buf[len - 1] = '\n'; buf[len - 1] = '\n';
return len; return len;
} }
......
...@@ -886,6 +886,9 @@ static void tps6598x_remove(struct i2c_client *client) ...@@ -886,6 +886,9 @@ static void tps6598x_remove(struct i2c_client *client)
{ {
struct tps6598x *tps = i2c_get_clientdata(client); struct tps6598x *tps = i2c_get_clientdata(client);
if (!client->irq)
cancel_delayed_work_sync(&tps->wq_poll);
tps6598x_disconnect(tps, 0); tps6598x_disconnect(tps, 0);
typec_unregister_port(tps->port); typec_unregister_port(tps->port);
usb_role_switch_put(tps->role_sw); usb_role_switch_put(tps->role_sw);
......
...@@ -74,6 +74,7 @@ struct class { ...@@ -74,6 +74,7 @@ struct class {
struct class_dev_iter { struct class_dev_iter {
struct klist_iter ki; struct klist_iter ki;
const struct device_type *type; const struct device_type *type;
struct subsys_private *sp;
}; };
int __must_check class_register(const struct class *class); int __must_check class_register(const struct class *class);
......
...@@ -443,7 +443,7 @@ static inline struct usb_composite_driver *to_cdriver( ...@@ -443,7 +443,7 @@ static inline struct usb_composite_driver *to_cdriver(
* @bcd_webusb_version: 0x0100 by default, WebUSB specification version * @bcd_webusb_version: 0x0100 by default, WebUSB specification version
* @b_webusb_vendor_code: 0x0 by default, vendor code for WebUSB * @b_webusb_vendor_code: 0x0 by default, vendor code for WebUSB
* @landing_page: empty by default, landing page to announce in WebUSB * @landing_page: empty by default, landing page to announce in WebUSB
* @use_webusb:: false by default, interested gadgets set it * @use_webusb: false by default, interested gadgets set it
* @os_desc_config: the configuration to be used with OS descriptors * @os_desc_config: the configuration to be used with OS descriptors
* @setup_pending: true when setup request is queued but not completed * @setup_pending: true when setup request is queued but not completed
* @os_desc_pending: true when os_desc request is queued but not completed * @os_desc_pending: true when os_desc request is queued but not completed
......
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