summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/chipidea/core.c5
-rw-r--r--drivers/usb/chipidea/debug.c3
-rw-r--r--drivers/usb/chipidea/otg_fsm.c8
-rw-r--r--drivers/usb/chipidea/udc.c8
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c41
-rw-r--r--drivers/usb/class/cdc-wdm.c17
-rw-r--r--drivers/usb/core/devio.c17
-rw-r--r--drivers/usb/core/hcd.c19
-rw-r--r--drivers/usb/core/hub.c40
-rw-r--r--drivers/usb/core/of.c6
-rw-r--r--drivers/usb/core/urb.c2
-rw-r--r--drivers/usb/core/usb-acpi.c26
-rw-r--r--drivers/usb/core/usb.c2
-rw-r--r--drivers/usb/dwc2/params.c2
-rw-r--r--drivers/usb/dwc3/dwc3-keystone.c4
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c4
-rw-r--r--drivers/usb/dwc3/gadget.c21
-rw-r--r--drivers/usb/early/xhci-dbc.c1
-rw-r--r--drivers/usb/gadget/composite.c11
-rw-r--r--drivers/usb/gadget/function/f_fs.c10
-rw-r--r--drivers/usb/gadget/function/f_phonet.c2
-rw-r--r--drivers/usb/gadget/function/u_serial.c2
-rw-r--r--drivers/usb/gadget/legacy/inode.c9
-rw-r--r--drivers/usb/gadget/udc/core.c9
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c19
-rw-r--r--drivers/usb/gadget/udc/net2280.c9
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c45
-rw-r--r--drivers/usb/host/Kconfig12
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-exynos.c4
-rw-r--r--drivers/usb/host/ehci-platform.c4
-rw-r--r--drivers/usb/host/ehci-sched.c2
-rw-r--r--drivers/usb/host/ehci-timer.c2
-rw-r--r--drivers/usb/host/fotg210-hcd.c2
-rw-r--r--drivers/usb/host/ohci-omap3.c211
-rw-r--r--drivers/usb/host/ohci-platform.c13
-rw-r--r--drivers/usb/host/r8a66597-hcd.c6
-rw-r--r--drivers/usb/host/uhci-hcd.c17
-rw-r--r--drivers/usb/host/uhci-hcd.h51
-rw-r--r--drivers/usb/host/uhci-platform.c22
-rw-r--r--drivers/usb/host/xhci-hub.c2
-rw-r--r--drivers/usb/host/xhci-mem.c99
-rw-r--r--drivers/usb/host/xhci-pci.c10
-rw-r--r--drivers/usb/host/xhci-plat.c2
-rw-r--r--drivers/usb/host/xhci-ring.c220
-rw-r--r--drivers/usb/host/xhci.c38
-rw-r--r--drivers/usb/host/xhci.h22
-rw-r--r--drivers/usb/misc/chaoskey.c2
-rw-r--r--drivers/usb/misc/iowarrior.c13
-rw-r--r--drivers/usb/misc/legousbtower.c1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c2
-rw-r--r--drivers/usb/misc/usbsevseg.c18
-rw-r--r--drivers/usb/mtu3/mtu3.h8
-rw-r--r--drivers/usb/musb/musb_dsps.c5
-rw-r--r--drivers/usb/musb/musb_host.c9
-rw-r--r--drivers/usb/musb/tusb6010_omap.c13
-rw-r--r--drivers/usb/serial/ftdi_sio.c10
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h2
-rw-r--r--drivers/usb/serial/io_ti.c5
-rw-r--r--drivers/usb/serial/ir-usb.c21
-rw-r--r--drivers/usb/serial/mct_u232.c2
-rw-r--r--drivers/usb/serial/option.c8
-rw-r--r--drivers/usb/serial/qcserial.c2
-rw-r--r--drivers/usb/storage/ene_ub6250.c177
-rw-r--r--drivers/usb/typec/typec.c136
-rw-r--r--drivers/usb/usbip/stub_main.c4
-rw-r--r--drivers/usb/usbip/stub_tx.c4
-rw-r--r--drivers/usb/usbip/vhci.h36
-rw-r--r--drivers/usb/usbip/vhci_hcd.c616
-rw-r--r--drivers/usb/usbip/vhci_rx.c16
-rw-r--r--drivers/usb/usbip/vhci_sysfs.c138
71 files changed, 1423 insertions, 907 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 9e217b1361ea..fe4fe2440729 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -843,7 +843,10 @@ static ssize_t ci_role_show(struct device *dev, struct device_attribute *attr,
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", ci_role(ci)->name);
+ if (ci->role != CI_ROLE_END)
+ return sprintf(buf, "%s\n", ci_role(ci)->name);
+
+ return 0;
}
static ssize_t ci_role_store(struct device *dev,
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 6d23eede4d8c..1c31e8a08810 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -294,7 +294,8 @@ static int ci_role_show(struct seq_file *s, void *data)
{
struct ci_hdrc *ci = s->private;
- seq_printf(s, "%s\n", ci_role(ci)->name);
+ if (ci->role != CI_ROLE_END)
+ seq_printf(s, "%s\n", ci_role(ci)->name);
return 0;
}
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 93e24ce61a3a..949183ede16f 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -234,7 +234,7 @@ static void ci_otg_add_timer(struct ci_hdrc *ci, enum otg_fsm_timer t)
ktime_set(timer_sec, timer_nsec));
ci->enabled_otg_timer_bits |= (1 << t);
if ((ci->next_otg_timer == NUM_OTG_FSM_TIMERS) ||
- (ci->hr_timeouts[ci->next_otg_timer] >
+ ktime_after(ci->hr_timeouts[ci->next_otg_timer],
ci->hr_timeouts[t])) {
ci->next_otg_timer = t;
hrtimer_start_range_ns(&ci->otg_fsm_hrtimer,
@@ -269,7 +269,7 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum otg_fsm_timer t)
for_each_set_bit(cur_timer, &enabled_timer_bits,
NUM_OTG_FSM_TIMERS) {
if ((next_timer == NUM_OTG_FSM_TIMERS) ||
- (ci->hr_timeouts[next_timer] <
+ ktime_before(ci->hr_timeouts[next_timer],
ci->hr_timeouts[cur_timer]))
next_timer = cur_timer;
}
@@ -397,13 +397,13 @@ static enum hrtimer_restart ci_otg_hrtimer_func(struct hrtimer *t)
now = ktime_get();
for_each_set_bit(cur_timer, &enabled_timer_bits, NUM_OTG_FSM_TIMERS) {
- if (now >= ci->hr_timeouts[cur_timer]) {
+ if (ktime_compare(now, ci->hr_timeouts[cur_timer]) >= 0) {
ci->enabled_otg_timer_bits &= ~(1 << cur_timer);
if (otg_timer_handlers[cur_timer])
ret = otg_timer_handlers[cur_timer](ci);
} else {
if ((next_timer == NUM_OTG_FSM_TIMERS) ||
- (ci->hr_timeouts[cur_timer] <
+ ktime_before(ci->hr_timeouts[cur_timer],
ci->hr_timeouts[next_timer]))
next_timer = cur_timer;
}
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 56d2d3213076..d68b125796f9 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1993,6 +1993,7 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
+ int ret;
if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
return -ENXIO;
@@ -2005,7 +2006,10 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
rdrv->stop = udc_id_switch_for_host;
rdrv->irq = udc_irq;
rdrv->name = "gadget";
- ci->roles[CI_ROLE_GADGET] = rdrv;
- return udc_start(ci);
+ ret = udc_start(ci);
+ if (!ret)
+ ci->roles[CI_ROLE_GADGET] = rdrv;
+
+ return ret;
}
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index e77a4ed4f021..9f4a0185dd60 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -108,6 +108,8 @@ struct imx_usbmisc {
const struct usbmisc_ops *ops;
};
+static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data);
+
static int usbmisc_imx25_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
@@ -242,10 +244,15 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
| MX53_USB_UHx_CTRL_ULPI_INT_EN;
writel(val, reg);
- /* Disable internal 60Mhz clock */
- reg = usbmisc->base + MX53_USB_CLKONOFF_CTRL_OFFSET;
- val = readl(reg) | MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF;
- writel(val, reg);
+ if (is_imx53_usbmisc(data)) {
+ /* Disable internal 60Mhz clock */
+ reg = usbmisc->base +
+ MX53_USB_CLKONOFF_CTRL_OFFSET;
+ val = readl(reg) |
+ MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF;
+ writel(val, reg);
+ }
+
}
if (data->disable_oc) {
reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
@@ -267,10 +274,15 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
| MX53_USB_UHx_CTRL_ULPI_INT_EN;
writel(val, reg);
- /* Disable internal 60Mhz clock */
- reg = usbmisc->base + MX53_USB_CLKONOFF_CTRL_OFFSET;
- val = readl(reg) | MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF;
- writel(val, reg);
+
+ if (is_imx53_usbmisc(data)) {
+ /* Disable internal 60Mhz clock */
+ reg = usbmisc->base +
+ MX53_USB_CLKONOFF_CTRL_OFFSET;
+ val = readl(reg) |
+ MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF;
+ writel(val, reg);
+ }
}
if (data->disable_oc) {
reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
@@ -456,6 +468,10 @@ static const struct usbmisc_ops imx27_usbmisc_ops = {
.init = usbmisc_imx27_init,
};
+static const struct usbmisc_ops imx51_usbmisc_ops = {
+ .init = usbmisc_imx53_init,
+};
+
static const struct usbmisc_ops imx53_usbmisc_ops = {
.init = usbmisc_imx53_init,
};
@@ -479,6 +495,13 @@ static const struct usbmisc_ops imx7d_usbmisc_ops = {
.set_wakeup = usbmisc_imx7d_set_wakeup,
};
+static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+
+ return usbmisc->ops == &imx53_usbmisc_ops;
+}
+
int imx_usbmisc_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc;
@@ -536,7 +559,7 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
},
{
.compatible = "fsl,imx51-usbmisc",
- .data = &imx53_usbmisc_ops,
+ .data = &imx51_usbmisc_ops,
},
{
.compatible = "fsl,imx53-usbmisc",
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 08669fee6d7f..8f972247b1c1 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -361,17 +361,9 @@ static ssize_t wdm_write
if (we < 0)
return usb_translate_errors(we);
- buf = kmalloc(count, GFP_KERNEL);
- if (!buf) {
- rv = -ENOMEM;
- goto outnl;
- }
-
- r = copy_from_user(buf, buffer, count);
- if (r > 0) {
- rv = -EFAULT;
- goto out_free_mem;
- }
+ buf = memdup_user(buffer, count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
/* concurrent writes and disconnect */
r = mutex_lock_interruptible(&desc->wlock);
@@ -441,8 +433,7 @@ static ssize_t wdm_write
usb_autopm_put_interface(desc->intf);
mutex_unlock(&desc->wlock);
-outnl:
- return rv < 0 ? rv : count;
+ return count;
out_free_mem_pm:
usb_autopm_put_interface(desc->intf);
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index cfc3cff6e8d5..0e7d0e81a7cb 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -475,11 +475,11 @@ static void snoop_urb(struct usb_device *udev,
if (userurb) { /* Async */
if (when == SUBMIT)
- dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
+ dev_info(&udev->dev, "userurb %pK, ep%d %s-%s, "
"length %u\n",
userurb, ep, t, d, length);
else
- dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
+ dev_info(&udev->dev, "userurb %pK, ep%d %s-%s, "
"actual_length %u status %d\n",
userurb, ep, t, d, length,
timeout_or_status);
@@ -1895,7 +1895,7 @@ static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
if (as) {
int retval;
- snoop(&ps->dev->dev, "reap %p\n", as->userurb);
+ snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
return retval;
@@ -1912,7 +1912,7 @@ static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
as = async_getcompleted(ps);
if (as) {
- snoop(&ps->dev->dev, "reap %p\n", as->userurb);
+ snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
} else {
@@ -2043,7 +2043,7 @@ static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
if (as) {
int retval;
- snoop(&ps->dev->dev, "reap %p\n", as->userurb);
+ snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
return retval;
@@ -2060,7 +2060,7 @@ static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *ar
as = async_getcompleted(ps);
if (as) {
- snoop(&ps->dev->dev, "reap %p\n", as->userurb);
+ snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
} else {
@@ -2489,7 +2489,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
#endif
case USBDEVFS_DISCARDURB:
- snoop(&dev->dev, "%s: DISCARDURB %p\n", __func__, p);
+ snoop(&dev->dev, "%s: DISCARDURB %pK\n", __func__, p);
ret = proc_unlinkurb(ps, p);
break;
@@ -2537,6 +2537,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
case USBDEVFS_DROP_PRIVILEGES:
ret = proc_drop_privileges(ps, p);
break;
+ case USBDEVFS_GET_SPEED:
+ ret = ps->dev->speed;
+ break;
}
done:
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 49550790a3cb..ab1bb3b538ac 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
+#include <linux/sched/task_stack.h>
#include <linux/slab.h>
#include <linux/completion.h>
#include <linux/utsname.h>
@@ -1076,7 +1077,6 @@ static void usb_deregister_bus (struct usb_bus *bus)
static int register_root_hub(struct usb_hcd *hcd)
{
struct device *parent_dev = hcd->self.controller;
- struct device *sysdev = hcd->self.sysdev;
struct usb_device *usb_dev = hcd->self.root_hub;
const int devnum = 1;
int retval;
@@ -1123,7 +1123,6 @@ static int register_root_hub(struct usb_hcd *hcd)
/* Did the HC die before the root hub was registered? */
if (HCD_DEAD(hcd))
usb_hc_died (hcd); /* This time clean up */
- usb_dev->dev.of_node = sysdev->of_node;
}
mutex_unlock(&usb_bus_idr_lock);
@@ -1523,6 +1522,14 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
if (hcd->self.uses_pio_for_control)
return ret;
if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
+ if (is_vmalloc_addr(urb->setup_packet)) {
+ WARN_ONCE(1, "setup packet is not dma capable\n");
+ return -EAGAIN;
+ } else if (object_is_on_stack(urb->setup_packet)) {
+ WARN_ONCE(1, "setup packet is on stack\n");
+ return -EAGAIN;
+ }
+
urb->setup_dma = dma_map_single(
hcd->self.sysdev,
urb->setup_packet,
@@ -1587,6 +1594,9 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
} else if (is_vmalloc_addr(urb->transfer_buffer)) {
WARN_ONCE(1, "transfer buffer not dma capable\n");
ret = -EAGAIN;
+ } else if (object_is_on_stack(urb->transfer_buffer)) {
+ WARN_ONCE(1, "transfer buffer is on stack\n");
+ ret = -EAGAIN;
} else {
urb->transfer_dma = dma_map_single(
hcd->self.sysdev,
@@ -1723,7 +1733,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
if (retval == 0)
retval = -EINPROGRESS;
else if (retval != -EIDRM && retval != -EBUSY)
- dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n",
+ dev_dbg(&udev->dev, "hcd_unlink_urb %pK fail %d\n",
urb, retval);
usb_put_dev(udev);
}
@@ -1890,7 +1900,7 @@ rescan:
/* kick hcd */
unlink1(hcd, urb, -ESHUTDOWN);
dev_dbg (hcd->self.controller,
- "shutdown urb %p ep%d%s%s\n",
+ "shutdown urb %pK ep%d%s%s\n",
urb, usb_endpoint_num(&ep->desc),
is_in ? "in" : "out",
({ char *s;
@@ -2520,6 +2530,7 @@ struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver,
hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
GFP_KERNEL);
if (!hcd->bandwidth_mutex) {
+ kfree(hcd->address0_mutex);
kfree(hcd);
dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
return NULL;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 9dca59ef18b3..59e0418a5ed5 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -362,7 +362,8 @@ static void usb_set_lpm_parameters(struct usb_device *udev)
}
/* USB 2.0 spec Section 11.24.4.5 */
-static int get_hub_descriptor(struct usb_device *hdev, void *data)
+static int get_hub_descriptor(struct usb_device *hdev,
+ struct usb_hub_descriptor *desc)
{
int i, ret, size;
unsigned dtype;
@@ -378,10 +379,18 @@ static int get_hub_descriptor(struct usb_device *hdev, void *data)
for (i = 0; i < 3; i++) {
ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
- dtype << 8, 0, data, size,
+ dtype << 8, 0, desc, size,
USB_CTRL_GET_TIMEOUT);
- if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
+ if (hub_is_superspeed(hdev)) {
+ if (ret == size)
+ return ret;
+ } else if (ret >= USB_DT_HUB_NONVAR_SIZE + 2) {
+ /* Make sure we have the DeviceRemovable field. */
+ size = USB_DT_HUB_NONVAR_SIZE + desc->bNbrPorts / 8 + 1;
+ if (ret < size)
+ return -EMSGSIZE;
return ret;
+ }
}
return -EINVAL;
}
@@ -1313,7 +1322,7 @@ static int hub_configure(struct usb_hub *hub,
}
mutex_init(&hub->status_mutex);
- hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
+ hub->descriptor = kzalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) {
ret = -ENOMEM;
goto fail;
@@ -1321,13 +1330,19 @@ static int hub_configure(struct usb_hub *hub,
/* Request the entire hub descriptor.
* hub->descriptor can handle USB_MAXCHILDREN ports,
- * but the hub can/will return fewer bytes here.
+ * but a (non-SS) hub can/will return fewer bytes here.
*/
ret = get_hub_descriptor(hdev, hub->descriptor);
if (ret < 0) {
message = "can't read hub descriptor";
goto fail;
- } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {
+ }
+
+ maxchild = USB_MAXCHILDREN;
+ if (hub_is_superspeed(hdev))
+ maxchild = min_t(unsigned, maxchild, USB_SS_MAXPORTS);
+
+ if (hub->descriptor->bNbrPorts > maxchild) {
message = "hub has too many ports!";
ret = -ENODEV;
goto fail;
@@ -3140,12 +3155,6 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (PMSG_IS_AUTO(msg))
goto err_ltm;
}
- if (usb_unlocked_disable_lpm(udev)) {
- dev_err(&udev->dev, "Failed to disable LPM before suspend\n.");
- status = -ENOMEM;
- if (PMSG_IS_AUTO(msg))
- goto err_lpm3;
- }
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
@@ -3172,9 +3181,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (status) {
dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);
- /* Try to enable USB3 LPM and LTM again */
- usb_unlocked_enable_lpm(udev);
- err_lpm3:
+ /* Try to enable USB3 LTM again */
usb_enable_ltm(udev);
err_ltm:
/* Try to enable USB2 hardware LPM again */
@@ -3458,9 +3465,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
if (udev->usb2_hw_lpm_capable == 1)
usb_set_usb2_hardware_lpm(udev, 1);
- /* Try to enable USB3 LTM and LPM */
+ /* Try to enable USB3 LTM */
usb_enable_ltm(udev);
- usb_unlocked_enable_lpm(udev);
}
usb_unlock_port(port_dev);
diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c
index d787f195a9a6..3863bb1ce8c5 100644
--- a/drivers/usb/core/of.c
+++ b/drivers/usb/core/of.c
@@ -28,7 +28,8 @@
*
* Find the node from device tree according to its port number.
*
- * Return: On success, a pointer to the device node, %NULL on failure.
+ * Return: A pointer to the node with incremented refcount if found, or
+ * %NULL otherwise.
*/
struct device_node *usb_of_get_child_node(struct device_node *parent,
int portnum)
@@ -53,6 +54,9 @@ EXPORT_SYMBOL_GPL(usb_of_get_child_node);
*
* Find the companion device from platform bus.
*
+ * Takes a reference to the returned struct device which needs to be dropped
+ * after use.
+ *
* Return: On success, a pointer to the companion device, %NULL on failure.
*/
struct device *usb_of_get_companion_dev(struct device *dev)
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index d75cb8c0f7df..47903d510955 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -338,7 +338,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (!urb || !urb->complete)
return -EINVAL;
if (urb->hcpriv) {
- WARN_ONCE(1, "URB %p submitted while active\n", urb);
+ WARN_ONCE(1, "URB %pK submitted while active\n", urb);
return -EBUSY;
}
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 2776cfe64c09..ef9cf4a21afe 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -127,6 +127,22 @@ out:
*/
#define USB_ACPI_LOCATION_VALID (1 << 31)
+static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
+ int raw)
+{
+ struct acpi_device *adev;
+
+ if (!parent)
+ return NULL;
+
+ list_for_each_entry(adev, &parent->children, node) {
+ if (acpi_device_adr(adev) == raw)
+ return adev;
+ }
+
+ return acpi_find_child_device(parent, raw, false);
+}
+
static struct acpi_device *usb_acpi_find_companion(struct device *dev)
{
struct usb_device *udev;
@@ -174,8 +190,10 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev)
int raw;
raw = usb_hcd_find_raw_port_number(hcd, port1);
- adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev),
- raw, false);
+
+ adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
+ raw);
+
if (!adev)
return NULL;
} else {
@@ -186,7 +204,9 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev)
return NULL;
acpi_bus_get_device(parent_handle, &adev);
- adev = acpi_find_child_device(adev, port1, false);
+
+ adev = usb_acpi_find_port(adev, port1);
+
if (!adev)
return NULL;
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 28b053cacc90..17681d5638ac 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -416,6 +416,7 @@ static void usb_release_dev(struct device *dev)
usb_destroy_configuration(udev);
usb_release_bos_descriptor(udev);
+ of_node_put(dev->of_node);
usb_put_hcd(hcd);
kfree(udev->product);
kfree(udev->manufacturer);
@@ -614,6 +615,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->route = 0;
dev->dev.parent = bus->controller;
+ device_set_of_node_from_dev(&dev->dev, bus->sysdev);
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
} else {
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 9cd8722f24f6..a3ffe97170ff 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -144,6 +144,8 @@ const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },
{ .compatible = "snps,dwc2" },
{ .compatible = "samsung,s3c6400-hsotg" },
+ { .compatible = "amlogic,meson8-usb",
+ .data = dwc2_set_amlogic_params },
{ .compatible = "amlogic,meson8b-usb",
.data = dwc2_set_amlogic_params },
{ .compatible = "amlogic,meson-gxbb-usb",
diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c
index 72664700b8a2..12ee23f53cdd 100644
--- a/drivers/usb/dwc3/dwc3-keystone.c
+++ b/drivers/usb/dwc3/dwc3-keystone.c
@@ -107,6 +107,10 @@ static int kdwc3_probe(struct platform_device *pdev)
return PTR_ERR(kdwc->usbss);
kdwc->clk = devm_clk_get(kdwc->dev, "usb");
+ if (IS_ERR(kdwc->clk)) {
+ dev_err(kdwc->dev, "unable to get usb clock\n");
+ return PTR_ERR(kdwc->clk);
+ }
error = clk_prepare_enable(kdwc->clk);
if (error < 0) {
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index a15ec71d0423..84a2cebfc712 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -39,6 +39,8 @@
#define PCI_DEVICE_ID_INTEL_APL 0x5aaa
#define PCI_DEVICE_ID_INTEL_KBP 0xa2b0
#define PCI_DEVICE_ID_INTEL_GLK 0x31aa
+#define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee
+#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
#define PCI_INTEL_BXT_DSM_UUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
#define PCI_INTEL_BXT_FUNC_PMU_PWR 4
@@ -270,6 +272,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
{ } /* Terminating Entry */
};
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 7fd4b22f4e97..9e41605a276b 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1300,14 +1300,24 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
__dwc3_gadget_start_isoc(dwc, dep, cur_uf);
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
}
+ return 0;
}
- return 0;
+
+ if ((dep->flags & DWC3_EP_BUSY) &&
+ !(dep->flags & DWC3_EP_MISSED_ISOC)) {
+ WARN_ON_ONCE(!dep->resource_index);
+ ret = __dwc3_gadget_kick_transfer(dep,
+ dep->resource_index);
+ }
+
+ goto out;
}
if (!dwc3_calc_trbs_left(dep))
return 0;
ret = __dwc3_gadget_kick_transfer(dep, 0);
+out:
if (ret == -EBUSY)
ret = 0;
@@ -3073,6 +3083,15 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
return IRQ_HANDLED;
}
+ /*
+ * With PCIe legacy interrupt, test shows that top-half irq handler can
+ * be called again after HW interrupt deassertion. Check if bottom-half
+ * irq event handler completes before caching new event to prevent
+ * losing events.
+ */
+ if (evt->flags & DWC3_EVENT_PENDING)
+ return IRQ_HANDLED;
+
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
count &= DWC3_GEVNTCOUNT_MASK;
if (!count)
diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index 1268818e2263..12fe70beae69 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -32,7 +32,6 @@
static struct xdbc_state xdbc;
static bool early_console_keep;
-#define XDBC_TRACE
#ifdef XDBC_TRACE
#define xdbc_trace trace_printk
#else
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index d62f53d7f418..dd74c99d6ce1 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -315,6 +315,9 @@ void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
list_del(&f->list);
if (f->unbind)
f->unbind(c, f);
+
+ if (f->bind_deactivated)
+ usb_function_activate(f);
}
EXPORT_SYMBOL_GPL(usb_remove_function);
@@ -961,12 +964,8 @@ static void remove_config(struct usb_composite_dev *cdev,
f = list_first_entry(&config->functions,
struct usb_function, list);
- list_del(&f->list);
- if (f->unbind) {
- DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
- f->unbind(config, f);
- /* may free memory for "f" */
- }
+
+ usb_remove_function(config, f);
}
list_del(&config->list);
if (config->unbind) {
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 519ea34ca699..d21874b35cf6 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1874,12 +1874,12 @@ static int ffs_func_eps_enable(struct ffs_function *func)
ep->ep->driver_data = ep;
ep->ep->desc = ds;
- comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds +
- USB_DT_ENDPOINT_SIZE);
- ep->ep->maxburst = comp_desc->bMaxBurst + 1;
-
- if (needs_comp_desc)
+ if (needs_comp_desc) {
+ comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds +
+ USB_DT_ENDPOINT_SIZE);
+ ep->ep->maxburst = comp_desc->bMaxBurst + 1;
ep->ep->comp_desc = comp_desc;
+ }
ret = usb_ep_enable(ep->ep);
if (likely(!ret)) {
diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c
index b4058f0000e4..6a1ce6a55158 100644
--- a/drivers/usb/gadget/function/f_phonet.c
+++ b/drivers/usb/gadget/function/f_phonet.c
@@ -281,7 +281,7 @@ static void pn_net_setup(struct net_device *dev)
dev->tx_queue_len = 1;
dev->netdev_ops = &pn_netdev_ops;
- dev->destructor = free_netdev;
+ dev->needs_free_netdev = true;
dev->header_ops = &phonet_header_ops;
}
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index 000677c991b0..9b0805f55ad7 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -1256,7 +1256,7 @@ static void gserial_console_exit(void)
struct gscons_info *info = &gscons_info;
unregister_console(&gserial_cons);
- if (info->console_thread != NULL)
+ if (!IS_ERR_OR_NULL(info->console_thread))
kthread_stop(info->console_thread);
gs_buf_free(&info->con_buf);
}
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index b9ca0a26cbd9..684900fcfe24 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1183,8 +1183,10 @@ dev_release (struct inode *inode, struct file *fd)
/* closing ep0 === shutdown all */
- if (dev->gadget_registered)
+ if (dev->gadget_registered) {
usb_gadget_unregister_driver (&gadgetfs_driver);
+ dev->gadget_registered = false;
+ }
/* at this point "good" hardware has disconnected the
* device from USB; the host won't see it any more.
@@ -1677,9 +1679,10 @@ static void
gadgetfs_suspend (struct usb_gadget *gadget)
{
struct dev_data *dev = get_gadget_data (gadget);
+ unsigned long flags;
INFO (dev, "suspended from state %d\n", dev->state);
- spin_lock (&dev->lock);
+ spin_lock_irqsave(&dev->lock, flags);
switch (dev->state) {
case STATE_DEV_SETUP: // VERY odd... host died??
case STATE_DEV_CONNECTED:
@@ -1690,7 +1693,7 @@ gadgetfs_suspend (struct usb_gadget *gadget)
default:
break;
}
- spin_unlock (&dev->lock);
+ spin_unlock_irqrestore(&dev->lock, flags);
}
static struct usb_gadget_driver gadgetfs_driver = {
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 08facbada30e..e6f04eee95c4 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
+#include <linux/sched/task_stack.h>
#include <linux/workqueue.h>
#include <linux/usb/ch9.h>
@@ -796,6 +797,14 @@ int usb_gadget_map_request_by_dev(struct device *dev,
req->num_mapped_sgs = mapped;
} else {
+ if (is_vmalloc_addr(req->buf)) {
+ dev_err(dev, "buffer is not dma capable\n");
+ return -EFAULT;
+ } else if (object_is_on_stack(req->buf)) {
+ dev_err(dev, "buffer is on stack\n");
+ return -EFAULT;
+ }
+
req->dma = dma_map_single(dev, req->buf, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 156380e4e0af..3c3760315910 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -442,23 +442,16 @@ static void set_link_state(struct dummy_hcd *dum_hcd)
/* Report reset and disconnect events to the driver */
if (dum->driver && (disconnect || reset)) {
stop_activity(dum);
- spin_unlock(&dum->lock);
if (reset)
usb_gadget_udc_reset(&dum->gadget, dum->driver);
else
dum->driver->disconnect(&dum->gadget);
- spin_lock(&dum->lock);
}
} else if (dum_hcd->active != dum_hcd->old_active) {
- if (dum_hcd->old_active && dum->driver->suspend) {
- spin_unlock(&dum->lock);
+ if (dum_hcd->old_active && dum->driver->suspend)
dum->driver->suspend(&dum->gadget);
- spin_lock(&dum->lock);
- } else if (!dum_hcd->old_active && dum->driver->resume) {
- spin_unlock(&dum->lock);
+ else if (!dum_hcd->old_active && dum->driver->resume)
dum->driver->resume(&dum->gadget);
- spin_lock(&dum->lock);
- }
}
dum_hcd->old_status = dum_hcd->port_status;
@@ -990,7 +983,9 @@ static int dummy_udc_stop(struct usb_gadget *g)
struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g);
struct dummy *dum = dum_hcd->dum;
+ spin_lock_irq(&dum->lock);
dum->driver = NULL;
+ spin_unlock_irq(&dum->lock);
return 0;
}
@@ -2015,7 +2010,7 @@ ss_hub_descriptor(struct usb_hub_descriptor *desc)
HUB_CHAR_COMMON_OCPM);
desc->bNbrPorts = 1;
desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
- desc->u.ss.DeviceRemovable = 0xffff;
+ desc->u.ss.DeviceRemovable = 0;
}
static inline void hub_descriptor(struct usb_hub_descriptor *desc)
@@ -2027,8 +2022,8 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc)
HUB_CHAR_INDV_PORT_LPSM |
HUB_CHAR_COMMON_OCPM);
desc->bNbrPorts = 1;
- desc->u.hs.DeviceRemovable[0] = 0xff;
- desc->u.hs.DeviceRemovable[1] = 0xff;
+ desc->u.hs.DeviceRemovable[0] = 0;
+ desc->u.hs.DeviceRemovable[1] = 0xff; /* PortPwrCtrlMask */
}
static int dummy_hub_control(
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index 29c3d11a0e1d..f608c1f85e61 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -2470,11 +2470,8 @@ static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver)
nuke(&dev->ep[i]);
/* report disconnect; the driver is already quiesced */
- if (driver) {
- spin_unlock(&dev->lock);
+ if (driver)
driver->disconnect(&dev->gadget);
- spin_lock(&dev->lock);
- }
usb_reinit(dev);
}
@@ -3348,8 +3345,6 @@ next_endpoints:
BIT(PCI_RETRY_ABORT_INTERRUPT))
static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
-__releases(dev->lock)
-__acquires(dev->lock)
{
struct net2280_ep *ep;
u32 tmp, num, mask, scratch;
@@ -3390,14 +3385,12 @@ __acquires(dev->lock)
if (disconnect || reset) {
stop_activity(dev, dev->driver);
ep0_start(dev);
- spin_unlock(&dev->lock);
if (reset)
usb_gadget_udc_reset
(&dev->gadget, dev->driver);
else
(dev->driver->disconnect)
(&dev->gadget);
- spin_lock(&dev->lock);
return;
}
}
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 078f7737ed6f..d8278322d5ac 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -697,7 +697,6 @@ static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3)
{
usb3_disconnect(usb3);
usb3_write(usb3, 0, USB3_P0_INT_ENA);
- usb3_write(usb3, 0, USB3_PN_INT_ENA);
usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA);
usb3_write(usb3, 0, USB3_USB_INT_ENA_1);
usb3_write(usb3, 0, USB3_USB_INT_ENA_2);
@@ -1820,7 +1819,13 @@ static void usb3_request_done_pipen(struct renesas_usb3 *usb3,
struct renesas_usb3_request *usb3_req,
int status)
{
- usb3_pn_stop(usb3);
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb3->lock, flags);
+ if (usb3_pn_change(usb3, usb3_ep->num))
+ usb3_pn_stop(usb3);
+ spin_unlock_irqrestore(&usb3->lock, flags);
+
usb3_disable_pipe_irq(usb3, usb3_ep->num);
usb3_request_done(usb3_ep, usb3_req, status);
@@ -1849,30 +1854,46 @@ static void usb3_irq_epc_pipen_bfrdy(struct renesas_usb3 *usb3, int num)
{
struct renesas_usb3_ep *usb3_ep = usb3_get_ep(usb3, num);
struct renesas_usb3_request *usb3_req = usb3_get_request(usb3_ep);
+ bool done = false;
if (!usb3_req)
return;
+ spin_lock(&usb3->lock);
+ if (usb3_pn_change(usb3, num))
+ goto out;
+
if (usb3_ep->dir_in) {
/* Do not stop the IN pipe here to detect LSTTR interrupt */
if (!usb3_write_pipe(usb3_ep, usb3_req, USB3_PN_WRITE))
usb3_clear_bit(usb3, PN_INT_BFRDY, USB3_PN_INT_ENA);
} else {
if (!usb3_read_pipe(usb3_ep, usb3_req, USB3_PN_READ))
- usb3_request_done_pipen(usb3, usb3_ep, usb3_req, 0);
+ done = true;
}
+
+out:
+ /* need to unlock because usb3_request_done_pipen() locks it */
+ spin_unlock(&usb3->lock);
+
+ if (done)
+ usb3_request_done_pipen(usb3, usb3_ep, usb3_req, 0);
}
static void usb3_irq_epc_pipen(struct renesas_usb3 *usb3, int num)
{
u32 pn_int_sta;
- if (usb3_pn_change(usb3, num) < 0)
+ spin_lock(&usb3->lock);
+ if (usb3_pn_change(usb3, num) < 0) {
+ spin_unlock(&usb3->lock);
return;
+ }
pn_int_sta = usb3_read(usb3, USB3_PN_INT_STA);
pn_int_sta &= usb3_read(usb3, USB3_PN_INT_ENA);
usb3_write(usb3, pn_int_sta, USB3_PN_INT_STA);
+ spin_unlock(&usb3->lock);
if (pn_int_sta & PN_INT_LSTTR)
usb3_irq_epc_pipen_lsttr(usb3, num);
if (pn_int_sta & PN_INT_BFRDY)
@@ -2042,6 +2063,7 @@ static int usb3_disable_pipe_n(struct renesas_usb3_ep *usb3_ep)
spin_lock_irqsave(&usb3->lock, flags);
if (!usb3_pn_change(usb3, usb3_ep->num)) {
+ usb3_write(usb3, 0, USB3_PN_INT_ENA);
usb3_write(usb3, 0, USB3_PN_RAMMAP);
usb3_clear_bit(usb3, PN_CON_EN, USB3_PN_CON);
}
@@ -2183,6 +2205,9 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
/* hook up the driver */
usb3->driver = driver;
+ pm_runtime_enable(usb3_to_dev(usb3));
+ pm_runtime_get_sync(usb3_to_dev(usb3));
+
renesas_usb3_init_controller(usb3);
return 0;
@@ -2191,14 +2216,14 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
static int renesas_usb3_stop(struct usb_gadget *gadget)
{
struct renesas_usb3 *usb3 = gadget_to_renesas_usb3(gadget);
- unsigned long flags;
- spin_lock_irqsave(&usb3->lock, flags);
usb3->softconnect = false;
usb3->gadget.speed = USB_SPEED_UNKNOWN;
usb3->driver = NULL;
renesas_usb3_stop_controller(usb3);
- spin_unlock_irqrestore(&usb3->lock, flags);
+
+ pm_runtime_put(usb3_to_dev(usb3));
+ pm_runtime_disable(usb3_to_dev(usb3));
return 0;
}
@@ -2275,9 +2300,6 @@ static int renesas_usb3_remove(struct platform_device *pdev)
device_remove_file(&pdev->dev, &dev_attr_role);
- pm_runtime_put(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
usb_del_gadget_udc(&usb3->gadget);
renesas_usb3_dma_free_prd(usb3, &pdev->dev);
@@ -2488,9 +2510,6 @@ static int renesas_usb3_probe(struct platform_device *pdev)
usb3->workaround_for_vbus = priv->workaround_for_vbus;
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
-
dev_info(&pdev->dev, "probed\n");
return 0;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index ababb91d654a..fa5692dec832 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -473,8 +473,12 @@ config USB_OHCI_HCD_AT91
config USB_OHCI_HCD_OMAP3
tristate "OHCI support for OMAP3 and later chips"
depends on (ARCH_OMAP3 || ARCH_OMAP4 || SOC_OMAP5)
+ select USB_OHCI_HCD_PLATFORM
default y
- ---help---
+ help
+ This option is deprecated now and the driver was removed, use
+ USB_OHCI_HCD_PLATFORM instead.
+
Enables support for the on-chip OHCI controller on
OMAP3 and later chips.
@@ -627,7 +631,11 @@ config USB_UHCI_SUPPORT_NON_PCI_HC
config USB_UHCI_PLATFORM
bool
- default y if ARCH_VT8500
+ default y if (ARCH_VT8500 || ARCH_ASPEED)
+
+config USB_UHCI_ASPEED
+ bool
+ default y if ARCH_ASPEED
config USB_UHCI_BIG_ENDIAN_MMIO
bool
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index c77b0a38557b..cf2691fffcc0 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -52,7 +52,6 @@ obj-$(CONFIG_USB_OHCI_HCD_PCI) += ohci-pci.o
obj-$(CONFIG_USB_OHCI_HCD_PLATFORM) += ohci-platform.o
obj-$(CONFIG_USB_OHCI_EXYNOS) += ohci-exynos.o
obj-$(CONFIG_USB_OHCI_HCD_OMAP1) += ohci-omap.o
-obj-$(CONFIG_USB_OHCI_HCD_OMAP3) += ohci-omap3.o
obj-$(CONFIG_USB_OHCI_HCD_SPEAR) += ohci-spear.o
obj-$(CONFIG_USB_OHCI_HCD_STI) += ohci-st.o
obj-$(CONFIG_USB_OHCI_HCD_AT91) += ohci-at91.o
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 7a603f66a9bc..26b641100639 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -279,7 +279,9 @@ static int exynos_ehci_resume(struct device *dev)
struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
int ret;
- clk_prepare_enable(exynos_ehci->clk);
+ ret = clk_prepare_enable(exynos_ehci->clk);
+ if (ret)
+ return ret;
ret = exynos_ehci_phy_enable(dev);
if (ret) {
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index bc7b9be12f54..f1908ea9fbd8 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -384,8 +384,10 @@ static int ehci_platform_resume(struct device *dev)
}
companion_dev = usb_of_get_companion_dev(hcd->self.controller);
- if (companion_dev)
+ if (companion_dev) {
device_pm_wait_for_dev(hcd->self.controller, companion_dev);
+ put_device(companion_dev);
+ }
ehci_resume(hcd, priv->reset_on_resume);
return 0;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 980a6b3b2da2..6bc6304672bc 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1105,7 +1105,7 @@ iso_stream_init(
addr |= epnum << 8;
addr |= dev->devnum;
stream->ps.usecs = HS_USECS_ISO(maxp);
- think_time = dev->tt ? dev->tt->think_time : 0;
+ think_time = dev->tt->think_time;
stream->ps.tt_usecs = NS_TO_US(think_time + usb_calc_bus_time(
dev->speed, is_input, 1, maxp));
hs_transfers = max(1u, (maxp + 187) / 188);
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index 3893b5bafd87..0b6cdb723192 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -424,7 +424,7 @@ static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t)
*/
now = ktime_get();
for_each_set_bit(e, &events, EHCI_HRTIMER_NUM_EVENTS) {
- if (now >= ehci->hr_timeouts[e])
+ if (ktime_compare(now, ehci->hr_timeouts[e]) >= 0)
event_handlers[e](ehci);
else
ehci_enable_event(ehci, e, false);
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index ced08dc229ad..457cc6525abd 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -1380,7 +1380,7 @@ static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t)
*/
now = ktime_get();
for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) {
- if (now >= fotg210->hr_timeouts[e])
+ if (ktime_compare(now, fotg210->hr_timeouts[e]) >= 0)
event_handlers[e](fotg210);
else
fotg210_enable_event(fotg210, e, false);
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
deleted file mode 100644
index ec15aebe8786..000000000000
--- a/drivers/usb/host/ohci-omap3.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * ohci-omap3.c - driver for OHCI on OMAP3 and later processors
- *
- * Bus Glue for OMAP3 USBHOST 3 port OHCI controller
- * This controller is also used in later OMAPs and AM35x chips
- *
- * Copyright (C) 2007-2010 Texas Instruments, Inc.
- * Author: Vikram Pandita <vikram.pandita@ti.com>
- * Author: Anand Gadiyar <gadiyar@ti.com>
- * Author: Keshava Munegowda <keshava_mgowda@ti.com>
- *
- * Based on ehci-omap.c and some other ohci glue layers
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * TODO (last updated Feb 27, 2011):
- * - add kernel-doc
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/usb/otg.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-
-#include "ohci.h"
-
-#define DRIVER_DESC "OHCI OMAP3 driver"
-
-static const char hcd_name[] = "ohci-omap3";
-static struct hc_driver __read_mostly ohci_omap3_hc_driver;
-
-/*
- * configure so an HC device and id are always provided
- * always called with process context; sleeping is OK
- */
-
-/**
- * ohci_hcd_omap3_probe - initialize OMAP-based HCDs
- *
- * Allocates basic resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
- */
-static int ohci_hcd_omap3_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct ohci_hcd *ohci;
- struct usb_hcd *hcd = NULL;
- void __iomem *regs = NULL;
- struct resource *res;
- int ret;
- int irq;
-
- if (usb_disabled())
- return -ENODEV;
-
- if (!dev->parent) {
- dev_err(dev, "Missing parent device\n");
- return -ENODEV;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(dev, "OHCI irq failed\n");
- return -ENODEV;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "UHH OHCI get resource failed\n");
- return -ENOMEM;
- }
-
- regs = ioremap(res->start, resource_size(res));
- if (!regs) {
- dev_err(dev, "UHH OHCI ioremap failed\n");
- return -ENOMEM;
- }
-
- /*
- * Right now device-tree probed devices don't get dma_mask set.
- * Since shared usb code relies on it, set it here for now.
- * Once we have dma capability bindings this can go away.
- */
- ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
- if (ret)
- goto err_io;
-
- ret = -ENODEV;
- hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,
- dev_name(dev));
- if (!hcd) {
- dev_err(dev, "usb_create_hcd failed\n");
- goto err_io;
- }
-
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
- hcd->regs = regs;
-
- pm_runtime_enable(dev);
- pm_runtime_get_sync(dev);
-
- ohci = hcd_to_ohci(hcd);
- /*
- * RemoteWakeupConnected has to be set explicitly before
- * calling ohci_run. The reset value of RWC is 0.
- */
- ohci->hc_control = OHCI_CTRL_RWC;
-
- ret = usb_add_hcd(hcd, irq, 0);
- if (ret) {
- dev_dbg(dev, "failed to add hcd with err %d\n", ret);
- goto err_add_hcd;
- }
- device_wakeup_enable(hcd->self.controller);
-
- return 0;
-
-err_add_hcd:
- pm_runtime_put_sync(dev);
- usb_put_hcd(hcd);
-
-err_io:
- iounmap(regs);
-
- return ret;
-}
-
-/*
- * may be called without controller electrically present
- * may be called with controller, bus, and devices active
- */
-
-/**
- * ohci_hcd_omap3_remove - shutdown processing for OHCI HCDs
- * @pdev: USB Host Controller being removed
- *
- * Reverses the effect of ohci_hcd_omap3_probe(), first invoking
- * the HCD's stop() method. It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
- */
-static int ohci_hcd_omap3_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct usb_hcd *hcd = dev_get_drvdata(dev);
-
- iounmap(hcd->regs);
- usb_remove_hcd(hcd);
- pm_runtime_put_sync(dev);
- pm_runtime_disable(dev);
- usb_put_hcd(hcd);
- return 0;
-}
-
-static const struct of_device_id omap_ohci_dt_ids[] = {
- { .compatible = "ti,ohci-omap3" },
- { }
-};
-
-MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids);
-
-static struct platform_driver ohci_hcd_omap3_driver = {
- .probe = ohci_hcd_omap3_probe,
- .remove = ohci_hcd_omap3_remove,
- .shutdown = usb_hcd_platform_shutdown,
- .driver = {
- .name = "ohci-omap3",
- .of_match_table = omap_ohci_dt_ids,
- },
-};
-
-static int __init ohci_omap3_init(void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
- ohci_init_driver(&ohci_omap3_hc_driver, NULL);
- return platform_driver_register(&ohci_hcd_omap3_driver);
-}
-module_init(ohci_omap3_init);
-
-static void __exit ohci_omap3_cleanup(void)
-{
- platform_driver_unregister(&ohci_hcd_omap3_driver);
-}
-module_exit(ohci_omap3_cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_ALIAS("platform:ohci-omap3");
-MODULE_AUTHOR("Anand Gadiyar <gadiyar@ti.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 6368fce43197..61fe2b985070 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -24,6 +24,7 @@
#include <linux/err.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/usb/ohci_pdriver.h>
#include <linux/usb.h>
@@ -163,6 +164,10 @@ static int ohci_platform_probe(struct platform_device *dev)
if (of_property_read_bool(dev->dev.of_node, "no-big-frame-no"))
ohci->flags |= OHCI_QUIRK_FRAME_NO;
+ if (of_property_read_bool(dev->dev.of_node,
+ "remote-wakeup-connected"))
+ ohci->hc_control = OHCI_CTRL_RWC;
+
of_property_read_u32(dev->dev.of_node, "num-ports",
&ohci->num_ports);
@@ -242,6 +247,8 @@ static int ohci_platform_probe(struct platform_device *dev)
}
#endif
+ pm_runtime_set_active(&dev->dev);
+ pm_runtime_enable(&dev->dev);
if (pdata->power_on) {
err = pdata->power_on(dev);
if (err < 0)
@@ -271,6 +278,7 @@ err_power:
if (pdata->power_off)
pdata->power_off(dev);
err_reset:
+ pm_runtime_disable(&dev->dev);
while (--rst >= 0)
reset_control_assert(priv->resets[rst]);
err_put_clks:
@@ -292,6 +300,7 @@ static int ohci_platform_remove(struct platform_device *dev)
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
int clk, rst;
+ pm_runtime_get_sync(&dev->dev);
usb_remove_hcd(hcd);
if (pdata->power_off)
@@ -305,6 +314,9 @@ static int ohci_platform_remove(struct platform_device *dev)
usb_put_hcd(hcd);
+ pm_runtime_put_sync(&dev->dev);
+ pm_runtime_disable(&dev->dev);
+
if (pdata == &ohci_platform_defaults)
dev->dev.platform_data = NULL;
@@ -350,6 +362,7 @@ static int ohci_platform_resume(struct device *dev)
static const struct of_device_id ohci_platform_ids[] = {
{ .compatible = "generic-ohci", },
{ .compatible = "cavium,octeon-6335-ohci", },
+ { .compatible = "ti,ohci-omap3", },
{ }
};
MODULE_DEVICE_TABLE(of, ohci_platform_ids);
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index bfa7fa3d2eea..7bf78be1fd32 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -1269,7 +1269,7 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
time = 30;
break;
default:
- time = 300;
+ time = 50;
break;
}
@@ -1785,6 +1785,7 @@ static void r8a66597_td_timer(unsigned long _r8a66597)
pipe = td->pipe;
pipe_stop(r8a66597, pipe);
+ /* Select a different address or endpoint */
new_td = td;
do {
list_move_tail(&new_td->queue,
@@ -1794,7 +1795,8 @@ static void r8a66597_td_timer(unsigned long _r8a66597)
new_td = td;
break;
}
- } while (td != new_td && td->address == new_td->address);
+ } while (td != new_td && td->address == new_td->address &&
+ td->pipe->info.epnum == new_td->pipe->info.epnum);
start_transfer(r8a66597, new_td);
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 94b150196d4f..c3267a78c94e 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -265,9 +265,13 @@ static void configure_hc(struct uhci_hcd *uhci)
static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
{
- /* If we have to ignore overcurrent events then almost by definition
- * we can't depend on resume-detect interrupts. */
- if (ignore_oc)
+ /*
+ * If we have to ignore overcurrent events then almost by definition
+ * we can't depend on resume-detect interrupts.
+ *
+ * Those interrupts also don't seem to work on ASpeed SoCs.
+ */
+ if (ignore_oc || uhci_is_aspeed(uhci))
return 1;
return uhci->resume_detect_interrupts_are_broken ?
@@ -384,6 +388,13 @@ static void start_rh(struct uhci_hcd *uhci)
{
uhci->is_stopped = 0;
+ /*
+ * Clear stale status bits on Aspeed as we get a stale HCH
+ * which causes problems later on
+ */
+ if (uhci_is_aspeed(uhci))
+ uhci_writew(uhci, uhci_readw(uhci, USBSTS), USBSTS);
+
/* Mark it configured and running with a 64-byte max packet.
* All interrupts are enabled, even though RESUME won't do anything.
*/
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 7fa318a3091d..91b22b2ea3aa 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -48,6 +48,8 @@
/* USB port status and control registers */
#define USBPORTSC1 16
#define USBPORTSC2 18
+#define USBPORTSC3 20
+#define USBPORTSC4 22
#define USBPORTSC_CCS 0x0001 /* Current Connect Status
* ("device present") */
#define USBPORTSC_CSC 0x0002 /* Connect Status Change */
@@ -427,6 +429,7 @@ struct uhci_hcd {
unsigned int wait_for_hp:1; /* Wait for HP port reset */
unsigned int big_endian_mmio:1; /* Big endian registers */
unsigned int big_endian_desc:1; /* Big endian descriptors */
+ unsigned int is_aspeed:1; /* Aspeed impl. workarounds */
/* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */
@@ -490,6 +493,12 @@ struct urb_priv {
#define PCI_VENDOR_ID_GENESYS 0x17a0
#define PCI_DEVICE_ID_GL880S_UHCI 0x8083
+/* Aspeed SoC needs some quirks */
+static inline bool uhci_is_aspeed(const struct uhci_hcd *uhci)
+{
+ return IS_ENABLED(CONFIG_USB_UHCI_ASPEED) && uhci->is_aspeed;
+}
+
/*
* Functions used to access controller registers. The UCHI spec says that host
* controller I/O registers are mapped into PCI I/O space. For non-PCI hosts
@@ -545,10 +554,42 @@ static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg)
#define uhci_big_endian_mmio(u) 0
#endif
+static inline int uhci_aspeed_reg(unsigned int reg)
+{
+ switch (reg) {
+ case USBCMD:
+ return 00;
+ case USBSTS:
+ return 0x04;
+ case USBINTR:
+ return 0x08;
+ case USBFRNUM:
+ return 0x80;
+ case USBFLBASEADD:
+ return 0x0c;
+ case USBSOF:
+ return 0x84;
+ case USBPORTSC1:
+ return 0x88;
+ case USBPORTSC2:
+ return 0x8c;
+ case USBPORTSC3:
+ return 0x90;
+ case USBPORTSC4:
+ return 0x94;
+ default:
+ pr_warn("UHCI: Unsupported register 0x%02x on Aspeed\n", reg);
+ /* Return an unimplemented register */
+ return 0x10;
+ }
+}
+
static inline u32 uhci_readl(const struct uhci_hcd *uhci, int reg)
{
if (uhci_has_pci_registers(uhci))
return inl(uhci->io_addr + reg);
+ else if (uhci_is_aspeed(uhci))
+ return readl(uhci->regs + uhci_aspeed_reg(reg));
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
else if (uhci_big_endian_mmio(uhci))
return readl_be(uhci->regs + reg);
@@ -561,6 +602,8 @@ static inline void uhci_writel(const struct uhci_hcd *uhci, u32 val, int reg)
{
if (uhci_has_pci_registers(uhci))
outl(val, uhci->io_addr + reg);
+ else if (uhci_is_aspeed(uhci))
+ writel(val, uhci->regs + uhci_aspeed_reg(reg));
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
else if (uhci_big_endian_mmio(uhci))
writel_be(val, uhci->regs + reg);
@@ -573,6 +616,8 @@ static inline u16 uhci_readw(const struct uhci_hcd *uhci, int reg)
{
if (uhci_has_pci_registers(uhci))
return inw(uhci->io_addr + reg);
+ else if (uhci_is_aspeed(uhci))
+ return readl(uhci->regs + uhci_aspeed_reg(reg));
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
else if (uhci_big_endian_mmio(uhci))
return readw_be(uhci->regs + reg);
@@ -585,6 +630,8 @@ static inline void uhci_writew(const struct uhci_hcd *uhci, u16 val, int reg)
{
if (uhci_has_pci_registers(uhci))
outw(val, uhci->io_addr + reg);
+ else if (uhci_is_aspeed(uhci))
+ writel(val, uhci->regs + uhci_aspeed_reg(reg));
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
else if (uhci_big_endian_mmio(uhci))
writew_be(val, uhci->regs + reg);
@@ -597,6 +644,8 @@ static inline u8 uhci_readb(const struct uhci_hcd *uhci, int reg)
{
if (uhci_has_pci_registers(uhci))
return inb(uhci->io_addr + reg);
+ else if (uhci_is_aspeed(uhci))
+ return readl(uhci->regs + uhci_aspeed_reg(reg));
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
else if (uhci_big_endian_mmio(uhci))
return readb_be(uhci->regs + reg);
@@ -609,6 +658,8 @@ static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg)
{
if (uhci_has_pci_registers(uhci))
outb(val, uhci->io_addr + reg);
+ else if (uhci_is_aspeed(uhci))
+ writel(val, uhci->regs + uhci_aspeed_reg(reg));
#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO
else if (uhci_big_endian_mmio(uhci))
writeb_be(val, uhci->regs + reg);
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index 32a6f3d8deec..1b4e086c33a0 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -15,7 +15,9 @@ static int uhci_platform_init(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- uhci->rh_numports = uhci_count_ports(hcd);
+ /* Probe number of ports if not already provided by DT */
+ if (!uhci->rh_numports)
+ uhci->rh_numports = uhci_count_ports(hcd);
/* Set up pointers to to generic functions */
uhci->reset_hc = uhci_generic_reset_hc;
@@ -63,6 +65,7 @@ static const struct hc_driver uhci_platform_hc_driver = {
static int uhci_hcd_platform_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct usb_hcd *hcd;
struct uhci_hcd *uhci;
struct resource *res;
@@ -98,6 +101,23 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
uhci->regs = hcd->regs;
+ /* Grab some things from the device-tree */
+ if (np) {
+ u32 num_ports;
+
+ if (of_property_read_u32(np, "#ports", &num_ports) == 0) {
+ uhci->rh_numports = num_ports;
+ dev_info(&pdev->dev,
+ "Detected %d ports from device-tree\n",
+ num_ports);
+ }
+ if (of_device_is_compatible(np, "aspeed,ast2400-uhci") ||
+ of_device_is_compatible(np, "aspeed,ast2500-uhci")) {
+ uhci->is_aspeed = 1;
+ dev_info(&pdev->dev,
+ "Enabled Aspeed implementation workarounds\n");
+ }
+ }
ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);
if (ret)
goto err_rmr;
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 5e3e9d4c6956..0dde49c35dd2 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -419,7 +419,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
wait_for_completion(cmd->completion);
if (cmd->status == COMP_COMMAND_ABORTED ||
- cmd->status == COMP_STOPPED) {
+ cmd->status == COMP_COMMAND_RING_STOPPED) {
xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");
ret = -ETIME;
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index bbe22bcc550a..2a82c927ded2 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -56,7 +56,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
}
if (max_packet) {
- seg->bounce_buf = kzalloc(max_packet, flags | GFP_DMA);
+ seg->bounce_buf = kzalloc(max_packet, flags);
if (!seg->bounce_buf) {
dma_pool_free(xhci->segment_pool, seg->trbs, dma);
kfree(seg);
@@ -407,64 +407,17 @@ fail:
return NULL;
}
-void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
+void xhci_free_endpoint_ring(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
unsigned int ep_index)
{
- int rings_cached;
-
- rings_cached = virt_dev->num_rings_cached;
- if (rings_cached < XHCI_MAX_RINGS_CACHED) {
- virt_dev->ring_cache[rings_cached] =
- virt_dev->eps[ep_index].ring;
- virt_dev->num_rings_cached++;
- xhci_dbg(xhci, "Cached old ring, "
- "%d ring%s cached\n",
- virt_dev->num_rings_cached,
- (virt_dev->num_rings_cached > 1) ? "s" : "");
- } else {
- xhci_ring_free(xhci, virt_dev->eps[ep_index].ring);
- xhci_dbg(xhci, "Ring cache full (%d rings), "
- "freeing ring\n",
- virt_dev->num_rings_cached);
- }
+ xhci_ring_free(xhci, virt_dev->eps[ep_index].ring);
virt_dev->eps[ep_index].ring = NULL;
}
-/* Zero an endpoint ring (except for link TRBs) and move the enqueue and dequeue
- * pointers to the beginning of the ring.
- */
-static void xhci_reinit_cached_ring(struct xhci_hcd *xhci,
- struct xhci_ring *ring, unsigned int cycle_state,
- enum xhci_ring_type type)
-{
- struct xhci_segment *seg = ring->first_seg;
- int i;
-
- do {
- memset(seg->trbs, 0,
- sizeof(union xhci_trb)*TRBS_PER_SEGMENT);
- if (cycle_state == 0) {
- for (i = 0; i < TRBS_PER_SEGMENT; i++)
- seg->trbs[i].link.control |=
- cpu_to_le32(TRB_CYCLE);
- }
- /* All endpoint rings have link TRBs */
- xhci_link_segments(xhci, seg, seg->next, type);
- seg = seg->next;
- } while (seg != ring->first_seg);
- ring->type = type;
- xhci_initialize_ring_info(ring, cycle_state);
- /* td list should be empty since all URBs have been cancelled,
- * but just in case...
- */
- INIT_LIST_HEAD(&ring->td_list);
-}
-
/*
* Expand an existing ring.
- * Look for a cached ring or allocate a new ring which has same segment numbers
- * and link the two rings.
+ * Allocate a new ring which has same segment numbers and link the two rings.
*/
int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_trbs, gfp_t flags)
@@ -968,12 +921,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
/* If necessary, update the number of active TTs on this root port */
xhci_update_tt_active_eps(xhci, dev, old_active_eps);
- if (dev->ring_cache) {
- for (i = 0; i < dev->num_rings_cached; i++)
- xhci_ring_free(xhci, dev->ring_cache[i]);
- kfree(dev->ring_cache);
- }
-
if (dev->in_ctx)
xhci_free_container_ctx(xhci, dev->in_ctx);
if (dev->out_ctx)
@@ -1062,14 +1009,6 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
if (!dev->eps[0].ring)
goto fail;
- /* Allocate pointers to the ring cache */
- dev->ring_cache = kzalloc(
- sizeof(struct xhci_ring *)*XHCI_MAX_RINGS_CACHED,
- flags);
- if (!dev->ring_cache)
- goto fail;
- dev->num_rings_cached = 0;
-
dev->udev = udev;
/* Point to output device context in dcbaa. */
@@ -1537,17 +1476,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
/* Set up the endpoint ring */
virt_dev->eps[ep_index].new_ring =
xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags);
- if (!virt_dev->eps[ep_index].new_ring) {
- /* Attempt to use the ring cache */
- if (virt_dev->num_rings_cached == 0)
- return -ENOMEM;
- virt_dev->num_rings_cached--;
- virt_dev->eps[ep_index].new_ring =
- virt_dev->ring_cache[virt_dev->num_rings_cached];
- virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
- xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
- 1, ring_type);
- }
+ if (!virt_dev->eps[ep_index].new_ring)
+ return -ENOMEM;
+
virt_dev->eps[ep_index].skip = false;
ep_ring = virt_dev->eps[ep_index].new_ring;
@@ -1724,7 +1655,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma);
for (i = 0; i < num_sp; i++) {
dma_addr_t dma;
- void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma,
+ void *buf = dma_zalloc_coherent(dev, xhci->page_size, &dma,
flags);
if (!buf)
goto fail_sp4;
@@ -2119,11 +2050,12 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
{
u32 temp, port_offset, port_count;
int i;
- u8 major_revision;
+ u8 major_revision, minor_revision;
struct xhci_hub *rhub;
temp = readl(addr);
major_revision = XHCI_EXT_PORT_MAJOR(temp);
+ minor_revision = XHCI_EXT_PORT_MINOR(temp);
if (major_revision == 0x03) {
rhub = &xhci->usb3_rhub;
@@ -2137,7 +2069,9 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
return;
}
rhub->maj_rev = XHCI_EXT_PORT_MAJOR(temp);
- rhub->min_rev = XHCI_EXT_PORT_MINOR(temp);
+
+ if (rhub->min_rev < minor_revision)
+ rhub->min_rev = minor_revision;
/* Port offset and count in the third dword, see section 7.2 */
temp = readl(addr + 2);
@@ -2307,10 +2241,11 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
/* Place limits on the number of roothub ports so that the hub
* descriptors aren't longer than the USB core will allocate.
*/
- if (xhci->num_usb3_ports > 15) {
+ if (xhci->num_usb3_ports > USB_SS_MAXPORTS) {
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Limiting USB 3.0 roothub ports to 15.");
- xhci->num_usb3_ports = 15;
+ "Limiting USB 3.0 roothub ports to %u.",
+ USB_SS_MAXPORTS);
+ xhci->num_usb3_ports = USB_SS_MAXPORTS;
}
if (xhci->num_usb2_ports > USB_MAXCHILDREN) {
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 7b86508ac8cf..1bcf971141c0 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -52,6 +52,7 @@
#define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8
#define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8
#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
+#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
static const char hcd_name[] = "xhci_hcd";
@@ -166,7 +167,8 @@ 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_BROXTON_M_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI ||
- pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) {
+ pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI)) {
xhci->quirks |= XHCI_PME_STUCK_QUIRK;
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
@@ -175,7 +177,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
- pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI))
+ pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI))
xhci->quirks |= XHCI_MISSING_CAS;
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
@@ -198,6 +201,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
pdev->device == 0x1042)
xhci->quirks |= XHCI_BROKEN_STREAMS;
+ if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+ pdev->device == 0x1142)
+ xhci->quirks |= XHCI_TRUST_TX_LENGTH;
if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241)
xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7;
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 7c2a9e7c8e0f..c04144b25a67 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -177,7 +177,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
- return -ENODEV;
+ return irq;
/*
* sysdev must point to a device that is known to the system firmware
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 74bf5c60a260..c50c902d009e 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -323,7 +323,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
if (i_cmd->status != COMP_COMMAND_ABORTED)
continue;
- i_cmd->status = COMP_STOPPED;
+ i_cmd->status = COMP_COMMAND_RING_STOPPED;
xhci_dbg(xhci, "Turn aborted command %p to no-op\n",
i_cmd->command_trb);
@@ -480,10 +480,34 @@ struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
return NULL;
}
+
+/*
+ * Get the hw dequeue pointer xHC stopped on, either directly from the
+ * endpoint context, or if streams are in use from the stream context.
+ * The returned hw_dequeue contains the lowest four bits with cycle state
+ * and possbile stream context type.
+ */
+static u64 xhci_get_hw_deq(struct xhci_hcd *xhci, struct xhci_virt_device *vdev,
+ unsigned int ep_index, unsigned int stream_id)
+{
+ struct xhci_ep_ctx *ep_ctx;
+ struct xhci_stream_ctx *st_ctx;
+ struct xhci_virt_ep *ep;
+
+ ep = &vdev->eps[ep_index];
+
+ if (ep->ep_state & EP_HAS_STREAMS) {
+ st_ctx = &ep->stream_info->stream_ctx_array[stream_id];
+ return le64_to_cpu(st_ctx->stream_ring);
+ }
+ ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
+ return le64_to_cpu(ep_ctx->deq);
+}
+
/*
* Move the xHC's endpoint ring dequeue pointer past cur_td.
* Record the new state of the xHC's endpoint ring dequeue segment,
- * dequeue pointer, and new consumer cycle state in state.
+ * dequeue pointer, stream id, and new consumer cycle state in state.
* Update our internal representation of the ring's dequeue pointer.
*
* We do this in three jumps:
@@ -521,24 +545,15 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
stream_id);
return;
}
-
/* Dig out the cycle state saved by the xHC during the stop ep cmd */
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
"Finding endpoint context");
- /* 4.6.9 the css flag is written to the stream context for streams */
- if (ep->ep_state & EP_HAS_STREAMS) {
- struct xhci_stream_ctx *ctx =
- &ep->stream_info->stream_ctx_array[stream_id];
- hw_dequeue = le64_to_cpu(ctx->stream_ring);
- } else {
- struct xhci_ep_ctx *ep_ctx
- = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
- hw_dequeue = le64_to_cpu(ep_ctx->deq);
- }
+ hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
new_seg = ep_ring->deq_seg;
new_deq = ep_ring->dequeue;
state->new_cycle_state = hw_dequeue & 0x1;
+ state->stream_id = stream_id;
/*
* We want to find the pointer, segment and cycle state of the new trb
@@ -641,8 +656,8 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
xhci_urb_free_priv(urb_priv);
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock(&xhci->lock);
- usb_hcd_giveback_urb(hcd, urb, status);
trace_xhci_urb_giveback(urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&xhci->lock);
}
@@ -691,7 +706,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
struct xhci_td *last_unlinked_td;
struct xhci_ep_ctx *ep_ctx;
struct xhci_virt_device *vdev;
-
+ u64 hw_deq;
struct xhci_dequeue_state deq_state;
if (unlikely(TRB_TO_SUSPEND_PORT(le32_to_cpu(trb->generic.field[3])))) {
@@ -715,7 +730,6 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
if (list_empty(&ep->cancelled_td_list)) {
xhci_stop_watchdog_timer_in_irq(xhci, ep);
- ep->stopped_td = NULL;
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
return;
}
@@ -753,12 +767,19 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
* If we stopped on the TD we need to cancel, then we have to
* move the xHC endpoint ring dequeue pointer past this TD.
*/
- if (cur_td == ep->stopped_td)
+ hw_deq = xhci_get_hw_deq(xhci, vdev, ep_index,
+ cur_td->urb->stream_id);
+ hw_deq &= ~0xf;
+
+ if (trb_in_td(xhci, cur_td->start_seg, cur_td->first_trb,
+ cur_td->last_trb, hw_deq, false)) {
xhci_find_new_dequeue_state(xhci, slot_id, ep_index,
- cur_td->urb->stream_id,
- cur_td, &deq_state);
- else
+ cur_td->urb->stream_id,
+ cur_td, &deq_state);
+ } else {
td_to_noop(xhci, ep_ring, cur_td, false);
+ }
+
remove_finished_td:
/*
* The event handler won't see a completion for this TD anymore,
@@ -773,15 +794,13 @@ remove_finished_td:
/* If necessary, queue a Set Transfer Ring Dequeue Pointer command */
if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
xhci_queue_new_dequeue_state(xhci, slot_id, ep_index,
- ep->stopped_td->urb->stream_id, &deq_state);
+ &deq_state);
xhci_ring_cmd_db(xhci);
} else {
/* Otherwise ring the doorbell(s) to restart queued transfers */
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
}
- ep->stopped_td = NULL;
-
/*
* Drop the lock and complete the URBs in the cancelled TD list.
* New TDs to be cancelled might be added to the end of the list before
@@ -1380,7 +1399,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
/* If CMD ring stopped we own the trbs between enqueue and dequeue */
- if (cmd_comp_code == COMP_STOPPED) {
+ if (cmd_comp_code == COMP_COMMAND_RING_STOPPED) {
complete_all(&xhci->cmd_ring_stop_completion);
return;
}
@@ -1436,8 +1455,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
break;
case TRB_CMD_NOOP:
/* Is this an aborted command turned to NO-OP? */
- if (cmd->status == COMP_STOPPED)
- cmd_comp_code = COMP_STOPPED;
+ if (cmd->status == COMP_COMMAND_RING_STOPPED)
+ cmd_comp_code = COMP_COMMAND_RING_STOPPED;
break;
case TRB_RESET_EP:
WARN_ON(slot_id != TRB_TO_SLOT_ID(
@@ -1800,7 +1819,8 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci,
static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id,
- struct xhci_td *td, union xhci_trb *ep_trb)
+ struct xhci_td *td, union xhci_trb *ep_trb,
+ enum xhci_ep_reset_type reset_type)
{
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
struct xhci_command *command;
@@ -1809,12 +1829,11 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
return;
ep->ep_state |= EP_HALTED;
- ep->stopped_stream = stream_id;
- xhci_queue_reset_ep(xhci, command, slot_id, ep_index);
- xhci_cleanup_stalled_ring(xhci, ep_index, td);
+ xhci_queue_reset_ep(xhci, command, slot_id, ep_index, reset_type);
- ep->stopped_stream = 0;
+ if (reset_type == EP_HARD_RESET)
+ xhci_cleanup_stalled_ring(xhci, ep_index, stream_id, td);
xhci_ring_cmd_db(xhci);
}
@@ -1909,7 +1928,7 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
union xhci_trb *ep_trb, struct xhci_transfer_event *event,
- struct xhci_virt_ep *ep, int *status, bool skip)
+ struct xhci_virt_ep *ep, int *status)
{
struct xhci_virt_device *xdev;
struct xhci_ep_ctx *ep_ctx;
@@ -1925,9 +1944,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
- if (skip)
- goto td_cleanup;
-
if (trb_comp_code == COMP_STOPPED_LENGTH_INVALID ||
trb_comp_code == COMP_STOPPED ||
trb_comp_code == COMP_STOPPED_SHORT_PACKET) {
@@ -1935,7 +1951,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
* stopped TDs. A stopped TD may be restarted, so don't update
* the ring dequeue pointer or take this TD off any lists yet.
*/
- ep->stopped_td = td;
return 0;
}
if (trb_comp_code == COMP_STALL_ERROR ||
@@ -1947,7 +1962,8 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
* The class driver clears the device side halt later.
*/
xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index,
- ep_ring->stream_id, td, ep_trb);
+ ep_ring->stream_id, td, ep_trb,
+ EP_HARD_RESET);
} else {
/* Update ring dequeue pointer */
while (ep_ring->dequeue != td->last_trb)
@@ -1955,7 +1971,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
inc_deq(xhci, ep_ring);
}
-td_cleanup:
return xhci_td_cleanup(xhci, td, ep_ring, status);
}
@@ -2075,7 +2090,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
td->urb->actual_length = requested;
finish_td:
- return finish_td(xhci, td, ep_trb, event, ep, status, false);
+ return finish_td(xhci, td, ep_trb, event, ep, status);
}
/*
@@ -2162,7 +2177,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
td->urb->actual_length += frame->actual_length;
- return finish_td(xhci, td, ep_trb, event, ep, status, false);
+ return finish_td(xhci, td, ep_trb, event, ep, status);
}
static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
@@ -2190,7 +2205,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
inc_deq(xhci, ep_ring);
inc_deq(xhci, ep_ring);
- return finish_td(xhci, td, NULL, event, ep, status, true);
+ return xhci_td_cleanup(xhci, td, ep_ring, status);
}
/*
@@ -2252,7 +2267,7 @@ finish_td:
remaining);
td->urb->actual_length = 0;
}
- return finish_td(xhci, td, ep_trb, event, ep, status, false);
+ return finish_td(xhci, td, ep_trb, event, ep, status);
}
/*
@@ -2280,39 +2295,46 @@ static int handle_tx_event(struct xhci_hcd *xhci,
bool handling_skipped_tds = false;
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
+ ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
+ trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
+ ep_trb_dma = le64_to_cpu(event->buffer);
+
xdev = xhci->devs[slot_id];
if (!xdev) {
xhci_err(xhci, "ERROR Transfer event pointed to bad slot %u\n",
slot_id);
- xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
- (unsigned long long) xhci_trb_virt_to_dma(
- xhci->event_ring->deq_seg,
- xhci->event_ring->dequeue),
- lower_32_bits(le64_to_cpu(event->buffer)),
- upper_32_bits(le64_to_cpu(event->buffer)),
- le32_to_cpu(event->transfer_len),
- le32_to_cpu(event->flags));
- return -ENODEV;
- }
-
- /* Endpoint ID is 1 based, our index is zero based */
- ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
+ goto err_out;
+ }
+
ep = &xdev->eps[ep_index];
- ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
+ ep_ring = xhci_dma_to_transfer_ring(ep, ep_trb_dma);
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
- if (!ep_ring || GET_EP_CTX_STATE(ep_ctx) == EP_STATE_DISABLED) {
+
+ if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_DISABLED) {
xhci_err(xhci,
- "ERROR Transfer event for disabled endpoint slot %u ep %u or incorrect stream ring\n",
+ "ERROR Transfer event for disabled endpoint slot %u ep %u\n",
slot_id, ep_index);
- xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
- (unsigned long long) xhci_trb_virt_to_dma(
- xhci->event_ring->deq_seg,
- xhci->event_ring->dequeue),
- lower_32_bits(le64_to_cpu(event->buffer)),
- upper_32_bits(le64_to_cpu(event->buffer)),
- le32_to_cpu(event->transfer_len),
- le32_to_cpu(event->flags));
- return -ENODEV;
+ goto err_out;
+ }
+
+ /* Some transfer events don't always point to a trb, see xhci 4.17.4 */
+ if (!ep_ring) {
+ switch (trb_comp_code) {
+ case COMP_STALL_ERROR:
+ case COMP_USB_TRANSACTION_ERROR:
+ case COMP_INVALID_STREAM_TYPE_ERROR:
+ case COMP_INVALID_STREAM_ID_ERROR:
+ xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, 0,
+ NULL, NULL, EP_SOFT_RESET);
+ goto cleanup;
+ case COMP_RING_UNDERRUN:
+ case COMP_RING_OVERRUN:
+ goto cleanup;
+ default:
+ xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n",
+ slot_id, ep_index);
+ goto err_out;
+ }
}
/* Count current td numbers if ep->skip is set */
@@ -2321,8 +2343,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
td_num++;
}
- ep_trb_dma = le64_to_cpu(event->buffer);
- trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
/* Look for common error cases */
switch (trb_comp_code) {
/* Skip codes that require special handling depending on
@@ -2339,6 +2359,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
slot_id, ep_index);
case COMP_SHORT_PACKET:
break;
+ /* Completion codes for endpoint stopped state */
case COMP_STOPPED:
xhci_dbg(xhci, "Stopped on Transfer TRB for slot %u ep %u\n",
slot_id, ep_index);
@@ -2353,18 +2374,13 @@ static int handle_tx_event(struct xhci_hcd *xhci,
"Stopped with short packet transfer detected for slot %u ep %u\n",
slot_id, ep_index);
break;
+ /* Completion codes for endpoint halted state */
case COMP_STALL_ERROR:
xhci_dbg(xhci, "Stalled endpoint for slot %u ep %u\n", slot_id,
ep_index);
ep->ep_state |= EP_HALTED;
status = -EPIPE;
break;
- case COMP_TRB_ERROR:
- xhci_warn(xhci,
- "WARN: TRB error for slot %u ep %u on endpoint\n",
- slot_id, ep_index);
- status = -EILSEQ;
- break;
case COMP_SPLIT_TRANSACTION_ERROR:
case COMP_USB_TRANSACTION_ERROR:
xhci_dbg(xhci, "Transfer error for slot %u ep %u on endpoint\n",
@@ -2376,6 +2392,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
slot_id, ep_index);
status = -EOVERFLOW;
break;
+ /* Completion codes for endpoint error state */
+ case COMP_TRB_ERROR:
+ xhci_warn(xhci,
+ "WARN: TRB error for slot %u ep %u on endpoint\n",
+ slot_id, ep_index);
+ status = -EILSEQ;
+ break;
+ /* completion codes not indicating endpoint state change */
case COMP_DATA_BUFFER_ERROR:
xhci_warn(xhci,
"WARN: HC couldn't access mem fast enough for slot %u ep %u\n",
@@ -2413,12 +2437,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
ep_index);
goto cleanup;
- case COMP_INCOMPATIBLE_DEVICE_ERROR:
- xhci_warn(xhci,
- "WARN: detect an incompatible device for slot %u ep %u",
- slot_id, ep_index);
- status = -EPROTO;
- break;
case COMP_MISSED_SERVICE_ERROR:
/*
* When encounter missed service error, one or more isoc tds
@@ -2437,6 +2455,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
"No Ping response error for slot %u ep %u, Skip one Isoc TD\n",
slot_id, ep_index);
goto cleanup;
+
+ case COMP_INCOMPATIBLE_DEVICE_ERROR:
+ /* needs disable slot command to recover */
+ xhci_warn(xhci,
+ "WARN: detect an incompatible device for slot %u ep %u",
+ slot_id, ep_index);
+ status = -EPROTO;
+ break;
default:
if (xhci_is_vendor_info_code(xhci, trb_comp_code)) {
status = 0;
@@ -2589,6 +2615,17 @@ cleanup:
} while (handling_skipped_tds);
return 0;
+
+err_out:
+ xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
+ (unsigned long long) xhci_trb_virt_to_dma(
+ xhci->event_ring->deq_seg,
+ xhci->event_ring->dequeue),
+ lower_32_bits(le64_to_cpu(event->buffer)),
+ upper_32_bits(le64_to_cpu(event->buffer)),
+ le32_to_cpu(event->transfer_len),
+ le32_to_cpu(event->flags));
+ return -ENODEV;
}
/*
@@ -2677,11 +2714,12 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
union xhci_trb *event_ring_deq;
irqreturn_t ret = IRQ_NONE;
+ unsigned long flags;
dma_addr_t deq;
u64 temp_64;
u32 status;
- spin_lock(&xhci->lock);
+ spin_lock_irqsave(&xhci->lock, flags);
/* Check if the xHC generated the interrupt, or the irq is shared */
status = readl(&xhci->op_regs->status);
if (status == ~(u32)0) {
@@ -2707,12 +2745,9 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
*/
status |= STS_EINT;
writel(status, &xhci->op_regs->status);
- /* FIXME when MSI-X is supported and there are multiple vectors */
- /* Clear the MSI-X event interrupt status */
- if (hcd->irq) {
+ if (!hcd->msi_enabled) {
u32 irq_pending;
- /* Acknowledge the PCI interrupt */
irq_pending = readl(&xhci->ir_set->irq_pending);
irq_pending |= IMAN_IP;
writel(irq_pending, &xhci->ir_set->irq_pending);
@@ -2757,7 +2792,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
ret = IRQ_HANDLED;
out:
- spin_unlock(&xhci->lock);
+ spin_unlock_irqrestore(&xhci->lock, flags);
return ret;
}
@@ -3965,13 +4000,12 @@ int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd,
/* Set Transfer Ring Dequeue Pointer command */
void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
- unsigned int stream_id,
struct xhci_dequeue_state *deq_state)
{
dma_addr_t addr;
u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
- u32 trb_stream_id = STREAM_ID_FOR_TRB(stream_id);
+ u32 trb_stream_id = STREAM_ID_FOR_TRB(deq_state->stream_id);
u32 trb_sct = 0;
u32 type = TRB_TYPE(TRB_SET_DEQ);
struct xhci_virt_ep *ep;
@@ -4009,7 +4043,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
ep->queued_deq_seg = deq_state->new_deq_seg;
ep->queued_deq_ptr = deq_state->new_deq_ptr;
- if (stream_id)
+ if (deq_state->stream_id)
trb_sct = SCT_FOR_TRB(SCT_PRI_TR);
ret = queue_command(xhci, cmd,
lower_32_bits(addr) | trb_sct | deq_state->new_cycle_state,
@@ -4029,12 +4063,16 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
}
int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd,
- int slot_id, unsigned int ep_index)
+ int slot_id, unsigned int ep_index,
+ enum xhci_ep_reset_type reset_type)
{
u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
u32 type = TRB_TYPE(TRB_RESET_EP);
+ if (reset_type == EP_SOFT_RESET)
+ type |= TRB_TSP;
+
return queue_command(xhci, cmd, 0, 0, 0,
trb_slot_id | trb_ep_index | type, false);
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 2d1310220832..56f85df013db 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -359,9 +359,10 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
/* fall back to msi*/
ret = xhci_setup_msi(xhci);
- if (!ret)
- /* hcd->irq is 0, we have MSI */
+ if (!ret) {
+ hcd->msi_enabled = 1;
return 0;
+ }
if (!pdev->irq) {
xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n");
@@ -1694,8 +1695,7 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
if (xhci->quirks & XHCI_MTK_HOST) {
ret = xhci_mtk_add_ep_quirk(hcd, udev, ep);
if (ret < 0) {
- xhci_free_or_cache_endpoint_ring(xhci,
- virt_dev, ep_index);
+ xhci_free_endpoint_ring(xhci, virt_dev, ep_index);
return ret;
}
}
@@ -1763,7 +1763,7 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
switch (*cmd_status) {
case COMP_COMMAND_ABORTED:
- case COMP_STOPPED:
+ case COMP_COMMAND_RING_STOPPED:
xhci_warn(xhci, "Timeout while waiting for configure endpoint command\n");
ret = -ETIME;
break;
@@ -1813,7 +1813,7 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
switch (*cmd_status) {
case COMP_COMMAND_ABORTED:
- case COMP_STOPPED:
+ case COMP_COMMAND_RING_STOPPED:
xhci_warn(xhci, "Timeout while waiting for evaluate context command\n");
ret = -ETIME;
break;
@@ -2719,23 +2719,23 @@ static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
for (i = 1; i < 31; i++) {
if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) &&
!(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) {
- xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
+ xhci_free_endpoint_ring(xhci, virt_dev, i);
xhci_check_bw_drop_ep_streams(xhci, virt_dev, i);
}
}
xhci_zero_in_ctx(xhci, virt_dev);
/*
* Install any rings for completely new endpoints or changed endpoints,
- * and free or cache any old rings from changed endpoints.
+ * and free any old rings from changed endpoints.
*/
for (i = 1; i < 31; i++) {
if (!virt_dev->eps[i].new_ring)
continue;
- /* Only cache or free the old ring if it exists.
+ /* Only free the old ring if it exists.
* It may not if this is the first add of an endpoint.
*/
if (virt_dev->eps[i].ring) {
- xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
+ xhci_free_endpoint_ring(xhci, virt_dev, i);
}
xhci_check_bw_drop_ep_streams(xhci, virt_dev, i);
virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;
@@ -2822,8 +2822,8 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
added_ctxs, added_ctxs);
}
-void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
- unsigned int ep_index, struct xhci_td *td)
+void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index,
+ unsigned int stream_id, struct xhci_td *td)
{
struct xhci_dequeue_state deq_state;
struct xhci_virt_ep *ep;
@@ -2836,7 +2836,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
* or it will attempt to resend it on the next doorbell ring.
*/
xhci_find_new_dequeue_state(xhci, udev->slot_id,
- ep_index, ep->stopped_stream, td, &deq_state);
+ ep_index, stream_id, td, &deq_state);
if (!deq_state.new_deq_ptr || !deq_state.new_deq_seg)
return;
@@ -2848,7 +2848,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
"Queueing new dequeue state");
xhci_queue_new_dequeue_state(xhci, udev->slot_id,
- ep_index, ep->stopped_stream, &deq_state);
+ ep_index, &deq_state);
} else {
/* Better hope no one uses the input context between now and the
* reset endpoint completion!
@@ -3335,7 +3335,7 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
*
* Wait for the Reset Device command to finish. Remove all structures
* associated with the endpoints that were disabled. Clear the input device
- * structure? Cache the rings? Reset the control endpoint 0 max packet size?
+ * structure? Reset the control endpoint 0 max packet size?
*
* If the virt_dev to be reset does not exist or does not match the udev,
* it means the device is lost, possibly due to the xHC restore error and
@@ -3432,7 +3432,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
ret = reset_device_cmd->status;
switch (ret) {
case COMP_COMMAND_ABORTED:
- case COMP_STOPPED:
+ case COMP_COMMAND_RING_STOPPED:
xhci_warn(xhci, "Timeout waiting for reset device command\n");
ret = -ETIME;
goto command_cleanup;
@@ -3465,7 +3465,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
spin_unlock_irqrestore(&xhci->lock, flags);
}
- /* Everything but endpoint 0 is disabled, so free or cache the rings. */
+ /* Everything but endpoint 0 is disabled, so free the rings. */
last_freed_endpoint = 1;
for (i = 1; i < 31; i++) {
struct xhci_virt_ep *ep = &virt_dev->eps[i];
@@ -3479,7 +3479,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
}
if (ep->ring) {
- xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
+ xhci_free_endpoint_ring(xhci, virt_dev, i);
last_freed_endpoint = i;
}
if (!list_empty(&virt_dev->eps[i].bw_endpoint_list))
@@ -3817,7 +3817,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
*/
switch (command->status) {
case COMP_COMMAND_ABORTED:
- case COMP_STOPPED:
+ case COMP_COMMAND_RING_STOPPED:
xhci_warn(xhci, "Timeout while waiting for setup device command\n");
ret = -ETIME;
break;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 73a28a986d5e..650a2d9d4aec 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -924,8 +924,6 @@ struct xhci_virt_ep {
#define EP_GETTING_NO_STREAMS (1 << 5)
/* ---- Related to URB cancellation ---- */
struct list_head cancelled_td_list;
- struct xhci_td *stopped_td;
- unsigned int stopped_stream;
/* Watchdog timer for stop endpoint command to cancel URBs */
struct timer_list stop_cmd_timer;
struct xhci_hcd *xhci;
@@ -993,10 +991,6 @@ struct xhci_virt_device {
struct xhci_container_ctx *out_ctx;
/* Used for addressing devices and configuration changes */
struct xhci_container_ctx *in_ctx;
- /* Rings saved to ensure old alt settings can be re-instated */
- struct xhci_ring **ring_cache;
- int num_rings_cached;
-#define XHCI_MAX_RINGS_CACHED 31
struct xhci_virt_ep eps[31];
u8 fake_port;
u8 real_port;
@@ -1210,6 +1204,11 @@ struct xhci_event_cmd {
/* Stop Ring - Transfer State Preserve */
#define TRB_TSP (1<<9)
+enum xhci_ep_reset_type {
+ EP_HARD_RESET,
+ EP_SOFT_RESET,
+};
+
/* Force Event */
#define TRB_TO_VF_INTR_TARGET(p) (((p) & (0x3ff << 22)) >> 22)
#define TRB_TO_VF_ID(p) (((p) & (0xff << 16)) >> 16)
@@ -1527,6 +1526,7 @@ struct xhci_dequeue_state {
struct xhci_segment *new_deq_seg;
union xhci_trb *new_deq_ptr;
int new_cycle_state;
+ unsigned int stream_id;
};
enum xhci_ring_type {
@@ -1960,7 +1960,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_trbs, gfp_t flags);
-void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
+void xhci_free_endpoint_ring(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
unsigned int ep_index);
struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
@@ -2044,7 +2044,8 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci,
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd,
dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed);
int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd,
- int slot_id, unsigned int ep_index);
+ int slot_id, unsigned int ep_index,
+ enum xhci_ep_reset_type reset_type);
int xhci_queue_reset_device(struct xhci_hcd *xhci, struct xhci_command *cmd,
u32 slot_id);
void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
@@ -2053,10 +2054,9 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
struct xhci_dequeue_state *state);
void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
- unsigned int stream_id,
struct xhci_dequeue_state *deq_state);
-void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
- unsigned int ep_index, struct xhci_td *td);
+void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index,
+ unsigned int stream_id, struct xhci_td *td);
void xhci_stop_endpoint_command_watchdog(unsigned long arg);
void xhci_handle_command_timeout(struct work_struct *work);
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index e9cae4d82af2..15d4e64d3b65 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -192,7 +192,7 @@ static int chaoskey_probe(struct usb_interface *interface,
dev->in_ep = in_ep;
- if (udev->descriptor.idVendor != ALEA_VENDOR_ID)
+ if (le16_to_cpu(udev->descriptor.idVendor) != ALEA_VENDOR_ID)
dev->reads_started = 1;
dev->size = size;
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 77569531b78a..7ca4c7e0ea0d 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -368,14 +368,9 @@ static ssize_t iowarrior_write(struct file *file,
case USB_DEVICE_ID_CODEMERCS_IOWPV2:
case USB_DEVICE_ID_CODEMERCS_IOW40:
/* IOW24 and IOW40 use a synchronous call */
- buf = kmalloc(count, GFP_KERNEL);
- if (!buf) {
- retval = -ENOMEM;
- goto exit;
- }
- if (copy_from_user(buf, user_buffer, count)) {
- retval = -EFAULT;
- kfree(buf);
+ buf = memdup_user(user_buffer, count);
+ if (IS_ERR(buf)) {
+ retval = PTR_ERR(buf);
goto exit;
}
retval = usb_set_report(dev->interface, 2, 0, buf, count);
@@ -554,7 +549,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice);
/* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */
- info.speed = le16_to_cpu(dev->udev->speed);
+ info.speed = dev->udev->speed;
info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber;
info.report_size = dev->report_size;
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index aa3c280fdf8d..0782ac6f5edf 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -926,6 +926,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
USB_MAJOR, dev->minor);
exit:
+ kfree(get_version_reply);
return retval;
error:
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 3c6948af726a..f019d80ca9e4 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -973,7 +973,7 @@ sisusbcon_set_origin(struct vc_data *c)
mutex_unlock(&sisusb->lock);
- return 1;
+ return true;
}
/* Interface routine */
diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c
index a0ba5298160c..388fae6373db 100644
--- a/drivers/usb/misc/usbsevseg.c
+++ b/drivers/usb/misc/usbsevseg.c
@@ -33,7 +33,7 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
/* the different text display modes the device is capable of */
-static char *display_textmodes[] = {"raw", "hex", "ascii", NULL};
+static const char *display_textmodes[] = {"raw", "hex", "ascii"};
struct usb_sevsegdev {
struct usb_device *udev;
@@ -280,7 +280,7 @@ static ssize_t show_attr_textmode(struct device *dev,
buf[0] = 0;
- for (i = 0; display_textmodes[i]; i++) {
+ for (i = 0; i < ARRAY_SIZE(display_textmodes); i++) {
if (mydev->textmode == i) {
strcat(buf, " [");
strcat(buf, display_textmodes[i]);
@@ -304,15 +304,13 @@ static ssize_t set_attr_textmode(struct device *dev,
struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
int i;
- for (i = 0; display_textmodes[i]; i++) {
- if (sysfs_streq(display_textmodes[i], buf)) {
- mydev->textmode = i;
- update_display_visual(mydev, GFP_KERNEL);
- return count;
- }
- }
+ i = sysfs_match_string(display_textmodes, buf);
+ if (i < 0)
+ return i;
- return -EINVAL;
+ mydev->textmode = i;
+ update_display_visual(mydev, GFP_KERNEL);
+ return count;
}
static DEVICE_ATTR(textmode, S_IRUGO | S_IWUSR, show_attr_textmode, set_attr_textmode);
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index aa6fd6a51221..7b6dc23d77e9 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -356,12 +356,8 @@ static inline struct mtu3_ep *to_mtu3_ep(struct usb_ep *ep)
static inline struct mtu3_request *next_request(struct mtu3_ep *mep)
{
- struct list_head *queue = &mep->req_list;
-
- if (list_empty(queue))
- return NULL;
-
- return list_first_entry(queue, struct mtu3_request, list);
+ return list_first_entry_or_null(&mep->req_list, struct mtu3_request,
+ list);
}
static inline void mtu3_writel(void __iomem *base, u32 offset, u32 data)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 9c7ee26ef388..bc6a9be2ccc5 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -245,6 +245,11 @@ static int dsps_check_status(struct musb *musb, void *unused)
dsps_mod_timer_optional(glue);
break;
case OTG_STATE_A_WAIT_BCON:
+ /* keep VBUS on for host-only mode */
+ if (musb->port_mode == MUSB_PORT_MODE_HOST) {
+ dsps_mod_timer_optional(glue);
+ break;
+ }
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
skip_session = 1;
/* fall */
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index ac3a4952abb4..dbe617a735d8 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2780,10 +2780,11 @@ int musb_host_setup(struct musb *musb, int power_budget)
int ret;
struct usb_hcd *hcd = musb->hcd;
- MUSB_HST_MODE(musb);
- musb->xceiv->otg->default_a = 1;
- musb->xceiv->otg->state = OTG_STATE_A_IDLE;
-
+ if (musb->port_mode == MUSB_PORT_MODE_HOST) {
+ MUSB_HST_MODE(musb);
+ musb->xceiv->otg->default_a = 1;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
+ }
otg_set_host(musb->xceiv->otg, &hcd->self);
hcd->self.otg_port = 1;
musb->xceiv->otg->host = &hcd->self;
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index 8b43c4b99f04..7870b37e0ea5 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -219,6 +219,7 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
u32 dma_remaining;
int src_burst, dst_burst;
u16 csr;
+ u32 psize;
int ch;
s8 dmareq;
s8 sync_dev;
@@ -390,15 +391,19 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
if (chdat->tx) {
/* Send transfer_packet_sz packets at a time */
- musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
- chdat->transfer_packet_sz);
+ psize = musb_readl(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET);
+ psize &= ~0x7ff;
+ psize |= chdat->transfer_packet_sz;
+ musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET, psize);
musb_writel(ep_conf, TUSB_EP_TX_OFFSET,
TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
} else {
/* Receive transfer_packet_sz packets at a time */
- musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
- chdat->transfer_packet_sz << 16);
+ psize = musb_readl(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET);
+ psize &= ~(0x7ff << 16);
+ psize |= (chdat->transfer_packet_sz << 16);
+ musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET, psize);
musb_writel(ep_conf, TUSB_EP_RX_OFFSET,
TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index d38780fa8788..aba74f817dc6 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -809,10 +809,10 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
{ USB_DEVICE(FTDI_VID, CYBER_CORTEX_AV_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
- { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
- .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
- { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID),
- .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID, 1) },
+ { USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID, 1) },
+ { USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_TINY_PID, 1) },
+ { USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_TINY_H_PID, 1) },
{ USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
@@ -1527,9 +1527,9 @@ static int set_serial_info(struct tty_struct *tty,
(new_serial.flags & ASYNC_FLAGS));
priv->custom_divisor = new_serial.custom_divisor;
+check_and_exit:
write_latency_timer(port);
-check_and_exit:
if ((old_priv.flags & ASYNC_SPD_MASK) !=
(priv->flags & ASYNC_SPD_MASK)) {
if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 71fb9e59db71..4fcf1cecb6d7 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -882,6 +882,8 @@
/* Olimex */
#define OLIMEX_VID 0x15BA
#define OLIMEX_ARM_USB_OCD_PID 0x0003
+#define OLIMEX_ARM_USB_TINY_PID 0x0004
+#define OLIMEX_ARM_USB_TINY_H_PID 0x002a
#define OLIMEX_ARM_USB_OCD_H_PID 0x002b
/*
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 87798e625d6c..6cefb9cb133d 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2336,8 +2336,11 @@ static void change_port_settings(struct tty_struct *tty,
if (!baud) {
/* pick a default, any default... */
baud = 9600;
- } else
+ } else {
+ /* Avoid a zero divisor. */
+ baud = min(baud, 461550);
tty_encode_baud_rate(tty, baud, baud);
+ }
edge_port->baud_rate = baud;
config->wBaudRate = (__u16)((461550L + baud/2) / baud);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 73956d48a0c5..f9734a96d516 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -197,6 +197,7 @@ static u8 ir_xbof_change(u8 xbof)
static int ir_startup(struct usb_serial *serial)
{
struct usb_irda_cs_descriptor *irda_desc;
+ int rates;
irda_desc = irda_usb_find_class_desc(serial, 0);
if (!irda_desc) {
@@ -205,18 +206,20 @@ static int ir_startup(struct usb_serial *serial)
return -ENODEV;
}
+ rates = le16_to_cpu(irda_desc->wBaudRate);
+
dev_dbg(&serial->dev->dev,
"%s - Baud rates supported:%s%s%s%s%s%s%s%s%s\n",
__func__,
- (irda_desc->wBaudRate & USB_IRDA_BR_2400) ? " 2400" : "",
- (irda_desc->wBaudRate & USB_IRDA_BR_9600) ? " 9600" : "",
- (irda_desc->wBaudRate & USB_IRDA_BR_19200) ? " 19200" : "",
- (irda_desc->wBaudRate & USB_IRDA_BR_38400) ? " 38400" : "",
- (irda_desc->wBaudRate & USB_IRDA_BR_57600) ? " 57600" : "",
- (irda_desc->wBaudRate & USB_IRDA_BR_115200) ? " 115200" : "",
- (irda_desc->wBaudRate & USB_IRDA_BR_576000) ? " 576000" : "",
- (irda_desc->wBaudRate & USB_IRDA_BR_1152000) ? " 1152000" : "",
- (irda_desc->wBaudRate & USB_IRDA_BR_4000000) ? " 4000000" : "");
+ (rates & USB_IRDA_BR_2400) ? " 2400" : "",
+ (rates & USB_IRDA_BR_9600) ? " 9600" : "",
+ (rates & USB_IRDA_BR_19200) ? " 19200" : "",
+ (rates & USB_IRDA_BR_38400) ? " 38400" : "",
+ (rates & USB_IRDA_BR_57600) ? " 57600" : "",
+ (rates & USB_IRDA_BR_115200) ? " 115200" : "",
+ (rates & USB_IRDA_BR_576000) ? " 576000" : "",
+ (rates & USB_IRDA_BR_1152000) ? " 1152000" : "",
+ (rates & USB_IRDA_BR_4000000) ? " 4000000" : "");
switch (irda_desc->bmAdditionalBOFs) {
case USB_IRDA_AB_48:
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index edbc81f205c2..70f346f1aa86 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -189,7 +189,7 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty,
return -ENOMEM;
divisor = mct_u232_calculate_baud_rate(serial, value, &speed);
- put_unaligned_le32(cpu_to_le32(divisor), buf);
+ put_unaligned_le32(divisor, buf);
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
MCT_U232_SET_BAUD_RATE_REQUEST,
MCT_U232_SET_REQUEST_TYPE,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index af67a0de6b5d..3bf61acfc26b 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -281,6 +281,7 @@ static void option_instat_callback(struct urb *urb);
#define TELIT_PRODUCT_LE922_USBCFG0 0x1042
#define TELIT_PRODUCT_LE922_USBCFG3 0x1043
#define TELIT_PRODUCT_LE922_USBCFG5 0x1045
+#define TELIT_PRODUCT_ME910 0x1100
#define TELIT_PRODUCT_LE920 0x1200
#define TELIT_PRODUCT_LE910 0x1201
#define TELIT_PRODUCT_LE910_USBCFG4 0x1206
@@ -640,6 +641,11 @@ static const struct option_blacklist_info simcom_sim7100e_blacklist = {
.reserved = BIT(5) | BIT(6),
};
+static const struct option_blacklist_info telit_me910_blacklist = {
+ .sendsetup = BIT(0),
+ .reserved = BIT(1) | BIT(3),
+};
+
static const struct option_blacklist_info telit_le910_blacklist = {
.sendsetup = BIT(0),
.reserved = BIT(1) | BIT(2),
@@ -1235,6 +1241,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff),
.driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
+ .driver_info = (kernel_ulong_t)&telit_me910_blacklist },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
.driver_info = (kernel_ulong_t)&telit_le910_blacklist },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 38b3f0d8cd58..fd509ed6cf70 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -162,6 +162,8 @@ static const struct usb_device_id id_table[] = {
{DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx */
{DEVICE_SWI(0x1199, 0x9078)}, /* Sierra Wireless EM74xx */
{DEVICE_SWI(0x1199, 0x9079)}, /* Sierra Wireless EM74xx */
+ {DEVICE_SWI(0x1199, 0x907a)}, /* Sierra Wireless EM74xx QDL */
+ {DEVICE_SWI(0x1199, 0x907b)}, /* Sierra Wireless EM74xx */
{DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 369f3c24815a..28100374f7bd 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -95,12 +95,12 @@ static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = {
#define REG_HW_TRAP1 0xFF89
/* SRB Status */
-#define SS_SUCCESS 0x00 /* No Sense */
-#define SS_NOT_READY 0x02
-#define SS_MEDIUM_ERR 0x03
-#define SS_HW_ERR 0x04
-#define SS_ILLEGAL_REQUEST 0x05
-#define SS_UNIT_ATTENTION 0x06
+#define SS_SUCCESS 0x000000 /* No Sense */
+#define SS_NOT_READY 0x023A00 /* Medium not present */
+#define SS_MEDIUM_ERR 0x031100 /* Unrecovered read error */
+#define SS_HW_ERR 0x040800 /* Communication failure */
+#define SS_ILLEGAL_REQUEST 0x052000 /* Invalid command */
+#define SS_UNIT_ATTENTION 0x062900 /* Reset occurred */
/* ENE Load FW Pattern */
#define SD_INIT1_PATTERN 1
@@ -446,6 +446,10 @@ struct ms_lib_ctrl {
#define SD_BLOCK_LEN 9
struct ene_ub6250_info {
+
+ /* I/O bounce buffer */
+ u8 *bbuf;
+
/* for 6250 code */
struct SD_STATUS SD_Status;
struct MS_STATUS MS_Status;
@@ -493,8 +497,11 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag);
static void ene_ub6250_info_destructor(void *extra)
{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) extra;
+
if (!extra)
return;
+ kfree(info->bbuf);
}
static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
@@ -577,24 +584,26 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
return USB_STOR_TRANSPORT_GOOD;
}
-static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
+static int do_scsi_request_sense(struct us_data *us, struct scsi_cmnd *srb)
{
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+ unsigned char buf[18];
- if (info->SD_Status.Insert && info->SD_Status.Ready)
- return USB_STOR_TRANSPORT_GOOD;
- else {
- ene_sd_init(us);
- return USB_STOR_TRANSPORT_GOOD;
- }
+ memset(buf, 0, 18);
+ buf[0] = 0x70; /* Current error */
+ buf[2] = info->SrbStatus >> 16; /* Sense key */
+ buf[7] = 10; /* Additional length */
+ buf[12] = info->SrbStatus >> 8; /* ASC */
+ buf[13] = info->SrbStatus; /* ASCQ */
+ usb_stor_set_xfer_buf(buf, sizeof(buf), srb);
return USB_STOR_TRANSPORT_GOOD;
}
-static int sd_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
+static int do_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
{
unsigned char data_ptr[36] = {
- 0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
+ 0x00, 0x00, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61,
0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30 };
@@ -603,6 +612,20 @@ static int sd_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
return USB_STOR_TRANSPORT_GOOD;
}
+static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ if (info->SD_Status.Insert && info->SD_Status.Ready)
+ return USB_STOR_TRANSPORT_GOOD;
+ else {
+ ene_sd_init(us);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
{
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
@@ -860,8 +883,9 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+ u8 *bbuf = info->bbuf;
int result;
- u8 ExtBuf[4];
u32 bn = PhyBlockAddr * 0x20 + PageNum;
result = ene_load_bincode(us, MS_RW_PATTERN);
@@ -901,7 +925,7 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16);
bcb->CDB[6] = 0x01;
- result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
+ result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -910,9 +934,9 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
ExtraDat->status0 = 0x10; /* Not yet,fireware support */
ExtraDat->status1 = 0x00; /* Not yet,fireware support */
- ExtraDat->ovrflg = ExtBuf[0];
- ExtraDat->mngflg = ExtBuf[1];
- ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
+ ExtraDat->ovrflg = bbuf[0];
+ ExtraDat->mngflg = bbuf[1];
+ ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]);
return USB_STOR_TRANSPORT_GOOD;
}
@@ -1332,8 +1356,9 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
u8 PageNum, struct ms_lib_type_extdat *ExtraDat)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+ u8 *bbuf = info->bbuf;
int result;
- u8 ExtBuf[4];
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
@@ -1347,7 +1372,7 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
bcb->CDB[2] = (unsigned char)(PhyBlock>>16);
bcb->CDB[6] = 0x01;
- result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
+ result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -1355,9 +1380,9 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
ExtraDat->intr = 0x80; /* Not yet, waiting for fireware support */
ExtraDat->status0 = 0x10; /* Not yet, waiting for fireware support */
ExtraDat->status1 = 0x00; /* Not yet, waiting for fireware support */
- ExtraDat->ovrflg = ExtBuf[0];
- ExtraDat->mngflg = ExtBuf[1];
- ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
+ ExtraDat->ovrflg = bbuf[0];
+ ExtraDat->mngflg = bbuf[1];
+ ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]);
return USB_STOR_TRANSPORT_GOOD;
}
@@ -1446,19 +1471,6 @@ static int ms_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
return USB_STOR_TRANSPORT_GOOD;
}
-static int ms_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
-{
- /* pr_info("MS_SCSI_Inquiry\n"); */
- unsigned char data_ptr[36] = {
- 0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
- 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61,
- 0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30};
-
- usb_stor_set_xfer_buf(data_ptr, 36, srb);
- return USB_STOR_TRANSPORT_GOOD;
-}
-
static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
{
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
@@ -1556,9 +1568,9 @@ static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
u16 PhyBlock, newblk, i;
u16 LogStart, LogEnde;
struct ms_lib_type_extdat extdat;
- u8 buf[0x200];
u32 count = 0, index = 0;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+ u8 *bbuf = info->bbuf;
for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) {
ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde);
@@ -1572,14 +1584,16 @@ static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
}
if (count == PhyBlock) {
- ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, &buf);
+ ms_lib_read_extrablock(us, PhyBlock, 0, 0x80,
+ bbuf);
count += 0x80;
}
index = (PhyBlock % 0x80) * 4;
- extdat.ovrflg = buf[index];
- extdat.mngflg = buf[index+1];
- extdat.logadr = memstick_logaddr(buf[index+2], buf[index+3]);
+ extdat.ovrflg = bbuf[index];
+ extdat.mngflg = bbuf[index+1];
+ extdat.logadr = memstick_logaddr(bbuf[index+2],
+ bbuf[index+3]);
if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
ms_lib_setacquired_errorblock(us, PhyBlock);
@@ -1929,6 +1943,8 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag)
bcb->CDB[0] = 0xEF;
result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
+ if (us->srb != NULL)
+ scsi_set_resid(us->srb, 0);
info->BIN_FLAG = flag;
kfree(buf);
@@ -2062,9 +2078,9 @@ static int ene_ms_init(struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- u8 buf[0x200];
u16 MSP_BlockSize, MSP_UserAreaBlocks;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+ u8 *bbuf = info->bbuf;
printk(KERN_INFO "transport --- ENE_MSInit\n");
@@ -2083,13 +2099,13 @@ static int ene_ms_init(struct us_data *us)
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x01;
- result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
+ result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
if (result != USB_STOR_XFER_GOOD) {
printk(KERN_ERR "Execution MS Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
/* the same part to test ENE */
- info->MS_Status = *(struct MS_STATUS *)&buf[0];
+ info->MS_Status = *(struct MS_STATUS *) bbuf;
if (info->MS_Status.Insert && info->MS_Status.Ready) {
printk(KERN_INFO "Insert = %x\n", info->MS_Status.Insert);
@@ -2098,15 +2114,15 @@ static int ene_ms_init(struct us_data *us)
printk(KERN_INFO "IsMSPHG = %x\n", info->MS_Status.IsMSPHG);
printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP);
if (info->MS_Status.IsMSPro) {
- MSP_BlockSize = (buf[6] << 8) | buf[7];
- MSP_UserAreaBlocks = (buf[10] << 8) | buf[11];
+ MSP_BlockSize = (bbuf[6] << 8) | bbuf[7];
+ MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11];
info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
} else {
ms_card_init(us); /* Card is MS (to ms.c)*/
}
usb_stor_dbg(us, "MS Init Code OK !!\n");
} else {
- usb_stor_dbg(us, "MS Card Not Ready --- %x\n", buf[0]);
+ usb_stor_dbg(us, "MS Card Not Ready --- %x\n", bbuf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -2116,9 +2132,9 @@ static int ene_ms_init(struct us_data *us)
static int ene_sd_init(struct us_data *us)
{
int result;
- u8 buf[0x200];
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+ u8 *bbuf = info->bbuf;
usb_stor_dbg(us, "transport --- ENE_SDInit\n");
/* SD Init Part-1 */
@@ -2152,17 +2168,17 @@ static int ene_sd_init(struct us_data *us)
bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
- result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
+ result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
if (result != USB_STOR_XFER_GOOD) {
usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
- info->SD_Status = *(struct SD_STATUS *)&buf[0];
+ info->SD_Status = *(struct SD_STATUS *) bbuf;
if (info->SD_Status.Insert && info->SD_Status.Ready) {
struct SD_STATUS *s = &info->SD_Status;
- ene_get_card_status(us, (unsigned char *)&buf);
+ ene_get_card_status(us, bbuf);
usb_stor_dbg(us, "Insert = %x\n", s->Insert);
usb_stor_dbg(us, "Ready = %x\n", s->Ready);
usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC);
@@ -2170,7 +2186,7 @@ static int ene_sd_init(struct us_data *us)
usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed);
usb_stor_dbg(us, "WtP = %x\n", s->WtP);
} else {
- usb_stor_dbg(us, "SD Card Not Ready --- %x\n", buf[0]);
+ usb_stor_dbg(us, "SD Card Not Ready --- %x\n", bbuf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_GOOD;
@@ -2180,13 +2196,15 @@ static int ene_sd_init(struct us_data *us)
static int ene_init(struct us_data *us)
{
int result;
- u8 misc_reg03 = 0;
+ u8 misc_reg03;
struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+ u8 *bbuf = info->bbuf;
- result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
+ result = ene_get_card_type(us, REG_CARD_STATUS, bbuf);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
+ misc_reg03 = bbuf[0];
if (misc_reg03 & 0x01) {
if (!info->SD_Status.Ready) {
result = ene_sd_init(us);
@@ -2210,13 +2228,15 @@ static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
int result;
struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
- info->SrbStatus = SS_SUCCESS;
switch (srb->cmnd[0]) {
case TEST_UNIT_READY:
result = sd_scsi_test_unit_ready(us, srb);
break; /* 0x00 */
+ case REQUEST_SENSE:
+ result = do_scsi_request_sense(us, srb);
+ break; /* 0x03 */
case INQUIRY:
- result = sd_scsi_inquiry(us, srb);
+ result = do_scsi_inquiry(us, srb);
break; /* 0x12 */
case MODE_SENSE:
result = sd_scsi_mode_sense(us, srb);
@@ -2240,6 +2260,8 @@ static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
result = USB_STOR_TRANSPORT_FAILED;
break;
}
+ if (result == USB_STOR_TRANSPORT_GOOD)
+ info->SrbStatus = SS_SUCCESS;
return result;
}
@@ -2250,13 +2272,16 @@ static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
{
int result;
struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
- info->SrbStatus = SS_SUCCESS;
+
switch (srb->cmnd[0]) {
case TEST_UNIT_READY:
result = ms_scsi_test_unit_ready(us, srb);
break; /* 0x00 */
+ case REQUEST_SENSE:
+ result = do_scsi_request_sense(us, srb);
+ break; /* 0x03 */
case INQUIRY:
- result = ms_scsi_inquiry(us, srb);
+ result = do_scsi_inquiry(us, srb);
break; /* 0x12 */
case MODE_SENSE:
result = ms_scsi_mode_sense(us, srb);
@@ -2275,26 +2300,29 @@ static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
result = USB_STOR_TRANSPORT_FAILED;
break;
}
+ if (result == USB_STOR_TRANSPORT_GOOD)
+ info->SrbStatus = SS_SUCCESS;
return result;
}
static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
{
- int result = 0;
+ int result = USB_STOR_XFER_GOOD;
struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
/*US_DEBUG(usb_stor_show_command(us, srb)); */
scsi_set_resid(srb, 0);
- if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) {
+ if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready)))
result = ene_init(us);
- } else {
+ if (result == USB_STOR_XFER_GOOD) {
+ result = USB_STOR_TRANSPORT_ERROR;
if (info->SD_Status.Ready)
result = sd_scsi_irp(us, srb);
if (info->MS_Status.Ready)
result = ms_scsi_irp(us, srb);
}
- return 0;
+ return result;
}
static struct scsi_host_template ene_ub6250_host_template;
@@ -2303,8 +2331,9 @@ static int ene_ub6250_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
int result;
- u8 misc_reg03 = 0;
+ u8 misc_reg03;
struct us_data *us;
+ struct ene_ub6250_info *info;
result = usb_stor_probe1(&us, intf, id,
(id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list,
@@ -2313,11 +2342,16 @@ static int ene_ub6250_probe(struct usb_interface *intf,
return result;
/* FIXME: where should the code alloc extra buf ? */
- if (!us->extra) {
- us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
- if (!us->extra)
- return -ENOMEM;
- us->extra_destructor = ene_ub6250_info_destructor;
+ us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
+ if (!us->extra)
+ return -ENOMEM;
+ us->extra_destructor = ene_ub6250_info_destructor;
+
+ info = (struct ene_ub6250_info *)(us->extra);
+ info->bbuf = kmalloc(512, GFP_KERNEL);
+ if (!info->bbuf) {
+ kfree(us->extra);
+ return -ENOMEM;
}
us->transport_name = "ene_ub6250";
@@ -2329,12 +2363,13 @@ static int ene_ub6250_probe(struct usb_interface *intf,
return result;
/* probe card type */
- result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
+ result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf);
if (result != USB_STOR_XFER_GOOD) {
usb_stor_disconnect(intf);
return USB_STOR_TRANSPORT_ERROR;
}
+ misc_reg03 = info->bbuf[0];
if (!(misc_reg03 & 0x01)) {
pr_info("ums_eneub6250: This driver only supports SD/MS cards. "
"It does not support SM cards.\n");
diff --git a/drivers/usb/typec/typec.c b/drivers/usb/typec/typec.c
index 89e540bb7ff3..24e355ba109d 100644
--- a/drivers/usb/typec/typec.c
+++ b/drivers/usb/typec/typec.c
@@ -11,6 +11,7 @@
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/usb/typec.h>
@@ -69,6 +70,8 @@ struct typec_port {
enum typec_role pwr_role;
enum typec_role vconn_role;
enum typec_pwr_opmode pwr_opmode;
+ enum typec_port_type port_type;
+ struct mutex port_type_lock;
const struct typec_capability *cap;
};
@@ -291,7 +294,7 @@ typec_altmode_roles_show(struct device *dev, struct device_attribute *attr,
}
static void typec_init_modes(struct typec_altmode *alt,
- struct typec_mode_desc *desc, bool is_port)
+ const struct typec_mode_desc *desc, bool is_port)
{
int i;
@@ -378,7 +381,8 @@ static const struct device_type typec_altmode_dev_type = {
};
static struct typec_altmode *
-typec_register_altmode(struct device *parent, struct typec_altmode_desc *desc)
+typec_register_altmode(struct device *parent,
+ const struct typec_altmode_desc *desc)
{
struct typec_altmode *alt;
int ret;
@@ -495,7 +499,7 @@ EXPORT_SYMBOL_GPL(typec_partner_set_identity);
*/
struct typec_altmode *
typec_partner_register_altmode(struct typec_partner *partner,
- struct typec_altmode_desc *desc)
+ const struct typec_altmode_desc *desc)
{
return typec_register_altmode(&partner->dev, desc);
}
@@ -590,7 +594,7 @@ static const struct device_type typec_plug_dev_type = {
*/
struct typec_altmode *
typec_plug_register_altmode(struct typec_plug *plug,
- struct typec_altmode_desc *desc)
+ const struct typec_altmode_desc *desc)
{
return typec_register_altmode(&plug->dev, desc);
}
@@ -789,6 +793,18 @@ static const char * const typec_data_roles[] = {
[TYPEC_HOST] = "host",
};
+static const char * const typec_port_types[] = {
+ [TYPEC_PORT_DFP] = "source",
+ [TYPEC_PORT_UFP] = "sink",
+ [TYPEC_PORT_DRP] = "dual",
+};
+
+static const char * const typec_port_types_drp[] = {
+ [TYPEC_PORT_DFP] = "dual [source] sink",
+ [TYPEC_PORT_UFP] = "dual source [sink]",
+ [TYPEC_PORT_DRP] = "[dual] source sink",
+};
+
static ssize_t
preferred_role_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t size)
@@ -846,11 +862,6 @@ static ssize_t data_role_store(struct device *dev,
struct typec_port *port = to_typec_port(dev);
int ret;
- if (port->cap->type != TYPEC_PORT_DRP) {
- dev_dbg(dev, "data role swap only supported with DRP ports\n");
- return -EOPNOTSUPP;
- }
-
if (!port->cap->dr_set) {
dev_dbg(dev, "data role swapping not supported\n");
return -EOPNOTSUPP;
@@ -860,11 +871,22 @@ static ssize_t data_role_store(struct device *dev,
if (ret < 0)
return ret;
+ mutex_lock(&port->port_type_lock);
+ if (port->port_type != TYPEC_PORT_DRP) {
+ dev_dbg(dev, "port type fixed at \"%s\"",
+ typec_port_types[port->port_type]);
+ ret = -EOPNOTSUPP;
+ goto unlock_and_ret;
+ }
+
ret = port->cap->dr_set(port->cap, ret);
if (ret)
- return ret;
+ goto unlock_and_ret;
- return size;
+ ret = size;
+unlock_and_ret:
+ mutex_unlock(&port->port_type_lock);
+ return ret;
}
static ssize_t data_role_show(struct device *dev,
@@ -885,7 +907,7 @@ static ssize_t power_role_store(struct device *dev,
const char *buf, size_t size)
{
struct typec_port *port = to_typec_port(dev);
- int ret = size;
+ int ret;
if (!port->cap->pd_revision) {
dev_dbg(dev, "USB Power Delivery not supported\n");
@@ -906,11 +928,22 @@ static ssize_t power_role_store(struct device *dev,
if (ret < 0)
return ret;
+ mutex_lock(&port->port_type_lock);
+ if (port->port_type != TYPEC_PORT_DRP) {
+ dev_dbg(dev, "port type fixed at \"%s\"",
+ typec_port_types[port->port_type]);
+ ret = -EOPNOTSUPP;
+ goto unlock_and_ret;
+ }
+
ret = port->cap->pr_set(port->cap, ret);
if (ret)
- return ret;
+ goto unlock_and_ret;
- return size;
+ ret = size;
+unlock_and_ret:
+ mutex_unlock(&port->port_type_lock);
+ return ret;
}
static ssize_t power_role_show(struct device *dev,
@@ -926,6 +959,57 @@ static ssize_t power_role_show(struct device *dev,
}
static DEVICE_ATTR_RW(power_role);
+static ssize_t
+port_type_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct typec_port *port = to_typec_port(dev);
+ int ret;
+ enum typec_port_type type;
+
+ if (!port->cap->port_type_set || port->cap->type != TYPEC_PORT_DRP) {
+ dev_dbg(dev, "changing port type not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = sysfs_match_string(typec_port_types, buf);
+ if (ret < 0)
+ return ret;
+
+ type = ret;
+ mutex_lock(&port->port_type_lock);
+
+ if (port->port_type == type) {
+ ret = size;
+ goto unlock_and_ret;
+ }
+
+ ret = port->cap->port_type_set(port->cap, type);
+ if (ret)
+ goto unlock_and_ret;
+
+ port->port_type = type;
+ ret = size;
+
+unlock_and_ret:
+ mutex_unlock(&port->port_type_lock);
+ return ret;
+}
+
+static ssize_t
+port_type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_port *port = to_typec_port(dev);
+
+ if (port->cap->type == TYPEC_PORT_DRP)
+ return sprintf(buf, "%s\n",
+ typec_port_types_drp[port->port_type]);
+
+ return sprintf(buf, "[%s]\n", typec_port_types[port->cap->type]);
+}
+static DEVICE_ATTR_RW(port_type);
+
static const char * const typec_pwr_opmodes[] = {
[TYPEC_PWR_MODE_USB] = "default",
[TYPEC_PWR_MODE_1_5A] = "1.5A",
@@ -1035,6 +1119,7 @@ static struct attribute *typec_attrs[] = {
&dev_attr_usb_power_delivery_revision.attr,
&dev_attr_usb_typec_revision.attr,
&dev_attr_vconn_source.attr,
+ &dev_attr_port_type.attr,
NULL,
};
ATTRIBUTE_GROUPS(typec);
@@ -1123,6 +1208,11 @@ void typec_set_vconn_role(struct typec_port *port, enum typec_role role)
}
EXPORT_SYMBOL_GPL(typec_set_vconn_role);
+static int partner_match(struct device *dev, void *data)
+{
+ return is_typec_partner(dev);
+}
+
/**
* typec_set_pwr_opmode - Report changed power operation mode
* @port: The USB Type-C Port where the mode was changed
@@ -1136,12 +1226,26 @@ EXPORT_SYMBOL_GPL(typec_set_vconn_role);
void typec_set_pwr_opmode(struct typec_port *port,
enum typec_pwr_opmode opmode)
{
+ struct device *partner_dev;
+
if (port->pwr_opmode == opmode)
return;
port->pwr_opmode = opmode;
sysfs_notify(&port->dev.kobj, NULL, "power_operation_mode");
kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
+
+ partner_dev = device_find_child(&port->dev, NULL, partner_match);
+ if (partner_dev) {
+ struct typec_partner *partner = to_typec_partner(partner_dev);
+
+ if (opmode == TYPEC_PWR_MODE_PD && !partner->usb_pd) {
+ partner->usb_pd = 1;
+ sysfs_notify(&partner_dev->kobj, NULL,
+ "supports_usb_power_delivery");
+ }
+ put_device(partner_dev);
+ }
}
EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
@@ -1159,7 +1263,7 @@ EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
*/
struct typec_altmode *
typec_port_register_altmode(struct typec_port *port,
- struct typec_altmode_desc *desc)
+ const struct typec_altmode_desc *desc)
{
return typec_register_altmode(&port->dev, desc);
}
@@ -1211,6 +1315,8 @@ struct typec_port *typec_register_port(struct device *parent,
port->id = id;
port->cap = cap;
+ port->port_type = cap->type;
+ mutex_init(&port->port_type_lock);
port->prefer_role = cap->prefer_role;
port->dev.class = typec_class;
diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c
index 44ab43fc4fcc..af10f7b131a4 100644
--- a/drivers/usb/usbip/stub_main.c
+++ b/drivers/usb/usbip/stub_main.c
@@ -262,7 +262,11 @@ void stub_device_cleanup_urbs(struct stub_device *sdev)
kmem_cache_free(stub_priv_cache, priv);
kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+
kfree(urb->setup_packet);
+ urb->setup_packet = NULL;
+
usb_free_urb(urb);
}
}
diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c
index 6b1e8c3f0e4b..be50cef645d8 100644
--- a/drivers/usb/usbip/stub_tx.c
+++ b/drivers/usb/usbip/stub_tx.c
@@ -28,7 +28,11 @@ static void stub_free_priv_and_urb(struct stub_priv *priv)
struct urb *urb = priv->urb;
kfree(urb->setup_packet);
+ urb->setup_packet = NULL;
+
kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+
list_del(&priv->list);
kmem_cache_free(stub_priv_cache, priv);
usb_free_urb(urb);
diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h
index 88b71c4e068f..5cfb59e98e44 100644
--- a/drivers/usb/usbip/vhci.h
+++ b/drivers/usb/usbip/vhci.h
@@ -72,6 +72,11 @@ struct vhci_unlink {
unsigned long unlink_seqnum;
};
+enum hub_speed {
+ HUB_SPEED_HIGH = 0,
+ HUB_SPEED_SUPER,
+};
+
/* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */
#ifdef CONFIG_USBIP_VHCI_HC_PORTS
#define VHCI_HC_PORTS CONFIG_USBIP_VHCI_HC_PORTS
@@ -79,6 +84,9 @@ struct vhci_unlink {
#define VHCI_HC_PORTS 8
#endif
+/* Each VHCI has 2 hubs (USB2 and USB3), each has VHCI_HC_PORTS ports */
+#define VHCI_PORTS (VHCI_HC_PORTS*2)
+
#ifdef CONFIG_USBIP_VHCI_NR_HCS
#define VHCI_NR_HCS CONFIG_USBIP_VHCI_NR_HCS
#else
@@ -87,10 +95,19 @@ struct vhci_unlink {
#define MAX_STATUS_NAME 16
-/* for usb_bus.hcpriv */
-struct vhci_hcd {
+struct vhci {
spinlock_t lock;
+ struct platform_device *pdev;
+
+ struct vhci_hcd *vhci_hcd_hs;
+ struct vhci_hcd *vhci_hcd_ss;
+};
+
+/* for usb_hcd.hcd_priv[0] */
+struct vhci_hcd {
+ struct vhci *vhci;
+
u32 port_status[VHCI_HC_PORTS];
unsigned resuming:1;
@@ -107,7 +124,7 @@ struct vhci_hcd {
};
extern int vhci_num_controllers;
-extern struct platform_device **vhci_pdevs;
+extern struct vhci *vhcis;
extern struct attribute_group vhci_attr_group;
/* vhci_hcd.c */
@@ -131,10 +148,10 @@ static inline __u32 port_to_rhport(__u32 port)
static inline int port_to_pdev_nr(__u32 port)
{
- return port / VHCI_HC_PORTS;
+ return port / VHCI_PORTS;
}
-static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd)
+static inline struct vhci_hcd *hcd_to_vhci_hcd(struct usb_hcd *hcd)
{
return (struct vhci_hcd *) (hcd->hcd_priv);
}
@@ -149,15 +166,14 @@ static inline const char *hcd_name(struct usb_hcd *hcd)
return (hcd)->self.bus_name;
}
-static inline struct usb_hcd *vhci_to_hcd(struct vhci_hcd *vhci)
+static inline struct usb_hcd *vhci_hcd_to_hcd(struct vhci_hcd *vhci_hcd)
{
- return container_of((void *) vhci, struct usb_hcd, hcd_priv);
+ return container_of((void *) vhci_hcd, struct usb_hcd, hcd_priv);
}
-static inline struct vhci_hcd *vdev_to_vhci(struct vhci_device *vdev)
+static inline struct vhci_hcd *vdev_to_vhci_hcd(struct vhci_device *vdev)
{
- return container_of(
- (void *)(vdev - vdev->rhport), struct vhci_hcd, vdev);
+ return container_of((void *)(vdev - vdev->rhport), struct vhci_hcd, vdev);
}
#endif /* __USBIP_VHCI_H */
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 5d8b2c261940..64c38603df7b 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -58,8 +58,7 @@ static const char driver_name[] = "vhci_hcd";
static const char driver_desc[] = "USB/IP Virtual Host Controller";
int vhci_num_controllers = VHCI_NR_HCS;
-
-struct platform_device **vhci_pdevs;
+struct vhci *vhcis;
static const char * const bit_desc[] = {
"CONNECTION", /*0*/
@@ -67,7 +66,7 @@ static const char * const bit_desc[] = {
"SUSPEND", /*2*/
"OVER_CURRENT", /*3*/
"RESET", /*4*/
- "R5", /*5*/
+ "L1", /*5*/
"R6", /*6*/
"R7", /*7*/
"POWER", /*8*/
@@ -83,7 +82,7 @@ static const char * const bit_desc[] = {
"C_SUSPEND", /*18*/
"C_OVER_CURRENT", /*19*/
"C_RESET", /*20*/
- "R21", /*21*/
+ "C_L1", /*21*/
"R22", /*22*/
"R23", /*23*/
"R24", /*24*/
@@ -96,10 +95,49 @@ static const char * const bit_desc[] = {
"R31", /*31*/
};
-static void dump_port_status_diff(u32 prev_status, u32 new_status)
+static const char * const bit_desc_ss[] = {
+ "CONNECTION", /*0*/
+ "ENABLE", /*1*/
+ "SUSPEND", /*2*/
+ "OVER_CURRENT", /*3*/
+ "RESET", /*4*/
+ "L1", /*5*/
+ "R6", /*6*/
+ "R7", /*7*/
+ "R8", /*8*/
+ "POWER", /*9*/
+ "HIGHSPEED", /*10*/
+ "PORT_TEST", /*11*/
+ "INDICATOR", /*12*/
+ "R13", /*13*/
+ "R14", /*14*/
+ "R15", /*15*/
+ "C_CONNECTION", /*16*/
+ "C_ENABLE", /*17*/
+ "C_SUSPEND", /*18*/
+ "C_OVER_CURRENT", /*19*/
+ "C_RESET", /*20*/
+ "C_BH_RESET", /*21*/
+ "C_LINK_STATE", /*22*/
+ "C_CONFIG_ERROR", /*23*/
+ "R24", /*24*/
+ "R25", /*25*/
+ "R26", /*26*/
+ "R27", /*27*/
+ "R28", /*28*/
+ "R29", /*29*/
+ "R30", /*30*/
+ "R31", /*31*/
+};
+
+static void dump_port_status_diff(u32 prev_status, u32 new_status, bool usb3)
{
int i = 0;
u32 bit = 1;
+ const char * const *desc = bit_desc;
+
+ if (usb3)
+ desc = bit_desc_ss;
pr_debug("status prev -> new: %08x -> %08x\n", prev_status, new_status);
while (bit) {
@@ -114,8 +152,12 @@ static void dump_port_status_diff(u32 prev_status, u32 new_status)
else
change = ' ';
- if (prev || new)
- pr_debug(" %c%s\n", change, bit_desc[i]);
+ if (prev || new) {
+ pr_debug(" %c%s\n", change, desc[i]);
+
+ if (bit == 1) /* USB_PORT_STAT_CONNECTION */
+ pr_debug(" %c%s\n", change, "USB_PORT_STAT_SPEED_5GBPS");
+ }
bit <<= 1;
i++;
}
@@ -124,7 +166,8 @@ static void dump_port_status_diff(u32 prev_status, u32 new_status)
void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed)
{
- struct vhci_hcd *vhci = vdev_to_vhci(vdev);
+ struct vhci_hcd *vhci_hcd = vdev_to_vhci_hcd(vdev);
+ struct vhci *vhci = vhci_hcd->vhci;
int rhport = vdev->rhport;
u32 status;
unsigned long flags;
@@ -133,7 +176,7 @@ void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed)
spin_lock_irqsave(&vhci->lock, flags);
- status = vhci->port_status[rhport];
+ status = vhci_hcd->port_status[rhport];
status |= USB_PORT_STAT_CONNECTION | (1 << USB_PORT_FEAT_C_CONNECTION);
@@ -148,16 +191,17 @@ void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed)
break;
}
- vhci->port_status[rhport] = status;
+ vhci_hcd->port_status[rhport] = status;
spin_unlock_irqrestore(&vhci->lock, flags);
- usb_hcd_poll_rh_status(vhci_to_hcd(vhci));
+ usb_hcd_poll_rh_status(vhci_hcd_to_hcd(vhci_hcd));
}
static void rh_port_disconnect(struct vhci_device *vdev)
{
- struct vhci_hcd *vhci = vdev_to_vhci(vdev);
+ struct vhci_hcd *vhci_hcd = vdev_to_vhci_hcd(vdev);
+ struct vhci *vhci = vhci_hcd->vhci;
int rhport = vdev->rhport;
u32 status;
unsigned long flags;
@@ -166,15 +210,15 @@ static void rh_port_disconnect(struct vhci_device *vdev)
spin_lock_irqsave(&vhci->lock, flags);
- status = vhci->port_status[rhport];
+ status = vhci_hcd->port_status[rhport];
status &= ~USB_PORT_STAT_CONNECTION;
status |= (1 << USB_PORT_FEAT_C_CONNECTION);
- vhci->port_status[rhport] = status;
+ vhci_hcd->port_status[rhport] = status;
spin_unlock_irqrestore(&vhci->lock, flags);
- usb_hcd_poll_rh_status(vhci_to_hcd(vhci));
+ usb_hcd_poll_rh_status(vhci_hcd_to_hcd(vhci_hcd));
}
#define PORT_C_MASK \
@@ -197,17 +241,15 @@ static void rh_port_disconnect(struct vhci_device *vdev)
*/
static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
{
- struct vhci_hcd *vhci;
- int retval;
+ struct vhci_hcd *vhci_hcd = hcd_to_vhci_hcd(hcd);
+ struct vhci *vhci = vhci_hcd->vhci;
+ int retval = DIV_ROUND_UP(VHCI_HC_PORTS + 1, 8);
int rhport;
int changed = 0;
unsigned long flags;
- retval = DIV_ROUND_UP(VHCI_HC_PORTS + 1, 8);
memset(buf, 0, retval);
- vhci = hcd_to_vhci(hcd);
-
spin_lock_irqsave(&vhci->lock, flags);
if (!HCD_HW_ACCESSIBLE(hcd)) {
usbip_dbg_vhci_rh("hw accessible flag not on?\n");
@@ -216,7 +258,7 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
/* check pseudo status register for each port */
for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) {
- if ((vhci->port_status[rhport] & PORT_C_MASK)) {
+ if ((vhci_hcd->port_status[rhport] & PORT_C_MASK)) {
/* The status of a port has been changed, */
usbip_dbg_vhci_rh("port %d status changed\n", rhport);
@@ -233,22 +275,62 @@ done:
return changed ? retval : 0;
}
+/* usb 3.0 root hub device descriptor */
+static struct {
+ struct usb_bos_descriptor bos;
+ struct usb_ss_cap_descriptor ss_cap;
+} __packed usb3_bos_desc = {
+
+ .bos = {
+ .bLength = USB_DT_BOS_SIZE,
+ .bDescriptorType = USB_DT_BOS,
+ .wTotalLength = cpu_to_le16(sizeof(usb3_bos_desc)),
+ .bNumDeviceCaps = 1,
+ },
+ .ss_cap = {
+ .bLength = USB_DT_USB_SS_CAP_SIZE,
+ .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
+ .bDevCapabilityType = USB_SS_CAP_TYPE,
+ .wSpeedSupported = cpu_to_le16(USB_5GBPS_OPERATION),
+ .bFunctionalitySupport = ilog2(USB_5GBPS_OPERATION),
+ },
+};
+
+static inline void
+ss_hub_descriptor(struct usb_hub_descriptor *desc)
+{
+ memset(desc, 0, sizeof *desc);
+ desc->bDescriptorType = USB_DT_SS_HUB;
+ desc->bDescLength = 12;
+ desc->wHubCharacteristics = cpu_to_le16(
+ HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM);
+ desc->bNbrPorts = VHCI_HC_PORTS;
+ desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
+ desc->u.ss.DeviceRemovable = 0xffff;
+}
+
static inline void hub_descriptor(struct usb_hub_descriptor *desc)
{
+ int width;
+
memset(desc, 0, sizeof(*desc));
desc->bDescriptorType = USB_DT_HUB;
- desc->bDescLength = 9;
desc->wHubCharacteristics = cpu_to_le16(
HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM);
+
desc->bNbrPorts = VHCI_HC_PORTS;
- desc->u.hs.DeviceRemovable[0] = 0xff;
- desc->u.hs.DeviceRemovable[1] = 0xff;
+ BUILD_BUG_ON(VHCI_HC_PORTS > USB_MAXCHILDREN);
+ width = desc->bNbrPorts / 8 + 1;
+ desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * width;
+ memset(&desc->u.hs.DeviceRemovable[0], 0, width);
+ memset(&desc->u.hs.DeviceRemovable[width], 0xff, width);
}
static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
- struct vhci_hcd *dum;
+ struct vhci_hcd *vhci_hcd;
+ struct vhci *vhci;
int retval = 0;
int rhport;
unsigned long flags;
@@ -260,21 +342,24 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/*
* NOTE:
- * wIndex shows the port number and begins from 1.
+ * wIndex (bits 0-7) shows the port number and begins from 1?
*/
+ wIndex = ((__u8)(wIndex & 0x00ff));
usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue,
wIndex);
+
if (wIndex > VHCI_HC_PORTS)
pr_err("invalid port number %d\n", wIndex);
- rhport = ((__u8)(wIndex & 0x00ff)) - 1;
+ rhport = wIndex - 1;
- dum = hcd_to_vhci(hcd);
+ vhci_hcd = hcd_to_vhci_hcd(hcd);
+ vhci = vhci_hcd->vhci;
- spin_lock_irqsave(&dum->lock, flags);
+ spin_lock_irqsave(&vhci->lock, flags);
/* store old status and compare now and old later */
if (usbip_dbg_flag_vhci_rh) {
- memcpy(prev_port_status, dum->port_status,
+ memcpy(prev_port_status, vhci_hcd->port_status,
sizeof(prev_port_status));
}
@@ -285,45 +370,56 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case ClearPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- if (dum->port_status[rhport] & USB_PORT_STAT_SUSPEND) {
+ if (hcd->speed == HCD_USB3) {
+ pr_err(" ClearPortFeature: USB_PORT_FEAT_SUSPEND req not "
+ "supported for USB 3.0 roothub\n");
+ goto error;
+ }
+ usbip_dbg_vhci_rh(
+ " ClearPortFeature: USB_PORT_FEAT_SUSPEND\n");
+ if (vhci_hcd->port_status[rhport] & USB_PORT_STAT_SUSPEND) {
/* 20msec signaling */
- dum->resuming = 1;
- dum->re_timeout =
- jiffies + msecs_to_jiffies(20);
+ vhci_hcd->resuming = 1;
+ vhci_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
}
break;
case USB_PORT_FEAT_POWER:
usbip_dbg_vhci_rh(
" ClearPortFeature: USB_PORT_FEAT_POWER\n");
- dum->port_status[rhport] = 0;
- dum->resuming = 0;
- break;
- case USB_PORT_FEAT_C_RESET:
- usbip_dbg_vhci_rh(
- " ClearPortFeature: USB_PORT_FEAT_C_RESET\n");
- switch (dum->vdev[rhport].speed) {
- case USB_SPEED_HIGH:
- dum->port_status[rhport] |=
- USB_PORT_STAT_HIGH_SPEED;
- break;
- case USB_SPEED_LOW:
- dum->port_status[rhport] |=
- USB_PORT_STAT_LOW_SPEED;
- break;
- default:
- break;
- }
+ if (hcd->speed == HCD_USB3)
+ vhci_hcd->port_status[rhport] &= ~USB_SS_PORT_STAT_POWER;
+ else
+ vhci_hcd->port_status[rhport] &= ~USB_PORT_STAT_POWER;
break;
default:
usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n",
wValue);
- dum->port_status[rhport] &= ~(1 << wValue);
+ vhci_hcd->port_status[rhport] &= ~(1 << wValue);
break;
}
break;
case GetHubDescriptor:
usbip_dbg_vhci_rh(" GetHubDescriptor\n");
- hub_descriptor((struct usb_hub_descriptor *) buf);
+ if (hcd->speed == HCD_USB3 &&
+ (wLength < USB_DT_SS_HUB_SIZE ||
+ wValue != (USB_DT_SS_HUB << 8))) {
+ pr_err("Wrong hub descriptor type for USB 3.0 roothub.\n");
+ goto error;
+ }
+ if (hcd->speed == HCD_USB3)
+ ss_hub_descriptor((struct usb_hub_descriptor *) buf);
+ else
+ hub_descriptor((struct usb_hub_descriptor *) buf);
+ break;
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ if (hcd->speed != HCD_USB3)
+ goto error;
+
+ if ((wValue >> 8) != USB_DT_BOS)
+ goto error;
+
+ memcpy(buf, &usb3_bos_desc, sizeof(usb3_bos_desc));
+ retval = sizeof(usb3_bos_desc);
break;
case GetHubStatus:
usbip_dbg_vhci_rh(" GetHubStatus\n");
@@ -331,7 +427,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case GetPortStatus:
usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex);
- if (wIndex > VHCI_HC_PORTS || wIndex < 1) {
+ if (wIndex < 1) {
pr_err("invalid port number %d\n", wIndex);
retval = -EPIPE;
}
@@ -341,36 +437,48 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/* whoever resets or resumes must GetPortStatus to
* complete it!!
*/
- if (dum->resuming && time_after(jiffies, dum->re_timeout)) {
- dum->port_status[rhport] |=
- (1 << USB_PORT_FEAT_C_SUSPEND);
- dum->port_status[rhport] &=
- ~(1 << USB_PORT_FEAT_SUSPEND);
- dum->resuming = 0;
- dum->re_timeout = 0;
+ if (vhci_hcd->resuming && time_after(jiffies, vhci_hcd->re_timeout)) {
+ vhci_hcd->port_status[rhport] |= (1 << USB_PORT_FEAT_C_SUSPEND);
+ vhci_hcd->port_status[rhport] &= ~(1 << USB_PORT_FEAT_SUSPEND);
+ vhci_hcd->resuming = 0;
+ vhci_hcd->re_timeout = 0;
}
- if ((dum->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) !=
- 0 && time_after(jiffies, dum->re_timeout)) {
- dum->port_status[rhport] |=
- (1 << USB_PORT_FEAT_C_RESET);
- dum->port_status[rhport] &=
- ~(1 << USB_PORT_FEAT_RESET);
- dum->re_timeout = 0;
+ if ((vhci_hcd->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) !=
+ 0 && time_after(jiffies, vhci_hcd->re_timeout)) {
+ vhci_hcd->port_status[rhport] |= (1 << USB_PORT_FEAT_C_RESET);
+ vhci_hcd->port_status[rhport] &= ~(1 << USB_PORT_FEAT_RESET);
+ vhci_hcd->re_timeout = 0;
- if (dum->vdev[rhport].ud.status ==
+ if (vhci_hcd->vdev[rhport].ud.status ==
VDEV_ST_NOTASSIGNED) {
usbip_dbg_vhci_rh(
" enable rhport %d (status %u)\n",
rhport,
- dum->vdev[rhport].ud.status);
- dum->port_status[rhport] |=
+ vhci_hcd->vdev[rhport].ud.status);
+ vhci_hcd->port_status[rhport] |=
USB_PORT_STAT_ENABLE;
}
+
+ if (hcd->speed < HCD_USB3) {
+ switch (vhci_hcd->vdev[rhport].speed) {
+ case USB_SPEED_HIGH:
+ vhci_hcd->port_status[rhport] |=
+ USB_PORT_STAT_HIGH_SPEED;
+ break;
+ case USB_SPEED_LOW:
+ vhci_hcd->port_status[rhport] |=
+ USB_PORT_STAT_LOW_SPEED;
+ break;
+ default:
+ pr_err("vhci_device speed not set\n");
+ break;
+ }
+ }
}
- ((__le16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]);
+ ((__le16 *) buf)[0] = cpu_to_le16(vhci_hcd->port_status[rhport]);
((__le16 *) buf)[1] =
- cpu_to_le16(dum->port_status[rhport] >> 16);
+ cpu_to_le16(vhci_hcd->port_status[rhport] >> 16);
usbip_dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0],
((u16 *)buf)[1]);
@@ -381,36 +489,119 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case SetPortFeature:
switch (wValue) {
+ case USB_PORT_FEAT_LINK_STATE:
+ usbip_dbg_vhci_rh(
+ " SetPortFeature: USB_PORT_FEAT_LINK_STATE\n");
+ if (hcd->speed != HCD_USB3) {
+ pr_err("USB_PORT_FEAT_LINK_STATE req not "
+ "supported for USB 2.0 roothub\n");
+ goto error;
+ }
+ /*
+ * Since this is dummy we don't have an actual link so
+ * there is nothing to do for the SET_LINK_STATE cmd
+ */
+ break;
+ case USB_PORT_FEAT_U1_TIMEOUT:
+ usbip_dbg_vhci_rh(
+ " SetPortFeature: USB_PORT_FEAT_U1_TIMEOUT\n");
+ case USB_PORT_FEAT_U2_TIMEOUT:
+ usbip_dbg_vhci_rh(
+ " SetPortFeature: USB_PORT_FEAT_U2_TIMEOUT\n");
+ /* TODO: add suspend/resume support! */
+ if (hcd->speed != HCD_USB3) {
+ pr_err("USB_PORT_FEAT_U1/2_TIMEOUT req not "
+ "supported for USB 2.0 roothub\n");
+ goto error;
+ }
+ break;
case USB_PORT_FEAT_SUSPEND:
usbip_dbg_vhci_rh(
" SetPortFeature: USB_PORT_FEAT_SUSPEND\n");
+ /* Applicable only for USB2.0 hub */
+ if (hcd->speed == HCD_USB3) {
+ pr_err("USB_PORT_FEAT_SUSPEND req not "
+ "supported for USB 3.0 roothub\n");
+ goto error;
+ }
+
+ vhci_hcd->port_status[rhport] |= USB_PORT_STAT_SUSPEND;
break;
+ case USB_PORT_FEAT_POWER:
+ usbip_dbg_vhci_rh(
+ " SetPortFeature: USB_PORT_FEAT_POWER\n");
+ if (hcd->speed == HCD_USB3)
+ vhci_hcd->port_status[rhport] |= USB_SS_PORT_STAT_POWER;
+ else
+ vhci_hcd->port_status[rhport] |= USB_PORT_STAT_POWER;
+ break;
+ case USB_PORT_FEAT_BH_PORT_RESET:
+ usbip_dbg_vhci_rh(
+ " SetPortFeature: USB_PORT_FEAT_BH_PORT_RESET\n");
+ /* Applicable only for USB3.0 hub */
+ if (hcd->speed != HCD_USB3) {
+ pr_err("USB_PORT_FEAT_BH_PORT_RESET req not "
+ "supported for USB 2.0 roothub\n");
+ goto error;
+ }
+ /* FALLS THROUGH */
case USB_PORT_FEAT_RESET:
usbip_dbg_vhci_rh(
" SetPortFeature: USB_PORT_FEAT_RESET\n");
- /* if it's already running, disconnect first */
- if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) {
- dum->port_status[rhport] &=
- ~(USB_PORT_STAT_ENABLE |
- USB_PORT_STAT_LOW_SPEED |
- USB_PORT_STAT_HIGH_SPEED);
- /* FIXME test that code path! */
+ /* if it's already enabled, disable */
+ if (hcd->speed == HCD_USB3) {
+ vhci_hcd->port_status[rhport] = 0;
+ vhci_hcd->port_status[rhport] =
+ (USB_SS_PORT_STAT_POWER |
+ USB_PORT_STAT_CONNECTION |
+ USB_PORT_STAT_RESET);
+ } else if (vhci_hcd->port_status[rhport] & USB_PORT_STAT_ENABLE) {
+ vhci_hcd->port_status[rhport] &= ~(USB_PORT_STAT_ENABLE
+ | USB_PORT_STAT_LOW_SPEED
+ | USB_PORT_STAT_HIGH_SPEED);
}
+
/* 50msec reset signaling */
- dum->re_timeout = jiffies + msecs_to_jiffies(50);
+ vhci_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
- /* FALLTHROUGH */
+ /* FALLS THROUGH */
default:
usbip_dbg_vhci_rh(" SetPortFeature: default %d\n",
wValue);
- dum->port_status[rhport] |= (1 << wValue);
- break;
+ if (hcd->speed == HCD_USB3) {
+ if ((vhci_hcd->port_status[rhport] &
+ USB_SS_PORT_STAT_POWER) != 0) {
+ vhci_hcd->port_status[rhport] |= (1 << wValue);
+ }
+ } else
+ if ((vhci_hcd->port_status[rhport] &
+ USB_PORT_STAT_POWER) != 0) {
+ vhci_hcd->port_status[rhport] |= (1 << wValue);
+ }
+ }
+ break;
+ case GetPortErrorCount:
+ usbip_dbg_vhci_rh(" GetPortErrorCount\n");
+ if (hcd->speed != HCD_USB3) {
+ pr_err("GetPortErrorCount req not "
+ "supported for USB 2.0 roothub\n");
+ goto error;
+ }
+ /* We'll always return 0 since this is a dummy hub */
+ *(__le32 *) buf = cpu_to_le32(0);
+ break;
+ case SetHubDepth:
+ usbip_dbg_vhci_rh(" SetHubDepth\n");
+ if (hcd->speed != HCD_USB3) {
+ pr_err("SetHubDepth req not supported for "
+ "USB 2.0 roothub\n");
+ goto error;
}
break;
-
default:
- pr_err("default: no such request\n");
-
+ pr_err("default hub control req: %04x v%04x i%04x l%d\n",
+ typeReq, wValue, wIndex, wLength);
+error:
/* "protocol stall" on error */
retval = -EPIPE;
}
@@ -420,12 +611,16 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/* Only dump valid port status */
if (rhport >= 0) {
dump_port_status_diff(prev_port_status[rhport],
- dum->port_status[rhport]);
+ vhci_hcd->port_status[rhport],
+ hcd->speed == HCD_USB3);
}
}
usbip_dbg_vhci_rh(" bye\n");
- spin_unlock_irqrestore(&dum->lock, flags);
+ spin_unlock_irqrestore(&vhci->lock, flags);
+
+ if ((vhci_hcd->port_status[rhport] & PORT_C_MASK) != 0)
+ usb_hcd_poll_rh_status(hcd);
return retval;
}
@@ -433,14 +628,14 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
static void vhci_tx_urb(struct urb *urb, struct vhci_device *vdev)
{
struct vhci_priv *priv;
- struct vhci_hcd *vhci;
+ struct vhci_hcd *vhci_hcd;
unsigned long flags;
if (!vdev) {
pr_err("could not get virtual device");
return;
}
- vhci = vdev_to_vhci(vdev);
+ vhci_hcd = vdev_to_vhci_hcd(vdev);
priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC);
if (!priv) {
@@ -450,7 +645,7 @@ static void vhci_tx_urb(struct urb *urb, struct vhci_device *vdev)
spin_lock_irqsave(&vdev->priv_lock, flags);
- priv->seqnum = atomic_inc_return(&vhci->seqnum);
+ priv->seqnum = atomic_inc_return(&vhci_hcd->seqnum);
if (priv->seqnum == 0xffff)
dev_info(&urb->dev->dev, "seqnum max\n");
@@ -465,10 +660,10 @@ static void vhci_tx_urb(struct urb *urb, struct vhci_device *vdev)
spin_unlock_irqrestore(&vdev->priv_lock, flags);
}
-static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
- gfp_t mem_flags)
+static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
{
- struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ struct vhci_hcd *vhci_hcd = hcd_to_vhci_hcd(hcd);
+ struct vhci *vhci = vhci_hcd->vhci;
struct device *dev = &urb->dev->dev;
u8 portnum = urb->dev->portnum;
int ret = 0;
@@ -482,7 +677,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
pr_err("invalid port number %d\n", portnum);
return -ENODEV;
}
- vdev = &vhci->vdev[portnum-1];
+ vdev = &vhci_hcd->vdev[portnum-1];
/* patch to usb_sg_init() is in 2.5.60 */
BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
@@ -635,7 +830,8 @@ no_need_unlink:
*/
static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
- struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ struct vhci_hcd *vhci_hcd = hcd_to_vhci_hcd(hcd);
+ struct vhci *vhci = vhci_hcd->vhci;
struct vhci_priv *priv;
struct vhci_device *vdev;
unsigned long flags;
@@ -686,7 +882,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock_irqrestore(&vhci->lock, flags);
- usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status);
+ usb_hcd_giveback_urb(hcd, urb, urb->status);
spin_lock_irqsave(&vhci->lock, flags);
} else {
@@ -704,7 +900,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
return -ENOMEM;
}
- unlink->seqnum = atomic_inc_return(&vhci->seqnum);
+ unlink->seqnum = atomic_inc_return(&vhci_hcd->seqnum);
if (unlink->seqnum == 0xffff)
pr_info("seqnum max\n");
@@ -728,8 +924,9 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
{
- struct vhci_hcd *vhci = vdev_to_vhci(vdev);
- struct usb_hcd *hcd = vhci_to_hcd(vhci);
+ struct vhci_hcd *vhci_hcd = vdev_to_vhci_hcd(vdev);
+ struct usb_hcd *hcd = vhci_hcd_to_hcd(vhci_hcd);
+ struct vhci *vhci = vhci_hcd->vhci;
struct vhci_unlink *unlink, *tmp;
unsigned long flags;
@@ -841,7 +1038,6 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
pr_info("disconnect device\n");
}
-
static void vhci_device_reset(struct usbip_device *ud)
{
struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
@@ -913,29 +1109,58 @@ static int hcd_name_to_id(const char *name)
return val;
}
+static int vhci_setup(struct usb_hcd *hcd)
+{
+ struct vhci *vhci = *((void **)dev_get_platdata(hcd->self.controller));
+ hcd->self.sg_tablesize = ~0;
+ if (usb_hcd_is_primary_hcd(hcd)) {
+ vhci->vhci_hcd_hs = hcd_to_vhci_hcd(hcd);
+ vhci->vhci_hcd_hs->vhci = vhci;
+ /*
+ * Mark the first roothub as being USB 2.0.
+ * The USB 3.0 roothub will be registered later by
+ * vhci_hcd_probe()
+ */
+ hcd->speed = HCD_USB2;
+ hcd->self.root_hub->speed = USB_SPEED_HIGH;
+ } else {
+ vhci->vhci_hcd_ss = hcd_to_vhci_hcd(hcd);
+ vhci->vhci_hcd_ss->vhci = vhci;
+ hcd->speed = HCD_USB3;
+ hcd->self.root_hub->speed = USB_SPEED_SUPER;
+ }
+ return 0;
+}
+
static int vhci_start(struct usb_hcd *hcd)
{
- struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ struct vhci_hcd *vhci_hcd = hcd_to_vhci_hcd(hcd);
int id, rhport;
- int err = 0;
+ int err;
usbip_dbg_vhci_hc("enter vhci_start\n");
+ if (usb_hcd_is_primary_hcd(hcd))
+ spin_lock_init(&vhci_hcd->vhci->lock);
+
/* initialize private data of usb_hcd */
for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) {
- struct vhci_device *vdev = &vhci->vdev[rhport];
+ struct vhci_device *vdev = &vhci_hcd->vdev[rhport];
vhci_device_init(vdev);
vdev->rhport = rhport;
}
- atomic_set(&vhci->seqnum, 0);
- spin_lock_init(&vhci->lock);
+ atomic_set(&vhci_hcd->seqnum, 0);
hcd->power_budget = 0; /* no limit */
hcd->uses_new_polling = 1;
+#ifdef CONFIG_USB_OTG
+ hcd->self.otg_port = 1;
+#endif
+
id = hcd_name_to_id(hcd_name(hcd));
if (id < 0) {
pr_err("invalid vhci name %s\n", hcd_name(hcd));
@@ -943,7 +1168,7 @@ static int vhci_start(struct usb_hcd *hcd)
}
/* vhci_hcd is now ready to be controlled through sysfs */
- if (id == 0) {
+ if (id == 0 && usb_hcd_is_primary_hcd(hcd)) {
err = vhci_init_attr_group();
if (err) {
pr_err("init attr group\n");
@@ -963,21 +1188,21 @@ static int vhci_start(struct usb_hcd *hcd)
static void vhci_stop(struct usb_hcd *hcd)
{
- struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ struct vhci_hcd *vhci_hcd = hcd_to_vhci_hcd(hcd);
int id, rhport;
usbip_dbg_vhci_hc("stop VHCI controller\n");
/* 1. remove the userland interface of vhci_hcd */
id = hcd_name_to_id(hcd_name(hcd));
- if (id == 0) {
+ if (id == 0 && usb_hcd_is_primary_hcd(hcd)) {
sysfs_remove_group(&hcd_dev(hcd)->kobj, &vhci_attr_group);
vhci_finish_attr_group();
}
/* 2. shutdown all the ports of vhci_hcd */
for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) {
- struct vhci_device *vdev = &vhci->vdev[rhport];
+ struct vhci_device *vdev = &vhci_hcd->vdev[rhport];
usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED);
usbip_stop_eh(&vdev->ud);
@@ -995,7 +1220,7 @@ static int vhci_get_frame_number(struct usb_hcd *hcd)
/* FIXME: suspend/resume */
static int vhci_bus_suspend(struct usb_hcd *hcd)
{
- struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ struct vhci *vhci = *((void **)dev_get_platdata(hcd->self.controller));
unsigned long flags;
dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
@@ -1009,7 +1234,7 @@ static int vhci_bus_suspend(struct usb_hcd *hcd)
static int vhci_bus_resume(struct usb_hcd *hcd)
{
- struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ struct vhci *vhci = *((void **)dev_get_platdata(hcd->self.controller));
int rc = 0;
unsigned long flags;
@@ -1031,13 +1256,32 @@ static int vhci_bus_resume(struct usb_hcd *hcd)
#define vhci_bus_resume NULL
#endif
+/* Change a group of bulk endpoints to support multiple stream IDs */
+static int vhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint **eps, unsigned int num_eps,
+ unsigned int num_streams, gfp_t mem_flags)
+{
+ dev_dbg(&hcd->self.root_hub->dev, "vhci_alloc_streams not implemented\n");
+ return 0;
+}
+
+/* Reverts a group of bulk endpoints back to not using stream IDs. */
+static int vhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint **eps, unsigned int num_eps,
+ gfp_t mem_flags)
+{
+ dev_dbg(&hcd->self.root_hub->dev, "vhci_free_streams not implemented\n");
+ return 0;
+}
+
static struct hc_driver vhci_hc_driver = {
.description = driver_name,
.product_desc = driver_desc,
.hcd_priv_size = sizeof(struct vhci_hcd),
- .flags = HCD_USB2,
+ .flags = HCD_USB3 | HCD_SHARED,
+ .reset = vhci_setup,
.start = vhci_start,
.stop = vhci_stop,
@@ -1050,11 +1294,16 @@ static struct hc_driver vhci_hc_driver = {
.hub_control = vhci_hub_control,
.bus_suspend = vhci_bus_suspend,
.bus_resume = vhci_bus_resume,
+
+ .alloc_streams = vhci_alloc_streams,
+ .free_streams = vhci_free_streams,
};
static int vhci_hcd_probe(struct platform_device *pdev)
{
- struct usb_hcd *hcd;
+ struct vhci *vhci;
+ struct usb_hcd *hcd_hs;
+ struct usb_hcd *hcd_ss;
int ret;
usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id);
@@ -1063,43 +1312,68 @@ static int vhci_hcd_probe(struct platform_device *pdev)
* Allocate and initialize hcd.
* Our private data is also allocated automatically.
*/
- hcd = usb_create_hcd(&vhci_hc_driver, &pdev->dev, dev_name(&pdev->dev));
- if (!hcd) {
- pr_err("create hcd failed\n");
+ hcd_hs = usb_create_hcd(&vhci_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd_hs) {
+ pr_err("create primary hcd failed\n");
return -ENOMEM;
}
- hcd->has_tt = 1;
+ hcd_hs->has_tt = 1;
/*
* Finish generic HCD structure initialization and register.
* Call the driver's reset() and start() routines.
*/
- ret = usb_add_hcd(hcd, 0, 0);
+ ret = usb_add_hcd(hcd_hs, 0, 0);
if (ret != 0) {
- pr_err("usb_add_hcd failed %d\n", ret);
- usb_put_hcd(hcd);
- return ret;
+ pr_err("usb_add_hcd hs failed %d\n", ret);
+ goto put_usb2_hcd;
+ }
+
+ hcd_ss = usb_create_shared_hcd(&vhci_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev), hcd_hs);
+ if (!hcd_ss) {
+ ret = -ENOMEM;
+ pr_err("create shared hcd failed\n");
+ goto remove_usb2_hcd;
+ }
+
+ ret = usb_add_hcd(hcd_ss, 0, 0);
+ if (ret) {
+ pr_err("usb_add_hcd ss failed %d\n", ret);
+ goto put_usb3_hcd;
}
usbip_dbg_vhci_hc("bye\n");
return 0;
+
+put_usb3_hcd:
+ usb_put_hcd(hcd_ss);
+remove_usb2_hcd:
+ usb_remove_hcd(hcd_hs);
+put_usb2_hcd:
+ usb_put_hcd(hcd_hs);
+ vhci->vhci_hcd_hs = NULL;
+ vhci->vhci_hcd_ss = NULL;
+ return ret;
}
static int vhci_hcd_remove(struct platform_device *pdev)
{
- struct usb_hcd *hcd;
-
- hcd = platform_get_drvdata(pdev);
- if (!hcd)
- return 0;
+ struct vhci *vhci = *((void **)dev_get_platdata(&pdev->dev));
/*
* Disconnects the root hub,
* then reverses the effects of usb_add_hcd(),
* invoking the HCD's stop() methods.
*/
- usb_remove_hcd(hcd);
- usb_put_hcd(hcd);
+ usb_remove_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_ss));
+ usb_put_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_ss));
+
+ usb_remove_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_hs));
+ usb_put_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_hs));
+
+ vhci->vhci_hcd_hs = NULL;
+ vhci->vhci_hcd_ss = NULL;
return 0;
}
@@ -1110,23 +1384,32 @@ static int vhci_hcd_remove(struct platform_device *pdev)
static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
{
struct usb_hcd *hcd;
- struct vhci_hcd *vhci;
+ struct vhci *vhci;
int rhport;
int connected = 0;
int ret = 0;
unsigned long flags;
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+
hcd = platform_get_drvdata(pdev);
if (!hcd)
return 0;
- vhci = hcd_to_vhci(hcd);
+
+ vhci = *((void **)dev_get_platdata(hcd->self.controller));
spin_lock_irqsave(&vhci->lock, flags);
- for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++)
- if (vhci->port_status[rhport] & USB_PORT_STAT_CONNECTION)
+ for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) {
+ if (vhci->vhci_hcd_hs->port_status[rhport] &
+ USB_PORT_STAT_CONNECTION)
connected += 1;
+ if (vhci->vhci_hcd_ss->port_status[rhport] &
+ USB_PORT_STAT_CONNECTION)
+ connected += 1;
+ }
+
spin_unlock_irqrestore(&vhci->lock, flags);
if (connected > 0) {
@@ -1174,34 +1457,16 @@ static struct platform_driver vhci_driver = {
},
};
-static int add_platform_device(int id)
-{
- struct platform_device *pdev;
- int dev_nr;
-
- if (id == 0)
- dev_nr = -1;
- else
- dev_nr = id;
-
- pdev = platform_device_register_simple(driver_name, dev_nr, NULL, 0);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
-
- *(vhci_pdevs + id) = pdev;
- return 0;
-}
-
static void del_platform_devices(void)
{
struct platform_device *pdev;
int i;
for (i = 0; i < vhci_num_controllers; i++) {
- pdev = *(vhci_pdevs + i);
+ pdev = vhcis[i].pdev;
if (pdev != NULL)
platform_device_unregister(pdev);
- *(vhci_pdevs + i) = NULL;
+ vhcis[i].pdev = NULL;
}
sysfs_remove_link(&platform_bus.kobj, driver_name);
}
@@ -1216,28 +1481,51 @@ static int __init vhci_hcd_init(void)
if (vhci_num_controllers < 1)
vhci_num_controllers = 1;
- vhci_pdevs = kcalloc(vhci_num_controllers, sizeof(void *), GFP_KERNEL);
- if (vhci_pdevs == NULL)
+ vhcis = kcalloc(vhci_num_controllers, sizeof(struct vhci), GFP_KERNEL);
+ if (vhcis == NULL)
return -ENOMEM;
+ for (i = 0; i < vhci_num_controllers; i++) {
+ vhcis[i].pdev = platform_device_alloc(driver_name, i);
+ if (!vhcis[i].pdev) {
+ i--;
+ while (i >= 0)
+ platform_device_put(vhcis[i--].pdev);
+ ret = -ENOMEM;
+ goto err_device_alloc;
+ }
+ }
+ for (i = 0; i < vhci_num_controllers; i++) {
+ void *vhci = &vhcis[i];
+ ret = platform_device_add_data(vhcis[i].pdev, &vhci, sizeof(void *));
+ if (ret)
+ goto err_driver_register;
+ }
+
ret = platform_driver_register(&vhci_driver);
if (ret)
goto err_driver_register;
for (i = 0; i < vhci_num_controllers; i++) {
- ret = add_platform_device(i);
- if (ret)
- goto err_platform_device_register;
+ ret = platform_device_add(vhcis[i].pdev);
+ if (ret < 0) {
+ i--;
+ while (i >= 0)
+ platform_device_del(vhcis[i--].pdev);
+ goto err_add_hcd;
+ }
}
pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
return ret;
-err_platform_device_register:
- del_platform_devices();
+err_add_hcd:
platform_driver_unregister(&vhci_driver);
err_driver_register:
- kfree(vhci_pdevs);
+ for (i = 0; i < vhci_num_controllers; i++)
+ platform_device_put(vhcis[i].pdev);
+err_device_alloc:
+ kfree(vhcis);
return ret;
}
@@ -1245,7 +1533,7 @@ static void __exit vhci_hcd_exit(void)
{
del_platform_devices();
platform_driver_unregister(&vhci_driver);
- kfree(vhci_pdevs);
+ kfree(vhcis);
}
module_init(vhci_hcd_init);
diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c
index fc2d319e2360..ef2f2d5ca6b2 100644
--- a/drivers/usb/usbip/vhci_rx.c
+++ b/drivers/usb/usbip/vhci_rx.c
@@ -70,7 +70,8 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum)
static void vhci_recv_ret_submit(struct vhci_device *vdev,
struct usbip_header *pdu)
{
- struct vhci_hcd *vhci = vdev_to_vhci(vdev);
+ struct vhci_hcd *vhci_hcd = vdev_to_vhci_hcd(vdev);
+ struct vhci *vhci = vhci_hcd->vhci;
struct usbip_device *ud = &vdev->ud;
struct urb *urb;
unsigned long flags;
@@ -82,7 +83,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
if (!urb) {
pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
pr_info("max seqnum %d\n",
- atomic_read(&vhci->seqnum));
+ atomic_read(&vhci_hcd->seqnum));
usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
return;
}
@@ -107,10 +108,10 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
spin_lock_irqsave(&vhci->lock, flags);
- usb_hcd_unlink_urb_from_ep(vhci_to_hcd(vhci), urb);
+ usb_hcd_unlink_urb_from_ep(vhci_hcd_to_hcd(vhci_hcd), urb);
spin_unlock_irqrestore(&vhci->lock, flags);
- usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status);
+ usb_hcd_giveback_urb(vhci_hcd_to_hcd(vhci_hcd), urb, urb->status);
usbip_dbg_vhci_rx("Leave\n");
}
@@ -143,7 +144,8 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
static void vhci_recv_ret_unlink(struct vhci_device *vdev,
struct usbip_header *pdu)
{
- struct vhci_hcd *vhci = vdev_to_vhci(vdev);
+ struct vhci_hcd *vhci_hcd = vdev_to_vhci_hcd(vdev);
+ struct vhci *vhci = vhci_hcd->vhci;
struct vhci_unlink *unlink;
struct urb *urb;
unsigned long flags;
@@ -177,10 +179,10 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
pr_info("urb->status %d\n", urb->status);
spin_lock_irqsave(&vhci->lock, flags);
- usb_hcd_unlink_urb_from_ep(vhci_to_hcd(vhci), urb);
+ usb_hcd_unlink_urb_from_ep(vhci_hcd_to_hcd(vhci_hcd), urb);
spin_unlock_irqrestore(&vhci->lock, flags);
- usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status);
+ usb_hcd_giveback_urb(vhci_hcd_to_hcd(vhci_hcd), urb, urb->status);
}
kfree(unlink);
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
index b96e5b189269..5778b640ba9c 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -29,13 +29,51 @@
/* TODO: refine locking ?*/
+/*
+ * output example:
+ * hub port sta spd dev socket local_busid
+ * hs 0000 004 000 00000000 c5a7bb80 1-2.3
+ * ................................................
+ * ss 0008 004 000 00000000 d8cee980 2-3.4
+ * ................................................
+ *
+ * IP address can be retrieved from a socket pointer address by looking
+ * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
+ * port number and its peer IP address.
+ */
+static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vdev)
+{
+ if (hub == HUB_SPEED_HIGH)
+ *out += sprintf(*out, "hs %04u %03u ",
+ port, vdev->ud.status);
+ else /* hub == HUB_SPEED_SUPER */
+ *out += sprintf(*out, "ss %04u %03u ",
+ port, vdev->ud.status);
+
+ if (vdev->ud.status == VDEV_ST_USED) {
+ *out += sprintf(*out, "%03u %08x ",
+ vdev->speed, vdev->devid);
+ *out += sprintf(*out, "%16p %s",
+ vdev->ud.tcp_socket,
+ dev_name(&vdev->udev->dev));
+
+ } else {
+ *out += sprintf(*out, "000 00000000 ");
+ *out += sprintf(*out, "0000000000000000 0-0");
+ }
+
+ *out += sprintf(*out, "\n");
+}
+
/* Sysfs entry to show port status */
static ssize_t status_show_vhci(int pdev_nr, char *out)
{
- struct platform_device *pdev = *(vhci_pdevs + pdev_nr);
- struct vhci_hcd *vhci;
+ struct platform_device *pdev = vhcis[pdev_nr].pdev;
+ struct vhci *vhci;
+ struct usb_hcd *hcd;
+ struct vhci_hcd *vhci_hcd;
char *s = out;
- int i = 0;
+ int i;
unsigned long flags;
if (!pdev || !out) {
@@ -43,41 +81,27 @@ static ssize_t status_show_vhci(int pdev_nr, char *out)
return 0;
}
- vhci = hcd_to_vhci(platform_get_drvdata(pdev));
+ hcd = platform_get_drvdata(pdev);
+ vhci_hcd = hcd_to_vhci_hcd(hcd);
+ vhci = vhci_hcd->vhci;
spin_lock_irqsave(&vhci->lock, flags);
- /*
- * output example:
- * port sta spd dev socket local_busid
- * 0000 004 000 00000000 c5a7bb80 1-2.3
- * 0001 004 000 00000000 d8cee980 2-3.4
- *
- * IP address can be retrieved from a socket pointer address by looking
- * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
- * port number and its peer IP address.
- */
for (i = 0; i < VHCI_HC_PORTS; i++) {
- struct vhci_device *vdev = &vhci->vdev[i];
+ struct vhci_device *vdev = &vhci->vhci_hcd_hs->vdev[i];
spin_lock(&vdev->ud.lock);
- out += sprintf(out, "%04u %03u ",
- (pdev_nr * VHCI_HC_PORTS) + i,
- vdev->ud.status);
-
- if (vdev->ud.status == VDEV_ST_USED) {
- out += sprintf(out, "%03u %08x ",
- vdev->speed, vdev->devid);
- out += sprintf(out, "%16p %s",
- vdev->ud.tcp_socket,
- dev_name(&vdev->udev->dev));
-
- } else {
- out += sprintf(out, "000 00000000 ");
- out += sprintf(out, "0000000000000000 0-0");
- }
+ port_show_vhci(&out, HUB_SPEED_HIGH,
+ pdev_nr * VHCI_PORTS + i, vdev);
+ spin_unlock(&vdev->ud.lock);
+ }
- out += sprintf(out, "\n");
+ for (i = 0; i < VHCI_HC_PORTS; i++) {
+ struct vhci_device *vdev = &vhci->vhci_hcd_ss->vdev[i];
+
+ spin_lock(&vdev->ud.lock);
+ port_show_vhci(&out, HUB_SPEED_SUPER,
+ pdev_nr * VHCI_PORTS + VHCI_HC_PORTS + i, vdev);
spin_unlock(&vdev->ud.lock);
}
@@ -92,8 +116,16 @@ static ssize_t status_show_not_ready(int pdev_nr, char *out)
int i = 0;
for (i = 0; i < VHCI_HC_PORTS; i++) {
- out += sprintf(out, "%04u %03u ",
- (pdev_nr * VHCI_HC_PORTS) + i,
+ out += sprintf(out, "hs %04u %03u ",
+ (pdev_nr * VHCI_PORTS) + i,
+ VDEV_ST_NOTASSIGNED);
+ out += sprintf(out, "000 00000000 0000000000000000 0-0");
+ out += sprintf(out, "\n");
+ }
+
+ for (i = 0; i < VHCI_HC_PORTS; i++) {
+ out += sprintf(out, "ss %04u %03u ",
+ (pdev_nr * VHCI_PORTS) + VHCI_HC_PORTS + i,
VDEV_ST_NOTASSIGNED);
out += sprintf(out, "000 00000000 0000000000000000 0-0");
out += sprintf(out, "\n");
@@ -125,7 +157,7 @@ static ssize_t status_show(struct device *dev,
int pdev_nr;
out += sprintf(out,
- "port sta spd dev socket local_busid\n");
+ "hub port sta spd dev socket local_busid\n");
pdev_nr = status_name_to_id(attr->attr.name);
if (pdev_nr < 0)
@@ -141,15 +173,19 @@ static ssize_t nports_show(struct device *dev, struct device_attribute *attr,
{
char *s = out;
- out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers);
+ /*
+ * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, thus the * 2.
+ */
+ out += sprintf(out, "%d\n", VHCI_PORTS * vhci_num_controllers);
return out - s;
}
static DEVICE_ATTR_RO(nports);
/* Sysfs entry to shutdown a virtual connection */
-static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport)
+static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)
{
- struct vhci_device *vdev = &vhci->vdev[rhport];
+ struct vhci_device *vdev = &vhci_hcd->vdev[rhport];
+ struct vhci *vhci = vhci_hcd->vhci;
unsigned long flags;
usbip_dbg_vhci_sysfs("enter\n");
@@ -195,6 +231,7 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
{
__u32 port = 0, pdev_nr = 0, rhport = 0;
struct usb_hcd *hcd;
+ struct vhci_hcd *vhci_hcd;
int ret;
if (kstrtoint(buf, 10, &port) < 0)
@@ -206,13 +243,20 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
if (!valid_port(pdev_nr, rhport))
return -EINVAL;
- hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
+ hcd = platform_get_drvdata(vhcis[pdev_nr].pdev);
if (hcd == NULL) {
dev_err(dev, "port is not ready %u\n", port);
return -EAGAIN;
}
- ret = vhci_port_disconnect(hcd_to_vhci(hcd), rhport);
+ usbip_dbg_vhci_sysfs("rhport %d\n", rhport);
+
+ if ((port / VHCI_HC_PORTS) % 2)
+ vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_ss;
+ else
+ vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_hs;
+
+ ret = vhci_port_disconnect(vhci_hcd, rhport);
if (ret < 0)
return -EINVAL;
@@ -233,6 +277,7 @@ static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed)
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
case USB_SPEED_WIRELESS:
+ case USB_SPEED_SUPER:
break;
default:
pr_err("Failed attach request for unsupported USB speed: %s\n",
@@ -262,8 +307,9 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
int sockfd = 0;
__u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0;
struct usb_hcd *hcd;
- struct vhci_hcd *vhci;
+ struct vhci_hcd *vhci_hcd;
struct vhci_device *vdev;
+ struct vhci *vhci;
int err;
unsigned long flags;
@@ -287,13 +333,19 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
if (!valid_args(pdev_nr, rhport, speed))
return -EINVAL;
- hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
+ hcd = platform_get_drvdata(vhcis[pdev_nr].pdev);
if (hcd == NULL) {
dev_err(dev, "port %d is not ready\n", port);
return -EAGAIN;
}
- vhci = hcd_to_vhci(hcd);
- vdev = &vhci->vdev[rhport];
+
+ vhci_hcd = hcd_to_vhci_hcd(hcd);
+ vhci = vhci_hcd->vhci;
+
+ if (speed == USB_SPEED_SUPER)
+ vdev = &vhci->vhci_hcd_ss->vdev[rhport];
+ else
+ vdev = &vhci->vhci_hcd_hs->vdev[rhport];
/* Extract socket from fd. */
socket = sockfd_lookup(sockfd, &err);