Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (260 commits) usb: renesas_usbhs: fixup inconsistent return from usbhs_pkt_push() usb/isp1760: Allow to optionally trigger low-level chip reset via GPIOLIB. USB: gadget: midi: memory leak in f_midi_bind_config() USB: gadget: midi: fix range check in f_midi_out_open() QE/FHCI: fixed the CONTROL bug usb: renesas_usbhs: tidyup for smatch warnings USB: Fix USB Kconfig dependency problem on 85xx/QoirQ platforms EHCI: workaround for MosChip controller bug usb: gadget: file_storage: fix race on unloading USB: ftdi_sio.c: Use ftdi async_icount structure for TIOCMIWAIT, as in other drivers USB: ftdi_sio.c:Fill MSR fields of the ftdi async_icount structure USB: ftdi_sio.c: Fill LSR fields of the ftdi async_icount structure USB: ftdi_sio.c:Fill TX field of the ftdi async_icount structure USB: ftdi_sio.c: Fill the RX field of the ftdi async_icount structure USB: ftdi_sio.c: Basic icount infrastructure for ftdi_sio usb/isp1760: Let OF bindings depend on general CONFIG_OF instead of PPC_OF . USB: ftdi_sio: Support TI/Luminary Micro Stellaris BD-ICDI Board USB: Fix runtime wakeup on OHCI xHCI/USB: Make xHCI driver have a BOS descriptor. usb: gadget: add new usb gadget for ACM and mass storage ...
This commit is contained in:
@@ -19,7 +19,7 @@ config USB_C67X00_HCD
|
||||
|
||||
config USB_XHCI_HCD
|
||||
tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)"
|
||||
depends on USB && PCI && EXPERIMENTAL
|
||||
depends on USB && USB_ARCH_HAS_XHCI && EXPERIMENTAL
|
||||
---help---
|
||||
The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
|
||||
"SuperSpeed" host controller hardware.
|
||||
@@ -515,6 +515,19 @@ config USB_R8A66597_HCD
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called r8a66597-hcd.
|
||||
|
||||
config USB_RENESAS_USBHS_HCD
|
||||
tristate "Renesas USBHS HCD support"
|
||||
depends on USB
|
||||
depends on USB_RENESAS_USBHS
|
||||
help
|
||||
The Renesas USBHS is a USB 2.0 host and peripheral controller.
|
||||
|
||||
Enable this option if your board has this chip, and you want
|
||||
to use it as a host controller. If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called renesas-usbhs.
|
||||
|
||||
config USB_WHCI_HCD
|
||||
tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
@@ -544,11 +557,11 @@ config USB_HWA_HCD
|
||||
will be called "hwa-hc".
|
||||
|
||||
config USB_IMX21_HCD
|
||||
tristate "iMX21 HCD support"
|
||||
depends on USB && ARM && MACH_MX21
|
||||
tristate "i.MX21 HCD support"
|
||||
depends on USB && ARM && ARCH_MXC
|
||||
help
|
||||
This driver enables support for the on-chip USB host in the
|
||||
iMX21 processor.
|
||||
i.MX21 processor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called "imx21-hcd".
|
||||
@@ -578,3 +591,10 @@ config USB_OCTEON_OHCI
|
||||
config USB_OCTEON2_COMMON
|
||||
bool
|
||||
default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
|
||||
|
||||
config USB_PXA168_EHCI
|
||||
bool "Marvell PXA168 on-chip EHCI HCD support"
|
||||
depends on USB_EHCI_HCD && ARCH_MMP
|
||||
help
|
||||
Enable support for Marvell PXA168 SoC's on-chip EHCI
|
||||
host controller
|
||||
|
@@ -11,8 +11,9 @@ fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
|
||||
|
||||
fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
|
||||
|
||||
xhci-hcd-y := xhci.o xhci-mem.o xhci-pci.o
|
||||
xhci-hcd-y := xhci.o xhci-mem.o
|
||||
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
|
||||
xhci-hcd-$(CONFIG_PCI) += xhci-pci.o
|
||||
|
||||
obj-$(CONFIG_USB_WHCI_HCD) += whci/
|
||||
|
||||
|
@@ -163,7 +163,7 @@ static int ehci_ath79_probe(struct platform_device *pdev)
|
||||
goto err_release_region;
|
||||
}
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret)
|
||||
goto err_iounmap;
|
||||
|
||||
|
@@ -181,7 +181,7 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
ret = usb_add_hcd(hcd, pdev->resource[1].start,
|
||||
IRQF_DISABLED | IRQF_SHARED);
|
||||
IRQF_SHARED);
|
||||
if (ret == 0) {
|
||||
platform_set_drvdata(pdev, hcd);
|
||||
return ret;
|
||||
@@ -293,7 +293,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -697,6 +697,19 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
|
||||
}
|
||||
#undef DBG_SCHED_LIMIT
|
||||
|
||||
static const char *rh_state_string(struct ehci_hcd *ehci)
|
||||
{
|
||||
switch (ehci->rh_state) {
|
||||
case EHCI_RH_HALTED:
|
||||
return "halted";
|
||||
case EHCI_RH_SUSPENDED:
|
||||
return "suspended";
|
||||
case EHCI_RH_RUNNING:
|
||||
return "running";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
@@ -730,11 +743,11 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
||||
temp = scnprintf (next, size,
|
||||
"bus %s, device %s\n"
|
||||
"%s\n"
|
||||
"EHCI %x.%02x, hcd state %d\n",
|
||||
"EHCI %x.%02x, rh state %s\n",
|
||||
hcd->self.controller->bus->name,
|
||||
dev_name(hcd->self.controller),
|
||||
hcd->product_desc,
|
||||
i >> 8, i & 0x0ff, hcd->state);
|
||||
i >> 8, i & 0x0ff, rh_state_string(ehci));
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
@@ -808,7 +821,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
||||
next += temp;
|
||||
|
||||
temp = scnprintf (next, size, "uframe %04x\n",
|
||||
ehci_readl(ehci, &ehci->regs->frame_index));
|
||||
ehci_read_frame_index(ehci));
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
|
@@ -134,7 +134,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
||||
|
||||
/* Don't need to set host mode here. It will be done by tdi_reset() */
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
goto err4;
|
||||
|
||||
@@ -392,7 +392,7 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
|
||||
|
||||
dev_dbg(dev, "suspending...\n");
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
dev->power.power_state = PMSG_SUSPEND;
|
||||
|
||||
/* ignore non-host interrupts */
|
||||
@@ -481,7 +481,7 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
|
||||
ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
|
||||
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
ehci->rh_state = EHCI_RH_RUNNING;
|
||||
dev->power.power_state = PMSG_ON;
|
||||
|
||||
tmp = ehci_readl(ehci, &ehci->regs->command);
|
||||
|
@@ -95,7 +95,7 @@ static const char hcd_name [] = "ehci_hcd";
|
||||
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
|
||||
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
|
||||
#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1)
|
||||
/* 200-ms async qh unlink delay */
|
||||
/* 5-ms async qh unlink delay */
|
||||
|
||||
/* Initial IRQ latency: faster than hw default */
|
||||
static int log2_irq_thresh = 0; // 0 to 6
|
||||
@@ -238,7 +238,7 @@ static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
|
||||
error = handshake(ehci, ptr, mask, done, usec);
|
||||
if (error) {
|
||||
ehci_halt(ehci);
|
||||
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
|
||||
ehci->rh_state = EHCI_RH_HALTED;
|
||||
ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
|
||||
ptr, mask, done, error);
|
||||
}
|
||||
@@ -278,7 +278,7 @@ static int ehci_reset (struct ehci_hcd *ehci)
|
||||
command |= CMD_RESET;
|
||||
dbg_cmd (ehci, "reset", command);
|
||||
ehci_writel(ehci, command, &ehci->regs->command);
|
||||
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
|
||||
ehci->rh_state = EHCI_RH_HALTED;
|
||||
ehci->next_statechange = jiffies;
|
||||
retval = handshake (ehci, &ehci->regs->command,
|
||||
CMD_RESET, 0, 250 * 1000);
|
||||
@@ -307,7 +307,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
|
||||
u32 temp;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
BUG ();
|
||||
#endif
|
||||
|
||||
@@ -356,7 +356,7 @@ static void ehci_iaa_watchdog(unsigned long param)
|
||||
*/
|
||||
if (ehci->reclaim
|
||||
&& !timer_pending(&ehci->iaa_watchdog)
|
||||
&& HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
|
||||
&& ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
u32 cmd, status;
|
||||
|
||||
/* If we get here, IAA is *REALLY* late. It's barely
|
||||
@@ -496,7 +496,7 @@ static void ehci_work (struct ehci_hcd *ehci)
|
||||
* misplace IRQs, and should let us run completely without IRQs.
|
||||
* such lossage has been observed on both VT6202 and VT8235.
|
||||
*/
|
||||
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING &&
|
||||
(ehci->async->qh_next.ptr != NULL ||
|
||||
ehci->periodic_sched != 0))
|
||||
timer_action (ehci, TIMER_IO_WATCHDOG);
|
||||
@@ -516,7 +516,7 @@ static void ehci_stop (struct usb_hcd *hcd)
|
||||
del_timer_sync(&ehci->iaa_watchdog);
|
||||
|
||||
spin_lock_irq(&ehci->lock);
|
||||
if (HC_IS_RUNNING (hcd->state))
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING)
|
||||
ehci_quiesce (ehci);
|
||||
|
||||
ehci_silence_controller(ehci);
|
||||
@@ -741,7 +741,7 @@ static int ehci_run (struct usb_hcd *hcd)
|
||||
* be started before the port switching actions could complete.
|
||||
*/
|
||||
down_write(&ehci_cf_port_reset_rwsem);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
ehci->rh_state = EHCI_RH_RUNNING;
|
||||
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
|
||||
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
|
||||
msleep(5);
|
||||
@@ -768,6 +768,35 @@ static int ehci_run (struct usb_hcd *hcd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
ehci->regs = (void __iomem *)ehci->caps +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
ehci->sbrn = HCD_USB2;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
||||
@@ -788,7 +817,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
||||
|
||||
/* Shared IRQ? */
|
||||
masked_status = status & INTR_MASK;
|
||||
if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
|
||||
if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
|
||||
spin_unlock(&ehci->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
@@ -952,7 +981,7 @@ static int ehci_urb_enqueue (
|
||||
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
{
|
||||
/* failfast */
|
||||
if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim)
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING && ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
|
||||
/* If the QH isn't linked then there's nothing we can do
|
||||
@@ -1079,7 +1108,7 @@ rescan:
|
||||
goto idle_timeout;
|
||||
}
|
||||
|
||||
if (!HC_IS_RUNNING (hcd->state))
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
qh->qh_state = QH_STATE_IDLE;
|
||||
switch (qh->qh_state) {
|
||||
case QH_STATE_LINKED:
|
||||
@@ -1166,8 +1195,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
|
||||
static int ehci_get_frame (struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
||||
return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
|
||||
ehci->periodic_size;
|
||||
return (ehci_read_frame_index(ehci) >> 3) % ehci->periodic_size;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@@ -1291,6 +1319,16 @@ MODULE_LICENSE ("GPL");
|
||||
#define PLATFORM_DRIVER ehci_grlib_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_PXA168_EHCI
|
||||
#include "ehci-pxa168.c"
|
||||
#define PLATFORM_DRIVER ehci_pxa168_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NLM_XLR
|
||||
#include "ehci-xls.c"
|
||||
#define PLATFORM_DRIVER ehci_xls_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
|
||||
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
|
||||
!defined(XILINX_OF_PLATFORM_DRIVER)
|
||||
|
@@ -236,10 +236,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
||||
}
|
||||
|
||||
/* stop schedules, clean any completed work */
|
||||
if (HC_IS_RUNNING(hcd->state)) {
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING)
|
||||
ehci_quiesce (ehci);
|
||||
hcd->state = HC_STATE_QUIESCING;
|
||||
}
|
||||
ehci->command = ehci_readl(ehci, &ehci->regs->command);
|
||||
ehci_work(ehci);
|
||||
|
||||
@@ -313,7 +311,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
||||
|
||||
/* turn off now-idle HC */
|
||||
ehci_halt (ehci);
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
|
||||
if (ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
@@ -382,6 +380,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
||||
|
||||
/* restore CMD_RUN, framelist size, and irq threshold */
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
ehci->rh_state = EHCI_RH_RUNNING;
|
||||
|
||||
/* Some controller/firmware combinations need a delay during which
|
||||
* they set up the port statuses. See Bugzilla #8190. */
|
||||
@@ -451,7 +450,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
||||
}
|
||||
|
||||
ehci->next_statechange = jiffies + msecs_to_jiffies(5);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
/* Now we can safely re-enable irqs */
|
||||
ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
|
||||
@@ -563,7 +561,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
|
||||
u32 ppcd = 0;
|
||||
|
||||
/* if !USB_SUSPEND, root hub timers won't get shut down ... */
|
||||
if (!HC_IS_RUNNING(hcd->state))
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
return 0;
|
||||
|
||||
/* init status to no-changes */
|
||||
|
@@ -236,7 +236,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
|
||||
priv->hcd = hcd;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret)
|
||||
goto err_add;
|
||||
|
||||
|
@@ -155,7 +155,7 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
|
||||
goto err3;
|
||||
|
@@ -228,7 +228,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add hcd with err %d\n", ret);
|
||||
goto err_add_hcd;
|
||||
|
@@ -277,7 +277,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
|
||||
printk(KERN_WARNING "Orion ehci -USB phy version isn't supported.\n");
|
||||
}
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (err)
|
||||
goto err4;
|
||||
|
||||
|
@@ -224,6 +224,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
pci_dev_put(p_smbus);
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_NETMOS:
|
||||
/* MosChip frame-index-register bug */
|
||||
ehci_info(ehci, "applying MosChip frame-index workaround\n");
|
||||
ehci->frame_index_bug = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* optional debug port, normally in the first BAR */
|
||||
@@ -439,7 +444,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@@ -167,7 +167,7 @@ static int __devinit ps3_ehci_probe(struct ps3_system_bus_device *dev)
|
||||
|
||||
ps3_system_bus_set_drvdata(dev, hcd);
|
||||
|
||||
result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
|
||||
result = usb_add_hcd(hcd, virq, 0);
|
||||
|
||||
if (result) {
|
||||
dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
|
||||
|
363
drivers/usb/host/ehci-pxa168.c
Normal file
363
drivers/usb/host/ehci-pxa168.c
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* drivers/usb/host/ehci-pxa168.c
|
||||
*
|
||||
* Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
|
||||
*
|
||||
* Based on drivers/usb/host/ehci-orion.c
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <mach/pxa168.h>
|
||||
|
||||
#define USB_PHY_CTRL_REG 0x4
|
||||
#define USB_PHY_PLL_REG 0x8
|
||||
#define USB_PHY_TX_REG 0xc
|
||||
|
||||
#define FBDIV_SHIFT 4
|
||||
|
||||
#define ICP_SHIFT 12
|
||||
#define ICP_15 2
|
||||
#define ICP_20 3
|
||||
#define ICP_25 4
|
||||
|
||||
#define KVCO_SHIFT 15
|
||||
|
||||
#define PLLCALI12_SHIFT 25
|
||||
#define CALI12_VDD 0
|
||||
#define CALI12_09 1
|
||||
#define CALI12_10 2
|
||||
#define CALI12_11 3
|
||||
|
||||
#define PLLVDD12_SHIFT 27
|
||||
#define VDD12_VDD 0
|
||||
#define VDD12_10 1
|
||||
#define VDD12_11 2
|
||||
#define VDD12_12 3
|
||||
|
||||
#define PLLVDD18_SHIFT 29
|
||||
#define VDD18_19 0
|
||||
#define VDD18_20 1
|
||||
#define VDD18_21 2
|
||||
#define VDD18_22 3
|
||||
|
||||
|
||||
#define PLL_READY (1 << 23)
|
||||
#define VCOCAL_START (1 << 21)
|
||||
#define REG_RCAL_START (1 << 12)
|
||||
|
||||
struct pxa168_usb_drv_data {
|
||||
struct ehci_hcd ehci;
|
||||
struct clk *pxa168_usb_clk;
|
||||
struct resource *usb_phy_res;
|
||||
void __iomem *usb_phy_reg_base;
|
||||
};
|
||||
|
||||
static int ehci_pxa168_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
ehci_reset(ehci);
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* data structure init
|
||||
*/
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct hc_driver ehci_pxa168_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Marvell PXA168 EHCI",
|
||||
.hcd_priv_size = sizeof(struct pxa168_usb_drv_data),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_pxa168_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
static int pxa168_usb_phy_init(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
void __iomem *usb_phy_reg_base;
|
||||
struct pxa168_usb_pdata *pdata;
|
||||
struct pxa168_usb_drv_data *drv_data;
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
unsigned long reg_val;
|
||||
int pll_retry_cont = 10000, err = 0;
|
||||
|
||||
drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
|
||||
pdata = (struct pxa168_usb_pdata *)pdev->dev.platform_data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no PHY register addr. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
ehci_pxa168_hc_driver.description)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
usb_phy_reg_base = ioremap(res->start, resource_size(res));
|
||||
if (usb_phy_reg_base == NULL) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
err = -EFAULT;
|
||||
goto err1;
|
||||
}
|
||||
drv_data->usb_phy_reg_base = usb_phy_reg_base;
|
||||
drv_data->usb_phy_res = res;
|
||||
|
||||
/* If someone wants to init USB phy in board specific way */
|
||||
if (pdata && pdata->phy_init)
|
||||
return pdata->phy_init(usb_phy_reg_base);
|
||||
|
||||
/* Power up the PHY and PLL */
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_CTRL_REG) | 0x3,
|
||||
usb_phy_reg_base + USB_PHY_CTRL_REG);
|
||||
|
||||
/* Configure PHY PLL */
|
||||
reg_val = readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~(0x7e03ffff);
|
||||
reg_val |= (VDD18_22 << PLLVDD18_SHIFT | VDD12_12 << PLLVDD12_SHIFT |
|
||||
CALI12_11 << PLLCALI12_SHIFT | 3 << KVCO_SHIFT |
|
||||
ICP_15 << ICP_SHIFT | 0xee << FBDIV_SHIFT | 0xb);
|
||||
writel(reg_val, usb_phy_reg_base + USB_PHY_PLL_REG);
|
||||
|
||||
/* Make sure PHY PLL is ready */
|
||||
while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
|
||||
if (!(pll_retry_cont--)) {
|
||||
dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
|
||||
err = -EIO;
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Toggle VCOCAL_START bit of U2PLL for PLL calibration */
|
||||
udelay(200);
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) | VCOCAL_START,
|
||||
usb_phy_reg_base + USB_PHY_PLL_REG);
|
||||
udelay(40);
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~VCOCAL_START,
|
||||
usb_phy_reg_base + USB_PHY_PLL_REG);
|
||||
|
||||
/* Toggle REG_RCAL_START bit of U2PTX for impedance calibration */
|
||||
udelay(400);
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) | REG_RCAL_START,
|
||||
usb_phy_reg_base + USB_PHY_TX_REG);
|
||||
udelay(40);
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) & ~REG_RCAL_START,
|
||||
usb_phy_reg_base + USB_PHY_TX_REG);
|
||||
|
||||
/* Make sure PHY PLL is ready again */
|
||||
pll_retry_cont = 0;
|
||||
while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
|
||||
if (!(pll_retry_cont--)) {
|
||||
dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
|
||||
err = -EIO;
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err2:
|
||||
iounmap(usb_phy_reg_base);
|
||||
err1:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devinit ehci_pxa168_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
struct pxa168_usb_drv_data *drv_data;
|
||||
void __iomem *regs;
|
||||
int irq, err = 0;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
pr_debug("Initializing pxa168-SoC USB Host Controller\n");
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no IRQ. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
err = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no register addr. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
err = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
ehci_pxa168_hc_driver.description)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
err = -EBUSY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
regs = ioremap(res->start, resource_size(res));
|
||||
if (regs == NULL) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
err = -EFAULT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(&ehci_pxa168_hc_driver,
|
||||
&pdev->dev, dev_name(&pdev->dev));
|
||||
if (!hcd) {
|
||||
err = -ENOMEM;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
|
||||
|
||||
/* Enable USB clock */
|
||||
drv_data->pxa168_usb_clk = clk_get(&pdev->dev, "PXA168-USBCLK");
|
||||
if (IS_ERR(drv_data->pxa168_usb_clk)) {
|
||||
dev_err(&pdev->dev, "Couldn't get USB clock\n");
|
||||
err = PTR_ERR(drv_data->pxa168_usb_clk);
|
||||
goto err4;
|
||||
}
|
||||
clk_enable(drv_data->pxa168_usb_clk);
|
||||
|
||||
err = pxa168_usb_phy_init(pdev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "USB PHY initialization failed\n");
|
||||
goto err5;
|
||||
}
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
hcd->regs = regs;
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
hcd->has_tt = 1;
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
|
||||
if (err)
|
||||
goto err5;
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
clk_disable(drv_data->pxa168_usb_clk);
|
||||
clk_put(drv_data->pxa168_usb_clk);
|
||||
err4:
|
||||
usb_put_hcd(hcd);
|
||||
err3:
|
||||
iounmap(regs);
|
||||
err2:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
err1:
|
||||
dev_err(&pdev->dev, "init %s fail, %d\n",
|
||||
dev_name(&pdev->dev), err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __exit ehci_pxa168_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct pxa168_usb_drv_data *drv_data =
|
||||
(struct pxa168_usb_drv_data *)hcd->hcd_priv;
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
/* Power down PHY & PLL */
|
||||
writel(readl(drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG) & (~0x3),
|
||||
drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG);
|
||||
|
||||
clk_disable(drv_data->pxa168_usb_clk);
|
||||
clk_put(drv_data->pxa168_usb_clk);
|
||||
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
|
||||
iounmap(drv_data->usb_phy_reg_base);
|
||||
release_mem_region(drv_data->usb_phy_res->start,
|
||||
resource_size(drv_data->usb_phy_res));
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:pxa168-ehci");
|
||||
|
||||
static struct platform_driver ehci_pxa168_driver = {
|
||||
.probe = ehci_pxa168_drv_probe,
|
||||
.remove = __exit_p(ehci_pxa168_drv_remove),
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver.name = "pxa168-ehci",
|
||||
};
|
@@ -111,8 +111,6 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
|
||||
}
|
||||
}
|
||||
|
||||
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
|
||||
wmb ();
|
||||
hw->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
|
||||
}
|
||||
|
||||
@@ -153,7 +151,7 @@ static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
qh->clearing_tt = 0;
|
||||
if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
|
||||
&& HC_IS_RUNNING(hcd->state))
|
||||
&& ehci->rh_state == EHCI_RH_RUNNING)
|
||||
qh_link_async(ehci, qh);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
}
|
||||
@@ -425,7 +423,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
|
||||
/* stop scanning when we reach qtds the hc is using */
|
||||
} else if (likely (!stopped
|
||||
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
|
||||
&& ehci->rh_state == EHCI_RH_RUNNING)) {
|
||||
break;
|
||||
|
||||
/* scan the whole queue for unlinks whenever it stops */
|
||||
@@ -433,7 +431,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
stopped = 1;
|
||||
|
||||
/* cancel everything if we halt, suspend, etc */
|
||||
if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
last_status = -ESHUTDOWN;
|
||||
|
||||
/* this qtd is active; skip it unless a previous qtd
|
||||
@@ -724,7 +722,8 @@ qh_urb_transaction (
|
||||
|
||||
/*
|
||||
* control requests may need a terminating data "status" ack;
|
||||
* bulk ones may need a terminating short packet (zero length).
|
||||
* other OUT ones may need a terminating short packet
|
||||
* (zero length).
|
||||
*/
|
||||
if (likely (urb->transfer_buffer_length != 0)) {
|
||||
int one_more = 0;
|
||||
@@ -733,7 +732,7 @@ qh_urb_transaction (
|
||||
one_more = 1;
|
||||
token ^= 0x0100; /* "in" <--> "out" */
|
||||
token |= QTD_TOGGLE; /* force DATA1 */
|
||||
} else if (usb_pipebulk (urb->pipe)
|
||||
} else if (usb_pipeout(urb->pipe)
|
||||
&& (urb->transfer_flags & URB_ZERO_PACKET)
|
||||
&& !(urb->transfer_buffer_length % maxpacket)) {
|
||||
one_more = 1;
|
||||
@@ -977,9 +976,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
/* in case a clear of CMD_ASE didn't take yet */
|
||||
(void)handshake(ehci, &ehci->regs->status,
|
||||
STS_ASS, 0, 150);
|
||||
cmd |= CMD_ASE | CMD_RUN;
|
||||
cmd |= CMD_ASE;
|
||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
|
||||
/* posted write need not be known to HC yet ... */
|
||||
}
|
||||
}
|
||||
@@ -1058,7 +1056,7 @@ static struct ehci_qh *qh_append_tds (
|
||||
*/
|
||||
token = qtd->hw_token;
|
||||
qtd->hw_token = HALT_BIT(ehci);
|
||||
wmb ();
|
||||
|
||||
dummy = qh->dummy;
|
||||
|
||||
dma = dummy->qtd_dma;
|
||||
@@ -1168,14 +1166,13 @@ static void end_unlink_async (struct ehci_hcd *ehci)
|
||||
|
||||
qh_completions (ehci, qh);
|
||||
|
||||
if (!list_empty (&qh->qtd_list)
|
||||
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
|
||||
if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
qh_link_async (ehci, qh);
|
||||
else {
|
||||
} else {
|
||||
/* it's not free to turn the async schedule on/off; leave it
|
||||
* active but idle for a while once it empties.
|
||||
*/
|
||||
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING
|
||||
&& ehci->async->qh_next.qh == NULL)
|
||||
timer_action (ehci, TIMER_ASYNC_OFF);
|
||||
}
|
||||
@@ -1211,7 +1208,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
/* stop async schedule right now? */
|
||||
if (unlikely (qh == ehci->async)) {
|
||||
/* can't get here without STS_ASS set */
|
||||
if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
|
||||
if (ehci->rh_state != EHCI_RH_HALTED
|
||||
&& !ehci->reclaim) {
|
||||
/* ... and CMD_IAAD clear */
|
||||
ehci_writel(ehci, cmd & ~CMD_ASE,
|
||||
@@ -1237,7 +1234,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
wmb ();
|
||||
|
||||
/* If the controller isn't running, we don't have to wait for it */
|
||||
if (unlikely(!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))) {
|
||||
if (unlikely(ehci->rh_state != EHCI_RH_RUNNING)) {
|
||||
/* if (unlikely (qh->reclaim != 0))
|
||||
* this will recurse, probably not much
|
||||
*/
|
||||
@@ -1260,7 +1257,7 @@ static void scan_async (struct ehci_hcd *ehci)
|
||||
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
|
||||
|
||||
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
|
||||
stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
|
||||
stopped = (ehci->rh_state != EHCI_RH_RUNNING);
|
||||
|
||||
ehci->qh_scan_next = ehci->async->qh_next.qh;
|
||||
while (ehci->qh_scan_next) {
|
||||
|
@@ -136,7 +136,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to add USB HCD\n");
|
||||
goto fail;
|
||||
@@ -270,7 +270,7 @@ static int s5p_ehci_resume(struct device *dev)
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -36,6 +36,27 @@
|
||||
|
||||
static int ehci_get_frame (struct usb_hcd *hcd);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
static unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
|
||||
{
|
||||
unsigned uf;
|
||||
|
||||
/*
|
||||
* The MosChip MCS9990 controller updates its microframe counter
|
||||
* a little before the frame counter, and occasionally we will read
|
||||
* the invalid intermediate value. Avoid problems by checking the
|
||||
* microframe number (the low-order 3 bits); if they are 0 then
|
||||
* re-read the register to get the correct value.
|
||||
*/
|
||||
uf = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0)))
|
||||
uf = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
return uf;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@@ -479,10 +500,9 @@ static int enable_periodic (struct ehci_hcd *ehci)
|
||||
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
|
||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||
/* posted write ... PSS happens later */
|
||||
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
|
||||
|
||||
/* make sure ehci_work scans these */
|
||||
ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
|
||||
ehci->next_uframe = ehci_read_frame_index(ehci)
|
||||
% (ehci->periodic_size << 3);
|
||||
if (unlikely(ehci->broken_periodic))
|
||||
ehci->last_periodic_enable = ktime_get_real();
|
||||
@@ -677,7 +697,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
|
||||
/* reschedule QH iff another request is queued */
|
||||
if (!list_empty(&qh->qtd_list) &&
|
||||
HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
|
||||
ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
rc = qh_schedule(ehci, qh);
|
||||
|
||||
/* An error here likely indicates handshake failure
|
||||
@@ -1409,7 +1429,7 @@ iso_stream_schedule (
|
||||
goto fail;
|
||||
}
|
||||
|
||||
now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
|
||||
now = ehci_read_frame_index(ehci) & (mod - 1);
|
||||
|
||||
/* Typical case: reuse current schedule, stream is still active.
|
||||
* Hopefully there are no gaps from the host falling behind
|
||||
@@ -2275,8 +2295,8 @@ scan_periodic (struct ehci_hcd *ehci)
|
||||
* Touches as few pages as possible: cache-friendly.
|
||||
*/
|
||||
now_uframe = ehci->next_uframe;
|
||||
if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
|
||||
clock = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
clock = ehci_read_frame_index(ehci);
|
||||
clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
|
||||
} else {
|
||||
clock = now_uframe + mod - 1;
|
||||
@@ -2310,7 +2330,7 @@ restart:
|
||||
union ehci_shadow temp;
|
||||
int live;
|
||||
|
||||
live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
|
||||
live = (ehci->rh_state == EHCI_RH_RUNNING);
|
||||
switch (hc32_to_cpu(ehci, type)) {
|
||||
case Q_TYPE_QH:
|
||||
/* handle any completions */
|
||||
@@ -2435,7 +2455,7 @@ restart:
|
||||
* We can't advance our scan without collecting the ISO
|
||||
* transfers that are still pending in this frame.
|
||||
*/
|
||||
if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
|
||||
if (incomplete && ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
ehci->next_uframe = now_uframe;
|
||||
break;
|
||||
}
|
||||
@@ -2451,12 +2471,11 @@ restart:
|
||||
if (now_uframe == clock) {
|
||||
unsigned now;
|
||||
|
||||
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING
|
||||
|| ehci->periodic_sched == 0)
|
||||
break;
|
||||
ehci->next_uframe = now_uframe;
|
||||
now = ehci_readl(ehci, &ehci->regs->frame_index) &
|
||||
(mod - 1);
|
||||
now = ehci_read_frame_index(ehci) & (mod - 1);
|
||||
if (now_uframe == now)
|
||||
break;
|
||||
|
||||
|
@@ -168,7 +168,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
|
||||
clk_enable(priv->fclk);
|
||||
clk_enable(priv->iclk);
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to add hcd");
|
||||
goto fail_add_hcd;
|
||||
|
@@ -154,7 +154,7 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
|
||||
ehci->clk = usbh_clk;
|
||||
|
||||
spear_start_ehci(ehci);
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (retval)
|
||||
goto fail_add_hcd;
|
||||
|
||||
|
@@ -674,7 +674,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
|
||||
}
|
||||
#endif
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to add USB HCD\n");
|
||||
goto fail;
|
||||
|
@@ -133,7 +133,7 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
ret = usb_add_hcd(hcd, pdev->resource[1].start,
|
||||
IRQF_DISABLED | IRQF_SHARED);
|
||||
IRQF_SHARED);
|
||||
if (ret == 0) {
|
||||
platform_set_drvdata(pdev, hcd);
|
||||
return ret;
|
||||
|
161
drivers/usb/host/ehci-xls.c
Normal file
161
drivers/usb/host/ehci-xls.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* EHCI HCD for Netlogic XLS processors.
|
||||
*
|
||||
* (C) Copyright 2011 Netlogic Microsystems Inc.
|
||||
*
|
||||
* Based on various ehci-*.c drivers
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static int ehci_xls_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
int retval;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ehci_xls_probe_internal(const struct hc_driver *driver,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *res;
|
||||
int retval, irq;
|
||||
|
||||
/* Get our IRQ from an earlier registered Platform Resource */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Get our Memory Handle */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Error: MMIO Handle %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
|
||||
if (!hcd) {
|
||||
retval = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = res->end - res->start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
|
||||
driver->description)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
retval = -EBUSY;
|
||||
goto err2;
|
||||
}
|
||||
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
|
||||
|
||||
if (hcd->regs == NULL) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
retval = -EFAULT;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
goto err4;
|
||||
return retval;
|
||||
|
||||
err4:
|
||||
iounmap(hcd->regs);
|
||||
err3:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err2:
|
||||
usb_put_hcd(hcd);
|
||||
err1:
|
||||
dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev),
|
||||
retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct hc_driver ehci_xls_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "XLS EHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_USB2 | HCD_MEMORY,
|
||||
.reset = ehci_xls_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
static int ehci_xls_probe(struct platform_device *pdev)
|
||||
{
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
return ehci_xls_probe_internal(&ehci_xls_hc_driver, pdev);
|
||||
}
|
||||
|
||||
static int ehci_xls_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("ehci-xls");
|
||||
|
||||
static struct platform_driver ehci_xls_driver = {
|
||||
.probe = ehci_xls_probe,
|
||||
.remove = ehci_xls_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "ehci-xls",
|
||||
},
|
||||
};
|
@@ -62,6 +62,12 @@ struct ehci_stats {
|
||||
|
||||
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
|
||||
|
||||
enum ehci_rh_state {
|
||||
EHCI_RH_HALTED,
|
||||
EHCI_RH_SUSPENDED,
|
||||
EHCI_RH_RUNNING
|
||||
};
|
||||
|
||||
struct ehci_hcd { /* one per controller */
|
||||
/* glue to PCI and HCD framework */
|
||||
struct ehci_caps __iomem *caps;
|
||||
@@ -70,6 +76,7 @@ struct ehci_hcd { /* one per controller */
|
||||
|
||||
__u32 hcs_params; /* cached register copy */
|
||||
spinlock_t lock;
|
||||
enum ehci_rh_state rh_state;
|
||||
|
||||
/* async schedule support */
|
||||
struct ehci_qh *async;
|
||||
@@ -139,6 +146,7 @@ struct ehci_hcd { /* one per controller */
|
||||
unsigned fs_i_thresh:1; /* Intel iso scheduling */
|
||||
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
|
||||
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
|
||||
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
|
||||
|
||||
/* required for usb32 quirk */
|
||||
#define OHCI_CTRL_HCFS (3 << 6)
|
||||
@@ -740,6 +748,22 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
/* For working around the MosChip frame-index-register bug */
|
||||
static unsigned ehci_read_frame_index(struct ehci_hcd *ehci);
|
||||
|
||||
#else
|
||||
|
||||
static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
|
||||
{
|
||||
return ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef DEBUG
|
||||
#define STUB_DEBUG_FILES
|
||||
#endif /* DEBUG */
|
||||
|
@@ -621,12 +621,15 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
|
||||
goto err_pram;
|
||||
}
|
||||
|
||||
pram_addr = cpm_muram_alloc_fixed(iprop[2], FHCI_PRAM_SIZE);
|
||||
pram_addr = cpm_muram_alloc(FHCI_PRAM_SIZE, 64);
|
||||
if (IS_ERR_VALUE(pram_addr)) {
|
||||
dev_err(dev, "failed to allocate usb pram\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_pram;
|
||||
}
|
||||
|
||||
qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, QE_CR_SUBBLOCK_USB,
|
||||
QE_CR_PROTOCOL_UNSPECIFIED, pram_addr);
|
||||
fhci->pram = cpm_muram_addr(pram_addr);
|
||||
|
||||
/* GPIOs and pins */
|
||||
@@ -686,7 +689,7 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
|
||||
}
|
||||
|
||||
ret = request_irq(fhci->timer->irq, fhci_frame_limit_timer_irq,
|
||||
IRQF_DISABLED, "qe timer (usb)", hcd);
|
||||
0, "qe timer (usb)", hcd);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request timer irq");
|
||||
goto err_timer_irq;
|
||||
@@ -745,7 +748,7 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
|
||||
out_be16(&fhci->regs->usb_event, 0xffff);
|
||||
out_be16(&fhci->regs->usb_mask, 0);
|
||||
|
||||
ret = usb_add_hcd(hcd, usb_irq, IRQF_DISABLED);
|
||||
ret = usb_add_hcd(hcd, usb_irq, 0);
|
||||
if (ret < 0)
|
||||
goto err_add_hcd;
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Freescale QUICC Engine USB Host Controller Driver
|
||||
*
|
||||
* Copyright (c) Freescale Semicondutor, Inc. 2006.
|
||||
* Copyright (c) Freescale Semicondutor, Inc. 2006, 2011.
|
||||
* Shlomi Gridish <gridish@freescale.com>
|
||||
* Jerry Huang <Chang-Ming.Huang@freescale.com>
|
||||
* Copyright (c) Logic Product Development, Inc. 2007
|
||||
@@ -810,9 +810,11 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb)
|
||||
ed->dev_addr = usb_pipedevice(urb->pipe);
|
||||
ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe,
|
||||
usb_pipeout(urb->pipe));
|
||||
/* setup stage */
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP,
|
||||
USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true);
|
||||
|
||||
/* data stage */
|
||||
if (data_len > 0) {
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
|
||||
usb_pipeout(urb->pipe) ? FHCI_TA_OUT :
|
||||
@@ -820,9 +822,18 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb)
|
||||
USB_TD_TOGGLE_DATA1, data, data_len, 0, 0,
|
||||
true);
|
||||
}
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
|
||||
usb_pipeout(urb->pipe) ? FHCI_TA_IN : FHCI_TA_OUT,
|
||||
USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
|
||||
|
||||
/* status stage */
|
||||
if (data_len > 0)
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
|
||||
(usb_pipeout(urb->pipe) ? FHCI_TA_IN :
|
||||
FHCI_TA_OUT),
|
||||
USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
|
||||
else
|
||||
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
|
||||
FHCI_TA_IN,
|
||||
USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
|
||||
|
||||
urb_state = US_CTRL_SETUP;
|
||||
break;
|
||||
case FHCI_TF_ISO:
|
||||
|
@@ -1891,7 +1891,7 @@ static int imx21_probe(struct platform_device *pdev)
|
||||
dev_info(imx21->dev, "Hardware HC revision: 0x%02X\n",
|
||||
(readl(imx21->regs + USBOTG_HWMODE) >> 16) & 0xFF);
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
ret = usb_add_hcd(hcd, irq, 0);
|
||||
if (ret != 0) {
|
||||
dev_err(imx21->dev, "usb_add_hcd() returned %d\n", ret);
|
||||
goto failed_add_hcd;
|
||||
|
@@ -1639,7 +1639,7 @@ static int __devinit isp116x_probe(struct platform_device *pdev)
|
||||
goto err6;
|
||||
}
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, irqflags | IRQF_DISABLED);
|
||||
ret = usb_add_hcd(hcd, irq, irqflags);
|
||||
if (ret)
|
||||
goto err6;
|
||||
|
||||
|
@@ -2358,7 +2358,7 @@ static int isp1362_hc_reset(struct usb_hcd *hcd)
|
||||
unsigned long flags;
|
||||
int clkrdy = 0;
|
||||
|
||||
pr_info("%s:\n", __func__);
|
||||
pr_debug("%s:\n", __func__);
|
||||
|
||||
if (isp1362_hcd->board && isp1362_hcd->board->reset) {
|
||||
isp1362_hcd->board->reset(hcd->self.controller, 1);
|
||||
@@ -2395,7 +2395,7 @@ static void isp1362_hc_stop(struct usb_hcd *hcd)
|
||||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
pr_info("%s:\n", __func__);
|
||||
pr_debug("%s:\n", __func__);
|
||||
|
||||
del_timer_sync(&hcd->rh_timer);
|
||||
|
||||
@@ -2523,7 +2523,7 @@ static int isp1362_hc_start(struct usb_hcd *hcd)
|
||||
u16 chipid;
|
||||
unsigned long flags;
|
||||
|
||||
pr_info("%s:\n", __func__);
|
||||
pr_debug("%s:\n", __func__);
|
||||
|
||||
spin_lock_irqsave(&isp1362_hcd->lock, flags);
|
||||
chipid = isp1362_read_reg16(isp1362_hcd, HCCHIPID);
|
||||
@@ -2773,7 +2773,7 @@ static int __devinit isp1362_probe(struct platform_device *pdev)
|
||||
if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL)
|
||||
irq_flags |= IRQF_TRIGGER_LOW;
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_DISABLED | IRQF_SHARED);
|
||||
retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
goto err6;
|
||||
pr_info("%s, irq %d\n", hcd->product_desc, irq);
|
||||
|
@@ -21,8 +21,10 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "isp1760-hcd.h"
|
||||
|
||||
@@ -39,7 +41,6 @@ struct isp1760_hcd {
|
||||
int int_done_map;
|
||||
struct memory_chunk memory_pool[BLOCKS];
|
||||
struct list_head controlqhs, bulkqhs, interruptqhs;
|
||||
int active_ptds;
|
||||
|
||||
/* periodic schedule support */
|
||||
#define DEFAULT_I_TDPS 1024
|
||||
@@ -48,6 +49,8 @@ struct isp1760_hcd {
|
||||
unsigned long reset_done;
|
||||
unsigned long next_statechange;
|
||||
unsigned int devflags;
|
||||
|
||||
int rst_gpio;
|
||||
};
|
||||
|
||||
static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
|
||||
@@ -114,6 +117,7 @@ struct isp1760_qh {
|
||||
u32 toggle;
|
||||
u32 ping;
|
||||
int slot;
|
||||
int tt_buffer_dirty; /* See USB2.0 spec section 11.17.5 */
|
||||
};
|
||||
|
||||
struct urb_listitem {
|
||||
@@ -432,6 +436,18 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
|
||||
int result;
|
||||
u32 scratch, hwmode;
|
||||
|
||||
/* low-level chip reset */
|
||||
if (gpio_is_valid(priv->rst_gpio)) {
|
||||
unsigned int rst_lvl;
|
||||
|
||||
rst_lvl = (priv->devflags &
|
||||
ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0;
|
||||
|
||||
gpio_set_value(priv->rst_gpio, rst_lvl);
|
||||
mdelay(50);
|
||||
gpio_set_value(priv->rst_gpio, !rst_lvl);
|
||||
}
|
||||
|
||||
/* Setup HW Mode Control: This assumes a level active-low interrupt */
|
||||
hwmode = HW_DATA_BUS_32BIT;
|
||||
|
||||
@@ -489,10 +505,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
|
||||
16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
|
||||
"analog" : "digital");
|
||||
|
||||
/* This is weird: at the first plug-in of a device there seems to be
|
||||
one packet queued that never gets returned? */
|
||||
priv->active_ptds = -1;
|
||||
|
||||
/* ATL reset */
|
||||
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
|
||||
mdelay(10);
|
||||
@@ -514,83 +526,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
|
||||
return priv_init(hcd);
|
||||
}
|
||||
|
||||
static void isp1760_init_maps(struct usb_hcd *hcd)
|
||||
{
|
||||
/*set last maps, for iso its only 1, else 32 tds bitmap*/
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
|
||||
reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
|
||||
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
|
||||
reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
|
||||
ATL_BUF_FILL | INT_BUF_FILL);
|
||||
}
|
||||
|
||||
static void isp1760_enable_interrupts(struct usb_hcd *hcd)
|
||||
{
|
||||
reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
/* step 23 passed */
|
||||
}
|
||||
|
||||
static int isp1760_run(struct usb_hcd *hcd)
|
||||
{
|
||||
int retval;
|
||||
u32 temp;
|
||||
u32 command;
|
||||
u32 chipid;
|
||||
|
||||
hcd->uses_new_polling = 1;
|
||||
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
isp1760_enable_interrupts(hcd);
|
||||
temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
|
||||
reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
|
||||
|
||||
command = reg_read32(hcd->regs, HC_USBCMD);
|
||||
command &= ~(CMD_LRESET|CMD_RESET);
|
||||
command |= CMD_RUN;
|
||||
reg_write32(hcd->regs, HC_USBCMD, command);
|
||||
|
||||
retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Spec says to write FLAG_CF as last config action, priv code grabs
|
||||
* the semaphore while doing so.
|
||||
*/
|
||||
down_write(&ehci_cf_port_reset_rwsem);
|
||||
reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
|
||||
|
||||
retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
|
||||
up_write(&ehci_cf_port_reset_rwsem);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
|
||||
dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
|
||||
chipid & 0xffff, chipid >> 16);
|
||||
|
||||
/* PTD Register Init Part 2, Step 28 */
|
||||
/* enable INTs */
|
||||
isp1760_init_maps(hcd);
|
||||
|
||||
/* GRR this is run-once init(), being done every time the HC starts.
|
||||
* So long as they're part of class devices, we can't do it init()
|
||||
* since the class device isn't created that early.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 base_to_chip(u32 base)
|
||||
{
|
||||
return ((base - 0x400) >> 3);
|
||||
@@ -813,28 +748,29 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
|
||||
WARN_ON(slots[slot].qh);
|
||||
WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
|
||||
|
||||
slots[slot].qtd = qtd;
|
||||
slots[slot].qh = qh;
|
||||
qh->slot = slot;
|
||||
qtd->status = QTD_XFER_STARTED; /* Set this before writing ptd, since
|
||||
interrupt routine may preempt and expects this value. */
|
||||
ptd_write(hcd->regs, ptd_offset, slot, ptd);
|
||||
priv->active_ptds++;
|
||||
|
||||
/* Make sure done map has not triggered from some unlinked transfer */
|
||||
if (ptd_offset == ATL_PTD_OFFSET) {
|
||||
priv->atl_done_map |= reg_read32(hcd->regs,
|
||||
HC_ATL_PTD_DONEMAP_REG);
|
||||
priv->atl_done_map &= ~(1 << qh->slot);
|
||||
priv->atl_done_map &= ~(1 << slot);
|
||||
} else {
|
||||
priv->int_done_map |= reg_read32(hcd->regs,
|
||||
HC_INT_PTD_DONEMAP_REG);
|
||||
priv->int_done_map &= ~(1 << slot);
|
||||
}
|
||||
|
||||
qh->slot = slot;
|
||||
qtd->status = QTD_XFER_STARTED;
|
||||
slots[slot].timestamp = jiffies;
|
||||
slots[slot].qtd = qtd;
|
||||
slots[slot].qh = qh;
|
||||
ptd_write(hcd->regs, ptd_offset, slot, ptd);
|
||||
|
||||
if (ptd_offset == ATL_PTD_OFFSET) {
|
||||
skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
|
||||
skip_map &= ~(1 << qh->slot);
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
|
||||
} else {
|
||||
priv->int_done_map |= reg_read32(hcd->regs,
|
||||
HC_INT_PTD_DONEMAP_REG);
|
||||
priv->int_done_map &= ~(1 << qh->slot);
|
||||
|
||||
skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
|
||||
skip_map &= ~(1 << qh->slot);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
|
||||
@@ -858,10 +794,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
||||
if (qtd->status < QTD_XFER_COMPLETE)
|
||||
break;
|
||||
|
||||
if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
|
||||
last_qtd = 1;
|
||||
else
|
||||
last_qtd = qtd->urb != qtd_next->urb;
|
||||
last_qtd = last_qtd_of_urb(qtd, qh);
|
||||
|
||||
if ((!last_qtd) && (qtd->status == QTD_RETIRE))
|
||||
qtd_next->status = QTD_RETIRE;
|
||||
@@ -902,7 +835,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
||||
urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
|
||||
GFP_ATOMIC);
|
||||
if (unlikely(!urb_listitem))
|
||||
break;
|
||||
break; /* Try again on next call */
|
||||
urb_listitem->urb = qtd->urb;
|
||||
list_add_tail(&urb_listitem->urb_list, urb_list);
|
||||
}
|
||||
@@ -928,6 +861,10 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure this endpoint's TT buffer is clean before queueing ptds */
|
||||
if (qh->tt_buffer_dirty)
|
||||
return;
|
||||
|
||||
if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
|
||||
qtd_list)->urb->pipe)) {
|
||||
ptd_offset = INT_PTD_OFFSET;
|
||||
@@ -1168,11 +1105,9 @@ static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
|
||||
return PTD_STATE_QTD_DONE;
|
||||
}
|
||||
|
||||
static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
||||
static void handle_done_ptds(struct usb_hcd *hcd)
|
||||
{
|
||||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
u32 imask;
|
||||
irqreturn_t irqret = IRQ_NONE;
|
||||
struct ptd ptd;
|
||||
struct isp1760_qh *qh;
|
||||
int slot;
|
||||
@@ -1181,27 +1116,14 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
||||
u32 ptd_offset;
|
||||
struct isp1760_qtd *qtd;
|
||||
int modified;
|
||||
static int last_active_ptds;
|
||||
int int_skip_map, atl_skip_map;
|
||||
int skip_map;
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
|
||||
priv->int_done_map &= ~skip_map;
|
||||
skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
|
||||
priv->atl_done_map &= ~skip_map;
|
||||
|
||||
if (!(hcd->state & HC_STATE_RUNNING))
|
||||
goto leave;
|
||||
|
||||
imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
|
||||
if (unlikely(!imask))
|
||||
goto leave;
|
||||
reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
|
||||
|
||||
int_skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
|
||||
atl_skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
|
||||
priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
|
||||
priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
|
||||
priv->int_done_map &= ~int_skip_map;
|
||||
priv->atl_done_map &= ~atl_skip_map;
|
||||
|
||||
modified = priv->int_done_map | priv->atl_done_map;
|
||||
modified = priv->int_done_map || priv->atl_done_map;
|
||||
|
||||
while (priv->int_done_map || priv->atl_done_map) {
|
||||
if (priv->int_done_map) {
|
||||
@@ -1240,7 +1162,6 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
||||
slots[slot].qtd = NULL;
|
||||
qh = slots[slot].qh;
|
||||
slots[slot].qh = NULL;
|
||||
priv->active_ptds--;
|
||||
qh->slot = -1;
|
||||
|
||||
WARN_ON(qtd->status != QTD_XFER_STARTED);
|
||||
@@ -1281,6 +1202,15 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
||||
|
||||
case PTD_STATE_URB_RETIRE:
|
||||
qtd->status = QTD_RETIRE;
|
||||
if ((qtd->urb->dev->speed != USB_SPEED_HIGH) &&
|
||||
(qtd->urb->status != -EPIPE) &&
|
||||
(qtd->urb->status != -EREMOTEIO)) {
|
||||
qh->tt_buffer_dirty = 1;
|
||||
if (usb_hub_clear_tt_buffer(qtd->urb))
|
||||
/* Clear failed; let's hope things work
|
||||
anyway */
|
||||
qh->tt_buffer_dirty = 0;
|
||||
}
|
||||
qtd = NULL;
|
||||
qh->toggle = 0;
|
||||
qh->ping = 0;
|
||||
@@ -1311,22 +1241,28 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
||||
|
||||
if (modified)
|
||||
schedule_ptds(hcd);
|
||||
}
|
||||
|
||||
/* ISP1760 Errata 2 explains that interrupts may be missed (or not
|
||||
happen?) if two USB devices are running simultaneously. Perhaps
|
||||
this happens when a PTD is finished during interrupt handling;
|
||||
enable SOF interrupts if PTDs are still scheduled when exiting this
|
||||
interrupt handler, just to be safe. */
|
||||
static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
||||
{
|
||||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
u32 imask;
|
||||
irqreturn_t irqret = IRQ_NONE;
|
||||
|
||||
if (priv->active_ptds != last_active_ptds) {
|
||||
if (priv->active_ptds > 0)
|
||||
reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
|
||||
INTERRUPT_ENABLE_SOT_MASK);
|
||||
else
|
||||
reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
|
||||
INTERRUPT_ENABLE_MASK);
|
||||
last_active_ptds = priv->active_ptds;
|
||||
}
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
if (!(hcd->state & HC_STATE_RUNNING))
|
||||
goto leave;
|
||||
|
||||
imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
|
||||
if (unlikely(!imask))
|
||||
goto leave;
|
||||
reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
|
||||
|
||||
priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
|
||||
priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
|
||||
|
||||
handle_done_ptds(hcd);
|
||||
|
||||
irqret = IRQ_HANDLED;
|
||||
leave:
|
||||
@@ -1335,6 +1271,138 @@ leave:
|
||||
return irqret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround for problem described in chip errata 2:
|
||||
*
|
||||
* Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
|
||||
* One solution suggested in the errata is to use SOF interrupts _instead_of_
|
||||
* ATL done interrupts (the "instead of" might be important since it seems
|
||||
* enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
|
||||
* to set the PTD's done bit in addition to not generating an interrupt!).
|
||||
*
|
||||
* So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
|
||||
* done bit is not being set. This is bad - it blocks the endpoint until reboot.
|
||||
*
|
||||
* If we use SOF interrupts only, we get latency between ptd completion and the
|
||||
* actual handling. This is very noticeable in testusb runs which takes several
|
||||
* minutes longer without ATL interrupts.
|
||||
*
|
||||
* A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
|
||||
* finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
|
||||
* slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
|
||||
* completed and its done map bit is set.
|
||||
*
|
||||
* The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
|
||||
* not to cause too much lag when this HW bug occurs, while still hopefully
|
||||
* ensuring that the check does not falsely trigger.
|
||||
*/
|
||||
#define SLOT_TIMEOUT 300
|
||||
#define SLOT_CHECK_PERIOD 200
|
||||
static struct timer_list errata2_timer;
|
||||
|
||||
void errata2_function(unsigned long data)
|
||||
{
|
||||
struct usb_hcd *hcd = (struct usb_hcd *) data;
|
||||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
int slot;
|
||||
struct ptd ptd;
|
||||
unsigned long spinflags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, spinflags);
|
||||
|
||||
for (slot = 0; slot < 32; slot++)
|
||||
if (priv->atl_slots[slot].qh && time_after(jiffies,
|
||||
priv->atl_slots[slot].timestamp +
|
||||
SLOT_TIMEOUT * HZ / 1000)) {
|
||||
ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
|
||||
if (!FROM_DW0_VALID(ptd.dw0) &&
|
||||
!FROM_DW3_ACTIVE(ptd.dw3))
|
||||
priv->atl_done_map |= 1 << slot;
|
||||
}
|
||||
|
||||
if (priv->atl_done_map)
|
||||
handle_done_ptds(hcd);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, spinflags);
|
||||
|
||||
errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
|
||||
add_timer(&errata2_timer);
|
||||
}
|
||||
|
||||
static int isp1760_run(struct usb_hcd *hcd)
|
||||
{
|
||||
int retval;
|
||||
u32 temp;
|
||||
u32 command;
|
||||
u32 chipid;
|
||||
|
||||
hcd->uses_new_polling = 1;
|
||||
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
/* Set PTD interrupt AND & OR maps */
|
||||
reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
/* step 23 passed */
|
||||
|
||||
temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
|
||||
reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
|
||||
|
||||
command = reg_read32(hcd->regs, HC_USBCMD);
|
||||
command &= ~(CMD_LRESET|CMD_RESET);
|
||||
command |= CMD_RUN;
|
||||
reg_write32(hcd->regs, HC_USBCMD, command);
|
||||
|
||||
retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Spec says to write FLAG_CF as last config action, priv code grabs
|
||||
* the semaphore while doing so.
|
||||
*/
|
||||
down_write(&ehci_cf_port_reset_rwsem);
|
||||
reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
|
||||
|
||||
retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
|
||||
up_write(&ehci_cf_port_reset_rwsem);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
init_timer(&errata2_timer);
|
||||
errata2_timer.function = errata2_function;
|
||||
errata2_timer.data = (unsigned long) hcd;
|
||||
errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
|
||||
add_timer(&errata2_timer);
|
||||
|
||||
chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
|
||||
dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
|
||||
chipid & 0xffff, chipid >> 16);
|
||||
|
||||
/* PTD Register Init Part 2, Step 28 */
|
||||
|
||||
/* Setup registers controlling PTD checking */
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
|
||||
reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
|
||||
ATL_BUF_FILL | INT_BUF_FILL);
|
||||
|
||||
/* GRR this is run-once init(), being done every time the HC starts.
|
||||
* So long as they're part of class devices, we can't do it init()
|
||||
* since the class device isn't created that early.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
|
||||
{
|
||||
qtd->data_buffer = databuffer;
|
||||
@@ -1503,7 +1571,6 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
||||
packetize_urb(hcd, urb, &new_qtds, mem_flags);
|
||||
if (list_empty(&new_qtds))
|
||||
return -ENOMEM;
|
||||
urb->hcpriv = NULL; /* Used to signal unlink to interrupt handler */
|
||||
|
||||
retval = 0;
|
||||
spin_lock_irqsave(&priv->lock, spinflags);
|
||||
@@ -1531,6 +1598,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
||||
qh = qh_alloc(GFP_ATOMIC);
|
||||
if (!qh) {
|
||||
retval = -ENOMEM;
|
||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&qh->qh_list, ep_queue);
|
||||
@@ -1570,7 +1638,41 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
|
||||
}
|
||||
|
||||
qh->slot = -1;
|
||||
priv->active_ptds--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
|
||||
* any active transfer belonging to the urb in the process.
|
||||
*/
|
||||
static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
||||
struct isp1760_qtd *qtd)
|
||||
{
|
||||
struct urb *urb;
|
||||
int urb_was_running;
|
||||
|
||||
urb = qtd->urb;
|
||||
urb_was_running = 0;
|
||||
list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) {
|
||||
if (qtd->urb != urb)
|
||||
break;
|
||||
|
||||
if (qtd->status >= QTD_XFER_STARTED)
|
||||
urb_was_running = 1;
|
||||
if (last_qtd_of_urb(qtd, qh) &&
|
||||
(qtd->status >= QTD_XFER_COMPLETE))
|
||||
urb_was_running = 0;
|
||||
|
||||
if (qtd->status == QTD_XFER_STARTED)
|
||||
kill_transfer(hcd, urb, qh);
|
||||
qtd->status = QTD_RETIRE;
|
||||
}
|
||||
|
||||
if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) {
|
||||
qh->tt_buffer_dirty = 1;
|
||||
if (usb_hub_clear_tt_buffer(urb))
|
||||
/* Clear failed; let's hope things work anyway */
|
||||
qh->tt_buffer_dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
|
||||
@@ -1595,9 +1697,8 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
|
||||
|
||||
list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
|
||||
if (qtd->urb == urb) {
|
||||
if (qtd->status == QTD_XFER_STARTED)
|
||||
kill_transfer(hcd, urb, qh);
|
||||
qtd->status = QTD_RETIRE;
|
||||
dequeue_urb_from_qtd(hcd, qh, qtd);
|
||||
break;
|
||||
}
|
||||
|
||||
urb->status = status;
|
||||
@@ -1622,12 +1723,11 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
|
||||
if (!qh)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
|
||||
if (qtd->status == QTD_XFER_STARTED)
|
||||
kill_transfer(hcd, qtd->urb, qh);
|
||||
qtd->status = QTD_RETIRE;
|
||||
qtd->urb->status = -ECONNRESET;
|
||||
}
|
||||
list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
|
||||
if (qtd->status != QTD_RETIRE) {
|
||||
dequeue_urb_from_qtd(hcd, qh, qtd);
|
||||
qtd->urb->status = -ECONNRESET;
|
||||
}
|
||||
|
||||
ep->hcpriv = NULL;
|
||||
/* Cannot free qh here since it will be parsed by schedule_ptds() */
|
||||
@@ -2021,6 +2121,8 @@ static void isp1760_stop(struct usb_hcd *hcd)
|
||||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
u32 temp;
|
||||
|
||||
del_timer(&errata2_timer);
|
||||
|
||||
isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
|
||||
NULL, 0);
|
||||
mdelay(20);
|
||||
@@ -2048,6 +2150,23 @@ static void isp1760_shutdown(struct usb_hcd *hcd)
|
||||
reg_write32(hcd->regs, HC_USBCMD, command);
|
||||
}
|
||||
|
||||
static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
struct isp1760_qh *qh = ep->hcpriv;
|
||||
unsigned long spinflags;
|
||||
|
||||
if (!qh)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, spinflags);
|
||||
qh->tt_buffer_dirty = 0;
|
||||
schedule_ptds(hcd);
|
||||
spin_unlock_irqrestore(&priv->lock, spinflags);
|
||||
}
|
||||
|
||||
|
||||
static const struct hc_driver isp1760_hc_driver = {
|
||||
.description = "isp1760-hcd",
|
||||
.product_desc = "NXP ISP1760 USB Host Controller",
|
||||
@@ -2064,6 +2183,7 @@ static const struct hc_driver isp1760_hc_driver = {
|
||||
.get_frame_number = isp1760_get_frame,
|
||||
.hub_status_data = isp1760_hub_status_data,
|
||||
.hub_control = isp1760_hub_control,
|
||||
.clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
int __init init_kmem_once(void)
|
||||
@@ -2102,6 +2222,7 @@ void deinit_kmem_cache(void)
|
||||
|
||||
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
|
||||
int irq, unsigned long irqflags,
|
||||
int rst_gpio,
|
||||
struct device *dev, const char *busname,
|
||||
unsigned int devflags)
|
||||
{
|
||||
@@ -2121,6 +2242,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
|
||||
|
||||
priv = hcd_to_priv(hcd);
|
||||
priv->devflags = devflags;
|
||||
priv->rst_gpio = rst_gpio;
|
||||
init_memory(priv);
|
||||
hcd->regs = ioremap(res_start, res_len);
|
||||
if (!hcd->regs) {
|
||||
|
@@ -4,6 +4,7 @@
|
||||
/* exports for if */
|
||||
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
|
||||
int irq, unsigned long irqflags,
|
||||
int rst_gpio,
|
||||
struct device *dev, const char *busname,
|
||||
unsigned int devflags);
|
||||
int init_kmem_once(void);
|
||||
@@ -73,7 +74,6 @@ void deinit_kmem_cache(void);
|
||||
#define HC_EOT_INT (1 << 3)
|
||||
#define HC_SOT_INT (1 << 1)
|
||||
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
|
||||
#define INTERRUPT_ENABLE_SOT_MASK (HC_SOT_INT)
|
||||
|
||||
#define HC_ISO_IRQ_MASK_OR_REG 0x318
|
||||
#define HC_INT_IRQ_MASK_OR_REG 0x31C
|
||||
@@ -107,6 +107,7 @@ struct ptd {
|
||||
struct slotinfo {
|
||||
struct isp1760_qh *qh;
|
||||
struct isp1760_qtd *qtd;
|
||||
unsigned long timestamp;
|
||||
};
|
||||
|
||||
|
||||
@@ -126,6 +127,7 @@ typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
||||
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
|
||||
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
|
||||
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
|
||||
#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */
|
||||
|
||||
/* chip memory management */
|
||||
struct memory_chunk {
|
||||
@@ -188,6 +190,7 @@ struct memory_chunk {
|
||||
#define DW3_BABBLE_BIT (1 << 29)
|
||||
#define DW3_HALT_BIT (1 << 30)
|
||||
#define DW3_ACTIVE_BIT (1 << 31)
|
||||
#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
|
||||
|
||||
#define INT_UNDERRUN (1 << 2)
|
||||
#define INT_BABBLE (1 << 1)
|
||||
|
@@ -17,19 +17,28 @@
|
||||
|
||||
#include "isp1760-hcd.h"
|
||||
|
||||
#ifdef CONFIG_PPC_OF
|
||||
#ifdef CONFIG_OF
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#include <linux/pci.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC_OF
|
||||
#ifdef CONFIG_OF
|
||||
struct isp1760 {
|
||||
struct usb_hcd *hcd;
|
||||
int rst_gpio;
|
||||
};
|
||||
|
||||
static int of_isp1760_probe(struct platform_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct isp1760 *drvdata;
|
||||
struct device_node *dp = dev->dev.of_node;
|
||||
struct resource *res;
|
||||
struct resource memory;
|
||||
@@ -39,6 +48,11 @@ static int of_isp1760_probe(struct platform_device *dev)
|
||||
int ret;
|
||||
const unsigned int *prop;
|
||||
unsigned int devflags = 0;
|
||||
enum of_gpio_flags gpio_flags;
|
||||
|
||||
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_address_to_resource(dp, 0, &memory);
|
||||
if (ret)
|
||||
@@ -78,32 +92,57 @@ static int of_isp1760_probe(struct platform_device *dev)
|
||||
if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
|
||||
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
|
||||
|
||||
hcd = isp1760_register(memory.start, res_len, virq,
|
||||
IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
|
||||
devflags);
|
||||
if (IS_ERR(hcd)) {
|
||||
ret = PTR_ERR(hcd);
|
||||
goto release_reg;
|
||||
drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
|
||||
if (gpio_is_valid(drvdata->rst_gpio)) {
|
||||
ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev));
|
||||
if (!ret) {
|
||||
if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) {
|
||||
devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH;
|
||||
gpio_direction_output(drvdata->rst_gpio, 0);
|
||||
} else {
|
||||
gpio_direction_output(drvdata->rst_gpio, 1);
|
||||
}
|
||||
} else {
|
||||
drvdata->rst_gpio = ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_set_drvdata(&dev->dev, hcd);
|
||||
drvdata->hcd = isp1760_register(memory.start, res_len, virq,
|
||||
IRQF_SHARED, drvdata->rst_gpio,
|
||||
&dev->dev, dev_name(&dev->dev),
|
||||
devflags);
|
||||
if (IS_ERR(drvdata->hcd)) {
|
||||
ret = PTR_ERR(drvdata->hcd);
|
||||
goto free_gpio;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&dev->dev, drvdata);
|
||||
return ret;
|
||||
|
||||
free_gpio:
|
||||
if (gpio_is_valid(drvdata->rst_gpio))
|
||||
gpio_free(drvdata->rst_gpio);
|
||||
release_reg:
|
||||
release_mem_region(memory.start, res_len);
|
||||
kfree(drvdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int of_isp1760_remove(struct platform_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
|
||||
struct isp1760 *drvdata = dev_get_drvdata(&dev->dev);
|
||||
|
||||
dev_set_drvdata(&dev->dev, NULL);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
usb_remove_hcd(drvdata->hcd);
|
||||
iounmap(drvdata->hcd->regs);
|
||||
release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
|
||||
usb_put_hcd(drvdata->hcd);
|
||||
|
||||
if (gpio_is_valid(drvdata->rst_gpio))
|
||||
gpio_free(drvdata->rst_gpio);
|
||||
|
||||
kfree(drvdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -240,7 +279,7 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
|
||||
|
||||
dev->dev.dma_mask = NULL;
|
||||
hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
|
||||
IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
|
||||
IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev),
|
||||
devflags);
|
||||
if (IS_ERR(hcd)) {
|
||||
ret_status = -ENODEV;
|
||||
@@ -313,7 +352,7 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
|
||||
resource_size_t mem_size;
|
||||
struct isp1760_platform_data *priv = pdev->dev.platform_data;
|
||||
unsigned int devflags = 0;
|
||||
unsigned long irqflags = IRQF_SHARED | IRQF_DISABLED;
|
||||
unsigned long irqflags = IRQF_SHARED;
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem_res) {
|
||||
@@ -351,7 +390,8 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
|
||||
irqflags, &pdev->dev, dev_name(&pdev->dev), devflags);
|
||||
irqflags, -ENOENT,
|
||||
&pdev->dev, dev_name(&pdev->dev), devflags);
|
||||
if (IS_ERR(hcd)) {
|
||||
pr_warning("isp1760: Failed to register the HCD device\n");
|
||||
ret = -ENODEV;
|
||||
@@ -396,7 +436,7 @@ static int __init isp1760_init(void)
|
||||
ret = platform_driver_register(&isp1760_plat_driver);
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
#ifdef CONFIG_PPC_OF
|
||||
#ifdef CONFIG_OF
|
||||
ret = platform_driver_register(&isp1760_of_driver);
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
@@ -416,7 +456,7 @@ module_init(isp1760_init);
|
||||
static void __exit isp1760_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&isp1760_plat_driver);
|
||||
#ifdef CONFIG_PPC_OF
|
||||
#ifdef CONFIG_OF
|
||||
platform_driver_unregister(&isp1760_of_driver);
|
||||
#endif
|
||||
#ifdef CONFIG_PCI
|
||||
|
@@ -111,7 +111,7 @@ static int ohci_ath79_probe(struct platform_device *pdev)
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
ret = usb_add_hcd(hcd, irq, 0);
|
||||
if (ret)
|
||||
goto err_stop_hcd;
|
||||
|
||||
|
@@ -218,7 +218,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
ret = usb_add_hcd(hcd, pdev->resource[1].start,
|
||||
IRQF_DISABLED | IRQF_SHARED);
|
||||
IRQF_SHARED);
|
||||
if (ret == 0) {
|
||||
platform_set_drvdata(pdev, hcd);
|
||||
return ret;
|
||||
|
@@ -344,7 +344,7 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
|
||||
error = -ENODEV;
|
||||
goto err4;
|
||||
}
|
||||
error = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
error = usb_add_hcd(hcd, irq, 0);
|
||||
if (error)
|
||||
goto err4;
|
||||
|
||||
|
@@ -81,7 +81,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
|
||||
retval = usb_add_hcd(hcd, pdev->resource[1].start, 0);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
|
@@ -1114,6 +1114,11 @@ MODULE_LICENSE ("GPL");
|
||||
#define PLATFORM_DRIVER ohci_hcd_ath79_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NLM_XLR
|
||||
#include "ohci-xls.c"
|
||||
#define PLATFORM_DRIVER ohci_xls_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && \
|
||||
!defined(PLATFORM_DRIVER) && \
|
||||
!defined(OMAP1_PLATFORM_DRIVER) && \
|
||||
|
@@ -356,10 +356,7 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
/* Does the root hub have a port wakeup pending? */
|
||||
if (ohci_readl(ohci, &ohci->regs->intrstatus) &
|
||||
(OHCI_INTR_RD | OHCI_INTR_RHSC))
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
}
|
||||
|
||||
/* Carry out polling-, autostop-, and autoresume-related state changes */
|
||||
|
@@ -164,7 +164,7 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev)
|
||||
|
||||
ohci_hcd_init(ohci);
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
|
||||
goto err3;
|
||||
|
@@ -14,7 +14,7 @@
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
#include <linux/signal.h> /* IRQF_DISABLED */
|
||||
#include <linux/signal.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -363,7 +363,7 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
|
||||
retval = -ENXIO;
|
||||
goto err3;
|
||||
}
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
retval = usb_add_hcd(hcd, irq, 0);
|
||||
if (retval)
|
||||
goto err3;
|
||||
|
||||
|
@@ -149,7 +149,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
|
||||
|
||||
res = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, "ohci");
|
||||
if (!ret) {
|
||||
if (!res) {
|
||||
dev_err(dev, "UHH OHCI get resource failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -180,7 +180,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
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;
|
||||
|
@@ -398,7 +398,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
|
||||
ohci_hcd_init(ohci);
|
||||
|
||||
dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
ret = usb_add_hcd(hcd, irq, 0);
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
|
||||
|
@@ -107,7 +107,7 @@ int usb_hcd_pnx8550_probe (const struct hc_driver *driver,
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
|
||||
retval = usb_add_hcd(hcd, dev->resource[1].start, 0);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
|
@@ -143,7 +143,7 @@ static int __devinit ohci_hcd_ppc_of_probe(struct platform_device *op)
|
||||
|
||||
ohci_hcd_init(ohci);
|
||||
|
||||
rv = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
rv = usb_add_hcd(hcd, irq, 0);
|
||||
if (rv == 0)
|
||||
return 0;
|
||||
|
||||
|
@@ -80,7 +80,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
|
||||
#endif
|
||||
ohci_hcd_init(ohci);
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
retval = usb_add_hcd(hcd, irq, 0);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
|
@@ -164,7 +164,7 @@ static int __devinit ps3_ohci_probe(struct ps3_system_bus_device *dev)
|
||||
|
||||
ps3_system_bus_set_drvdata(dev, hcd);
|
||||
|
||||
result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
|
||||
result = usb_add_hcd(hcd, virq, 0);
|
||||
|
||||
if (result) {
|
||||
dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
|
||||
|
@@ -359,7 +359,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
retval = usb_add_hcd(hcd, irq, 0);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
|
@@ -428,7 +428,7 @@ static struct ed *ed_get (
|
||||
ed->type = usb_pipetype(pipe);
|
||||
|
||||
info |= (ep->desc.bEndpointAddress & ~USB_DIR_IN) << 7;
|
||||
info |= le16_to_cpu(ep->desc.wMaxPacketSize) << 16;
|
||||
info |= usb_endpoint_maxp(&ep->desc) << 16;
|
||||
if (udev->speed == USB_SPEED_LOW)
|
||||
info |= ED_LOWSPEED;
|
||||
/* only control transfers store pids in tds */
|
||||
@@ -444,7 +444,7 @@ static struct ed *ed_get (
|
||||
ed->load = usb_calc_bus_time (
|
||||
udev->speed, !is_out,
|
||||
ed->type == PIPE_ISOCHRONOUS,
|
||||
le16_to_cpu(ep->desc.wMaxPacketSize))
|
||||
usb_endpoint_maxp(&ep->desc))
|
||||
/ 1000;
|
||||
}
|
||||
}
|
||||
|
@@ -384,7 +384,7 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
|
||||
retval = usb_add_hcd(hcd, dev->resource[1].start, 0);
|
||||
if (retval != 0)
|
||||
goto err_ioremap;
|
||||
|
||||
|
@@ -143,7 +143,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
|
||||
sa1111_start_hc(dev);
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, dev->irq[1], IRQF_DISABLED);
|
||||
retval = usb_add_hcd(hcd, dev->irq[1], 0);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
|
@@ -109,7 +109,7 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev)
|
||||
hcd->regs = (void __iomem *)res->start;
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret != 0) {
|
||||
err("Failed to add hcd");
|
||||
usb_put_hcd(hcd);
|
||||
|
@@ -165,7 +165,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (retval)
|
||||
goto err5;
|
||||
|
||||
|
@@ -152,7 +152,7 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
|
||||
spear_start_ohci(ohci_p);
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), IRQF_DISABLED);
|
||||
retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
|
@@ -169,7 +169,7 @@ static int ssb_ohci_attach(struct ssb_device *dev)
|
||||
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs)
|
||||
goto err_put_hcd;
|
||||
err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
|
||||
if (err)
|
||||
goto err_iounmap;
|
||||
|
||||
|
@@ -244,7 +244,7 @@ static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev)
|
||||
ohci = hcd_to_ohci(hcd);
|
||||
ohci_hcd_init(ohci);
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
ret = usb_add_hcd(hcd, irq, 0);
|
||||
if (ret)
|
||||
goto err_add_hcd;
|
||||
|
||||
|
151
drivers/usb/host/ohci-xls.c
Normal file
151
drivers/usb/host/ohci-xls.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* OHCI HCD for Netlogic XLS processors.
|
||||
*
|
||||
* (C) Copyright 2011 Netlogic Microsystems Inc.
|
||||
*
|
||||
* Based on ohci-au1xxx.c, and other Linux OHCI drivers.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/signal.h>
|
||||
|
||||
static int ohci_xls_probe_internal(const struct hc_driver *driver,
|
||||
struct platform_device *dev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct usb_hcd *hcd;
|
||||
int retval, irq;
|
||||
|
||||
/* Get our IRQ from an earlier registered Platform Resource */
|
||||
irq = platform_get_irq(dev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&dev->dev, "Found HC with no IRQ\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Get our Memory Handle */
|
||||
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&dev->dev, "MMIO Handle incorrect!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(driver, &dev->dev, "XLS");
|
||||
if (!hcd) {
|
||||
retval = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = res->end - res->start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
|
||||
driver->description)) {
|
||||
dev_dbg(&dev->dev, "Controller already in use\n");
|
||||
retval = -EBUSY;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (hcd->regs == NULL) {
|
||||
dev_dbg(&dev->dev, "error mapping memory\n");
|
||||
retval = -EFAULT;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
goto err4;
|
||||
return retval;
|
||||
|
||||
err4:
|
||||
iounmap(hcd->regs);
|
||||
err3:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err2:
|
||||
usb_put_hcd(hcd);
|
||||
err1:
|
||||
dev_err(&dev->dev, "init fail, %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ohci_xls_reset(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
|
||||
ohci_hcd_init(ohci);
|
||||
return ohci_init(ohci);
|
||||
}
|
||||
|
||||
static int __devinit ohci_xls_start(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci;
|
||||
int ret;
|
||||
|
||||
ohci = hcd_to_ohci(hcd);
|
||||
ret = ohci_run(ohci);
|
||||
if (ret < 0) {
|
||||
err("can't start %s", hcd->self.bus_name);
|
||||
ohci_stop(hcd);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hc_driver ohci_xls_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "XLS OHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ohci_hcd),
|
||||
.irq = ohci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB11,
|
||||
.reset = ohci_xls_reset,
|
||||
.start = ohci_xls_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
.urb_enqueue = ohci_urb_enqueue,
|
||||
.urb_dequeue = ohci_urb_dequeue,
|
||||
.endpoint_disable = ohci_endpoint_disable,
|
||||
.get_frame_number = ohci_get_frame,
|
||||
.hub_status_data = ohci_hub_status_data,
|
||||
.hub_control = ohci_hub_control,
|
||||
#ifdef CONFIG_PM
|
||||
.bus_suspend = ohci_bus_suspend,
|
||||
.bus_resume = ohci_bus_resume,
|
||||
#endif
|
||||
.start_port_reset = ohci_start_port_reset,
|
||||
};
|
||||
|
||||
static int ohci_xls_probe(struct platform_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug("In ohci_xls_probe");
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
ret = ohci_xls_probe_internal(&ohci_xls_hc_driver, dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ohci_xls_remove(struct platform_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ohci_xls_driver = {
|
||||
.probe = ohci_xls_probe,
|
||||
.remove = ohci_xls_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "ohci-xls-0",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
@@ -959,7 +959,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
|
||||
info.pipenum = get_empty_pipenum(r8a66597, ep);
|
||||
info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
|
||||
info.epnum = usb_endpoint_num(ep);
|
||||
info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
|
||||
info.maxpacket = usb_endpoint_maxp(ep);
|
||||
info.type = get_r8a66597_type(usb_endpoint_type(ep));
|
||||
info.bufnum = get_bufnum(info.pipenum);
|
||||
info.buf_bsize = get_buf_bsize(info.pipenum);
|
||||
@@ -2519,7 +2519,7 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->has_tt = 1;
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger);
|
||||
ret = usb_add_hcd(hcd, irq, irq_trigger);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to add hcd\n");
|
||||
goto clean_up3;
|
||||
|
@@ -1729,7 +1729,7 @@ sl811h_probe(struct platform_device *dev)
|
||||
* Use resource IRQ flags if set by platform device setup.
|
||||
*/
|
||||
irqflags |= IRQF_SHARED;
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | irqflags);
|
||||
retval = usb_add_hcd(hcd, irq, irqflags);
|
||||
if (retval != 0)
|
||||
goto err6;
|
||||
|
||||
|
@@ -294,50 +294,50 @@ __acquires(uhci->lock)
|
||||
* and that remote wakeups should be enabled.
|
||||
*/
|
||||
egsm_enable = USBCMD_EGSM;
|
||||
uhci->RD_enable = 1;
|
||||
int_enable = USBINTR_RESUME;
|
||||
wakeup_enable = 1;
|
||||
|
||||
/* In auto-stop mode wakeups must always be detected, but
|
||||
* Resume-Detect interrupts may be prohibited. (In the absence
|
||||
* of CONFIG_PM, they are always disallowed.)
|
||||
/*
|
||||
* In auto-stop mode, we must be able to detect new connections.
|
||||
* The user can force us to poll by disabling remote wakeup;
|
||||
* otherwise we will use the EGSM/RD mechanism.
|
||||
*/
|
||||
if (auto_stop) {
|
||||
if (!device_may_wakeup(&rhdev->dev))
|
||||
int_enable = 0;
|
||||
|
||||
/* In bus-suspend mode wakeups may be disabled, but if they are
|
||||
* allowed then so are Resume-Detect interrupts.
|
||||
*/
|
||||
} else {
|
||||
#ifdef CONFIG_PM
|
||||
if (!rhdev->do_remote_wakeup)
|
||||
wakeup_enable = 0;
|
||||
#endif
|
||||
egsm_enable = int_enable = 0;
|
||||
}
|
||||
|
||||
/* EGSM causes the root hub to echo a 'K' signal (resume) out any
|
||||
* port which requests a remote wakeup. According to the USB spec,
|
||||
* every hub is supposed to do this. But if we are ignoring
|
||||
* remote-wakeup requests anyway then there's no point to it.
|
||||
* We also shouldn't enable EGSM if it's broken.
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* In bus-suspend mode, we use the wakeup setting specified
|
||||
* for the root hub.
|
||||
*/
|
||||
if (!wakeup_enable || global_suspend_mode_is_broken(uhci))
|
||||
egsm_enable = 0;
|
||||
else {
|
||||
if (!rhdev->do_remote_wakeup)
|
||||
wakeup_enable = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we're ignoring wakeup events then there's no reason to
|
||||
* enable Resume-Detect interrupts. We also shouldn't enable
|
||||
* them if they are broken or disallowed.
|
||||
/*
|
||||
* UHCI doesn't distinguish between wakeup requests from downstream
|
||||
* devices and local connect/disconnect events. There's no way to
|
||||
* enable one without the other; both are controlled by EGSM. Thus
|
||||
* if wakeups are disallowed then EGSM must be turned off -- in which
|
||||
* case remote wakeup requests from downstream during system sleep
|
||||
* will be lost.
|
||||
*
|
||||
* This logic may lead us to enabling RD but not EGSM. The UHCI
|
||||
* spec foolishly says that RD works only when EGSM is on, but
|
||||
* there's no harm in enabling it anyway -- perhaps some chips
|
||||
* will implement it!
|
||||
* In addition, if EGSM is broken then we can't use it. Likewise,
|
||||
* if Resume-Detect interrupts are broken then we can't use them.
|
||||
*
|
||||
* Finally, neither EGSM nor RD is useful by itself. Without EGSM,
|
||||
* the RD status bit will never get set. Without RD, the controller
|
||||
* won't generate interrupts to tell the system about wakeup events.
|
||||
*/
|
||||
if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) ||
|
||||
!int_enable)
|
||||
uhci->RD_enable = int_enable = 0;
|
||||
if (!wakeup_enable || global_suspend_mode_is_broken(uhci) ||
|
||||
resume_detect_interrupts_are_broken(uhci))
|
||||
egsm_enable = int_enable = 0;
|
||||
|
||||
uhci->RD_enable = !!int_enable;
|
||||
uhci_writew(uhci, int_enable, USBINTR);
|
||||
uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD);
|
||||
mb();
|
||||
@@ -364,10 +364,12 @@ __acquires(uhci->lock)
|
||||
uhci->rh_state = new_state;
|
||||
uhci->is_stopped = UHCI_IS_STOPPED;
|
||||
|
||||
/* If interrupts don't work and remote wakeup is enabled then
|
||||
* the suspended root hub needs to be polled.
|
||||
/*
|
||||
* If remote wakeup is enabled but either EGSM or RD interrupts
|
||||
* doesn't work, then we won't get an interrupt when a wakeup event
|
||||
* occurs. Thus the suspended root hub needs to be polled.
|
||||
*/
|
||||
if (!int_enable && wakeup_enable)
|
||||
if (wakeup_enable && (!int_enable || !egsm_enable))
|
||||
set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
|
||||
else
|
||||
clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
|
||||
|
@@ -280,7 +280,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
|
||||
qh->load = usb_calc_bus_time(udev->speed,
|
||||
usb_endpoint_dir_in(&hep->desc),
|
||||
qh->type == USB_ENDPOINT_XFER_ISOC,
|
||||
le16_to_cpu(hep->desc.wMaxPacketSize))
|
||||
usb_endpoint_maxp(&hep->desc))
|
||||
/ 1000 + 1;
|
||||
|
||||
} else { /* Skeleton QH */
|
||||
@@ -792,7 +792,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
|
||||
{
|
||||
struct uhci_td *td;
|
||||
unsigned long destination, status;
|
||||
int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
|
||||
int maxsze = usb_endpoint_maxp(&qh->hep->desc);
|
||||
int len = urb->transfer_buffer_length;
|
||||
dma_addr_t data = urb->transfer_dma;
|
||||
__hc32 *plink;
|
||||
@@ -918,7 +918,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
||||
{
|
||||
struct uhci_td *td;
|
||||
unsigned long destination, status;
|
||||
int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
|
||||
int maxsze = usb_endpoint_maxp(&qh->hep->desc);
|
||||
int len = urb->transfer_buffer_length;
|
||||
int this_sg_len;
|
||||
dma_addr_t data;
|
||||
|
@@ -65,6 +65,12 @@
|
||||
/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
|
||||
#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17))
|
||||
|
||||
/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */
|
||||
#define XHCI_L1C (1 << 16)
|
||||
|
||||
/* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */
|
||||
#define XHCI_HLC (1 << 19)
|
||||
|
||||
/* command register values to disable interrupts and halt the HC */
|
||||
/* start/stop HC execution - do not write unless HC is halted*/
|
||||
#define XHCI_CMD_RUN (1 << 0)
|
||||
|
@@ -28,6 +28,25 @@
|
||||
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
|
||||
PORT_RC | PORT_PLC | PORT_PE)
|
||||
|
||||
/* usb 1.1 root hub device descriptor */
|
||||
static u8 usb_bos_descriptor [] = {
|
||||
USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */
|
||||
USB_DT_BOS, /* __u8 bDescriptorType */
|
||||
0x0F, 0x00, /* __le16 wTotalLength, 15 bytes */
|
||||
0x1, /* __u8 bNumDeviceCaps */
|
||||
/* First device capability */
|
||||
USB_DT_USB_SS_CAP_SIZE, /* __u8 bLength, 10 bytes */
|
||||
USB_DT_DEVICE_CAPABILITY, /* Device Capability */
|
||||
USB_SS_CAP_TYPE, /* bDevCapabilityType, SUPERSPEED_USB */
|
||||
0x00, /* bmAttributes, LTM off by default */
|
||||
USB_5GBPS_OPERATION, 0x00, /* wSpeedsSupported, 5Gbps only */
|
||||
0x03, /* bFunctionalitySupport,
|
||||
USB 3.0 speed only */
|
||||
0x00, /* bU1DevExitLat, set later. */
|
||||
0x00, 0x00 /* __le16 bU2DevExitLat, set later. */
|
||||
};
|
||||
|
||||
|
||||
static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
|
||||
struct usb_hub_descriptor *desc, int ports)
|
||||
{
|
||||
@@ -232,7 +251,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
|
||||
continue;
|
||||
speed = xhci->devs[i]->udev->speed;
|
||||
if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3))
|
||||
&& xhci->devs[i]->port == port) {
|
||||
&& xhci->devs[i]->fake_port == port) {
|
||||
slot_id = i;
|
||||
break;
|
||||
}
|
||||
@@ -392,13 +411,39 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
|
||||
return max_ports;
|
||||
}
|
||||
|
||||
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
||||
int port_id, u32 link_state)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
temp = xhci_readl(xhci, port_array[port_id]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | link_state;
|
||||
xhci_writel(xhci, temp, port_array[port_id]);
|
||||
}
|
||||
|
||||
/* Test and clear port RWC bit */
|
||||
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
||||
int port_id, u32 port_bit)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
temp = xhci_readl(xhci, port_array[port_id]);
|
||||
if (temp & port_bit) {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp |= port_bit;
|
||||
xhci_writel(xhci, temp, port_array[port_id]);
|
||||
}
|
||||
}
|
||||
|
||||
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
u16 wIndex, char *buf, u16 wLength)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int max_ports;
|
||||
unsigned long flags;
|
||||
u32 temp, temp1, status;
|
||||
u32 temp, status;
|
||||
int retval = 0;
|
||||
__le32 __iomem **port_array;
|
||||
int slot_id;
|
||||
@@ -429,6 +474,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
xhci_hub_descriptor(hcd, xhci,
|
||||
(struct usb_hub_descriptor *) buf);
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
if ((wValue & 0xff00) != (USB_DT_BOS << 8))
|
||||
goto error;
|
||||
|
||||
if (hcd->speed != HCD_USB3)
|
||||
goto error;
|
||||
|
||||
memcpy(buf, &usb_bos_descriptor,
|
||||
USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE);
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
|
||||
buf[12] = HCS_U1_LATENCY(temp);
|
||||
put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
|
||||
case GetPortStatus:
|
||||
if (!wIndex || wIndex > max_ports)
|
||||
goto error;
|
||||
@@ -472,11 +532,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
xhci_dbg(xhci, "Resume USB2 port %d\n",
|
||||
wIndex + 1);
|
||||
bus_state->resume_done[wIndex] = 0;
|
||||
temp1 = xhci_port_state_to_neutral(temp);
|
||||
temp1 &= ~PORT_PLS_MASK;
|
||||
temp1 |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp1, port_array[wIndex]);
|
||||
|
||||
xhci_set_link_state(xhci, port_array, wIndex,
|
||||
XDEV_U0);
|
||||
xhci_dbg(xhci, "set port %d resume\n",
|
||||
wIndex + 1);
|
||||
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
||||
@@ -551,10 +608,19 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
if ((temp & PORT_PLS_MASK) != XDEV_U0) {
|
||||
/* Resume the port to U0 first */
|
||||
xhci_set_link_state(xhci, port_array, wIndex,
|
||||
XDEV_U0);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(10);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
}
|
||||
/* In spec software should not attempt to suspend
|
||||
* a port unless the port reports that it is in the
|
||||
* enabled (PED = ‘1’,PLS < ‘3’) state.
|
||||
*/
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
|
||||
|| (temp & PORT_PLS_MASK) >= XDEV_U3) {
|
||||
xhci_warn(xhci, "USB core suspending device "
|
||||
@@ -573,10 +639,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
xhci_stop_device(xhci, slot_id, 1);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U3;
|
||||
xhci_writel(xhci, temp, port_array[wIndex]);
|
||||
xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(10); /* wait device to enter */
|
||||
@@ -610,10 +673,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
}
|
||||
}
|
||||
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | link_state;
|
||||
xhci_writel(xhci, temp, port_array[wIndex]);
|
||||
xhci_set_link_state(xhci, port_array, wIndex,
|
||||
link_state);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(20); /* wait device to enter */
|
||||
@@ -677,24 +738,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
if ((temp & PORT_PE) == 0)
|
||||
goto error;
|
||||
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_RESUME;
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock,
|
||||
flags);
|
||||
xhci_set_link_state(xhci, port_array, wIndex,
|
||||
XDEV_RESUME);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(20);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci,
|
||||
port_array[wIndex]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp,
|
||||
port_array[wIndex]);
|
||||
xhci_set_link_state(xhci, port_array, wIndex,
|
||||
XDEV_U0);
|
||||
}
|
||||
bus_state->port_c_suspend |= 1 << wIndex;
|
||||
|
||||
@@ -910,25 +960,18 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
||||
if (test_bit(port_index, &bus_state->bus_suspended) &&
|
||||
(temp & PORT_PLS_MASK)) {
|
||||
if (DEV_SUPERSPEED(temp)) {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, port_array[port_index]);
|
||||
xhci_set_link_state(xhci, port_array,
|
||||
port_index, XDEV_U0);
|
||||
} else {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_RESUME;
|
||||
xhci_writel(xhci, temp, port_array[port_index]);
|
||||
xhci_set_link_state(xhci, port_array,
|
||||
port_index, XDEV_RESUME);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(20);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci, port_array[port_index]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, port_array[port_index]);
|
||||
xhci_set_link_state(xhci, port_array,
|
||||
port_index, XDEV_U0);
|
||||
}
|
||||
/* wait for the port to enter U0 and report port link
|
||||
* state change.
|
||||
@@ -938,12 +981,8 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
/* Clear PLC */
|
||||
temp = xhci_readl(xhci, port_array[port_index]);
|
||||
if (temp & PORT_PLC) {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp |= PORT_PLC;
|
||||
xhci_writel(xhci, temp, port_array[port_index]);
|
||||
}
|
||||
xhci_test_and_clear_bit(xhci, port_array, port_index,
|
||||
PORT_PLC);
|
||||
|
||||
slot_id = xhci_find_slot_id_by_port(hcd,
|
||||
xhci, port_index + 1);
|
||||
|
@@ -61,8 +61,6 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flag
|
||||
|
||||
static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
|
||||
{
|
||||
if (!seg)
|
||||
return;
|
||||
if (seg->trbs) {
|
||||
xhci_dbg(xhci, "Freeing DMA segment at %p (virtual) 0x%llx (DMA)\n",
|
||||
seg->trbs, (unsigned long long)seg->dma);
|
||||
@@ -81,7 +79,7 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
|
||||
* related flags, such as End TRB, Toggle Cycle, and no snoop.
|
||||
*/
|
||||
static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
|
||||
struct xhci_segment *next, bool link_trbs)
|
||||
struct xhci_segment *next, bool link_trbs, bool isoc)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
@@ -97,7 +95,9 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
|
||||
val &= ~TRB_TYPE_BITMASK;
|
||||
val |= TRB_TYPE(TRB_LINK);
|
||||
/* Always set the chain bit with 0.95 hardware */
|
||||
if (xhci_link_trb_quirk(xhci))
|
||||
/* Set chain bit for isoc rings on AMD 0.96 host */
|
||||
if (xhci_link_trb_quirk(xhci) ||
|
||||
(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST)))
|
||||
val |= TRB_CHAIN;
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
|
||||
}
|
||||
@@ -112,18 +112,20 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
||||
struct xhci_segment *seg;
|
||||
struct xhci_segment *first_seg;
|
||||
|
||||
if (!ring || !ring->first_seg)
|
||||
if (!ring)
|
||||
return;
|
||||
first_seg = ring->first_seg;
|
||||
seg = first_seg->next;
|
||||
xhci_dbg(xhci, "Freeing ring at %p\n", ring);
|
||||
while (seg != first_seg) {
|
||||
struct xhci_segment *next = seg->next;
|
||||
xhci_segment_free(xhci, seg);
|
||||
seg = next;
|
||||
if (ring->first_seg) {
|
||||
first_seg = ring->first_seg;
|
||||
seg = first_seg->next;
|
||||
xhci_dbg(xhci, "Freeing ring at %p\n", ring);
|
||||
while (seg != first_seg) {
|
||||
struct xhci_segment *next = seg->next;
|
||||
xhci_segment_free(xhci, seg);
|
||||
seg = next;
|
||||
}
|
||||
xhci_segment_free(xhci, first_seg);
|
||||
ring->first_seg = NULL;
|
||||
}
|
||||
xhci_segment_free(xhci, first_seg);
|
||||
ring->first_seg = NULL;
|
||||
kfree(ring);
|
||||
}
|
||||
|
||||
@@ -152,7 +154,7 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring)
|
||||
* See section 4.9.1 and figures 15 and 16.
|
||||
*/
|
||||
static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
|
||||
unsigned int num_segs, bool link_trbs, gfp_t flags)
|
||||
unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags)
|
||||
{
|
||||
struct xhci_ring *ring;
|
||||
struct xhci_segment *prev;
|
||||
@@ -178,12 +180,12 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
|
||||
next = xhci_segment_alloc(xhci, flags);
|
||||
if (!next)
|
||||
goto fail;
|
||||
xhci_link_segments(xhci, prev, next, link_trbs);
|
||||
xhci_link_segments(xhci, prev, next, link_trbs, isoc);
|
||||
|
||||
prev = next;
|
||||
num_segs--;
|
||||
}
|
||||
xhci_link_segments(xhci, prev, ring->first_seg, link_trbs);
|
||||
xhci_link_segments(xhci, prev, ring->first_seg, link_trbs, isoc);
|
||||
|
||||
if (link_trbs) {
|
||||
/* See section 4.9.2.1 and 6.4.4.1 */
|
||||
@@ -229,14 +231,14 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
|
||||
* pointers to the beginning of the ring.
|
||||
*/
|
||||
static void xhci_reinit_cached_ring(struct xhci_hcd *xhci,
|
||||
struct xhci_ring *ring)
|
||||
struct xhci_ring *ring, bool isoc)
|
||||
{
|
||||
struct xhci_segment *seg = ring->first_seg;
|
||||
do {
|
||||
memset(seg->trbs, 0,
|
||||
sizeof(union xhci_trb)*TRBS_PER_SEGMENT);
|
||||
/* All endpoint rings have link TRBs */
|
||||
xhci_link_segments(xhci, seg, seg->next, 1);
|
||||
xhci_link_segments(xhci, seg, seg->next, 1, isoc);
|
||||
seg = seg->next;
|
||||
} while (seg != ring->first_seg);
|
||||
xhci_initialize_ring_info(ring);
|
||||
@@ -315,7 +317,7 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
|
||||
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
|
||||
|
||||
if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
|
||||
pci_free_consistent(pdev,
|
||||
dma_free_coherent(&pdev->dev,
|
||||
sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
|
||||
stream_ctx, dma);
|
||||
else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
|
||||
@@ -343,9 +345,9 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
|
||||
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
|
||||
|
||||
if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
|
||||
return pci_alloc_consistent(pdev,
|
||||
return dma_alloc_coherent(&pdev->dev,
|
||||
sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
|
||||
dma);
|
||||
dma, mem_flags);
|
||||
else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
|
||||
return dma_pool_alloc(xhci->small_streams_pool,
|
||||
mem_flags, dma);
|
||||
@@ -540,7 +542,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
|
||||
*/
|
||||
for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
|
||||
stream_info->stream_rings[cur_stream] =
|
||||
xhci_ring_alloc(xhci, 1, true, mem_flags);
|
||||
xhci_ring_alloc(xhci, 1, true, false, mem_flags);
|
||||
cur_ring = stream_info->stream_rings[cur_stream];
|
||||
if (!cur_ring)
|
||||
goto cleanup_rings;
|
||||
@@ -687,11 +689,103 @@ static void xhci_init_endpoint_timer(struct xhci_hcd *xhci,
|
||||
ep->xhci = xhci;
|
||||
}
|
||||
|
||||
/* All the xhci_tds in the ring's TD list should be freed at this point */
|
||||
static void xhci_free_tt_info(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
int slot_id)
|
||||
{
|
||||
struct list_head *tt;
|
||||
struct list_head *tt_list_head;
|
||||
struct list_head *tt_next;
|
||||
struct xhci_tt_bw_info *tt_info;
|
||||
|
||||
/* If the device never made it past the Set Address stage,
|
||||
* it may not have the real_port set correctly.
|
||||
*/
|
||||
if (virt_dev->real_port == 0 ||
|
||||
virt_dev->real_port > HCS_MAX_PORTS(xhci->hcs_params1)) {
|
||||
xhci_dbg(xhci, "Bad real port.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tt_list_head = &(xhci->rh_bw[virt_dev->real_port - 1].tts);
|
||||
if (list_empty(tt_list_head))
|
||||
return;
|
||||
|
||||
list_for_each(tt, tt_list_head) {
|
||||
tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list);
|
||||
if (tt_info->slot_id == slot_id)
|
||||
break;
|
||||
}
|
||||
/* Cautionary measure in case the hub was disconnected before we
|
||||
* stored the TT information.
|
||||
*/
|
||||
if (tt_info->slot_id != slot_id)
|
||||
return;
|
||||
|
||||
tt_next = tt->next;
|
||||
tt_info = list_entry(tt, struct xhci_tt_bw_info,
|
||||
tt_list);
|
||||
/* Multi-TT hubs will have more than one entry */
|
||||
do {
|
||||
list_del(tt);
|
||||
kfree(tt_info);
|
||||
tt = tt_next;
|
||||
if (list_empty(tt_list_head))
|
||||
break;
|
||||
tt_next = tt->next;
|
||||
tt_info = list_entry(tt, struct xhci_tt_bw_info,
|
||||
tt_list);
|
||||
} while (tt_info->slot_id == slot_id);
|
||||
}
|
||||
|
||||
int xhci_alloc_tt_info(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags)
|
||||
{
|
||||
struct xhci_tt_bw_info *tt_info;
|
||||
unsigned int num_ports;
|
||||
int i, j;
|
||||
|
||||
if (!tt->multi)
|
||||
num_ports = 1;
|
||||
else
|
||||
num_ports = hdev->maxchild;
|
||||
|
||||
for (i = 0; i < num_ports; i++, tt_info++) {
|
||||
struct xhci_interval_bw_table *bw_table;
|
||||
|
||||
tt_info = kzalloc(sizeof(*tt_info), mem_flags);
|
||||
if (!tt_info)
|
||||
goto free_tts;
|
||||
INIT_LIST_HEAD(&tt_info->tt_list);
|
||||
list_add(&tt_info->tt_list,
|
||||
&xhci->rh_bw[virt_dev->real_port - 1].tts);
|
||||
tt_info->slot_id = virt_dev->udev->slot_id;
|
||||
if (tt->multi)
|
||||
tt_info->ttport = i+1;
|
||||
bw_table = &tt_info->bw_table;
|
||||
for (j = 0; j < XHCI_MAX_INTERVAL; j++)
|
||||
INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints);
|
||||
}
|
||||
return 0;
|
||||
|
||||
free_tts:
|
||||
xhci_free_tt_info(xhci, virt_dev, virt_dev->udev->slot_id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
/* All the xhci_tds in the ring's TD list should be freed at this point.
|
||||
* Should be called with xhci->lock held if there is any chance the TT lists
|
||||
* will be manipulated by the configure endpoint, allocate device, or update
|
||||
* hub functions while this function is removing the TT entries from the list.
|
||||
*/
|
||||
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
|
||||
{
|
||||
struct xhci_virt_device *dev;
|
||||
int i;
|
||||
int old_active_eps = 0;
|
||||
|
||||
/* Slot ID 0 is reserved */
|
||||
if (slot_id == 0 || !xhci->devs[slot_id])
|
||||
@@ -702,13 +796,29 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
if (dev->tt_info)
|
||||
old_active_eps = dev->tt_info->active_eps;
|
||||
|
||||
for (i = 0; i < 31; ++i) {
|
||||
if (dev->eps[i].ring)
|
||||
xhci_ring_free(xhci, dev->eps[i].ring);
|
||||
if (dev->eps[i].stream_info)
|
||||
xhci_free_stream_info(xhci,
|
||||
dev->eps[i].stream_info);
|
||||
/* Endpoints on the TT/root port lists should have been removed
|
||||
* when usb_disable_device() was called for the device.
|
||||
* We can't drop them anyway, because the udev might have gone
|
||||
* away by this point, and we can't tell what speed it was.
|
||||
*/
|
||||
if (!list_empty(&dev->eps[i].bw_endpoint_list))
|
||||
xhci_warn(xhci, "Slot %u endpoint %u "
|
||||
"not removed from BW list!\n",
|
||||
slot_id, i);
|
||||
}
|
||||
/* If this is a hub, free the TT(s) from the TT list */
|
||||
xhci_free_tt_info(xhci, dev, 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++)
|
||||
@@ -762,10 +872,11 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
|
||||
for (i = 0; i < 31; i++) {
|
||||
xhci_init_endpoint_timer(xhci, &dev->eps[i]);
|
||||
INIT_LIST_HEAD(&dev->eps[i].cancelled_td_list);
|
||||
INIT_LIST_HEAD(&dev->eps[i].bw_endpoint_list);
|
||||
}
|
||||
|
||||
/* Allocate endpoint 0 ring */
|
||||
dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, flags);
|
||||
dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, false, flags);
|
||||
if (!dev->eps[0].ring)
|
||||
goto fail;
|
||||
|
||||
@@ -921,9 +1032,40 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
||||
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
|
||||
top_dev = top_dev->parent)
|
||||
/* Found device below root hub */;
|
||||
dev->port = top_dev->portnum;
|
||||
dev->fake_port = top_dev->portnum;
|
||||
dev->real_port = port_num;
|
||||
xhci_dbg(xhci, "Set root hub portnum to %d\n", port_num);
|
||||
xhci_dbg(xhci, "Set fake root hub portnum to %d\n", dev->port);
|
||||
xhci_dbg(xhci, "Set fake root hub portnum to %d\n", dev->fake_port);
|
||||
|
||||
/* Find the right bandwidth table that this device will be a part of.
|
||||
* If this is a full speed device attached directly to a root port (or a
|
||||
* decendent of one), it counts as a primary bandwidth domain, not a
|
||||
* secondary bandwidth domain under a TT. An xhci_tt_info structure
|
||||
* will never be created for the HS root hub.
|
||||
*/
|
||||
if (!udev->tt || !udev->tt->hub->parent) {
|
||||
dev->bw_table = &xhci->rh_bw[port_num - 1].bw_table;
|
||||
} else {
|
||||
struct xhci_root_port_bw_info *rh_bw;
|
||||
struct xhci_tt_bw_info *tt_bw;
|
||||
|
||||
rh_bw = &xhci->rh_bw[port_num - 1];
|
||||
/* Find the right TT. */
|
||||
list_for_each_entry(tt_bw, &rh_bw->tts, tt_list) {
|
||||
if (tt_bw->slot_id != udev->tt->hub->slot_id)
|
||||
continue;
|
||||
|
||||
if (!dev->udev->tt->multi ||
|
||||
(udev->tt->multi &&
|
||||
tt_bw->ttport == dev->udev->ttport)) {
|
||||
dev->bw_table = &tt_bw->bw_table;
|
||||
dev->tt_info = tt_bw;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dev->tt_info)
|
||||
xhci_warn(xhci, "WARN: Didn't find a matching TT\n");
|
||||
}
|
||||
|
||||
/* Is this a LS/FS device under an external HS hub? */
|
||||
if (udev->tt && udev->tt->hub->parent) {
|
||||
@@ -1141,8 +1283,8 @@ static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
|
||||
if (udev->speed == USB_SPEED_SUPER)
|
||||
return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
|
||||
|
||||
max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
|
||||
max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize) & 0x1800) >> 11;
|
||||
max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
|
||||
max_burst = (usb_endpoint_maxp(&ep->desc) & 0x1800) >> 11;
|
||||
/* A 0 in max burst means 1 transfer per ESIT */
|
||||
return max_packet * (max_burst + 1);
|
||||
}
|
||||
@@ -1175,10 +1317,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc))
|
||||
virt_dev->eps[ep_index].new_ring =
|
||||
xhci_ring_alloc(xhci, 8, true, mem_flags);
|
||||
xhci_ring_alloc(xhci, 8, true, true, mem_flags);
|
||||
else
|
||||
virt_dev->eps[ep_index].new_ring =
|
||||
xhci_ring_alloc(xhci, 1, true, mem_flags);
|
||||
xhci_ring_alloc(xhci, 1, true, false, mem_flags);
|
||||
if (!virt_dev->eps[ep_index].new_ring) {
|
||||
/* Attempt to use the ring cache */
|
||||
if (virt_dev->num_rings_cached == 0)
|
||||
@@ -1187,7 +1329,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
||||
virt_dev->ring_cache[virt_dev->num_rings_cached];
|
||||
virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
|
||||
virt_dev->num_rings_cached--;
|
||||
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring);
|
||||
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
|
||||
usb_endpoint_xfer_isoc(&ep->desc) ? true : false);
|
||||
}
|
||||
virt_dev->eps[ep_index].skip = false;
|
||||
ep_ring = virt_dev->eps[ep_index].new_ring;
|
||||
@@ -1211,7 +1354,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
||||
/* Set the max packet size and max burst */
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
max_packet = le16_to_cpu(ep->desc.wMaxPacketSize);
|
||||
max_packet = usb_endpoint_maxp(&ep->desc);
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
|
||||
/* dig out max burst from ep companion desc */
|
||||
max_packet = ep->ss_ep_comp.bMaxBurst;
|
||||
@@ -1223,14 +1366,14 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc) ||
|
||||
usb_endpoint_xfer_int(&ep->desc)) {
|
||||
max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize)
|
||||
max_burst = (usb_endpoint_maxp(&ep->desc)
|
||||
& 0x1800) >> 11;
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_burst));
|
||||
}
|
||||
/* Fall through */
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_LOW:
|
||||
max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
|
||||
max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
|
||||
break;
|
||||
default:
|
||||
@@ -1286,6 +1429,70 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci,
|
||||
*/
|
||||
}
|
||||
|
||||
void xhci_clear_endpoint_bw_info(struct xhci_bw_info *bw_info)
|
||||
{
|
||||
bw_info->ep_interval = 0;
|
||||
bw_info->mult = 0;
|
||||
bw_info->num_packets = 0;
|
||||
bw_info->max_packet_size = 0;
|
||||
bw_info->type = 0;
|
||||
bw_info->max_esit_payload = 0;
|
||||
}
|
||||
|
||||
void xhci_update_bw_info(struct xhci_hcd *xhci,
|
||||
struct xhci_container_ctx *in_ctx,
|
||||
struct xhci_input_control_ctx *ctrl_ctx,
|
||||
struct xhci_virt_device *virt_dev)
|
||||
{
|
||||
struct xhci_bw_info *bw_info;
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
unsigned int ep_type;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < 31; ++i) {
|
||||
bw_info = &virt_dev->eps[i].bw_info;
|
||||
|
||||
/* We can't tell what endpoint type is being dropped, but
|
||||
* unconditionally clearing the bandwidth info for non-periodic
|
||||
* endpoints should be harmless because the info will never be
|
||||
* set in the first place.
|
||||
*/
|
||||
if (!EP_IS_ADDED(ctrl_ctx, i) && EP_IS_DROPPED(ctrl_ctx, i)) {
|
||||
/* Dropped endpoint */
|
||||
xhci_clear_endpoint_bw_info(bw_info);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (EP_IS_ADDED(ctrl_ctx, i)) {
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, i);
|
||||
ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2));
|
||||
|
||||
/* Ignore non-periodic endpoints */
|
||||
if (ep_type != ISOC_OUT_EP && ep_type != INT_OUT_EP &&
|
||||
ep_type != ISOC_IN_EP &&
|
||||
ep_type != INT_IN_EP)
|
||||
continue;
|
||||
|
||||
/* Added or changed endpoint */
|
||||
bw_info->ep_interval = CTX_TO_EP_INTERVAL(
|
||||
le32_to_cpu(ep_ctx->ep_info));
|
||||
/* Number of packets and mult are zero-based in the
|
||||
* input context, but we want one-based for the
|
||||
* interval table.
|
||||
*/
|
||||
bw_info->mult = CTX_TO_EP_MULT(
|
||||
le32_to_cpu(ep_ctx->ep_info)) + 1;
|
||||
bw_info->num_packets = CTX_TO_MAX_BURST(
|
||||
le32_to_cpu(ep_ctx->ep_info2)) + 1;
|
||||
bw_info->max_packet_size = MAX_PACKET_DECODED(
|
||||
le32_to_cpu(ep_ctx->ep_info2));
|
||||
bw_info->type = ep_type;
|
||||
bw_info->max_esit_payload = CTX_TO_MAX_ESIT_PAYLOAD(
|
||||
le32_to_cpu(ep_ctx->tx_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy.
|
||||
* Useful when you want to change one particular aspect of the endpoint and then
|
||||
* issue a configure endpoint command.
|
||||
@@ -1344,10 +1551,9 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
|
||||
if (!xhci->scratchpad)
|
||||
goto fail_sp;
|
||||
|
||||
xhci->scratchpad->sp_array =
|
||||
pci_alloc_consistent(to_pci_dev(dev),
|
||||
xhci->scratchpad->sp_array = dma_alloc_coherent(dev,
|
||||
num_sp * sizeof(u64),
|
||||
&xhci->scratchpad->sp_dma);
|
||||
&xhci->scratchpad->sp_dma, flags);
|
||||
if (!xhci->scratchpad->sp_array)
|
||||
goto fail_sp2;
|
||||
|
||||
@@ -1364,8 +1570,8 @@ 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 = pci_alloc_consistent(to_pci_dev(dev),
|
||||
xhci->page_size, &dma);
|
||||
void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma,
|
||||
flags);
|
||||
if (!buf)
|
||||
goto fail_sp5;
|
||||
|
||||
@@ -1378,7 +1584,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
|
||||
|
||||
fail_sp5:
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
pci_free_consistent(to_pci_dev(dev), xhci->page_size,
|
||||
dma_free_coherent(dev, xhci->page_size,
|
||||
xhci->scratchpad->sp_buffers[i],
|
||||
xhci->scratchpad->sp_dma_buffers[i]);
|
||||
}
|
||||
@@ -1388,7 +1594,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
|
||||
kfree(xhci->scratchpad->sp_buffers);
|
||||
|
||||
fail_sp3:
|
||||
pci_free_consistent(to_pci_dev(dev), num_sp * sizeof(u64),
|
||||
dma_free_coherent(dev, num_sp * sizeof(u64),
|
||||
xhci->scratchpad->sp_array,
|
||||
xhci->scratchpad->sp_dma);
|
||||
|
||||
@@ -1412,13 +1618,13 @@ static void scratchpad_free(struct xhci_hcd *xhci)
|
||||
num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
|
||||
|
||||
for (i = 0; i < num_sp; i++) {
|
||||
pci_free_consistent(pdev, xhci->page_size,
|
||||
dma_free_coherent(&pdev->dev, xhci->page_size,
|
||||
xhci->scratchpad->sp_buffers[i],
|
||||
xhci->scratchpad->sp_dma_buffers[i]);
|
||||
}
|
||||
kfree(xhci->scratchpad->sp_dma_buffers);
|
||||
kfree(xhci->scratchpad->sp_buffers);
|
||||
pci_free_consistent(pdev, num_sp * sizeof(u64),
|
||||
dma_free_coherent(&pdev->dev, num_sp * sizeof(u64),
|
||||
xhci->scratchpad->sp_array,
|
||||
xhci->scratchpad->sp_dma);
|
||||
kfree(xhci->scratchpad);
|
||||
@@ -1463,18 +1669,10 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
|
||||
|
||||
void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv)
|
||||
{
|
||||
int last;
|
||||
|
||||
if (!urb_priv)
|
||||
return;
|
||||
|
||||
last = urb_priv->length - 1;
|
||||
if (last >= 0) {
|
||||
int i;
|
||||
for (i = 0; i <= last; i++)
|
||||
kfree(urb_priv->td[i]);
|
||||
if (urb_priv) {
|
||||
kfree(urb_priv->td[0]);
|
||||
kfree(urb_priv);
|
||||
}
|
||||
kfree(urb_priv);
|
||||
}
|
||||
|
||||
void xhci_free_command(struct xhci_hcd *xhci,
|
||||
@@ -1489,6 +1687,8 @@ void xhci_free_command(struct xhci_hcd *xhci,
|
||||
void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
|
||||
struct dev_info *dev_info, *next;
|
||||
unsigned long flags;
|
||||
int size;
|
||||
int i;
|
||||
|
||||
@@ -1500,7 +1700,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||
}
|
||||
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
|
||||
if (xhci->erst.entries)
|
||||
pci_free_consistent(pdev, size,
|
||||
dma_free_coherent(&pdev->dev, size,
|
||||
xhci->erst.entries, xhci->erst.erst_dma_addr);
|
||||
xhci->erst.entries = NULL;
|
||||
xhci_dbg(xhci, "Freed ERST\n");
|
||||
@@ -1540,17 +1740,25 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||
|
||||
xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
|
||||
if (xhci->dcbaa)
|
||||
pci_free_consistent(pdev, sizeof(*xhci->dcbaa),
|
||||
dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa),
|
||||
xhci->dcbaa, xhci->dcbaa->dma);
|
||||
xhci->dcbaa = NULL;
|
||||
|
||||
scratchpad_free(xhci);
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
list_for_each_entry_safe(dev_info, next, &xhci->lpm_failed_devs, list) {
|
||||
list_del(&dev_info->list);
|
||||
kfree(dev_info);
|
||||
}
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
||||
xhci->num_usb2_ports = 0;
|
||||
xhci->num_usb3_ports = 0;
|
||||
kfree(xhci->usb2_ports);
|
||||
kfree(xhci->usb3_ports);
|
||||
kfree(xhci->port_array);
|
||||
kfree(xhci->rh_bw);
|
||||
|
||||
xhci->page_size = 0;
|
||||
xhci->page_shift = 0;
|
||||
@@ -1762,6 +1970,23 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
|
||||
if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
|
||||
/* WTF? "Valid values are ‘1’ to MaxPorts" */
|
||||
return;
|
||||
|
||||
/* Check the host's USB2 LPM capability */
|
||||
if ((xhci->hci_version == 0x96) && (major_revision != 0x03) &&
|
||||
(temp & XHCI_L1C)) {
|
||||
xhci_dbg(xhci, "xHCI 0.96: support USB2 software lpm\n");
|
||||
xhci->sw_lpm_support = 1;
|
||||
}
|
||||
|
||||
if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) {
|
||||
xhci_dbg(xhci, "xHCI 1.0: support USB2 software lpm\n");
|
||||
xhci->sw_lpm_support = 1;
|
||||
if (temp & XHCI_HLC) {
|
||||
xhci_dbg(xhci, "xHCI 1.0: support USB2 hardware lpm\n");
|
||||
xhci->hw_lpm_support = 1;
|
||||
}
|
||||
}
|
||||
|
||||
port_offset--;
|
||||
for (i = port_offset; i < (port_offset + port_count); i++) {
|
||||
/* Duplicate entry. Ignore the port if the revisions differ. */
|
||||
@@ -1806,7 +2031,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
||||
__le32 __iomem *addr;
|
||||
u32 offset;
|
||||
unsigned int num_ports;
|
||||
int i, port_index;
|
||||
int i, j, port_index;
|
||||
|
||||
addr = &xhci->cap_regs->hcc_params;
|
||||
offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr));
|
||||
@@ -1821,6 +2046,18 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
||||
if (!xhci->port_array)
|
||||
return -ENOMEM;
|
||||
|
||||
xhci->rh_bw = kzalloc(sizeof(*xhci->rh_bw)*num_ports, flags);
|
||||
if (!xhci->rh_bw)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < num_ports; i++) {
|
||||
struct xhci_interval_bw_table *bw_table;
|
||||
|
||||
INIT_LIST_HEAD(&xhci->rh_bw[i].tts);
|
||||
bw_table = &xhci->rh_bw[i].bw_table;
|
||||
for (j = 0; j < XHCI_MAX_INTERVAL; j++)
|
||||
INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints);
|
||||
}
|
||||
|
||||
/*
|
||||
* For whatever reason, the first capability offset is from the
|
||||
* capability register base, not from the HCCPARAMS register.
|
||||
@@ -1959,8 +2196,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
* Section 5.4.8 - doorbell array must be
|
||||
* "physically contiguous and 64-byte (cache line) aligned".
|
||||
*/
|
||||
xhci->dcbaa = pci_alloc_consistent(to_pci_dev(dev),
|
||||
sizeof(*xhci->dcbaa), &dma);
|
||||
xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
|
||||
GFP_KERNEL);
|
||||
if (!xhci->dcbaa)
|
||||
goto fail;
|
||||
memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
|
||||
@@ -1994,14 +2231,14 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
dma_pool_create("xHCI 1KB stream ctx arrays",
|
||||
dev, MEDIUM_STREAM_ARRAY_SIZE, 16, 0);
|
||||
/* Any stream context array bigger than MEDIUM_STREAM_ARRAY_SIZE
|
||||
* will be allocated with pci_alloc_consistent()
|
||||
* will be allocated with dma_alloc_coherent()
|
||||
*/
|
||||
|
||||
if (!xhci->small_streams_pool || !xhci->medium_streams_pool)
|
||||
goto fail;
|
||||
|
||||
/* Set up the command ring to have one segments for now. */
|
||||
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags);
|
||||
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags);
|
||||
if (!xhci->cmd_ring)
|
||||
goto fail;
|
||||
xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
|
||||
@@ -2032,14 +2269,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
* the event ring segment table (ERST). Section 4.9.3.
|
||||
*/
|
||||
xhci_dbg(xhci, "// Allocating event ring\n");
|
||||
xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, flags);
|
||||
xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, false,
|
||||
flags);
|
||||
if (!xhci->event_ring)
|
||||
goto fail;
|
||||
if (xhci_check_trb_in_td_math(xhci, flags) < 0)
|
||||
goto fail;
|
||||
|
||||
xhci->erst.entries = pci_alloc_consistent(to_pci_dev(dev),
|
||||
sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS, &dma);
|
||||
xhci->erst.entries = dma_alloc_coherent(dev,
|
||||
sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma,
|
||||
GFP_KERNEL);
|
||||
if (!xhci->erst.entries)
|
||||
goto fail;
|
||||
xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n",
|
||||
@@ -2102,6 +2341,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
if (xhci_setup_port_arrays(xhci, flags))
|
||||
goto fail;
|
||||
|
||||
INIT_LIST_HEAD(&xhci->lpm_failed_devs);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
@@ -51,61 +51,9 @@ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||
static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
int retval;
|
||||
u32 temp;
|
||||
|
||||
hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
|
||||
|
||||
if (usb_hcd_is_primary_hcd(hcd)) {
|
||||
xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
|
||||
if (!xhci)
|
||||
return -ENOMEM;
|
||||
*((struct xhci_hcd **) hcd->hcd_priv) = xhci;
|
||||
xhci->main_hcd = hcd;
|
||||
/* Mark the first roothub as being USB 2.0.
|
||||
* The xHCI driver will register the USB 3.0 roothub.
|
||||
*/
|
||||
hcd->speed = HCD_USB2;
|
||||
hcd->self.root_hub->speed = USB_SPEED_HIGH;
|
||||
/*
|
||||
* USB 2.0 roothub under xHCI has an integrated TT,
|
||||
* (rate matching hub) as opposed to having an OHCI/UHCI
|
||||
* companion controller.
|
||||
*/
|
||||
hcd->has_tt = 1;
|
||||
} else {
|
||||
/* xHCI private pointer was set in xhci_pci_probe for the second
|
||||
* registered roothub.
|
||||
*/
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
|
||||
if (HCC_64BIT_ADDR(temp)) {
|
||||
xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
|
||||
dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
|
||||
} else {
|
||||
dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
xhci->cap_regs = hcd->regs;
|
||||
xhci->op_regs = hcd->regs +
|
||||
HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase));
|
||||
xhci->run_regs = hcd->regs +
|
||||
(xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK);
|
||||
/* Cache read-only capability registers */
|
||||
xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1);
|
||||
xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2);
|
||||
xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
|
||||
xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
|
||||
xhci->hci_version = HC_VERSION(xhci->hcc_params);
|
||||
xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
|
||||
xhci_print_registers(xhci);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
||||
/* Look for vendor-specific quirks */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
|
||||
@@ -128,6 +76,9 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||
if (pdev->vendor == PCI_VENDOR_ID_NEC)
|
||||
xhci->quirks |= XHCI_NEC_HOST;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD && xhci->hci_version == 0x96)
|
||||
xhci->quirks |= XHCI_AMD_0x96_HOST;
|
||||
|
||||
/* AMD PLL quirk */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
|
||||
xhci->quirks |= XHCI_AMD_PLL_FIX;
|
||||
@@ -136,39 +87,29 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||
xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
|
||||
xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
|
||||
xhci->limit_active_eps = 64;
|
||||
xhci->quirks |= XHCI_SW_BW_CHECKING;
|
||||
}
|
||||
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
|
||||
pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
|
||||
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||||
xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the HC is halted. */
|
||||
retval = xhci_halt(xhci);
|
||||
/* called during probe() after chip reset completes */
|
||||
static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
int retval;
|
||||
|
||||
retval = xhci_gen_setup(hcd, xhci_pci_quirks);
|
||||
if (retval)
|
||||
goto error;
|
||||
return retval;
|
||||
|
||||
xhci_dbg(xhci, "Resetting HCD\n");
|
||||
/* Reset the internal HC memory state and registers. */
|
||||
retval = xhci_reset(xhci);
|
||||
if (retval)
|
||||
goto error;
|
||||
xhci_dbg(xhci, "Reset complete\n");
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
|
||||
if (HCC_64BIT_ADDR(temp)) {
|
||||
xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
|
||||
dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
|
||||
} else {
|
||||
dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
|
||||
}
|
||||
|
||||
xhci_dbg(xhci, "Calling HCD init\n");
|
||||
/* Initialize HCD and host controller data structures. */
|
||||
retval = xhci_init(hcd);
|
||||
if (retval)
|
||||
goto error;
|
||||
xhci_dbg(xhci, "Called HCD init\n");
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
if (!usb_hcd_is_primary_hcd(hcd))
|
||||
return 0;
|
||||
|
||||
pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
|
||||
xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
|
||||
@@ -178,7 +119,6 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||
if (!retval)
|
||||
return retval;
|
||||
|
||||
error:
|
||||
kfree(xhci);
|
||||
return retval;
|
||||
}
|
||||
@@ -222,7 +162,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
|
||||
|
||||
retval = usb_add_hcd(xhci->shared_hcd, dev->irq,
|
||||
IRQF_DISABLED | IRQF_SHARED);
|
||||
IRQF_SHARED);
|
||||
if (retval)
|
||||
goto put_usb3_hcd;
|
||||
/* Roothub already marked as USB 3.0 speed */
|
||||
@@ -344,6 +284,11 @@ static const struct hc_driver xhci_pci_hc_driver = {
|
||||
.hub_status_data = xhci_hub_status_data,
|
||||
.bus_suspend = xhci_bus_suspend,
|
||||
.bus_resume = xhci_bus_resume,
|
||||
/*
|
||||
* call back when device connected and addressed
|
||||
*/
|
||||
.update_device = xhci_update_device,
|
||||
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@@ -375,12 +320,12 @@ static struct pci_driver xhci_pci_driver = {
|
||||
#endif
|
||||
};
|
||||
|
||||
int xhci_register_pci(void)
|
||||
int __init xhci_register_pci(void)
|
||||
{
|
||||
return pci_register_driver(&xhci_pci_driver);
|
||||
}
|
||||
|
||||
void xhci_unregister_pci(void)
|
||||
void __exit xhci_unregister_pci(void)
|
||||
{
|
||||
pci_unregister_driver(&xhci_pci_driver);
|
||||
}
|
||||
|
@@ -185,7 +185,7 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
|
||||
* prepare_transfer()?
|
||||
*/
|
||||
static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
bool consumer, bool more_trbs_coming)
|
||||
bool consumer, bool more_trbs_coming, bool isoc)
|
||||
{
|
||||
u32 chain;
|
||||
union xhci_trb *next;
|
||||
@@ -212,11 +212,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
if (!chain && !more_trbs_coming)
|
||||
break;
|
||||
|
||||
/* If we're not dealing with 0.95 hardware,
|
||||
/* If we're not dealing with 0.95 hardware or
|
||||
* isoc rings on AMD 0.96 host,
|
||||
* carry over the chain bit of the previous TRB
|
||||
* (which may mean the chain bit is cleared).
|
||||
*/
|
||||
if (!xhci_link_trb_quirk(xhci)) {
|
||||
if (!(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST))
|
||||
&& !xhci_link_trb_quirk(xhci)) {
|
||||
next->link.control &=
|
||||
cpu_to_le32(~TRB_CHAIN);
|
||||
next->link.control |=
|
||||
@@ -1329,10 +1331,8 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
||||
|
||||
if (DEV_SUPERSPEED(temp)) {
|
||||
xhci_dbg(xhci, "resume SS port %d\n", port_id);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, port_array[faked_port_index]);
|
||||
xhci_set_link_state(xhci, port_array, faked_port_index,
|
||||
XDEV_U0);
|
||||
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
||||
faked_port_index);
|
||||
if (!slot_id) {
|
||||
@@ -1342,10 +1342,8 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
||||
xhci_ring_device(xhci, slot_id);
|
||||
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
|
||||
/* Clear PORT_PLC */
|
||||
temp = xhci_readl(xhci, port_array[faked_port_index]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp |= PORT_PLC;
|
||||
xhci_writel(xhci, temp, port_array[faked_port_index]);
|
||||
xhci_test_and_clear_bit(xhci, port_array,
|
||||
faked_port_index, PORT_PLC);
|
||||
} else {
|
||||
xhci_dbg(xhci, "resume HS port %d\n", port_id);
|
||||
bus_state->resume_done[faked_port_index] = jiffies +
|
||||
@@ -1356,6 +1354,10 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
||||
}
|
||||
}
|
||||
|
||||
if (hcd->speed != HCD_USB3)
|
||||
xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
|
||||
PORT_PLC);
|
||||
|
||||
cleanup:
|
||||
/* Update event ring dequeue pointer before dropping the lock */
|
||||
inc_deq(xhci, xhci->event_ring, true);
|
||||
@@ -2192,7 +2194,8 @@ cleanup:
|
||||
if ((urb->actual_length != urb->transfer_buffer_length &&
|
||||
(urb->transfer_flags &
|
||||
URB_SHORT_NOT_OK)) ||
|
||||
status != 0)
|
||||
(status != 0 &&
|
||||
!usb_endpoint_xfer_isoc(&urb->ep->desc)))
|
||||
xhci_dbg(xhci, "Giveback URB %p, len = %d, "
|
||||
"expected = %x, status = %d\n",
|
||||
urb, urb->actual_length,
|
||||
@@ -2409,7 +2412,7 @@ irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
|
||||
* prepare_transfer()?
|
||||
*/
|
||||
static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
bool consumer, bool more_trbs_coming,
|
||||
bool consumer, bool more_trbs_coming, bool isoc,
|
||||
u32 field1, u32 field2, u32 field3, u32 field4)
|
||||
{
|
||||
struct xhci_generic_trb *trb;
|
||||
@@ -2419,7 +2422,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
trb->field[1] = cpu_to_le32(field2);
|
||||
trb->field[2] = cpu_to_le32(field3);
|
||||
trb->field[3] = cpu_to_le32(field4);
|
||||
inc_enq(xhci, ring, consumer, more_trbs_coming);
|
||||
inc_enq(xhci, ring, consumer, more_trbs_coming, isoc);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2427,7 +2430,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
* FIXME allocate segments if the ring is full.
|
||||
*/
|
||||
static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||
u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
|
||||
u32 ep_state, unsigned int num_trbs, bool isoc, gfp_t mem_flags)
|
||||
{
|
||||
/* Make sure the endpoint has been added to xHC schedule */
|
||||
switch (ep_state) {
|
||||
@@ -2469,10 +2472,11 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||
next = ring->enqueue;
|
||||
|
||||
while (last_trb(xhci, ring, ring->enq_seg, next)) {
|
||||
/* If we're not dealing with 0.95 hardware,
|
||||
* clear the chain bit.
|
||||
/* If we're not dealing with 0.95 hardware or isoc rings
|
||||
* on AMD 0.96 host, clear the chain bit.
|
||||
*/
|
||||
if (!xhci_link_trb_quirk(xhci))
|
||||
if (!xhci_link_trb_quirk(xhci) && !(isoc &&
|
||||
(xhci->quirks & XHCI_AMD_0x96_HOST)))
|
||||
next->link.control &= cpu_to_le32(~TRB_CHAIN);
|
||||
else
|
||||
next->link.control |= cpu_to_le32(TRB_CHAIN);
|
||||
@@ -2505,6 +2509,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,
|
||||
unsigned int num_trbs,
|
||||
struct urb *urb,
|
||||
unsigned int td_index,
|
||||
bool isoc,
|
||||
gfp_t mem_flags)
|
||||
{
|
||||
int ret;
|
||||
@@ -2522,7 +2527,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,
|
||||
|
||||
ret = prepare_ring(xhci, ep_ring,
|
||||
le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
|
||||
num_trbs, mem_flags);
|
||||
num_trbs, isoc, mem_flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -2711,7 +2716,7 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
|
||||
* running_total.
|
||||
*/
|
||||
packets_transferred = (running_total + trb_buff_len) /
|
||||
le16_to_cpu(urb->ep->desc.wMaxPacketSize);
|
||||
usb_endpoint_maxp(&urb->ep->desc);
|
||||
|
||||
return xhci_td_remainder(total_packet_count - packets_transferred);
|
||||
}
|
||||
@@ -2741,11 +2746,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
num_trbs = count_sg_trbs_needed(xhci, urb);
|
||||
num_sgs = urb->num_sgs;
|
||||
total_packet_count = roundup(urb->transfer_buffer_length,
|
||||
le16_to_cpu(urb->ep->desc.wMaxPacketSize));
|
||||
usb_endpoint_maxp(&urb->ep->desc));
|
||||
|
||||
trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
num_trbs, urb, 0, mem_flags);
|
||||
num_trbs, urb, 0, false, mem_flags);
|
||||
if (trb_buff_len < 0)
|
||||
return trb_buff_len;
|
||||
|
||||
@@ -2840,7 +2845,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
more_trbs_coming = true;
|
||||
else
|
||||
more_trbs_coming = false;
|
||||
queue_trb(xhci, ep_ring, false, more_trbs_coming,
|
||||
queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
|
||||
lower_32_bits(addr),
|
||||
upper_32_bits(addr),
|
||||
length_field,
|
||||
@@ -2931,7 +2936,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
num_trbs, urb, 0, mem_flags);
|
||||
num_trbs, urb, 0, false, mem_flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -2948,7 +2953,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
|
||||
running_total = 0;
|
||||
total_packet_count = roundup(urb->transfer_buffer_length,
|
||||
le16_to_cpu(urb->ep->desc.wMaxPacketSize));
|
||||
usb_endpoint_maxp(&urb->ep->desc));
|
||||
/* How much data is in the first TRB? */
|
||||
addr = (u64) urb->transfer_dma;
|
||||
trb_buff_len = TRB_MAX_BUFF_SIZE -
|
||||
@@ -3003,7 +3008,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
more_trbs_coming = true;
|
||||
else
|
||||
more_trbs_coming = false;
|
||||
queue_trb(xhci, ep_ring, false, more_trbs_coming,
|
||||
queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
|
||||
lower_32_bits(addr),
|
||||
upper_32_bits(addr),
|
||||
length_field,
|
||||
@@ -3063,7 +3068,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
num_trbs++;
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
num_trbs, urb, 0, mem_flags);
|
||||
num_trbs, urb, 0, false, mem_flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -3096,7 +3101,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
}
|
||||
}
|
||||
|
||||
queue_trb(xhci, ep_ring, false, true,
|
||||
queue_trb(xhci, ep_ring, false, true, false,
|
||||
setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16,
|
||||
le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16,
|
||||
TRB_LEN(8) | TRB_INTR_TARGET(0),
|
||||
@@ -3116,7 +3121,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
if (urb->transfer_buffer_length > 0) {
|
||||
if (setup->bRequestType & USB_DIR_IN)
|
||||
field |= TRB_DIR_IN;
|
||||
queue_trb(xhci, ep_ring, false, true,
|
||||
queue_trb(xhci, ep_ring, false, true, false,
|
||||
lower_32_bits(urb->transfer_dma),
|
||||
upper_32_bits(urb->transfer_dma),
|
||||
length_field,
|
||||
@@ -3132,7 +3137,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
field = 0;
|
||||
else
|
||||
field = TRB_DIR_IN;
|
||||
queue_trb(xhci, ep_ring, false, false,
|
||||
queue_trb(xhci, ep_ring, false, false, false,
|
||||
0,
|
||||
0,
|
||||
TRB_INTR_TARGET(0),
|
||||
@@ -3269,7 +3274,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
td_len = urb->iso_frame_desc[i].length;
|
||||
td_remain_len = td_len;
|
||||
total_packet_count = roundup(td_len,
|
||||
le16_to_cpu(urb->ep->desc.wMaxPacketSize));
|
||||
usb_endpoint_maxp(&urb->ep->desc));
|
||||
/* A zero-length transfer still involves at least one packet. */
|
||||
if (total_packet_count == 0)
|
||||
total_packet_count++;
|
||||
@@ -3281,7 +3286,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
|
||||
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
|
||||
urb->stream_id, trbs_per_td, urb, i, mem_flags);
|
||||
urb->stream_id, trbs_per_td, urb, i, true,
|
||||
mem_flags);
|
||||
if (ret < 0) {
|
||||
if (i == 0)
|
||||
return ret;
|
||||
@@ -3351,7 +3357,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
remainder |
|
||||
TRB_INTR_TARGET(0);
|
||||
|
||||
queue_trb(xhci, ep_ring, false, more_trbs_coming,
|
||||
queue_trb(xhci, ep_ring, false, more_trbs_coming, true,
|
||||
lower_32_bits(addr),
|
||||
upper_32_bits(addr),
|
||||
length_field,
|
||||
@@ -3433,7 +3439,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
* Do not insert any td of the urb to the ring if the check failed.
|
||||
*/
|
||||
ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
|
||||
num_trbs, mem_flags);
|
||||
num_trbs, true, mem_flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -3492,7 +3498,7 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,
|
||||
reserved_trbs++;
|
||||
|
||||
ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
|
||||
reserved_trbs, GFP_ATOMIC);
|
||||
reserved_trbs, false, GFP_ATOMIC);
|
||||
if (ret < 0) {
|
||||
xhci_err(xhci, "ERR: No room for command on command ring\n");
|
||||
if (command_must_succeed)
|
||||
@@ -3500,8 +3506,8 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,
|
||||
"unfailable commands failed.\n");
|
||||
return ret;
|
||||
}
|
||||
queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3,
|
||||
field4 | xhci->cmd_ring->cycle_state);
|
||||
queue_trb(xhci, xhci->cmd_ring, false, false, false, field1, field2,
|
||||
field3, field4 | xhci->cmd_ring->cycle_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -272,6 +272,7 @@ struct xhci_op_regs {
|
||||
*/
|
||||
#define PORT_PLS_MASK (0xf << 5)
|
||||
#define XDEV_U0 (0x0 << 5)
|
||||
#define XDEV_U2 (0x2 << 5)
|
||||
#define XDEV_U3 (0x3 << 5)
|
||||
#define XDEV_RESUME (0xf << 5)
|
||||
/* true: port has power (see HCC_PPC) */
|
||||
@@ -362,7 +363,13 @@ struct xhci_op_regs {
|
||||
/* Bits 24:31 for port testing */
|
||||
|
||||
/* USB2 Protocol PORTSPMSC */
|
||||
#define PORT_RWE (1 << 0x3)
|
||||
#define PORT_L1S_MASK 7
|
||||
#define PORT_L1S_SUCCESS 1
|
||||
#define PORT_RWE (1 << 3)
|
||||
#define PORT_HIRD(p) (((p) & 0xf) << 4)
|
||||
#define PORT_HIRD_MASK (0xf << 4)
|
||||
#define PORT_L1DS(p) (((p) & 0xff) << 8)
|
||||
#define PORT_HLE (1 << 16)
|
||||
|
||||
/**
|
||||
* struct xhci_intr_reg - Interrupt Register Set
|
||||
@@ -611,11 +618,13 @@ struct xhci_ep_ctx {
|
||||
#define EP_STATE_ERROR 4
|
||||
/* Mult - Max number of burtst within an interval, in EP companion desc. */
|
||||
#define EP_MULT(p) (((p) & 0x3) << 8)
|
||||
#define CTX_TO_EP_MULT(p) (((p) >> 8) & 0x3)
|
||||
/* bits 10:14 are Max Primary Streams */
|
||||
/* bit 15 is Linear Stream Array */
|
||||
/* Interval - period between requests to an endpoint - 125u increments. */
|
||||
#define EP_INTERVAL(p) (((p) & 0xff) << 16)
|
||||
#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff))
|
||||
#define CTX_TO_EP_INTERVAL(p) (((p) >> 16) & 0xff)
|
||||
#define EP_MAXPSTREAMS_MASK (0x1f << 10)
|
||||
#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK)
|
||||
/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */
|
||||
@@ -640,6 +649,7 @@ struct xhci_ep_ctx {
|
||||
/* bit 6 reserved */
|
||||
/* bit 7 is Host Initiate Disable - for disabling stream selection */
|
||||
#define MAX_BURST(p) (((p)&0xff) << 8)
|
||||
#define CTX_TO_MAX_BURST(p) (((p) >> 8) & 0xff)
|
||||
#define MAX_PACKET(p) (((p)&0xffff) << 16)
|
||||
#define MAX_PACKET_MASK (0xffff << 16)
|
||||
#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff)
|
||||
@@ -652,6 +662,7 @@ struct xhci_ep_ctx {
|
||||
/* tx_info bitmasks */
|
||||
#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff)
|
||||
#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16)
|
||||
#define CTX_TO_MAX_ESIT_PAYLOAD(p) (((p) >> 16) & 0xffff)
|
||||
|
||||
/* deq bitmasks */
|
||||
#define EP_CTX_CYCLE_MASK (1 << 0)
|
||||
@@ -670,6 +681,11 @@ struct xhci_input_control_ctx {
|
||||
__le32 rsvd2[6];
|
||||
};
|
||||
|
||||
#define EP_IS_ADDED(ctrl_ctx, i) \
|
||||
(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))
|
||||
#define EP_IS_DROPPED(ctrl_ctx, i) \
|
||||
(le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1)))
|
||||
|
||||
/* Represents everything that is needed to issue a command on the command ring.
|
||||
* It's useful to pre-allocate these for commands that cannot fail due to
|
||||
* out-of-memory errors, like freeing streams.
|
||||
@@ -731,6 +747,67 @@ struct xhci_stream_info {
|
||||
#define SMALL_STREAM_ARRAY_SIZE 256
|
||||
#define MEDIUM_STREAM_ARRAY_SIZE 1024
|
||||
|
||||
/* Some Intel xHCI host controllers need software to keep track of the bus
|
||||
* bandwidth. Keep track of endpoint info here. Each root port is allocated
|
||||
* the full bus bandwidth. We must also treat TTs (including each port under a
|
||||
* multi-TT hub) as a separate bandwidth domain. The direct memory interface
|
||||
* (DMI) also limits the total bandwidth (across all domains) that can be used.
|
||||
*/
|
||||
struct xhci_bw_info {
|
||||
/* ep_interval is zero-based */
|
||||
unsigned int ep_interval;
|
||||
/* mult and num_packets are one-based */
|
||||
unsigned int mult;
|
||||
unsigned int num_packets;
|
||||
unsigned int max_packet_size;
|
||||
unsigned int max_esit_payload;
|
||||
unsigned int type;
|
||||
};
|
||||
|
||||
/* "Block" sizes in bytes the hardware uses for different device speeds.
|
||||
* The logic in this part of the hardware limits the number of bits the hardware
|
||||
* can use, so must represent bandwidth in a less precise manner to mimic what
|
||||
* the scheduler hardware computes.
|
||||
*/
|
||||
#define FS_BLOCK 1
|
||||
#define HS_BLOCK 4
|
||||
#define SS_BLOCK 16
|
||||
#define DMI_BLOCK 32
|
||||
|
||||
/* Each device speed has a protocol overhead (CRC, bit stuffing, etc) associated
|
||||
* with each byte transferred. SuperSpeed devices have an initial overhead to
|
||||
* set up bursts. These are in blocks, see above. LS overhead has already been
|
||||
* translated into FS blocks.
|
||||
*/
|
||||
#define DMI_OVERHEAD 8
|
||||
#define DMI_OVERHEAD_BURST 4
|
||||
#define SS_OVERHEAD 8
|
||||
#define SS_OVERHEAD_BURST 32
|
||||
#define HS_OVERHEAD 26
|
||||
#define FS_OVERHEAD 20
|
||||
#define LS_OVERHEAD 128
|
||||
/* The TTs need to claim roughly twice as much bandwidth (94 bytes per
|
||||
* microframe ~= 24Mbps) of the HS bus as the devices can actually use because
|
||||
* of overhead associated with split transfers crossing microframe boundaries.
|
||||
* 31 blocks is pure protocol overhead.
|
||||
*/
|
||||
#define TT_HS_OVERHEAD (31 + 94)
|
||||
#define TT_DMI_OVERHEAD (25 + 12)
|
||||
|
||||
/* Bandwidth limits in blocks */
|
||||
#define FS_BW_LIMIT 1285
|
||||
#define TT_BW_LIMIT 1320
|
||||
#define HS_BW_LIMIT 1607
|
||||
#define SS_BW_LIMIT_IN 3906
|
||||
#define DMI_BW_LIMIT_IN 3906
|
||||
#define SS_BW_LIMIT_OUT 3906
|
||||
#define DMI_BW_LIMIT_OUT 3906
|
||||
|
||||
/* Percentage of bus bandwidth reserved for non-periodic transfers */
|
||||
#define FS_BW_RESERVED 10
|
||||
#define HS_BW_RESERVED 20
|
||||
#define SS_BW_RESERVED 10
|
||||
|
||||
struct xhci_virt_ep {
|
||||
struct xhci_ring *ring;
|
||||
/* Related to endpoints that are configured to use stream IDs only */
|
||||
@@ -772,8 +849,39 @@ struct xhci_virt_ep {
|
||||
* process the missed tds on the endpoint ring.
|
||||
*/
|
||||
bool skip;
|
||||
/* Bandwidth checking storage */
|
||||
struct xhci_bw_info bw_info;
|
||||
struct list_head bw_endpoint_list;
|
||||
};
|
||||
|
||||
enum xhci_overhead_type {
|
||||
LS_OVERHEAD_TYPE = 0,
|
||||
FS_OVERHEAD_TYPE,
|
||||
HS_OVERHEAD_TYPE,
|
||||
};
|
||||
|
||||
struct xhci_interval_bw {
|
||||
unsigned int num_packets;
|
||||
/* Sorted by max packet size.
|
||||
* Head of the list is the greatest max packet size.
|
||||
*/
|
||||
struct list_head endpoints;
|
||||
/* How many endpoints of each speed are present. */
|
||||
unsigned int overhead[3];
|
||||
};
|
||||
|
||||
#define XHCI_MAX_INTERVAL 16
|
||||
|
||||
struct xhci_interval_bw_table {
|
||||
unsigned int interval0_esit_payload;
|
||||
struct xhci_interval_bw interval_bw[XHCI_MAX_INTERVAL];
|
||||
/* Includes reserved bandwidth for async endpoints */
|
||||
unsigned int bw_used;
|
||||
unsigned int ss_bw_in;
|
||||
unsigned int ss_bw_out;
|
||||
};
|
||||
|
||||
|
||||
struct xhci_virt_device {
|
||||
struct usb_device *udev;
|
||||
/*
|
||||
@@ -798,7 +906,32 @@ struct xhci_virt_device {
|
||||
/* Status of the last command issued for this device */
|
||||
u32 cmd_status;
|
||||
struct list_head cmd_list;
|
||||
u8 port;
|
||||
u8 fake_port;
|
||||
u8 real_port;
|
||||
struct xhci_interval_bw_table *bw_table;
|
||||
struct xhci_tt_bw_info *tt_info;
|
||||
};
|
||||
|
||||
/*
|
||||
* For each roothub, keep track of the bandwidth information for each periodic
|
||||
* interval.
|
||||
*
|
||||
* If a high speed hub is attached to the roothub, each TT associated with that
|
||||
* hub is a separate bandwidth domain. The interval information for the
|
||||
* endpoints on the devices under that TT will appear in the TT structure.
|
||||
*/
|
||||
struct xhci_root_port_bw_info {
|
||||
struct list_head tts;
|
||||
unsigned int num_active_tts;
|
||||
struct xhci_interval_bw_table bw_table;
|
||||
};
|
||||
|
||||
struct xhci_tt_bw_info {
|
||||
struct list_head tt_list;
|
||||
int slot_id;
|
||||
int ttport;
|
||||
struct xhci_interval_bw_table bw_table;
|
||||
int active_eps;
|
||||
};
|
||||
|
||||
|
||||
@@ -1198,6 +1331,12 @@ struct s3_save {
|
||||
u64 erst_dequeue;
|
||||
};
|
||||
|
||||
/* Use for lpm */
|
||||
struct dev_info {
|
||||
u32 dev_id;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct xhci_bus_state {
|
||||
unsigned long bus_suspended;
|
||||
unsigned long next_statechange;
|
||||
@@ -1261,12 +1400,16 @@ struct xhci_hcd {
|
||||
struct xhci_erst erst;
|
||||
/* Scratchpad */
|
||||
struct xhci_scratchpad *scratchpad;
|
||||
/* Store LPM test failed devices' information */
|
||||
struct list_head lpm_failed_devs;
|
||||
|
||||
/* slot enabling and address device helpers */
|
||||
struct completion addr_dev;
|
||||
int slot_id;
|
||||
/* Internal mirror of the HW's dcbaa */
|
||||
struct xhci_virt_device *devs[MAX_HC_SLOTS];
|
||||
/* For keeping track of bandwidth domains per roothub. */
|
||||
struct xhci_root_port_bw_info *rh_bw;
|
||||
|
||||
/* DMA pools */
|
||||
struct dma_pool *device_pool;
|
||||
@@ -1318,6 +1461,8 @@ struct xhci_hcd {
|
||||
#define XHCI_EP_LIMIT_QUIRK (1 << 5)
|
||||
#define XHCI_BROKEN_MSI (1 << 6)
|
||||
#define XHCI_RESET_ON_RESUME (1 << 7)
|
||||
#define XHCI_SW_BW_CHECKING (1 << 8)
|
||||
#define XHCI_AMD_0x96_HOST (1 << 9)
|
||||
unsigned int num_active_eps;
|
||||
unsigned int limit_active_eps;
|
||||
/* There are two roothubs to keep track of bus suspend info for */
|
||||
@@ -1330,6 +1475,10 @@ struct xhci_hcd {
|
||||
/* Array of pointers to USB 2.0 PORTSC registers */
|
||||
__le32 __iomem **usb2_ports;
|
||||
unsigned int num_usb2_ports;
|
||||
/* support xHCI 0.96 spec USB2 software LPM */
|
||||
unsigned sw_lpm_support:1;
|
||||
/* support xHCI 1.0 spec USB2 hardware LPM */
|
||||
unsigned hw_lpm_support:1;
|
||||
};
|
||||
|
||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||
@@ -1401,9 +1550,7 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
|
||||
|
||||
static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
|
||||
return ((HC_VERSION(temp) == 0x95) &&
|
||||
(xhci->quirks & XHCI_LINK_TRB_QUIRK));
|
||||
return xhci->quirks & XHCI_LINK_TRB_QUIRK;
|
||||
}
|
||||
|
||||
/* xHCI debugging */
|
||||
@@ -1438,6 +1585,20 @@ unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
|
||||
unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index);
|
||||
unsigned int xhci_last_valid_endpoint(u32 added_ctxs);
|
||||
void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep);
|
||||
void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
|
||||
struct xhci_bw_info *ep_bw,
|
||||
struct xhci_interval_bw_table *bw_table,
|
||||
struct usb_device *udev,
|
||||
struct xhci_virt_ep *virt_ep,
|
||||
struct xhci_tt_bw_info *tt_info);
|
||||
void xhci_update_tt_active_eps(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
int old_active_eps);
|
||||
void xhci_clear_endpoint_bw_info(struct xhci_bw_info *bw_info);
|
||||
void xhci_update_bw_info(struct xhci_hcd *xhci,
|
||||
struct xhci_container_ctx *in_ctx,
|
||||
struct xhci_input_control_ctx *ctrl_ctx,
|
||||
struct xhci_virt_device *virt_dev);
|
||||
void xhci_endpoint_copy(struct xhci_hcd *xhci,
|
||||
struct xhci_container_ctx *in_ctx,
|
||||
struct xhci_container_ctx *out_ctx,
|
||||
@@ -1483,9 +1644,13 @@ void xhci_free_command(struct xhci_hcd *xhci,
|
||||
/* xHCI PCI glue */
|
||||
int xhci_register_pci(void);
|
||||
void xhci_unregister_pci(void);
|
||||
#else
|
||||
static inline int xhci_register_pci(void) { return 0; }
|
||||
static inline void xhci_unregister_pci(void) {}
|
||||
#endif
|
||||
|
||||
/* xHCI host controller glue */
|
||||
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
|
||||
void xhci_quiesce(struct xhci_hcd *xhci);
|
||||
int xhci_halt(struct xhci_hcd *xhci);
|
||||
int xhci_reset(struct xhci_hcd *xhci);
|
||||
@@ -1493,6 +1658,7 @@ int xhci_init(struct usb_hcd *hcd);
|
||||
int xhci_run(struct usb_hcd *hcd);
|
||||
void xhci_stop(struct usb_hcd *hcd);
|
||||
void xhci_shutdown(struct usb_hcd *hcd);
|
||||
int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int xhci_suspend(struct xhci_hcd *xhci);
|
||||
@@ -1507,6 +1673,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd);
|
||||
irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd);
|
||||
int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_alloc_tt_info(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
int xhci_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);
|
||||
@@ -1514,6 +1684,9 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
gfp_t mem_flags);
|
||||
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, int enable);
|
||||
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
|
||||
@@ -1572,6 +1745,10 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
|
||||
unsigned int ep_index, unsigned int stream_id);
|
||||
|
||||
/* xHCI roothub code */
|
||||
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
||||
int port_id, u32 link_state);
|
||||
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
||||
int port_id, u32 port_bit);
|
||||
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
|
||||
char *buf, u16 wLength);
|
||||
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
|
||||
|
Reference in New Issue
Block a user