diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 09:40:49 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 09:40:49 -0800 |
commit | e4ee8b85b7657d9c769b727038faabdc2e6a3412 (patch) | |
tree | e6b52a1e866ed77b09b267f60f8f1b5449228325 /drivers/usb/host | |
parent | 7109a04eae81c41ed529da9f3c48c3655ccea741 (diff) | |
parent | d08dd3f3dd2ae351b793fc5b76abdbf0fd317b12 (diff) |
Merge tag 'usb-4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH:
"Here is the big USB and PHY driver update for 4.16-rc1.
Along with the normally expected XHCI, MUSB, and Gadget driver
patches, there are some PHY driver fixes, license cleanups, sysfs
attribute cleanups, usbip changes, and a raft of other smaller fixes
and additions.
Full details are in the shortlog.
All of these have been in the linux-next tree for a long time with no
reported issues"
* tag 'usb-4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (137 commits)
USB: serial: pl2303: new device id for Chilitag
USB: misc: fix up some remaining DEVICE_ATTR() usages
USB: musb: fix up one odd DEVICE_ATTR() usage
USB: atm: fix up some remaining DEVICE_ATTR() usage
USB: move many drivers to use DEVICE_ATTR_WO
USB: move many drivers to use DEVICE_ATTR_RO
USB: move many drivers to use DEVICE_ATTR_RW
USB: misc: chaoskey: Use true and false for boolean values
USB: storage: remove old wording about how to submit a change
USB: storage: remove invalid URL from drivers
usb: ehci-omap: don't complain on -EPROBE_DEFER when no PHY found
usbip: list: don't list devices attached to vhci_hcd
usbip: prevent bind loops on devices attached to vhci_hcd
USB: serial: remove redundant initializations of 'mos_parport'
usb/gadget: Fix "high bandwidth" check in usb_gadget_ep_match_desc()
usb: gadget: compress return logic into one line
usbip: vhci_hcd: update 'status' file header and format
USB: serial: simple: add Motorola Tetra driver
CDC-ACM: apply quirk for card reader
usb: option: Add support for FS040U modem
...
Diffstat (limited to 'drivers/usb/host')
25 files changed, 2050 insertions, 512 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index b80a94e632af..6150bed7cfa8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -27,6 +27,14 @@ config USB_XHCI_HCD module will be called xhci-hcd. if USB_XHCI_HCD +config USB_XHCI_DBGCAP + bool "xHCI support for debug capability" + depends on TTY + ---help--- + Say 'Y' to enable the support for the xHCI debug capability. Make + sure that your xHCI host supports the extended debug capability and + you want a TTY serial device based on the xHCI debug capability + before enabling this option. If unsure, say 'N'. config USB_XHCI_PCI tristate diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 32b036e2ffef..4ede4ce12366 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -14,6 +14,11 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o xhci-hcd-y := xhci.o xhci-mem.o xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o xhci-hcd-y += xhci-trace.o + +ifneq ($(CONFIG_USB_XHCI_DBGCAP), ) + xhci-hcd-y += xhci-dbgcap.o xhci-dbgtty.o +endif + ifneq ($(CONFIG_USB_XHCI_MTK), ) xhci-hcd-y += xhci-mtk-sch.o endif diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 854b146a457d..8d8bafc70c1f 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -167,7 +167,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) continue; ret = PTR_ERR(phy); - dev_err(dev, "Can't get PHY device for port %d: %d\n", + if (ret != -EPROBE_DEFER) + dev_err(dev, "Can't get PHY for port %d: %d\n", i, ret); goto err_phy; } diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c index 71fb61dd4a87..8f75cb7b197c 100644 --- a/drivers/usb/host/ehci-sysfs.c +++ b/drivers/usb/host/ehci-sysfs.c @@ -7,7 +7,7 @@ /* Display the ports dedicated to the companion controller */ -static ssize_t show_companion(struct device *dev, +static ssize_t companion_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -34,7 +34,7 @@ static ssize_t show_companion(struct device *dev, * Syntax is "[-]portnum", where a leading '-' sign means * return control of the port to the EHCI controller. */ -static ssize_t store_companion(struct device *dev, +static ssize_t companion_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -59,13 +59,13 @@ static ssize_t store_companion(struct device *dev, set_owner(ehci, portnum, new_owner); return count; } -static DEVICE_ATTR(companion, 0644, show_companion, store_companion); +static DEVICE_ATTR_RW(companion); /* * Display / Set uframe_periodic_max */ -static ssize_t show_uframe_periodic_max(struct device *dev, +static ssize_t uframe_periodic_max_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -78,7 +78,7 @@ static ssize_t show_uframe_periodic_max(struct device *dev, } -static ssize_t store_uframe_periodic_max(struct device *dev, +static ssize_t uframe_periodic_max_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -143,7 +143,7 @@ out_unlock: spin_unlock_irqrestore (&ehci->lock, flags); return ret; } -static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max); +static DEVICE_ATTR_RW(uframe_periodic_max); static inline int create_sysfs_files(struct ehci_hcd *ehci) diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 62fc955085a1..d8abf401918a 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -1865,11 +1865,9 @@ static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210, qh = kzalloc(sizeof(*qh), GFP_ATOMIC); if (!qh) goto done; - qh->hw = (struct fotg210_qh_hw *) - dma_pool_alloc(fotg210->qh_pool, flags, &dma); + qh->hw = dma_pool_zalloc(fotg210->qh_pool, flags, &dma); if (!qh->hw) goto fail; - memset(qh->hw, 0, sizeof(*qh->hw)); qh->qh_dma = dma; INIT_LIST_HEAD(&qh->qtd_list); @@ -4121,7 +4119,7 @@ static int itd_urb_transaction(struct fotg210_iso_stream *stream, } else { alloc_itd: spin_unlock_irqrestore(&fotg210->lock, flags); - itd = dma_pool_alloc(fotg210->itd_pool, mem_flags, + itd = dma_pool_zalloc(fotg210->itd_pool, mem_flags, &itd_dma); spin_lock_irqsave(&fotg210->lock, flags); if (!itd) { @@ -4131,7 +4129,6 @@ alloc_itd: } } - memset(itd, 0, sizeof(*itd)); itd->itd_dma = itd_dma; list_add(&itd->itd_list, &sched->td_list); } @@ -4696,7 +4693,7 @@ static void scan_isoc(struct fotg210_hcd *fotg210) /* Display / Set uframe_periodic_max */ -static ssize_t show_uframe_periodic_max(struct device *dev, +static ssize_t uframe_periodic_max_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fotg210_hcd *fotg210; @@ -4708,7 +4705,7 @@ static ssize_t show_uframe_periodic_max(struct device *dev, } -static ssize_t store_uframe_periodic_max(struct device *dev, +static ssize_t uframe_periodic_max_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct fotg210_hcd *fotg210; @@ -4775,8 +4772,7 @@ out_unlock: return ret; } -static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, - store_uframe_periodic_max); +static DEVICE_ATTR_RW(uframe_periodic_max); static inline int create_sysfs_files(struct fotg210_hcd *fotg210) { diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 0c507a0cfe1f..a55cbba40a5a 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -413,7 +413,7 @@ static int ohci_da8xx_probe(struct platform_device *pdev) da8xx_ohci = to_da8xx_ohci(hcd); da8xx_ohci->hcd = hcd; - da8xx_ohci->usb11_clk = devm_clk_get(&pdev->dev, "usb11"); + da8xx_ohci->usb11_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(da8xx_ohci->usb11_clk)) { error = PTR_ERR(da8xx_ohci->usb11_clk); if (error != -EPROBE_DEFER) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index f5c90217777a..f9c3947577fc 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -600,7 +600,7 @@ static int uhci_start(struct usb_hcd *hcd) uhci->dentry = dentry; #endif - uhci->frame = dma_alloc_coherent(uhci_dev(uhci), + uhci->frame = dma_zalloc_coherent(uhci_dev(uhci), UHCI_NUMFRAMES * sizeof(*uhci->frame), &uhci->frame_dma_handle, GFP_KERNEL); if (!uhci->frame) { @@ -608,7 +608,6 @@ static int uhci_start(struct usb_hcd *hcd) "unable to allocate consistent memory for frame list\n"); goto err_alloc_frame; } - memset(uhci->frame, 0, UHCI_NUMFRAMES * sizeof(*uhci->frame)); uhci->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu), GFP_KERNEL); diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index f1cc47292a59..7f9f33c8c232 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -4,6 +4,7 @@ #include <linux/list.h> #include <linux/usb.h> +#include <linux/clk.h> #define usb_packetid(pipe) (usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT) #define PIPE_DEVEP_MASK 0x0007ff00 @@ -447,6 +448,8 @@ struct uhci_hcd { int total_load; /* Sum of array values */ short load[MAX_PHASE]; /* Periodic allocations */ + struct clk *clk; /* (optional) clock source */ + /* Reset host controller */ void (*reset_hc) (struct uhci_hcd *uhci); int (*check_and_reset_hc) (struct uhci_hcd *uhci); diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index 6cb16d4b2257..89700e26fb29 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -89,6 +89,8 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) if (!hcd) return -ENOMEM; + uhci = hcd_to_uhci(hcd); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { @@ -98,8 +100,6 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - uhci = hcd_to_uhci(hcd); - uhci->regs = hcd->regs; /* Grab some things from the device-tree */ @@ -119,13 +119,28 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) "Enabled Aspeed implementation workarounds\n"); } } + + /* Get and enable clock if any specified */ + uhci->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(uhci->clk)) { + ret = PTR_ERR(uhci->clk); + goto err_rmr; + } + ret = clk_prepare_enable(uhci->clk); + if (ret) { + dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", ret); + goto err_rmr; + } + ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); if (ret) - goto err_rmr; + goto err_clk; device_wakeup_enable(hcd->self.controller); return 0; +err_clk: + clk_disable_unprepare(uhci->clk); err_rmr: usb_put_hcd(hcd); @@ -135,7 +150,9 @@ err_rmr: static int uhci_hcd_platform_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + clk_disable_unprepare(uhci->clk); usb_remove_hcd(hcd); usb_put_hcd(hcd); diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index d40438238938..35fcb826152c 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -73,8 +73,7 @@ static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb) { struct urb_priv *urbp = urb->hcpriv; - if (!(urb->transfer_flags & URB_NO_FSBR)) - urbp->fsbr = 1; + urbp->fsbr = 1; } static void uhci_urbp_wants_fsbr(struct uhci_hcd *uhci, struct urb_priv *urbp) diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index c5ac9efb076a..276fb34c8efd 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -90,9 +90,7 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) while (qset->ntds) { struct whc_qtd *td; - int t; - t = qset->td_start; td = &qset->qtd[qset->td_start]; status = le32_to_cpu(td->status); diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 584d7b9a3683..386abf26641d 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -10,267 +10,6 @@ #include "xhci.h" -#define XHCI_INIT_VALUE 0x0 - -/* Add verbose debugging later, just print everything for now */ - -void xhci_dbg_regs(struct xhci_hcd *xhci) -{ - u32 temp; - - xhci_dbg(xhci, "// xHCI capability registers at %p:\n", - xhci->cap_regs); - temp = readl(&xhci->cap_regs->hc_capbase); - xhci_dbg(xhci, "// @%p = 0x%x (CAPLENGTH AND HCIVERSION)\n", - &xhci->cap_regs->hc_capbase, temp); - xhci_dbg(xhci, "// CAPLENGTH: 0x%x\n", - (unsigned int) HC_LENGTH(temp)); - xhci_dbg(xhci, "// HCIVERSION: 0x%x\n", - (unsigned int) HC_VERSION(temp)); - - xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs); - - temp = readl(&xhci->cap_regs->run_regs_off); - xhci_dbg(xhci, "// @%p = 0x%x RTSOFF\n", - &xhci->cap_regs->run_regs_off, - (unsigned int) temp & RTSOFF_MASK); - xhci_dbg(xhci, "// xHCI runtime registers at %p:\n", xhci->run_regs); - - temp = readl(&xhci->cap_regs->db_off); - xhci_dbg(xhci, "// @%p = 0x%x DBOFF\n", &xhci->cap_regs->db_off, temp); - xhci_dbg(xhci, "// Doorbell array at %p:\n", xhci->dba); -} - -static void xhci_print_cap_regs(struct xhci_hcd *xhci) -{ - u32 temp; - u32 hci_version; - - xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs); - - temp = readl(&xhci->cap_regs->hc_capbase); - hci_version = HC_VERSION(temp); - xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n", - (unsigned int) temp); - xhci_dbg(xhci, "CAPLENGTH: 0x%x\n", - (unsigned int) HC_LENGTH(temp)); - xhci_dbg(xhci, "HCIVERSION: 0x%x\n", hci_version); - - temp = readl(&xhci->cap_regs->hcs_params1); - xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n", - (unsigned int) temp); - xhci_dbg(xhci, " Max device slots: %u\n", - (unsigned int) HCS_MAX_SLOTS(temp)); - xhci_dbg(xhci, " Max interrupters: %u\n", - (unsigned int) HCS_MAX_INTRS(temp)); - xhci_dbg(xhci, " Max ports: %u\n", - (unsigned int) HCS_MAX_PORTS(temp)); - - temp = readl(&xhci->cap_regs->hcs_params2); - xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n", - (unsigned int) temp); - xhci_dbg(xhci, " Isoc scheduling threshold: %u\n", - (unsigned int) HCS_IST(temp)); - xhci_dbg(xhci, " Maximum allowed segments in event ring: %u\n", - (unsigned int) HCS_ERST_MAX(temp)); - - temp = readl(&xhci->cap_regs->hcs_params3); - xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n", - (unsigned int) temp); - xhci_dbg(xhci, " Worst case U1 device exit latency: %u\n", - (unsigned int) HCS_U1_LATENCY(temp)); - xhci_dbg(xhci, " Worst case U2 device exit latency: %u\n", - (unsigned int) HCS_U2_LATENCY(temp)); - - temp = readl(&xhci->cap_regs->hcc_params); - xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp); - xhci_dbg(xhci, " HC generates %s bit addresses\n", - HCC_64BIT_ADDR(temp) ? "64" : "32"); - xhci_dbg(xhci, " HC %s Contiguous Frame ID Capability\n", - HCC_CFC(temp) ? "has" : "hasn't"); - xhci_dbg(xhci, " HC %s generate Stopped - Short Package event\n", - HCC_SPC(temp) ? "can" : "can't"); - /* FIXME */ - xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); - - temp = readl(&xhci->cap_regs->run_regs_off); - xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK); - - /* xhci 1.1 controllers have the HCCPARAMS2 register */ - if (hci_version > 0x100) { - temp = readl(&xhci->cap_regs->hcc_params2); - xhci_dbg(xhci, "HCC PARAMS2 0x%x:\n", (unsigned int) temp); - xhci_dbg(xhci, " HC %s Force save context capability", - HCC2_FSC(temp) ? "supports" : "doesn't support"); - xhci_dbg(xhci, " HC %s Large ESIT Payload Capability", - HCC2_LEC(temp) ? "supports" : "doesn't support"); - xhci_dbg(xhci, " HC %s Extended TBC capability", - HCC2_ETC(temp) ? "supports" : "doesn't support"); - } -} - -static void xhci_print_command_reg(struct xhci_hcd *xhci) -{ - u32 temp; - - temp = readl(&xhci->op_regs->command); - xhci_dbg(xhci, "USBCMD 0x%x:\n", temp); - xhci_dbg(xhci, " HC is %s\n", - (temp & CMD_RUN) ? "running" : "being stopped"); - xhci_dbg(xhci, " HC has %sfinished hard reset\n", - (temp & CMD_RESET) ? "not " : ""); - xhci_dbg(xhci, " Event Interrupts %s\n", - (temp & CMD_EIE) ? "enabled " : "disabled"); - xhci_dbg(xhci, " Host System Error Interrupts %s\n", - (temp & CMD_HSEIE) ? "enabled " : "disabled"); - xhci_dbg(xhci, " HC has %sfinished light reset\n", - (temp & CMD_LRESET) ? "not " : ""); -} - -static void xhci_print_status(struct xhci_hcd *xhci) -{ - u32 temp; - - temp = readl(&xhci->op_regs->status); - xhci_dbg(xhci, "USBSTS 0x%x:\n", temp); - xhci_dbg(xhci, " Event ring is %sempty\n", - (temp & STS_EINT) ? "not " : ""); - xhci_dbg(xhci, " %sHost System Error\n", - (temp & STS_FATAL) ? "WARNING: " : "No "); - xhci_dbg(xhci, " HC is %s\n", - (temp & STS_HALT) ? "halted" : "running"); -} - -static void xhci_print_op_regs(struct xhci_hcd *xhci) -{ - xhci_dbg(xhci, "xHCI operational registers at %p:\n", xhci->op_regs); - xhci_print_command_reg(xhci); - xhci_print_status(xhci); -} - -static void xhci_print_ports(struct xhci_hcd *xhci) -{ - __le32 __iomem *addr; - int i, j; - int ports; - char *names[NUM_PORT_REGS] = { - "status", - "power", - "link", - "reserved", - }; - - ports = HCS_MAX_PORTS(xhci->hcs_params1); - addr = &xhci->op_regs->port_status_base; - for (i = 0; i < ports; i++) { - for (j = 0; j < NUM_PORT_REGS; j++) { - xhci_dbg(xhci, "%p port %s reg = 0x%x\n", - addr, names[j], - (unsigned int) readl(addr)); - addr++; - } - } -} - -void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num) -{ - struct xhci_intr_reg __iomem *ir_set = &xhci->run_regs->ir_set[set_num]; - void __iomem *addr; - u32 temp; - u64 temp_64; - - addr = &ir_set->irq_pending; - temp = readl(addr); - if (temp == XHCI_INIT_VALUE) - return; - - xhci_dbg(xhci, " %p: ir_set[%i]\n", ir_set, set_num); - - xhci_dbg(xhci, " %p: ir_set.pending = 0x%x\n", addr, - (unsigned int)temp); - - addr = &ir_set->irq_control; - temp = readl(addr); - xhci_dbg(xhci, " %p: ir_set.control = 0x%x\n", addr, - (unsigned int)temp); - - addr = &ir_set->erst_size; - temp = readl(addr); - xhci_dbg(xhci, " %p: ir_set.erst_size = 0x%x\n", addr, - (unsigned int)temp); - - addr = &ir_set->rsvd; - temp = readl(addr); - if (temp != XHCI_INIT_VALUE) - xhci_dbg(xhci, " WARN: %p: ir_set.rsvd = 0x%x\n", - addr, (unsigned int)temp); - - addr = &ir_set->erst_base; - temp_64 = xhci_read_64(xhci, addr); - xhci_dbg(xhci, " %p: ir_set.erst_base = @%08llx\n", - addr, temp_64); - - addr = &ir_set->erst_dequeue; - temp_64 = xhci_read_64(xhci, addr); - xhci_dbg(xhci, " %p: ir_set.erst_dequeue = @%08llx\n", - addr, temp_64); -} - -void xhci_print_run_regs(struct xhci_hcd *xhci) -{ - u32 temp; - int i; - - xhci_dbg(xhci, "xHCI runtime registers at %p:\n", xhci->run_regs); - temp = readl(&xhci->run_regs->microframe_index); - xhci_dbg(xhci, " %p: Microframe index = 0x%x\n", - &xhci->run_regs->microframe_index, - (unsigned int) temp); - for (i = 0; i < 7; i++) { - temp = readl(&xhci->run_regs->rsvd[i]); - if (temp != XHCI_INIT_VALUE) - xhci_dbg(xhci, " WARN: %p: Rsvd[%i] = 0x%x\n", - &xhci->run_regs->rsvd[i], - i, (unsigned int) temp); - } -} - -void xhci_print_registers(struct xhci_hcd *xhci) -{ - xhci_print_cap_regs(xhci); - xhci_print_op_regs(xhci); - xhci_print_ports(xhci); -} - -void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) -{ - u64 addr = erst->erst_dma_addr; - int i; - struct xhci_erst_entry *entry; - - for (i = 0; i < erst->num_entries; i++) { - entry = &erst->entries[i]; - xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", - addr, - lower_32_bits(le64_to_cpu(entry->seg_addr)), - upper_32_bits(le64_to_cpu(entry->seg_addr)), - le32_to_cpu(entry->seg_size), - le32_to_cpu(entry->rsvd)); - addr += sizeof(*entry); - } -} - -void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) -{ - u64 val; - - val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n", - lower_32_bits(val)); - xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n", - upper_32_bits(val)); -} - char *xhci_get_slot_state(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx) { diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c new file mode 100644 index 000000000000..a1ab8acf39ba --- /dev/null +++ b/drivers/usb/host/xhci-dbgcap.c @@ -0,0 +1,996 @@ +/** + * xhci-dbgcap.c - xHCI debug capability support + * + * Copyright (C) 2017 Intel Corporation + * + * Author: Lu Baolu <baolu.lu@linux.intel.com> + */ +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/nls.h> + +#include "xhci.h" +#include "xhci-trace.h" +#include "xhci-dbgcap.h" + +static inline void * +dbc_dma_alloc_coherent(struct xhci_hcd *xhci, size_t size, + dma_addr_t *dma_handle, gfp_t flags) +{ + void *vaddr; + + vaddr = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, + size, dma_handle, flags); + memset(vaddr, 0, size); + return vaddr; +} + +static inline void +dbc_dma_free_coherent(struct xhci_hcd *xhci, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ + if (cpu_addr) + dma_free_coherent(xhci_to_hcd(xhci)->self.sysdev, + size, cpu_addr, dma_handle); +} + +static u32 xhci_dbc_populate_strings(struct dbc_str_descs *strings) +{ + struct usb_string_descriptor *s_desc; + u32 string_length; + + /* Serial string: */ + s_desc = (struct usb_string_descriptor *)strings->serial; + utf8s_to_utf16s(DBC_STRING_SERIAL, strlen(DBC_STRING_SERIAL), + UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData, + DBC_MAX_STRING_LENGTH); + + s_desc->bLength = (strlen(DBC_STRING_SERIAL) + 1) * 2; + s_desc->bDescriptorType = USB_DT_STRING; + string_length = s_desc->bLength; + string_length <<= 8; + + /* Product string: */ + s_desc = (struct usb_string_descriptor *)strings->product; + utf8s_to_utf16s(DBC_STRING_PRODUCT, strlen(DBC_STRING_PRODUCT), + UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData, + DBC_MAX_STRING_LENGTH); + + s_desc->bLength = (strlen(DBC_STRING_PRODUCT) + 1) * 2; + s_desc->bDescriptorType = USB_DT_STRING; + string_length += s_desc->bLength; + string_length <<= 8; + + /* Manufacture string: */ + s_desc = (struct usb_string_descriptor *)strings->manufacturer; + utf8s_to_utf16s(DBC_STRING_MANUFACTURER, + strlen(DBC_STRING_MANUFACTURER), + UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData, + DBC_MAX_STRING_LENGTH); + + s_desc->bLength = (strlen(DBC_STRING_MANUFACTURER) + 1) * 2; + s_desc->bDescriptorType = USB_DT_STRING; + string_length += s_desc->bLength; + string_length <<= 8; + + /* String0: */ + strings->string0[0] = 4; + strings->string0[1] = USB_DT_STRING; + strings->string0[2] = 0x09; + strings->string0[3] = 0x04; + string_length += 4; + + return string_length; +} + +static void xhci_dbc_init_contexts(struct xhci_hcd *xhci, u32 string_length) +{ + struct xhci_dbc *dbc; + struct dbc_info_context *info; + struct xhci_ep_ctx *ep_ctx; + u32 dev_info; + dma_addr_t deq, dma; + unsigned int max_burst; + + dbc = xhci->dbc; + if (!dbc) + return; + + /* Populate info Context: */ + info = (struct dbc_info_context *)dbc->ctx->bytes; + dma = dbc->string_dma; + info->string0 = cpu_to_le64(dma); + info->manufacturer = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH); + info->product = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 2); + info->serial = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 3); + info->length = cpu_to_le32(string_length); + + /* Populate bulk out endpoint context: */ + ep_ctx = dbc_bulkout_ctx(dbc); + max_burst = DBC_CTRL_MAXBURST(readl(&dbc->regs->control)); + deq = dbc_bulkout_enq(dbc); + ep_ctx->ep_info = 0; + ep_ctx->ep_info2 = dbc_epctx_info2(BULK_OUT_EP, 1024, max_burst); + ep_ctx->deq = cpu_to_le64(deq | dbc->ring_out->cycle_state); + + /* Populate bulk in endpoint context: */ + ep_ctx = dbc_bulkin_ctx(dbc); + deq = dbc_bulkin_enq(dbc); + ep_ctx->ep_info = 0; + ep_ctx->ep_info2 = dbc_epctx_info2(BULK_IN_EP, 1024, max_burst); + ep_ctx->deq = cpu_to_le64(deq | dbc->ring_in->cycle_state); + + /* Set DbC context and info registers: */ + xhci_write_64(xhci, dbc->ctx->dma, &dbc->regs->dccp); + + dev_info = cpu_to_le32((DBC_VENDOR_ID << 16) | DBC_PROTOCOL); + writel(dev_info, &dbc->regs->devinfo1); + + dev_info = cpu_to_le32((DBC_DEVICE_REV << 16) | DBC_PRODUCT_ID); + writel(dev_info, &dbc->regs->devinfo2); +} + +static void xhci_dbc_giveback(struct dbc_request *req, int status) + __releases(&dbc->lock) + __acquires(&dbc->lock) +{ + struct dbc_ep *dep = req->dep; + struct xhci_dbc *dbc = dep->dbc; + struct xhci_hcd *xhci = dbc->xhci; + struct device *dev = xhci_to_hcd(dbc->xhci)->self.sysdev; + + list_del_init(&req->list_pending); + req->trb_dma = 0; + req->trb = NULL; + + if (req->status == -EINPROGRESS) + req->status = status; + + trace_xhci_dbc_giveback_request(req); + + dma_unmap_single(dev, + req->dma, + req->length, + dbc_ep_dma_direction(dep)); + + /* Give back the transfer request: */ + spin_unlock(&dbc->lock); + req->complete(xhci, req); + spin_lock(&dbc->lock); +} + +static void xhci_dbc_flush_single_request(struct dbc_request *req) +{ + union xhci_trb *trb = req->trb; + + trb->generic.field[0] = 0; + trb->generic.field[1] = 0; + trb->generic.field[2] = 0; + trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE); + trb->generic.field[3] |= cpu_to_le32(TRB_TYPE(TRB_TR_NOOP)); + + xhci_dbc_giveback(req, -ESHUTDOWN); +} + +static void xhci_dbc_flush_endpoint_requests(struct dbc_ep *dep) +{ + struct dbc_request *req, *tmp; + + list_for_each_entry_safe(req, tmp, &dep->list_pending, list_pending) + xhci_dbc_flush_single_request(req); +} + +static void xhci_dbc_flush_reqests(struct xhci_dbc *dbc) +{ + xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_OUT]); + xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_IN]); +} + +struct dbc_request * +dbc_alloc_request(struct dbc_ep *dep, gfp_t gfp_flags) +{ + struct dbc_request *req; + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + req->dep = dep; + INIT_LIST_HEAD(&req->list_pending); + INIT_LIST_HEAD(&req->list_pool); + req->direction = dep->direction; + + trace_xhci_dbc_alloc_request(req); + + return req; +} + +void +dbc_free_request(struct dbc_ep *dep, struct dbc_request *req) +{ + trace_xhci_dbc_free_request(req); + + kfree(req); +} + +static void +xhci_dbc_queue_trb(struct xhci_ring *ring, u32 field1, + u32 field2, u32 field3, u32 field4) +{ + union xhci_trb *trb, *next; + + trb = ring->enqueue; + trb->generic.field[0] = cpu_to_le32(field1); + trb->generic.field[1] = cpu_to_le32(field2); + trb->generic.field[2] = cpu_to_le32(field3); + trb->generic.field[3] = cpu_to_le32(field4); + + trace_xhci_dbc_gadget_ep_queue(ring, &trb->generic); + + ring->num_trbs_free--; + next = ++(ring->enqueue); + if (TRB_TYPE_LINK_LE32(next->link.control)) { + next->link.control ^= cpu_to_le32(TRB_CYCLE); + ring->enqueue = ring->enq_seg->trbs; + ring->cycle_state ^= 1; + } +} + +static int xhci_dbc_queue_bulk_tx(struct dbc_ep *dep, + struct dbc_request *req) +{ + u64 addr; + union xhci_trb *trb; + unsigned int num_trbs; + struct xhci_dbc *dbc = dep->dbc; + struct xhci_ring *ring = dep->ring; + u32 length, control, cycle; + + num_trbs = count_trbs(req->dma, req->length); + WARN_ON(num_trbs != 1); + if (ring->num_trbs_free < num_trbs) + return -EBUSY; + + addr = req->dma; |