summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-dbg.c4
-rw-r--r--drivers/usb/host/ehci-pci.c9
-rw-r--r--drivers/usb/host/ehci-platform.c3
-rw-r--r--drivers/usb/host/ehci-q.c7
-rw-r--r--drivers/usb/host/ehci-sched.c4
-rw-r--r--drivers/usb/host/fotg210-hcd.c4
-rw-r--r--drivers/usb/host/ohci-dbg.c4
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c2
-rw-r--r--drivers/usb/host/xen-hcd.c61
-rw-r--r--drivers/usb/host/xhci-dbgcap.c145
-rw-r--r--drivers/usb/host/xhci-dbgcap.h26
-rw-r--r--drivers/usb/host/xhci-dbgtty.c86
-rw-r--r--drivers/usb/host/xhci-hub.c5
-rw-r--r--drivers/usb/host/xhci-mem.c22
-rw-r--r--drivers/usb/host/xhci-mtk-sch.c7
-rw-r--r--drivers/usb/host/xhci-mtk.c81
-rw-r--r--drivers/usb/host/xhci-mtk.h5
-rw-r--r--drivers/usb/host/xhci-plat.c13
-rw-r--r--drivers/usb/host/xhci-rcar.c2
-rw-r--r--drivers/usb/host/xhci.c65
-rw-r--r--drivers/usb/host/xhci.h16
21 files changed, 321 insertions, 250 deletions
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 0b7f1edd9eec..c063fb042926 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -931,7 +931,7 @@ static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
static int fill_buffer(struct debug_buffer *buf)
{
- int ret = 0;
+ int ret;
if (!buf->output_buf)
buf->output_buf = vmalloc(buf->alloc_size);
@@ -956,7 +956,7 @@ static ssize_t debug_output(struct file *file, char __user *user_buf,
size_t len, loff_t *offset)
{
struct debug_buffer *buf = file->private_data;
- int ret = 0;
+ int ret;
mutex_lock(&buf->mutex);
if (buf->count == 0) {
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index e87cf3a00fa4..638f03b89739 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -21,6 +21,9 @@ static const char hcd_name[] = "ehci-pci";
/* defined here to avoid adding to pci_ids.h for single instance use */
#define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70
+#define PCI_VENDOR_ID_ASPEED 0x1a03
+#define PCI_DEVICE_ID_ASPEED_EHCI 0x2603
+
/*-------------------------------------------------------------------------*/
#define PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC 0x0939
static inline bool is_intel_quark_x1000(struct pci_dev *pdev)
@@ -222,6 +225,12 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
ehci->has_synopsys_hc_bug = 1;
}
break;
+ case PCI_VENDOR_ID_ASPEED:
+ if (pdev->device == PCI_DEVICE_ID_ASPEED_EHCI) {
+ ehci_info(ehci, "applying Aspeed HC workaround\n");
+ ehci->is_aspeed = 1;
+ }
+ break;
}
/* optional debug port, normally in the first BAR */
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index c3dc906274d9..1115431a255d 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -43,7 +43,6 @@
#define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
#define BCM_USB_FIFO_THRESHOLD 0x00800040
-#define bcm_iproc_insnreg01 hostpc[0]
struct ehci_platform_priv {
struct clk *clks[EHCI_MAX_CLKS];
@@ -81,7 +80,7 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
if (of_device_is_compatible(pdev->dev.of_node, "brcm,xgs-iproc-ehci"))
ehci_writel(ehci, BCM_USB_FIFO_THRESHOLD,
- &ehci->regs->bcm_iproc_insnreg01);
+ &ehci->regs->brcm_insnreg[1]);
return 0;
}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 2cbf4f85bff3..a2a5c2996350 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -33,12 +33,13 @@
/* fill a qtd, returning how much of the buffer we were able to queue up */
-static int
+static unsigned int
qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf,
size_t len, int token, int maxpacket)
{
- int i, count;
+ unsigned int count;
u64 addr = buf;
+ int i;
/* one buffer entry per 4K ... first might be short or unaligned */
qtd->hw_buf[0] = cpu_to_hc32(ehci, (u32)addr);
@@ -652,7 +653,7 @@ qh_urb_transaction (
* and may serve as a control status ack
*/
for (;;) {
- int this_qtd_len;
+ unsigned int this_qtd_len;
this_qtd_len = qtd_fill(ehci, qtd, buf, this_sg_len, token,
maxpacket);
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 0f85aa9b2fb1..bd542b6fc46b 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1165,10 +1165,8 @@ static struct ehci_iso_sched *
iso_sched_alloc(unsigned packets, gfp_t mem_flags)
{
struct ehci_iso_sched *iso_sched;
- int size = sizeof(*iso_sched);
- size += packets * sizeof(struct ehci_iso_packet);
- iso_sched = kzalloc(size, mem_flags);
+ iso_sched = kzalloc(struct_size(iso_sched, packet, packets), mem_flags);
if (likely(iso_sched != NULL))
INIT_LIST_HEAD(&iso_sched->td_list);
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index 7af17c8e069b..c3fd375b4778 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -4014,10 +4014,8 @@ static struct fotg210_iso_sched *iso_sched_alloc(unsigned packets,
gfp_t mem_flags)
{
struct fotg210_iso_sched *iso_sched;
- int size = sizeof(*iso_sched);
- size += packets * sizeof(struct fotg210_iso_packet);
- iso_sched = kzalloc(size, mem_flags);
+ iso_sched = kzalloc(struct_size(iso_sched, packet, packets), mem_flags);
if (likely(iso_sched != NULL))
INIT_LIST_HEAD(&iso_sched->td_list);
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 4f267dc93882..76bc8d56325d 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -680,7 +680,7 @@ static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci,
static int fill_buffer(struct debug_buffer *buf)
{
- int ret = 0;
+ int ret;
if (!buf->page)
buf->page = (char *)get_zeroed_page(GFP_KERNEL);
@@ -705,7 +705,7 @@ static ssize_t debug_output(struct file *file, char __user *user_buf,
size_t len, loff_t *offset)
{
struct debug_buffer *buf = file->private_data;
- int ret = 0;
+ int ret;
mutex_lock(&buf->mutex);
if (buf->count == 0) {
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index e82ff2a49672..b741670525e3 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -1685,7 +1685,7 @@ static struct list_head *qh_urb_transaction(struct oxu_hcd *oxu,
token |= (1 /* "in" */ << 8);
/* else it's already initted to "out" pid (0 << 8) */
- maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, !is_input);
/*
* buffer gets wrapped in one or more qtds;
diff --git a/drivers/usb/host/xen-hcd.c b/drivers/usb/host/xen-hcd.c
index 19b8c7ed74cb..210f91bf661c 100644
--- a/drivers/usb/host/xen-hcd.c
+++ b/drivers/usb/host/xen-hcd.c
@@ -51,6 +51,7 @@ struct vdevice_status {
struct usb_shadow {
struct xenusb_urb_request req;
struct urb *urb;
+ bool in_flight;
};
struct xenhcd_info {
@@ -589,14 +590,12 @@ static void xenhcd_gnttab_map(struct xenhcd_info *info, void *addr, int length,
int nr_pages, int flags)
{
grant_ref_t ref;
- unsigned long buffer_mfn;
unsigned int offset;
unsigned int len = length;
unsigned int bytes;
int i;
for (i = 0; i < nr_pages; i++) {
- buffer_mfn = PFN_DOWN(arbitrary_virt_to_machine(addr).maddr);
offset = offset_in_page(addr);
bytes = PAGE_SIZE - offset;
@@ -605,7 +604,7 @@ static void xenhcd_gnttab_map(struct xenhcd_info *info, void *addr, int length,
ref = gnttab_claim_grant_reference(gref_head);
gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id,
- buffer_mfn, flags);
+ virt_to_gfn(addr), flags);
seg[i].gref = ref;
seg[i].offset = (__u16)offset;
seg[i].length = (__u16)bytes;
@@ -722,6 +721,12 @@ static void xenhcd_gnttab_done(struct xenhcd_info *info, unsigned int id)
int nr_segs = 0;
int i;
+ if (!shadow->in_flight) {
+ xenhcd_set_error(info, "Illegal request id");
+ return;
+ }
+ shadow->in_flight = false;
+
nr_segs = shadow->req.nr_buffer_segs;
if (xenusb_pipeisoc(shadow->req.pipe))
@@ -805,6 +810,7 @@ static int xenhcd_do_request(struct xenhcd_info *info, struct urb_priv *urbp)
info->urb_ring.req_prod_pvt++;
info->shadow[id].urb = urb;
+ info->shadow[id].in_flight = true;
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->urb_ring, notify);
if (notify)
@@ -933,10 +939,27 @@ static int xenhcd_unlink_urb(struct xenhcd_info *info, struct urb_priv *urbp)
return ret;
}
-static int xenhcd_urb_request_done(struct xenhcd_info *info)
+static void xenhcd_res_to_urb(struct xenhcd_info *info,
+ struct xenusb_urb_response *res, struct urb *urb)
+{
+ if (unlikely(!urb))
+ return;
+
+ if (res->actual_length > urb->transfer_buffer_length)
+ urb->actual_length = urb->transfer_buffer_length;
+ else if (res->actual_length < 0)
+ urb->actual_length = 0;
+ else
+ urb->actual_length = res->actual_length;
+ urb->error_count = res->error_count;
+ urb->start_frame = res->start_frame;
+ xenhcd_giveback_urb(info, urb, res->status);
+}
+
+static int xenhcd_urb_request_done(struct xenhcd_info *info,
+ unsigned int *eoiflag)
{
struct xenusb_urb_response res;
- struct urb *urb;
RING_IDX i, rp;
__u16 id;
int more_to_do = 0;
@@ -963,16 +986,12 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
xenhcd_gnttab_done(info, id);
if (info->error)
goto err;
- urb = info->shadow[id].urb;
- if (likely(urb)) {
- urb->actual_length = res.actual_length;
- urb->error_count = res.error_count;
- urb->start_frame = res.start_frame;
- xenhcd_giveback_urb(info, urb, res.status);
- }
+ xenhcd_res_to_urb(info, &res, info->shadow[id].urb);
}
xenhcd_add_id_to_freelist(info, id);
+
+ *eoiflag = 0;
}
info->urb_ring.rsp_cons = i;
@@ -990,7 +1009,7 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
return 0;
}
-static int xenhcd_conn_notify(struct xenhcd_info *info)
+static int xenhcd_conn_notify(struct xenhcd_info *info, unsigned int *eoiflag)
{
struct xenusb_conn_response res;
struct xenusb_conn_request *req;
@@ -1035,6 +1054,8 @@ static int xenhcd_conn_notify(struct xenhcd_info *info)
info->conn_ring.req_prod_pvt);
req->id = id;
info->conn_ring.req_prod_pvt++;
+
+ *eoiflag = 0;
}
if (rc != info->conn_ring.req_prod_pvt)
@@ -1057,14 +1078,19 @@ static int xenhcd_conn_notify(struct xenhcd_info *info)
static irqreturn_t xenhcd_int(int irq, void *dev_id)
{
struct xenhcd_info *info = (struct xenhcd_info *)dev_id;
+ unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
- if (unlikely(info->error))
+ if (unlikely(info->error)) {
+ xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
return IRQ_HANDLED;
+ }
- while (xenhcd_urb_request_done(info) | xenhcd_conn_notify(info))
+ while (xenhcd_urb_request_done(info, &eoiflag) |
+ xenhcd_conn_notify(info, &eoiflag))
/* Yield point for this unbounded loop. */
cond_resched();
+ xen_irq_lateeoi(irq, eoiflag);
return IRQ_HANDLED;
}
@@ -1141,9 +1167,9 @@ static int xenhcd_setup_rings(struct xenbus_device *dev,
goto fail;
}
- err = bind_evtchn_to_irq(info->evtchn);
+ err = bind_evtchn_to_irq_lateeoi(info->evtchn);
if (err <= 0) {
- xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq");
+ xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq_lateeoi");
goto fail;
}
@@ -1496,6 +1522,7 @@ static struct usb_hcd *xenhcd_create_hcd(struct xenbus_device *dev)
for (i = 0; i < XENUSB_URB_RING_SIZE; i++) {
info->shadow[i].req.id = i + 1;
info->shadow[i].urb = NULL;
+ info->shadow[i].in_flight = false;
}
info->shadow[XENUSB_URB_RING_SIZE - 1].req.id = 0x0fff;
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index ccb0156fcebe..e61155fa6379 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -914,59 +914,6 @@ static void xhci_dbc_handle_events(struct work_struct *work)
mod_delayed_work(system_wq, &dbc->event_work, 1);
}
-static void xhci_do_dbc_exit(struct xhci_hcd *xhci)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&xhci->lock, flags);
- kfree(xhci->dbc);
- xhci->dbc = NULL;
- spin_unlock_irqrestore(&xhci->lock, flags);
-}
-
-static int xhci_do_dbc_init(struct xhci_hcd *xhci)
-{
- u32 reg;
- struct xhci_dbc *dbc;
- unsigned long flags;
- void __iomem *base;
- int dbc_cap_offs;
-
- base = &xhci->cap_regs->hc_capbase;
- dbc_cap_offs = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_DEBUG);
- if (!dbc_cap_offs)
- return -ENODEV;
-
- dbc = kzalloc(sizeof(*dbc), GFP_KERNEL);
- if (!dbc)
- return -ENOMEM;
-
- dbc->regs = base + dbc_cap_offs;
-
- /* We will avoid using DbC in xhci driver if it's in use. */
- reg = readl(&dbc->regs->control);
- if (reg & DBC_CTRL_DBC_ENABLE) {
- kfree(dbc);
- return -EBUSY;
- }
-
- spin_lock_irqsave(&xhci->lock, flags);
- if (xhci->dbc) {
- spin_unlock_irqrestore(&xhci->lock, flags);
- kfree(dbc);
- return -EBUSY;
- }
- xhci->dbc = dbc;
- spin_unlock_irqrestore(&xhci->lock, flags);
-
- dbc->xhci = xhci;
- dbc->dev = xhci_to_hcd(xhci)->self.sysdev;
- INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events);
- spin_lock_init(&dbc->lock);
-
- return 0;
-}
-
static ssize_t dbc_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1026,44 +973,86 @@ static ssize_t dbc_store(struct device *dev,
static DEVICE_ATTR_RW(dbc);
-int xhci_dbc_init(struct xhci_hcd *xhci)
+struct xhci_dbc *
+xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *driver)
{
+ struct xhci_dbc *dbc;
int ret;
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
- ret = xhci_do_dbc_init(xhci);
- if (ret)
- goto init_err3;
+ dbc = kzalloc(sizeof(*dbc), GFP_KERNEL);
+ if (!dbc)
+ return NULL;
- ret = xhci_dbc_tty_probe(xhci);
- if (ret)
- goto init_err2;
+ dbc->regs = base;
+ dbc->dev = dev;
+ dbc->driver = driver;
+
+ if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE)
+ return NULL;
+
+ INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events);
+ spin_lock_init(&dbc->lock);
ret = device_create_file(dev, &dev_attr_dbc);
if (ret)
- goto init_err1;
+ goto err;
- return 0;
+ return dbc;
+err:
+ kfree(dbc);
+ return NULL;
+}
+
+/* undo what xhci_alloc_dbc() did */
+void xhci_dbc_remove(struct xhci_dbc *dbc)
+{
+ if (!dbc)
+ return;
+ /* stop hw, stop wq and call dbc->ops->stop() */
+ xhci_dbc_stop(dbc);
+
+ /* remove sysfs files */
+ device_remove_file(dbc->dev, &dev_attr_dbc);
+
+ kfree(dbc);
+}
+
+
+int xhci_create_dbc_dev(struct xhci_hcd *xhci)
+{
+ struct device *dev;
+ void __iomem *base;
+ int ret;
+ int dbc_cap_offs;
+
+ /* create all parameters needed resembling a dbc device */
+ dev = xhci_to_hcd(xhci)->self.controller;
+ base = &xhci->cap_regs->hc_capbase;
+
+ dbc_cap_offs = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_DEBUG);
+ if (!dbc_cap_offs)
+ return -ENODEV;
+
+ /* already allocated and in use */
+ if (xhci->dbc)
+ return -EBUSY;
+
+ ret = xhci_dbc_tty_probe(dev, base + dbc_cap_offs, xhci);
-init_err1:
- xhci_dbc_tty_remove(xhci->dbc);
-init_err2:
- xhci_do_dbc_exit(xhci);
-init_err3:
return ret;
}
-void xhci_dbc_exit(struct xhci_hcd *xhci)
+void xhci_remove_dbc_dev(struct xhci_hcd *xhci)
{
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ unsigned long flags;
if (!xhci->dbc)
return;
- device_remove_file(dev, &dev_attr_dbc);
xhci_dbc_tty_remove(xhci->dbc);
- xhci_dbc_stop(xhci->dbc);
- xhci_do_dbc_exit(xhci);
+ spin_lock_irqsave(&xhci->lock, flags);
+ xhci->dbc = NULL;
+ spin_unlock_irqrestore(&xhci->lock, flags);
}
#ifdef CONFIG_PM
@@ -1098,3 +1087,13 @@ int xhci_dbc_resume(struct xhci_hcd *xhci)
return ret;
}
#endif /* CONFIG_PM */
+
+int xhci_dbc_init(void)
+{
+ return dbc_tty_init();
+}
+
+void xhci_dbc_exit(void)
+{
+ dbc_tty_exit();
+}
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index c70b78d504eb..ca04192fdab1 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h
@@ -100,6 +100,7 @@ struct dbc_ep {
struct dbc_port {
struct tty_port port;
spinlock_t port_lock; /* port access */
+ int minor;
struct list_head read_pool;
struct list_head read_queue;
@@ -194,10 +195,17 @@ static inline struct dbc_ep *get_out_ep(struct xhci_dbc *dbc)
}
#ifdef CONFIG_USB_XHCI_DBGCAP
-int xhci_dbc_init(struct xhci_hcd *xhci);
-void xhci_dbc_exit(struct xhci_hcd *xhci);
-int xhci_dbc_tty_probe(struct xhci_hcd *xhci);
+int xhci_create_dbc_dev(struct xhci_hcd *xhci);
+void xhci_remove_dbc_dev(struct xhci_hcd *xhci);
+int xhci_dbc_init(void);
+void xhci_dbc_exit(void);
+int dbc_tty_init(void);
+void dbc_tty_exit(void);
+int xhci_dbc_tty_probe(struct device *dev, void __iomem *res, struct xhci_hcd *xhci);
void xhci_dbc_tty_remove(struct xhci_dbc *dbc);
+struct xhci_dbc *xhci_alloc_dbc(struct device *dev, void __iomem *res,
+ const struct dbc_driver *driver);
+void xhci_dbc_remove(struct xhci_dbc *dbc);
struct dbc_request *dbc_alloc_request(struct xhci_dbc *dbc,
unsigned int direction,
gfp_t flags);
@@ -208,15 +216,21 @@ int xhci_dbc_suspend(struct xhci_hcd *xhci);
int xhci_dbc_resume(struct xhci_hcd *xhci);
#endif /* CONFIG_PM */
#else
-static inline int xhci_dbc_init(struct xhci_hcd *xhci)
+static inline int xhci_create_dbc_dev(struct xhci_hcd *xhci)
{
return 0;
}
-static inline void xhci_dbc_exit(struct xhci_hcd *xhci)
+static inline void xhci_remove_dbc_dev(struct xhci_hcd *xhci)
+{
+}
+static inline int xhci_dbc_init(void)
+{
+ return 0;
+}
+static inline void xhci_dbc_exit(void)
{
}
-
static inline int xhci_dbc_suspend(struct xhci_hcd *xhci)
{
return 0;
diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c
index eb46e642e87a..d3acc0829ee5 100644
--- a/drivers/usb/host/xhci-dbgtty.c
+++ b/drivers/usb/host/xhci-dbgtty.c
@@ -10,14 +10,14 @@
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/idr.h>
#include "xhci.h"
#include "xhci-dbgcap.h"
-static int dbc_tty_init(void);
-static void dbc_tty_exit(void);
-
static struct tty_driver *dbc_tty_driver;
+static struct idr dbc_tty_minors;
+static DEFINE_MUTEX(dbc_tty_minors_lock);
static inline struct dbc_port *dbc_to_port(struct xhci_dbc *dbc)
{
@@ -180,7 +180,14 @@ xhci_dbc_free_requests(struct list_head *head)
static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
- struct dbc_port *port = driver->driver_state;
+ struct dbc_port *port;
+
+ mutex_lock(&dbc_tty_minors_lock);
+ port = idr_find(&dbc_tty_minors, tty->index);
+ mutex_unlock(&dbc_tty_minors_lock);
+
+ if (!port)
+ return -ENXIO;
tty->driver_data = port;
@@ -409,6 +416,15 @@ static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc)
xhci_dbc_tty_init_port(dbc, port);
+ mutex_lock(&dbc_tty_minors_lock);
+ port->minor = idr_alloc(&dbc_tty_minors, port, 0, 64, GFP_KERNEL);
+ mutex_unlock(&dbc_tty_minors_lock);
+
+ if (port->minor < 0) {
+ ret = port->minor;
+ goto err_idr;
+ }
+
ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL);
if (ret)
goto err_exit_port;
@@ -424,7 +440,7 @@ static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc)
goto err_free_requests;
tty_dev = tty_port_register_device(&port->port,
- dbc_tty_driver, 0, NULL);
+ dbc_tty_driver, port->minor, NULL);
if (IS_ERR(tty_dev)) {
ret = PTR_ERR(tty_dev);
goto err_free_requests;
@@ -440,6 +456,8 @@ err_free_requests:
err_free_fifo:
kfifo_free(&port->write_fifo);
err_exit_port:
+ idr_remove(&dbc_tty_minors, port->minor);
+err_idr:
xhci_dbc_tty_exit_port(port);
dev_err(dbc->dev, "can't register tty port, err %d\n", ret);
@@ -453,10 +471,14 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
if (!port->registered)
return;
- tty_unregister_device(dbc_tty_driver, 0);
+ tty_unregister_device(dbc_tty_driver, port->minor);
xhci_dbc_tty_exit_port(port);
port->registered = false;
+ mutex_lock(&dbc_tty_minors_lock);
+ idr_remove(&dbc_tty_minors, port->minor);
+ mutex_unlock(&dbc_tty_minors_lock);
+
kfifo_free(&port->write_fifo);
xhci_dbc_free_requests(&port->read_pool);
xhci_dbc_free_requests(&port->read_queue);
@@ -468,33 +490,35 @@ static const struct dbc_driver dbc_driver = {
.disconnect = xhci_dbc_tty_unregister_device,
};
-int xhci_dbc_tty_probe(struct xhci_hcd *xhci)
+int xhci_dbc_tty_probe(struct device *dev, void __iomem *base, struct xhci_hcd *xhci)
{
- struct xhci_dbc *dbc = xhci->dbc;
+ struct xhci_dbc *dbc;
struct dbc_port *port;
int status;
- /* dbc_tty_init will be called by module init() in the future */
- status = dbc_tty_init();
- if (status)
- return status;
+ if (!dbc_tty_driver)
+ return -ENODEV;
port = kzalloc(sizeof(*port), GFP_KERNEL);
- if (!port) {
+ if (!port)
+ return -ENOMEM;
+
+ dbc = xhci_alloc_dbc(dev, base, &dbc_driver);
+
+ if (!dbc) {
status = -ENOMEM;
- goto out;
+ goto out2;
}
- dbc->driver = &dbc_driver;
dbc->priv = port;
-
- dbc_tty_driver->driver_state = port;
+ /* get rid of xhci once this is a real driver binding to a device */
+ xhci->dbc = dbc;
return 0;
-out:
- /* dbc_tty_exit will be called by module_exit() in the future */
- dbc_tty_exit();
+out2:
+ kfree(port);
+
return status;
}
@@ -506,22 +530,22 @@ void xhci_dbc_tty_remove(struct xhci_dbc *dbc)
{
struct dbc_port *port = dbc_to_port(dbc);
- dbc->driver = NULL;
- dbc->priv = NULL;
+ xhci_dbc_remove(dbc);
kfree(port);
-
- /* dbc_tty_exit will be called by module_exit() in the future */
- dbc_tty_exit();
}
-static int dbc_tty_init(void)
+int dbc_tty_init(void)
{
int ret;
- dbc_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW |
+ idr_init(&dbc_tty_minors);
+
+ dbc_tty_driver = tty_alloc_driver(64, TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
- if (IS_ERR(dbc_tty_driver))
+ if (IS_ERR(dbc_tty_driver)) {
+ idr_destroy(&dbc_tty_minors);
return PTR_ERR(dbc_tty_driver);
+ }
dbc_tty_driver->driver_name = "dbc_serial";
dbc_tty_driver->name = "ttyDBC";
@@ -540,15 +564,19 @@ static int dbc_tty_init(void)
if (ret) {
pr_err("Can't register dbc tty driver\n");
tty_driver_kref_put(dbc_tty_driver);
+ idr_destroy(&dbc_tty_minors);
}
+
return ret;
}
-static void dbc_tty_exit(void)
+void dbc_tty_exit(void)
{
if (dbc_tty_driver) {
tty_unregister_driver(dbc_tty_driver);
tty_driver_kref_put(dbc_tty_driver);
dbc_tty_driver = NULL;
}
+
+ idr_destroy(&dbc_tty_minors);
}
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index df3522dab31b..1e7dc130c39a 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -762,7 +762,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
}
pm_runtime_allow(xhci_to_hcd(xhci)->self.controller);
xhci->test_mode = 0;
- return xhci_reset(xhci);
+ return xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
}
void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
@@ -1088,6 +1088,9 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
if (link_state == XDEV_U2)
*status |= USB_PORT_STAT_L1;
if (link_state == XDEV_U0) {
+ if (bus_state->resume_done[portnum])
+ usb_hcd_end_port_resume(&port->rhub->hcd->self,
+ portnum);
bus_state->resume_done[portnum] = 0;
clear_bit(portnum, &bus_state->resuming_ports);
if (bus_state->suspended_ports & (1 << portnum)) {
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 0e312066c5c6..bbb27ee2c6a3 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -57,7 +57,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
/* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
if (cycle_state == 0) {
for (i = 0; i < TRBS_PER_SEGMENT; i++)
- seg->trbs[i].link.control |= cpu_to_le32(TRB_CYCLE);
+ seg->trbs[i].link.control = cpu_to_le32(TRB_CYCLE);
}
seg->dma = dma;
seg->next = NULL;
@@ -433,8 +433,7 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
(TRBS_PER_SEGMENT - 1);
/* Allocate number of segments we needed, or double the ring size */
- num_segs = ring->num_segs > num_segs_needed ?
- ring->num_segs : num_segs_needed;
+ num_segs = max(ring->num_segs, num_segs_needed);
ret = xhci_alloc_segments_for_ring(xhci, &first, &last,
num_segs, ring->cycle_state, ring->type,
@@ -1846,9 +1845,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->event_ring = NULL;
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
- if (xhci->lpm_command)
- xhci_free_command(xhci, xhci->lpm_command);
- xhci->lpm_command = NULL;
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL;
@@ -2395,11 +2391,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
page_size = readl(&xhci->op_regs->page_size);
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Supported page size register = 0x%x", page_size);
- for (i = 0; i < 16; i++) {
- if ((0x1 & page_size) != 0)
- break;
- page_size = page_size >> 1;
- }
+ i = ffs(page_size);
if (i < 16)
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Supported page size of %iK", (1 << (i+12)) / 1024);
@@ -2425,7 +2417,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
writel(val, &xhci->op_regs->config_reg);
/*
- * xHCI section 5.4.6 - doorbell array must be
+ * xHCI section 5.4.6 - Device Context array must be
* "physically contiguous and 64-byte (cache line) aligned".
*/
xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
@@ -2488,10 +2480,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
"// Setting command ring address to 0x%016llx", val_64);
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
- xhci->lpm_command = xhci_alloc_command_with_ctx(xhci, true, flags);
- if (!xhci->lpm_command)
- goto fail;
-
/* Reserve one command ring TRB for disabling LPM.
* Since the USB core grabs the shared usb_bus bandwidth mutex before
* disabling LPM, we only need to reserve one TRB for all devices.
@@ -2583,7 +2571,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
fail:
xhci_halt(xhci);
- xhci_reset(xhci);
+ xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
xhci_mem_cleanup(xhci);
return -ENOMEM;
}
diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index edbfa82c6565..f3139ce7b0a9 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -248,7 +248,6 @@ create_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
struct mu3h_sch_bw_info *bw_info;
struct mu3h_sch_tt *tt = NULL;
u32 len_bw_budget_table;
- size_t mem_size;
bw_info = get_bw_info(mtk, udev, ep);
if (!bw_info)
@@ -262,9 +261,9 @@ create_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
else
len_bw_budget_table = 1;
- mem_size = sizeof(struct mu3h_sch_ep_info) +
- len_bw_budget_table * sizeof(u32);
- sch_ep = kzalloc(mem_size, GFP_KERNEL);
+ sch_ep = kzalloc(struct_size(sch_ep, bw_budget_table,
+ len_bw_budget_table),
+ GFP_KERNEL);
if (!sch_ep)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 91738af0ab14..b1045f534a4b 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -95,6 +95,19 @@
#define WC0_SSUSB0_CDEN BIT(6)
#define WC0_IS_SPM_EN BIT(1)
+/* mt8195 */
+#define PERI_WK_CTRL0_8195 0x04
+#define WC0_IS_P_95 BIT(30) /* polarity */
+#define WC0_IS_C_95(x) ((u32)(((x) & 0x7) << 27))
+#define WC0_IS_EN_P3_95 BIT(26)
+#define WC0_IS_EN_P2_95 BIT(25)
+#define WC0_IS_EN_P1_95 BIT(24)
+
+#define PERI_WK_CTRL1_8195 0x20
+#define WC1_IS_C_95(x) ((u32)(((x) & 0xf) << 28))
+#define WC1_IS_P_95 BIT(12)
+#define WC1_IS_EN_P0_95 BIT(6)
+
/* mt2712 etc */
#define PERI_SSUSB_SPM_CTRL 0x0
#define SSC_IP_SLEEP_EN BIT(4)
@@ -105,6 +118,10 @@ enum ssusb_uwk_vers {
SSUSB_UWK_V2,
SSUSB_UWK_V1_1 = 101, /* specific revision 1.01 */
SSUSB_UWK_V1_2, /* specific revision 1.2 */
+ SSUSB_UWK_V1_3, /* mt8195 IP0 */
+ SSUSB_UWK_V1_4, /* mt8195 IP1 */
+ SSUSB_UWK_V1_5, /* mt8195 IP2 */
+ SSUSB_UWK_V1_6, /* mt8195 IP3 */
};
/*
@@ -308,6 +325,26 @@ static void usb_wakeup_ip_sleep_set(struct xhci_hcd_mtk *mtk, bool enable)
msk = WC0_SSUSB0_CDEN | WC0_IS_SPM_EN;
val = enable ? msk : 0;
break;
+ case SSUSB_UWK_V1_3:
+ reg = mtk->uwk_reg_base + PERI_WK_CTRL1_8195;
+ msk = WC1_IS_EN_P0_95 | WC1_IS_C_95(0xf) | WC1_IS_P_95;
+ val = enable ? (WC1_IS_EN_P0_95 | WC1_IS_C_95(0x1)) : 0;
+ break;
+ case SSUSB_UWK_V1_4:
+ reg = mtk->uwk_reg_base + PERI_WK_CTRL0_8195;
+ msk = WC0_IS_EN_P1_95 | WC0_IS_C_95(0x7) | WC0_IS_P_95;
+ val = enable ? (WC0_IS_EN_P1_95 | WC0_IS_C_95(0x1)) : 0;
+ break;
+ case SSUSB_UWK_V1_5:
+ reg = mtk->uwk_reg_base + PERI_WK_CTRL0_8195;
+ msk = WC0_IS_EN_P2_95 | WC0_IS_C_95(0x7) | WC0_IS_P_95;
+ val = enable ? (WC0_IS_EN_P2_95 | WC0_IS_C_95(0x1)) : 0;
+ break;
+ case SSUSB_UWK_V1_6:
+ reg = mtk->uwk_reg_base + PERI_WK_CTRL0_8195;
+ msk = WC0_IS_EN_P3_95 | WC0_IS_C_95(0x7) | WC0_IS_P_95;
+ val = enable ? (WC0_IS_EN_P3_95 | WC0_IS_C_95(0x1)) : 0;
+ break;
case SSUSB_UWK_V2:
reg = mtk->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;
@@ -364,29 +401,14 @@ static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk)
return devm_clk_bulk_get_optional(mtk->dev, BULK_CLKS_NUM, clks);
}
-static int xhci_mtk_ldos_enable(struct xhci_hcd_mtk *mtk)
+static int xhci_mtk_vregs_get(struct xhci_hcd_mtk *mtk)
{
- int ret;
+ struct regulator_bulk_data *supplies = mtk->supplies;
- ret = regulator_enable(mtk->vbus);
- if (ret) {
- dev_err(mtk->dev, "failed to enable vbus\n");
- return ret;
- }
+ supplies[0].supply = "vbus";
+ supplies[1].supply = "vusb33";
- ret = regulator_enable(mtk->vusb33);
- if (ret) {
- dev_err(mtk->dev, "failed to enable vusb33\n");
- regulator_disable(mtk->vbus);
- return ret;
- }
- return 0;
-}
-
-static void xhci_mtk_ldos_disable(struct xhci_hcd_mtk *mtk)
-{
- regulator_disable(mtk->vbus);
- regulator_disable(mtk->vusb33);
+ return devm_regulator_bulk_get(mtk->dev, BULK_VREGS_NUM, supplies);
}
static void xhci_mtk_quirks(struct device *dev, struct xhci_hcd *xhci)
@@ -476,17 +498,10 @@ static int xhci_mtk_probe(struct platform_device *pdev)
return -ENOMEM;
mtk->dev = dev;
- mtk->vbus = devm_regulator_get(dev, "vbus");
- if (IS_ERR(mtk->vbus)) {
- dev_err(dev, "fail to get vbus\n");
- return PTR_ERR(mtk->vbus);
- }
- mtk->vusb33 = devm_regulator_get(dev, "vusb33");
- if (IS_ERR(mtk->vusb33)) {
- dev_err(dev, "fail to get vusb33\n");
- return PTR_ERR(mtk->vusb33);
- }
+ ret = xhci_mtk_vregs_get(mtk);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
ret = xhci_mtk_clks_get(mtk);
if (ret)
@@ -527,7 +542,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
- ret = xhci_mtk_ldos_enable(mtk);
+ ret = regulator_bulk_enable(BULK_VREGS_NUM, mtk->supplies);
if (ret)
goto disable_pm;
@@ -636,7 +651,7 @@ disable_clk:
clk_bulk_disable_unprepare(BULK_CLKS_NUM, mtk->clks);
disable_ldos:
- xhci_mtk_ldos_disable(mtk);
+ regulator_bulk_disable(BULK_VREGS_NUM, mtk->supplies);
disable_pm:
pm_runtime_put_noidle(dev);
@@ -664,7 +679,7 @@ static int xhci_mtk_remove(struct platform_device *pdev)
usb_put_hcd(hcd);
xhci_mtk_sch_exit(mtk);
clk_bulk_disable_unprepare(BULK_CLKS_NUM, mtk->clks);
- xhci_mtk_ldos_disable(mtk);
+ regulator_bulk_disable(BULK_VREGS_NUM, mtk->supplies);
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index 4b1ea89f959a..ffd4b493b4ba 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -11,10 +11,12 @@
#include <linux/clk.h>
#include <linux/hashtable.h>
+#include <linux/regulator/consumer.h>
#include "xhci.h"
#define BULK_CLKS_NUM 5
+#define BULK_VREGS_NUM 2
/* support at most 64 ep, use 32 size hash table */
#define SCH_EP_HASH_BITS 5
@@ -150,9 +152,8 @@ struct xhci_hcd_mtk {
int num_u3_ports;
int u2p_dis_msk;
int u3p_dis_msk;
- struct regulator *vusb33;
- struct regulator *vbus;
struct clk_bulk_data clks[BULK_CLKS_NUM];
+ struct regulator_bulk_data supplies[BULK_VREGS_NUM];
unsigned int has_ippc:1;
unsigned int lpm_support:1;
unsigned int u2_lpm_disable:1;
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index dc570ce4e831..8094da34825e 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -226,20 +226,13 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (!sysdev)
sysdev = &pdev->dev;
- /* Try to set 64-bit DMA first */
if (WARN_ON(!sysdev->dma_mask))
/* Platform did not initialize dma_mask */
- ret = dma_coerce_mask_and_coherent(sysdev,
- DMA_BIT_MASK(64));
+ ret = dma_coerce_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
else
ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
-
- /* If seting 64-bit DMA mask fails, fall back to 32-bit DMA mask */
- if (ret) {
- ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
- }
+ if (ret)
+ return ret;
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index 9888ba7d85b6..aef0258a7160 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -82,7 +82,7 @@ static const struct soc_device_attribute rcar_quirks_match[] = {
.soc_id = "r8a7795", .revision = "ES1.*",
.data = (void *)RCAR_XHCI_FIRMWARE_V2,
},
- { /* sentinel */ },
+ { /* sentinel */ }
};
static void xhci_rcar_start_gen2(struct usb_hcd *hcd)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 2d378543bc3a..642610c78f58 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -65,7 +65,7 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
* handshake done). There are two failure modes: "usec" have passed (major
* hardware flakeout), or the register reads as all-ones (hardware removed).
*/
-int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
+int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us)
{
u32 result;
int ret;
@@ -73,7 +73,7 @@ int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
ret = readl_poll_timeout_atomic(ptr, result,
(result & mask) == done ||
result == U32_MAX,
- 1, usec);
+ 1, timeout_us);
if (result == U32_MAX) /* card removed */
return -ENODEV;
@@ -110,6 +110,7 @@ void xhci_quiesce(struct xhci_hcd *xhci)
int xhci_halt(struct xhci_hcd *xhci)
{
int ret;
+
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Halt the HC");
xhci_quiesce(xhci);
@@ -119,8 +120,10 @@ int xhci_halt(struct xhci_hcd *xhci)
xhci_warn(xhci, "Host halt failed, %d\n", ret);
return ret;
}
+
xhci->xhc_state |= XHCI_STATE_HALTED;
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
+
return ret;
}
@@ -162,7 +165,7 @@ int xhci_start(struct xhci_hcd *xhci)
* Transactions will be terminated immediately, and operational registers
* will be set to their defaults.
*/
-int xhci_reset(struct xhci_hcd *xhci)
+int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us)
{
u32 command;
u32 state;
@@ -195,8 +198,7 @@ int xhci_reset(struct xhci_hcd *xhci)
if (xhci->quirks & XHCI_INTEL_HOST)
udelay(1000);
- ret = xhci_handshake(&xhci->op_regs->command,
- CMD_RESET, 0, 10 * 1000 * 1000);
+ ret = xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, timeout_us);
if (ret)
return ret;
@@ -209,8 +211,7 @@ int xhci_reset(struct xhci_hcd *xhci)
* xHCI cannot write to any doorbells or operational registers other
* than status until the "Controller Not Ready" flag is cleared.
*/
- ret = xhci_handshake(&xhci->op_regs->status,
- STS_CNR, 0, 10 * 1000 * 1000);
+ ret = xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, timeout_us);
xhci->usb2_rhub.bus_state.port_c_suspend = 0;
xhci->usb2_rhub.bus_state.suspended_ports = 0;
@@ -324,7 +325,7 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
*/
static int xhci_setup_msix(struct xhci_hcd *xhci)
{
- int i, ret = 0;
+ int i, ret;
struct usb_hcd *hcd = xhci_to_hcd(xhci);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
@@ -578,7 +579,7 @@ static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci)
static int xhci_init(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- int retval = 0;
+ int retval;
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init");
spin_lock_init(&xhci->lock);
@@ -695,7 +696,7 @@ int xhci_run(struct usb_hcd *hcd)
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Finished xhci_run for USB2 roothub");
- xhci_dbc_init(xhci);
+ xhci_create_dbc_dev(xhci);
xhci_debugfs_init(xhci);
@@ -725,13 +726,13 @@ static void xhci_stop(struct usb_hcd *hcd)
return;
}
- xhci_dbc_exit(xhci);
+ xhci_remove_dbc_dev(xhci);
spin_lock_irq(&xhci->lock);
xhci->xhc_state |= XHCI_STATE_HALTED;
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
xhci_halt(xhci);
- xhci_reset(xhci);
+ xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
spin_unlock_irq(&xhci->lock);
xhci_cleanup_msix(xhci);
@@ -784,7 +785,7 @@ void xhci_shutdown(struct usb_hcd *hcd)
xhci_halt(xhci);
/* Workaround for spurious wakeups at shutdown with HSW */
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
- xhci_reset(xhci);
+ xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
spin_unlock_irq(&xhci->lock);
xhci_cleanup_msix(xhci);
@@ -1170,7 +1171,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
xhci_dbg(xhci, "Stop HCD\n");
xhci_halt(xhci);
xhci_zero_64b_regs(xhci);
- retval = xhci_reset(xhci);
+ retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC);
spin_unlock_irq(&xhci->lock);
if (retval)
return retval;
@@ -3160,8 +3161,6 @@ rescan:
ep_index = xhci_get_endpoint_index(&host_ep->desc);
ep = &vdev->eps[ep_index];
- if (!ep)
- goto done;
/* wait for hub_tt_work to finish clearing hub TT */
if (ep->ep_state & EP_CLEARING_TT) {
@@ -3219,8 +3218,6 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
return;
ep_index = xhci_get_endpoint_index(&host_ep->desc);
ep = &vdev->eps[ep_index];
- if (!ep)
- return;
/* Bail out if toggle is already being cleared by a endpoint reset */
spin_lock_irqsave(&xhci->lock, flags);
@@ -3978,7 +3975,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
struct xhci_command *command;
unsigned long flags;
u32 state;
- int ret = 0;
+ int ret;
command = xhci_alloc_command(xhci, true, GFP_KERNEL);
if (!command)
@@ -4014,7 +4011,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
xhci_free_command(xhci, command);
- return ret;
+ return 0;
}
/*
@@ -4354,6 +4351,10 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
unsigned long flags;
int ret;
+ command = xhci_alloc_command_with_ctx(xhci, true, GFP_KERNEL);
+ if (!command)
+ return -ENOMEM;
+
spin_lock_irqsave(&xhci->lock, flags);
virt_dev = xhci->devs[udev->slot_id];
@@ -4370,10 +4371,10 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
}
/* Attempt to issue an Evaluate Context command to change the MEL. */
- command = xhci->lpm_command;
ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
if (!ctrl_ctx) {
spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_free_command(xhci, command);
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
return -ENOMEM;
@@ -4400,6 +4401,9 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
virt_dev->current_mel = max_exit_latency;
spin_unlock_irqrestore(&xhci->lock, flags);
}
+
+ xhci_free_command(xhci, command);
+
return ret;
}
@@ -4520,18 +4524,8 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
exit_latency = xhci_besl_encoding[hird];
spin_unlock_irqrestore(&xhci->lock, flags);
- /* USB 3.0 code dedicate one xhci->lpm_command->in_ctx
- * input context for link powermanagement evaluate
- * context commands. It is protected by hcd->bandwidth
- * mutex and is shared by all devices. We need to set
- * the max ext latency in USB 2 BESL LPM as well, so
- * use the same mutex and xhci_change_max_exit_latency()
- */
- mutex_lock(hcd->bandwidth_mutex);
ret = xhci_change_max_exit_latency(xhci, udev,
exit_latency);
- mutex_unlock(hcd->bandwidth_mutex);
-
if (ret < 0)
return ret;
spin_lock_irqsave(&xhci->lock, flags);
@@ -4559,9 +4553,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
readl(pm_addr);
if (udev->usb2_hw_lpm_besl_capable) {
spin_unlock_irqrestore(&xhci->lock, flags);
- mutex_lock(hcd->bandwidth_mutex);
xhci_change_max_exit_latency(xhci, udev, 0);
- mutex_unlock(hcd->bandwidth_mutex);
readl_poll_timeout(ports[port_num]->addr, pm_val,
(pm_val & PORT_PLS_MASK) == XDEV_U0,
100, 10000);
@@ -5290,8 +5282,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
xhci->hcs_params1 = readl(&xhci->cap_regs->hcs_params1);
xhci->hcs_params2 = readl(&xhci->cap_regs->hcs_params2);
xhci->hcs_params3 = readl(&xhci->cap_regs->hcs_params3);
- xhci->hcc_params = readl(&xhci->cap_regs->hc_capbase);
- xhci->hci_version = HC_VERSION(xhci->hcc_params);
+ xhci->hci_version = HC_VERSION(readl(&xhci->cap_regs->hc_capbase));
xhci->hcc_params = readl(&xhci->cap_regs->hcc_params);
if (xhci->hci_version > 0x100)
xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
@@ -5316,7 +5307,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
xhci_dbg(xhci, "Resetting HCD\n");
/* Reset the internal HC memory state and registers. */
- retval = xhci_reset(xhci);
+ retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC);
if (retval)
return retval;
xhci_dbg(xhci, "Reset complete\n");
@@ -5505,6 +5496,7 @@ static int __init xhci_hcd_init(void)
return -ENODEV;
xhci_debugfs_create_root();
+ xhci_dbc_init();
return 0;
}
@@ -5516,6 +5508,7 @@ static int __init xhci_hcd_init(void)
static void __exit xhci_hcd_fini(void)
{
xhci_debugfs_remove_root();
+ xhci_dbc_exit();
}
module_init(xhci_hcd_init);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 5a75fe563123..473a33ce299e 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -229,6 +229,9 @@ struct xhci_op_regs {
#define CMD_ETE (1 << 14)
/* bits 15:31 are reserved (and should be preserved on writes). */
+#define XHCI_RESET_LONG_USEC (10 * 1000 * 1000)
+#define XHCI_RESET_SHORT_USEC (250 * 1000)
+
/* IMAN - Interrupt Management Register */
#define IMAN_IE (1 << 1)
#define IMAN_IP (1 << 0)
@@ -1812,8 +1815,6 @@ struct xhci_hcd {
/* slot enabling and address device helpers */
/* these are not thread safe so use mutex */
struct mutex mutex;
- /* For USB 3.0 LPM enable/disable. */
- struct xhci_command *lpm_command;
/* Internal mirror of the HW's dcbaa */
struct xhci_virt_device *devs[MAX_HC_SLOTS];
/* For keeping track of bandwidth domains per roothub. */
@@ -2083,11 +2084,11 @@ void xhci_free_container_ctx(struct xhci_hcd *xhci,
/* xHCI host controller glue */
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
-int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
+int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us);
void xhci_quiesce(struct xhci_hcd *xhci);
int xhci_halt(struct xhci_hcd *xhci);
int xhci_start(struct xhci_hcd *xhci);
-int xhci_reset(struct xhci_hcd *xhci);
+int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us);
int xhci_run(struct usb_hcd *hcd);
int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
void xhci_shutdown(struct usb_hcd *hcd);
@@ -2467,6 +2468,8 @@ static inline const char *xhci_decode_ctrl_ctx(char *str,
unsigned int bit;
int ret = 0;
+ str[0] = '\0';
+
if (drop) {
ret = sprintf(str, "Drop:");
for_each_set_bit(bit, &drop, 32)
@@ -2624,8 +2627,11 @@ static inline const char *xhci_decode_usbsts(char *str, u32 usbsts)
{
int ret = 0;
+ ret = sprintf(str, " 0x%08x", usbsts);
+
if (usbsts == ~(u32)0)
- return " 0xffffffff";
+ return str;
+
if (usbsts & STS_HALT)
ret += sprintf(str + ret, " HCHalted");
if (usbsts & STS_FATAL)