Merge commit 'origin/master' into next
This commit is contained in:
@@ -17,6 +17,26 @@ config USB_C67X00_HCD
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called c67x00.
|
||||
|
||||
config USB_XHCI_HCD
|
||||
tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)"
|
||||
depends on USB && PCI && EXPERIMENTAL
|
||||
---help---
|
||||
The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
|
||||
"SuperSpeed" host controller hardware.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called xhci-hcd.
|
||||
|
||||
config USB_XHCI_HCD_DEBUGGING
|
||||
bool "Debugging for the xHCI host controller"
|
||||
depends on USB_XHCI_HCD
|
||||
---help---
|
||||
Say 'Y' to turn on debugging for the xHCI host controller driver.
|
||||
This will spew debugging output, even in interrupt context.
|
||||
This should only be used for debugging xHCI driver bugs.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config USB_EHCI_HCD
|
||||
tristate "EHCI HCD (USB 2.0) support"
|
||||
depends on USB && USB_ARCH_HAS_EHCI
|
||||
|
@@ -12,6 +12,7 @@ fhci-objs := fhci-hcd.o fhci-hub.o fhci-q.o fhci-mem.o \
|
||||
ifeq ($(CONFIG_FHCI_DEBUG),y)
|
||||
fhci-objs += fhci-dbg.o
|
||||
endif
|
||||
xhci-objs := xhci-hcd.o xhci-mem.o xhci-pci.o xhci-ring.o xhci-hub.o xhci-dbg.o
|
||||
|
||||
obj-$(CONFIG_USB_WHCI_HCD) += whci/
|
||||
|
||||
@@ -23,6 +24,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
|
||||
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
|
||||
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
|
||||
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
|
||||
obj-$(CONFIG_USB_XHCI_HCD) += xhci.o
|
||||
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
|
||||
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
|
||||
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
|
||||
|
@@ -97,6 +97,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
|
@@ -309,6 +309,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
|
@@ -1024,6 +1024,51 @@ done:
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct ehci_qh *qh;
|
||||
int eptype = usb_endpoint_type(&ep->desc);
|
||||
|
||||
if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
|
||||
return;
|
||||
|
||||
rescan:
|
||||
spin_lock_irq(&ehci->lock);
|
||||
qh = ep->hcpriv;
|
||||
|
||||
/* For Bulk and Interrupt endpoints we maintain the toggle state
|
||||
* in the hardware; the toggle bits in udev aren't used at all.
|
||||
* When an endpoint is reset by usb_clear_halt() we must reset
|
||||
* the toggle bit in the QH.
|
||||
*/
|
||||
if (qh) {
|
||||
if (!list_empty(&qh->qtd_list)) {
|
||||
WARN_ONCE(1, "clear_halt for a busy endpoint\n");
|
||||
} else if (qh->qh_state == QH_STATE_IDLE) {
|
||||
qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
|
||||
} else {
|
||||
/* It's not safe to write into the overlay area
|
||||
* while the QH is active. Unlink it first and
|
||||
* wait for the unlink to complete.
|
||||
*/
|
||||
if (qh->qh_state == QH_STATE_LINKED) {
|
||||
if (eptype == USB_ENDPOINT_XFER_BULK) {
|
||||
unlink_async(ehci, qh);
|
||||
} else {
|
||||
intr_deschedule(ehci, qh);
|
||||
(void) qh_schedule(ehci, qh);
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
schedule_timeout_uninterruptible(1);
|
||||
goto rescan;
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
}
|
||||
|
||||
static int ehci_get_frame (struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
||||
@@ -1097,7 +1142,7 @@ static int __init ehci_hcd_init(void)
|
||||
sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
|
||||
|
||||
#ifdef DEBUG
|
||||
ehci_debug_root = debugfs_create_dir("ehci", NULL);
|
||||
ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);
|
||||
if (!ehci_debug_root) {
|
||||
retval = -ENOENT;
|
||||
goto err_debug;
|
||||
|
@@ -391,7 +391,7 @@ static inline void create_companion_file(struct ehci_hcd *ehci)
|
||||
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
i = device_create_file(ehci_to_hcd(ehci)->self.dev,
|
||||
i = device_create_file(ehci_to_hcd(ehci)->self.controller,
|
||||
&dev_attr_companion);
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ static inline void remove_companion_file(struct ehci_hcd *ehci)
|
||||
{
|
||||
/* with integrated TT there is no companion! */
|
||||
if (!ehci_is_TDI(ehci))
|
||||
device_remove_file(ehci_to_hcd(ehci)->self.dev,
|
||||
device_remove_file(ehci_to_hcd(ehci)->self.controller,
|
||||
&dev_attr_companion);
|
||||
}
|
||||
|
||||
|
@@ -51,6 +51,7 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = {
|
||||
.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,
|
||||
|
@@ -149,6 +149,7 @@ static const struct hc_driver ehci_orion_hc_driver = {
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
@@ -187,7 +188,7 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
|
||||
}
|
||||
}
|
||||
|
||||
static int __init ehci_orion_drv_probe(struct platform_device *pdev)
|
||||
static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct orion_ehci_data *pd = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
|
@@ -268,7 +268,7 @@ done:
|
||||
* Also they depend on separate root hub suspend/resume.
|
||||
*/
|
||||
|
||||
static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||
static int ehci_pci_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
unsigned long flags;
|
||||
@@ -293,12 +293,6 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
/* make sure snapshot being resumed re-enumerates everything */
|
||||
if (message.event == PM_EVENT_PRETHAW) {
|
||||
ehci_halt(ehci);
|
||||
ehci_reset(ehci);
|
||||
}
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
bail:
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
@@ -309,7 +303,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ehci_pci_resume(struct usb_hcd *hcd)
|
||||
static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
@@ -322,10 +316,12 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
|
||||
/* Mark hardware accessible again as we are out of D3 state by now */
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* If CF is still set, we maintained PCI Vaux power.
|
||||
/* If CF is still set and we aren't resuming from hibernation
|
||||
* then we maintained PCI Vaux power.
|
||||
* Just undo the effect of ehci_pci_suspend().
|
||||
*/
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
|
||||
!hibernated) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
@@ -335,7 +331,6 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ehci_dbg(ehci, "lost power, restarting\n");
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
/* Else reset, to cope with power loss or flush-to-storage
|
||||
@@ -393,6 +388,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
@@ -429,10 +425,11 @@ static struct pci_driver ehci_pci_driver = {
|
||||
|
||||
.probe = usb_hcd_pci_probe,
|
||||
.remove = usb_hcd_pci_remove,
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = usb_hcd_pci_suspend,
|
||||
.resume = usb_hcd_pci_resume,
|
||||
#endif
|
||||
.shutdown = usb_hcd_pci_shutdown,
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.driver = {
|
||||
.pm = &usb_hcd_pci_pm_ops
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
@@ -61,6 +61,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
|
@@ -65,6 +65,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
|
||||
.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,
|
||||
|
@@ -93,22 +93,6 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
|
||||
qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
|
||||
qh->hw_alt_next = EHCI_LIST_END(ehci);
|
||||
|
||||
/* Except for control endpoints, we make hardware maintain data
|
||||
* toggle (like OHCI) ... here (re)initialize the toggle in the QH,
|
||||
* and set the pseudo-toggle in udev. Only usb_clear_halt() will
|
||||
* ever clear it.
|
||||
*/
|
||||
if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
|
||||
unsigned is_out, epnum;
|
||||
|
||||
is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
|
||||
epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
|
||||
if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
|
||||
qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
|
||||
usb_settoggle (qh->dev, epnum, is_out, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
|
||||
wmb ();
|
||||
qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
|
||||
@@ -850,7 +834,6 @@ done:
|
||||
qh->qh_state = QH_STATE_IDLE;
|
||||
qh->hw_info1 = cpu_to_hc32(ehci, info1);
|
||||
qh->hw_info2 = cpu_to_hc32(ehci, info2);
|
||||
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
|
||||
qh_refresh (ehci, qh);
|
||||
return qh;
|
||||
}
|
||||
@@ -881,7 +864,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
}
|
||||
}
|
||||
|
||||
/* clear halt and/or toggle; and maybe recover from silicon quirk */
|
||||
/* clear halt and maybe recover from silicon quirk */
|
||||
if (qh->qh_state == QH_STATE_IDLE)
|
||||
qh_refresh (ehci, qh);
|
||||
|
||||
|
@@ -760,8 +760,10 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
if (status) {
|
||||
/* "normal" case, uframing flexible except with splits */
|
||||
if (qh->period) {
|
||||
frame = qh->period - 1;
|
||||
do {
|
||||
int i;
|
||||
|
||||
for (i = qh->period; status && i > 0; --i) {
|
||||
frame = ++ehci->random_frame % qh->period;
|
||||
for (uframe = 0; uframe < 8; uframe++) {
|
||||
status = check_intr_schedule (ehci,
|
||||
frame, uframe, qh,
|
||||
@@ -769,7 +771,7 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
if (status == 0)
|
||||
break;
|
||||
}
|
||||
} while (status && frame--);
|
||||
}
|
||||
|
||||
/* qh->period == 0 means every uframe */
|
||||
} else {
|
||||
|
@@ -116,6 +116,7 @@ struct ehci_hcd { /* one per controller */
|
||||
struct timer_list watchdog;
|
||||
unsigned long actions;
|
||||
unsigned stamp;
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
u32 command;
|
||||
|
||||
|
@@ -108,7 +108,7 @@ void fhci_dfs_create(struct fhci_hcd *fhci)
|
||||
{
|
||||
struct device *dev = fhci_to_hcd(fhci)->self.controller;
|
||||
|
||||
fhci->dfs_root = debugfs_create_dir(dev_name(dev), NULL);
|
||||
fhci->dfs_root = debugfs_create_dir(dev_name(dev), usb_debug_root);
|
||||
if (!fhci->dfs_root) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
|
@@ -172,25 +172,6 @@ error_cluster_id_get:
|
||||
|
||||
}
|
||||
|
||||
static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg)
|
||||
{
|
||||
struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
|
||||
struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
|
||||
dev_err(wusbhc->dev, "%s (%p [%p], 0x%lx) UNIMPLEMENTED\n", __func__,
|
||||
usb_hcd, hwahc, *(unsigned long *) &msg);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int hwahc_op_resume(struct usb_hcd *usb_hcd)
|
||||
{
|
||||
struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
|
||||
struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
|
||||
|
||||
dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
|
||||
usb_hcd, hwahc);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/*
|
||||
* No need to abort pipes, as when this is called, all the children
|
||||
* has been disconnected and that has done it [through
|
||||
@@ -598,8 +579,6 @@ static struct hc_driver hwahc_hc_driver = {
|
||||
.flags = HCD_USB2, /* FIXME */
|
||||
.reset = hwahc_op_reset,
|
||||
.start = hwahc_op_start,
|
||||
.pci_suspend = hwahc_op_suspend,
|
||||
.pci_resume = hwahc_op_resume,
|
||||
.stop = hwahc_op_stop,
|
||||
.get_frame_number = hwahc_op_get_frame_number,
|
||||
.urb_enqueue = hwahc_op_urb_enqueue,
|
||||
|
@@ -431,7 +431,7 @@ static struct dentry *ohci_debug_root;
|
||||
|
||||
struct debug_buffer {
|
||||
ssize_t (*fill_func)(struct debug_buffer *); /* fill method */
|
||||
struct device *dev;
|
||||
struct ohci_hcd *ohci;
|
||||
struct mutex mutex; /* protect filling of buffer */
|
||||
size_t count; /* number of characters filled into buffer */
|
||||
char *page;
|
||||
@@ -505,15 +505,11 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
|
||||
|
||||
static ssize_t fill_async_buffer(struct debug_buffer *buf)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
struct usb_hcd *hcd;
|
||||
struct ohci_hcd *ohci;
|
||||
size_t temp;
|
||||
unsigned long flags;
|
||||
|
||||
bus = dev_get_drvdata(buf->dev);
|
||||
hcd = bus_to_hcd(bus);
|
||||
ohci = hcd_to_ohci(hcd);
|
||||
ohci = buf->ohci;
|
||||
|
||||
/* display control and bulk lists together, for simplicity */
|
||||
spin_lock_irqsave (&ohci->lock, flags);
|
||||
@@ -529,8 +525,6 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
|
||||
|
||||
static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
struct usb_hcd *hcd;
|
||||
struct ohci_hcd *ohci;
|
||||
struct ed **seen, *ed;
|
||||
unsigned long flags;
|
||||
@@ -542,9 +536,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
|
||||
return 0;
|
||||
seen_count = 0;
|
||||
|
||||
bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
|
||||
hcd = bus_to_hcd(bus);
|
||||
ohci = hcd_to_ohci(hcd);
|
||||
ohci = buf->ohci;
|
||||
next = buf->page;
|
||||
size = PAGE_SIZE;
|
||||
|
||||
@@ -626,7 +618,6 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
|
||||
|
||||
static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
struct usb_hcd *hcd;
|
||||
struct ohci_hcd *ohci;
|
||||
struct ohci_regs __iomem *regs;
|
||||
@@ -635,9 +626,8 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
||||
char *next;
|
||||
u32 rdata;
|
||||
|
||||
bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
|
||||
hcd = bus_to_hcd(bus);
|
||||
ohci = hcd_to_ohci(hcd);
|
||||
ohci = buf->ohci;
|
||||
hcd = ohci_to_hcd(ohci);
|
||||
regs = ohci->regs;
|
||||
next = buf->page;
|
||||
size = PAGE_SIZE;
|
||||
@@ -710,7 +700,7 @@ done:
|
||||
return PAGE_SIZE - size;
|
||||
}
|
||||
|
||||
static struct debug_buffer *alloc_buffer(struct device *dev,
|
||||
static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci,
|
||||
ssize_t (*fill_func)(struct debug_buffer *))
|
||||
{
|
||||
struct debug_buffer *buf;
|
||||
@@ -718,7 +708,7 @@ static struct debug_buffer *alloc_buffer(struct device *dev,
|
||||
buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
|
||||
|
||||
if (buf) {
|
||||
buf->dev = dev;
|
||||
buf->ohci = ohci;
|
||||
buf->fill_func = fill_func;
|
||||
mutex_init(&buf->mutex);
|
||||
}
|
||||
@@ -810,26 +800,25 @@ static int debug_registers_open(struct inode *inode, struct file *file)
|
||||
static inline void create_debug_files (struct ohci_hcd *ohci)
|
||||
{
|
||||
struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
|
||||
struct device *dev = bus->dev;
|
||||
|
||||
ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root);
|
||||
if (!ohci->debug_dir)
|
||||
goto dir_error;
|
||||
|
||||
ohci->debug_async = debugfs_create_file("async", S_IRUGO,
|
||||
ohci->debug_dir, dev,
|
||||
ohci->debug_dir, ohci,
|
||||
&debug_async_fops);
|
||||
if (!ohci->debug_async)
|
||||
goto async_error;
|
||||
|
||||
ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
|
||||
ohci->debug_dir, dev,
|
||||
ohci->debug_dir, ohci,
|
||||
&debug_periodic_fops);
|
||||
if (!ohci->debug_periodic)
|
||||
goto periodic_error;
|
||||
|
||||
ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
|
||||
ohci->debug_dir, dev,
|
||||
ohci->debug_dir, ohci,
|
||||
&debug_registers_fops);
|
||||
if (!ohci->debug_registers)
|
||||
goto registers_error;
|
||||
|
@@ -571,7 +571,7 @@ static int ohci_init (struct ohci_hcd *ohci)
|
||||
*/
|
||||
static int ohci_run (struct ohci_hcd *ohci)
|
||||
{
|
||||
u32 mask, temp;
|
||||
u32 mask, val;
|
||||
int first = ohci->fminterval == 0;
|
||||
struct usb_hcd *hcd = ohci_to_hcd(ohci);
|
||||
|
||||
@@ -580,8 +580,8 @@ static int ohci_run (struct ohci_hcd *ohci)
|
||||
/* boot firmware should have set this up (5.1.1.3.1) */
|
||||
if (first) {
|
||||
|
||||
temp = ohci_readl (ohci, &ohci->regs->fminterval);
|
||||
ohci->fminterval = temp & 0x3fff;
|
||||
val = ohci_readl (ohci, &ohci->regs->fminterval);
|
||||
ohci->fminterval = val & 0x3fff;
|
||||
if (ohci->fminterval != FI)
|
||||
ohci_dbg (ohci, "fminterval delta %d\n",
|
||||
ohci->fminterval - FI);
|
||||
@@ -600,25 +600,25 @@ static int ohci_run (struct ohci_hcd *ohci)
|
||||
|
||||
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
|
||||
case OHCI_USB_OPER:
|
||||
temp = 0;
|
||||
val = 0;
|
||||
break;
|
||||
case OHCI_USB_SUSPEND:
|
||||
case OHCI_USB_RESUME:
|
||||
ohci->hc_control &= OHCI_CTRL_RWC;
|
||||
ohci->hc_control |= OHCI_USB_RESUME;
|
||||
temp = 10 /* msec wait */;
|
||||
val = 10 /* msec wait */;
|
||||
break;
|
||||
// case OHCI_USB_RESET:
|
||||
default:
|
||||
ohci->hc_control &= OHCI_CTRL_RWC;
|
||||
ohci->hc_control |= OHCI_USB_RESET;
|
||||
temp = 50 /* msec wait */;
|
||||
val = 50 /* msec wait */;
|
||||
break;
|
||||
}
|
||||
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
|
||||
// flush the writes
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
msleep(temp);
|
||||
msleep(val);
|
||||
|
||||
memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
|
||||
|
||||
@@ -628,9 +628,9 @@ static int ohci_run (struct ohci_hcd *ohci)
|
||||
retry:
|
||||
/* HC Reset requires max 10 us delay */
|
||||
ohci_writel (ohci, OHCI_HCR, &ohci->regs->cmdstatus);
|
||||
temp = 30; /* ... allow extra time */
|
||||
val = 30; /* ... allow extra time */
|
||||
while ((ohci_readl (ohci, &ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
|
||||
if (--temp == 0) {
|
||||
if (--val == 0) {
|
||||
spin_unlock_irq (&ohci->lock);
|
||||
ohci_err (ohci, "USB HC reset timed out!\n");
|
||||
return -1;
|
||||
@@ -699,23 +699,23 @@ retry:
|
||||
ohci_writel (ohci, mask, &ohci->regs->intrenable);
|
||||
|
||||
/* handle root hub init quirks ... */
|
||||
temp = roothub_a (ohci);
|
||||
temp &= ~(RH_A_PSM | RH_A_OCPM);
|
||||
val = roothub_a (ohci);
|
||||
val &= ~(RH_A_PSM | RH_A_OCPM);
|
||||
if (ohci->flags & OHCI_QUIRK_SUPERIO) {
|
||||
/* NSC 87560 and maybe others */
|
||||
temp |= RH_A_NOCP;
|
||||
temp &= ~(RH_A_POTPGT | RH_A_NPS);
|
||||
ohci_writel (ohci, temp, &ohci->regs->roothub.a);
|
||||
val |= RH_A_NOCP;
|
||||
val &= ~(RH_A_POTPGT | RH_A_NPS);
|
||||
ohci_writel (ohci, val, &ohci->regs->roothub.a);
|
||||
} else if ((ohci->flags & OHCI_QUIRK_AMD756) ||
|
||||
(ohci->flags & OHCI_QUIRK_HUB_POWER)) {
|
||||
/* hub power always on; required for AMD-756 and some
|
||||
* Mac platforms. ganged overcurrent reporting, if any.
|
||||
*/
|
||||
temp |= RH_A_NPS;
|
||||
ohci_writel (ohci, temp, &ohci->regs->roothub.a);
|
||||
val |= RH_A_NPS;
|
||||
ohci_writel (ohci, val, &ohci->regs->roothub.a);
|
||||
}
|
||||
ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
|
||||
ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM,
|
||||
ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM,
|
||||
&ohci->regs->roothub.b);
|
||||
// flush those writes
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
@@ -724,7 +724,7 @@ retry:
|
||||
spin_unlock_irq (&ohci->lock);
|
||||
|
||||
// POTPGT delay is bits 24-31, in 2 ms units.
|
||||
mdelay ((temp >> 23) & 0x1fe);
|
||||
mdelay ((val >> 23) & 0x1fe);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
if (quirk_zfmicro(ohci)) {
|
||||
@@ -1105,7 +1105,7 @@ static int __init ohci_hcd_mod_init(void)
|
||||
set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
|
||||
|
||||
#ifdef DEBUG
|
||||
ohci_debug_root = debugfs_create_dir("ohci", NULL);
|
||||
ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root);
|
||||
if (!ohci_debug_root) {
|
||||
retval = -ENOENT;
|
||||
goto error_debug;
|
||||
|
@@ -372,7 +372,7 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
|
||||
static int ohci_pci_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
unsigned long flags;
|
||||
@@ -394,10 +394,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
|
||||
ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
|
||||
(void)ohci_readl(ohci, &ohci->regs->intrdisable);
|
||||
|
||||
/* make sure snapshot being resumed re-enumerates everything */
|
||||
if (message.event == PM_EVENT_PRETHAW)
|
||||
ohci_usb_reset(ohci);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
bail:
|
||||
spin_unlock_irqrestore (&ohci->lock, flags);
|
||||
@@ -406,9 +402,14 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
|
||||
}
|
||||
|
||||
|
||||
static int ohci_pci_resume (struct usb_hcd *hcd)
|
||||
static int ohci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
{
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* Make sure resume from hibernation re-enumerates everything */
|
||||
if (hibernated)
|
||||
ohci_usb_reset(hcd_to_ohci(hcd));
|
||||
|
||||
ohci_finish_controller_resume(hcd);
|
||||
return 0;
|
||||
}
|
||||
@@ -484,12 +485,11 @@ static struct pci_driver ohci_pci_driver = {
|
||||
|
||||
.probe = usb_hcd_pci_probe,
|
||||
.remove = usb_hcd_pci_remove,
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = usb_hcd_pci_suspend,
|
||||
.resume = usb_hcd_pci_resume,
|
||||
#endif
|
||||
|
||||
.shutdown = usb_hcd_pci_shutdown,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.driver = {
|
||||
.pm = &usb_hcd_pci_pm_ops
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/acpi.h>
|
||||
#include "pci-quirks.h"
|
||||
#include "xhci-ext-caps.h"
|
||||
|
||||
|
||||
#define UHCI_USBLEGSUP 0xc0 /* legacy support */
|
||||
@@ -341,7 +342,127 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* handshake - spin reading a register until handshake completes
|
||||
* @ptr: address of hc register to be read
|
||||
* @mask: bits to look at in result of read
|
||||
* @done: value of those bits when handshake succeeds
|
||||
* @wait_usec: timeout in microseconds
|
||||
* @delay_usec: delay in microseconds to wait between polling
|
||||
*
|
||||
* Polls a register every delay_usec microseconds.
|
||||
* Returns 0 when the mask bits have the value done.
|
||||
* Returns -ETIMEDOUT if this condition is not true after
|
||||
* wait_usec microseconds have passed.
|
||||
*/
|
||||
static int handshake(void __iomem *ptr, u32 mask, u32 done,
|
||||
int wait_usec, int delay_usec)
|
||||
{
|
||||
u32 result;
|
||||
|
||||
do {
|
||||
result = readl(ptr);
|
||||
result &= mask;
|
||||
if (result == done)
|
||||
return 0;
|
||||
udelay(delay_usec);
|
||||
wait_usec -= delay_usec;
|
||||
} while (wait_usec > 0);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* PCI Quirks for xHCI.
|
||||
*
|
||||
* Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS.
|
||||
* It signals to the BIOS that the OS wants control of the host controller,
|
||||
* and then waits 5 seconds for the BIOS to hand over control.
|
||||
* If we timeout, assume the BIOS is broken and take control anyway.
|
||||
*/
|
||||
static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
||||
{
|
||||
void __iomem *base;
|
||||
int ext_cap_offset;
|
||||
void __iomem *op_reg_base;
|
||||
u32 val;
|
||||
int timeout;
|
||||
|
||||
if (!mmio_resource_enabled(pdev, 0))
|
||||
return;
|
||||
|
||||
base = ioremap_nocache(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0));
|
||||
if (base == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Find the Legacy Support Capability register -
|
||||
* this is optional for xHCI host controllers.
|
||||
*/
|
||||
ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
|
||||
do {
|
||||
if (!ext_cap_offset)
|
||||
/* We've reached the end of the extended capabilities */
|
||||
goto hc_init;
|
||||
val = readl(base + ext_cap_offset);
|
||||
if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
|
||||
break;
|
||||
ext_cap_offset = xhci_find_next_cap_offset(base, ext_cap_offset);
|
||||
} while (1);
|
||||
|
||||
/* If the BIOS owns the HC, signal that the OS wants it, and wait */
|
||||
if (val & XHCI_HC_BIOS_OWNED) {
|
||||
writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset);
|
||||
|
||||
/* Wait for 5 seconds with 10 microsecond polling interval */
|
||||
timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
|
||||
0, 5000, 10);
|
||||
|
||||
/* Assume a buggy BIOS and take HC ownership anyway */
|
||||
if (timeout) {
|
||||
dev_warn(&pdev->dev, "xHCI BIOS handoff failed"
|
||||
" (BIOS bug ?) %08x\n", val);
|
||||
writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable any BIOS SMIs */
|
||||
writel(XHCI_LEGACY_DISABLE_SMI,
|
||||
base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
||||
|
||||
hc_init:
|
||||
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
|
||||
|
||||
/* Wait for the host controller to be ready before writing any
|
||||
* operational or runtime registers. Wait 5 seconds and no more.
|
||||
*/
|
||||
timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
|
||||
5000, 10);
|
||||
/* Assume a buggy HC and start HC initialization anyway */
|
||||
if (timeout) {
|
||||
val = readl(op_reg_base + XHCI_STS_OFFSET);
|
||||
dev_warn(&pdev->dev,
|
||||
"xHCI HW not ready after 5 sec (HC bug?) "
|
||||
"status = 0x%x\n", val);
|
||||
}
|
||||
|
||||
/* Send the halt and disable interrupts command */
|
||||
val = readl(op_reg_base + XHCI_CMD_OFFSET);
|
||||
val &= ~(XHCI_CMD_RUN | XHCI_IRQS);
|
||||
writel(val, op_reg_base + XHCI_CMD_OFFSET);
|
||||
|
||||
/* Wait for the HC to halt - poll every 125 usec (one microframe). */
|
||||
timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_HALT, 1,
|
||||
XHCI_MAX_HALT_USEC, 125);
|
||||
if (timeout) {
|
||||
val = readl(op_reg_base + XHCI_STS_OFFSET);
|
||||
dev_warn(&pdev->dev,
|
||||
"xHCI HW did not halt within %d usec "
|
||||
"status = 0x%x\n", XHCI_MAX_HALT_USEC, val);
|
||||
}
|
||||
|
||||
iounmap(base);
|
||||
}
|
||||
|
||||
static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
|
||||
{
|
||||
@@ -351,5 +472,7 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
|
||||
quirk_usb_handoff_ohci(pdev);
|
||||
else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI)
|
||||
quirk_usb_disable_ehci(pdev);
|
||||
else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
|
||||
quirk_usb_handoff_xhci(pdev);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
|
||||
|
@@ -46,31 +46,10 @@ MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Yoshihiro Shimoda");
|
||||
MODULE_ALIAS("platform:r8a66597_hcd");
|
||||
|
||||
#define DRIVER_VERSION "10 Apr 2008"
|
||||
#define DRIVER_VERSION "2009-05-26"
|
||||
|
||||
static const char hcd_name[] = "r8a66597_hcd";
|
||||
|
||||
/* module parameters */
|
||||
#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
|
||||
static unsigned short clock = XTAL12;
|
||||
module_param(clock, ushort, 0644);
|
||||
MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
|
||||
"(default=0)");
|
||||
#endif
|
||||
|
||||
static unsigned short vif = LDRV;
|
||||
module_param(vif, ushort, 0644);
|
||||
MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
|
||||
|
||||
static unsigned short endian;
|
||||
module_param(endian, ushort, 0644);
|
||||
MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
|
||||
|
||||
static unsigned short irq_sense = 0xff;
|
||||
module_param(irq_sense, ushort, 0644);
|
||||
MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
|
||||
"(default=32)");
|
||||
|
||||
static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
|
||||
static int r8a66597_get_frame(struct usb_hcd *hcd);
|
||||
|
||||
@@ -136,7 +115,8 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
|
||||
}
|
||||
} while ((tmp & USBE) != USBE);
|
||||
r8a66597_bclr(r8a66597, USBE, SYSCFG0);
|
||||
r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0);
|
||||
r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata), XTAL,
|
||||
SYSCFG0);
|
||||
|
||||
i = 0;
|
||||
r8a66597_bset(r8a66597, XCKE, SYSCFG0);
|
||||
@@ -203,6 +183,9 @@ static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
|
||||
static int enable_controller(struct r8a66597 *r8a66597)
|
||||
{
|
||||
int ret, port;
|
||||
u16 vif = r8a66597->pdata->vif ? LDRV : 0;
|
||||
u16 irq_sense = r8a66597->irq_sense_low ? INTL : 0;
|
||||
u16 endian = r8a66597->pdata->endian ? BIGEND : 0;
|
||||
|
||||
ret = r8a66597_clock_enable(r8a66597);
|
||||
if (ret < 0)
|
||||
@@ -2373,7 +2356,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init r8a66597_probe(struct platform_device *pdev)
|
||||
static int __devinit r8a66597_probe(struct platform_device *pdev)
|
||||
{
|
||||
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
|
||||
char clk_name[8];
|
||||
@@ -2418,6 +2401,12 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
if (pdev->dev.platform_data == NULL) {
|
||||
dev_err(&pdev->dev, "no platform data\n");
|
||||
ret = -ENODEV;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
/* initialize hcd */
|
||||
hcd = usb_create_hcd(&r8a66597_hc_driver, &pdev->dev, (char *)hcd_name);
|
||||
if (!hcd) {
|
||||
@@ -2428,6 +2417,8 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
||||
r8a66597 = hcd_to_r8a66597(hcd);
|
||||
memset(r8a66597, 0, sizeof(struct r8a66597));
|
||||
dev_set_drvdata(&pdev->dev, r8a66597);
|
||||
r8a66597->pdata = pdev->dev.platform_data;
|
||||
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
|
||||
|
||||
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
|
||||
snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
|
||||
@@ -2458,29 +2449,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
|
||||
/* irq_sense setting on cmdline takes precedence over resource
|
||||
* settings, so the introduction of irqflags in IRQ resourse
|
||||
* won't disturb existing setups */
|
||||
switch (irq_sense) {
|
||||
case INTL:
|
||||
irq_trigger = IRQF_TRIGGER_LOW;
|
||||
break;
|
||||
case 0:
|
||||
irq_trigger = IRQF_TRIGGER_FALLING;
|
||||
break;
|
||||
case 0xff:
|
||||
if (irq_trigger)
|
||||
irq_sense = (irq_trigger & IRQF_TRIGGER_LOW) ?
|
||||
INTL : 0;
|
||||
else {
|
||||
irq_sense = INTL;
|
||||
irq_trigger = IRQF_TRIGGER_LOW;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unknown irq_sense value.\n");
|
||||
}
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to add hcd\n");
|
||||
|
@@ -30,6 +30,8 @@
|
||||
#include <linux/clk.h>
|
||||
#endif
|
||||
|
||||
#include <linux/usb/r8a66597.h>
|
||||
|
||||
#define SYSCFG0 0x00
|
||||
#define SYSCFG1 0x02
|
||||
#define SYSSTS0 0x04
|
||||
@@ -488,6 +490,7 @@ struct r8a66597 {
|
||||
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
|
||||
struct clk *clk;
|
||||
#endif
|
||||
struct r8a66597_platdata *pdata;
|
||||
struct r8a66597_device device0;
|
||||
struct r8a66597_root_hub root_hub[R8A66597_MAX_ROOT_HUB];
|
||||
struct list_head pipe_queue[R8A66597_MAX_NUM_PIPE];
|
||||
@@ -506,6 +509,7 @@ struct r8a66597 {
|
||||
unsigned long child_connect_map[4];
|
||||
|
||||
unsigned bus_suspended:1;
|
||||
unsigned irq_sense_low:1;
|
||||
};
|
||||
|
||||
static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd)
|
||||
@@ -660,10 +664,36 @@ static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
|
||||
{
|
||||
unsigned long dvstctr_reg = get_dvstctr_reg(port);
|
||||
|
||||
if (power)
|
||||
r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
|
||||
else
|
||||
r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
|
||||
if (r8a66597->pdata->port_power) {
|
||||
r8a66597->pdata->port_power(port, power);
|
||||
} else {
|
||||
if (power)
|
||||
r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
|
||||
else
|
||||
r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata)
|
||||
{
|
||||
u16 clock = 0;
|
||||
|
||||
switch (pdata->xtal) {
|
||||
case R8A66597_PLATDATA_XTAL_12MHZ:
|
||||
clock = XTAL12;
|
||||
break;
|
||||
case R8A66597_PLATDATA_XTAL_24MHZ:
|
||||
clock = XTAL24;
|
||||
break;
|
||||
case R8A66597_PLATDATA_XTAL_48MHZ:
|
||||
clock = XTAL48;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "r8a66597: platdata clock is wrong.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return clock;
|
||||
}
|
||||
|
||||
#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
|
||||
|
@@ -769,7 +769,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||
static int uhci_pci_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
int rc = 0;
|
||||
@@ -795,10 +795,6 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
|
||||
|
||||
/* FIXME: Enable non-PME# remote wakeup? */
|
||||
|
||||
/* make sure snapshot being resumed re-enumerates everything */
|
||||
if (message.event == PM_EVENT_PRETHAW)
|
||||
uhci_hc_died(uhci);
|
||||
|
||||
done_okay:
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
done:
|
||||
@@ -806,7 +802,7 @@ done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int uhci_pci_resume(struct usb_hcd *hcd)
|
||||
static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
{
|
||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||
|
||||
@@ -820,6 +816,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
|
||||
|
||||
spin_lock_irq(&uhci->lock);
|
||||
|
||||
/* Make sure resume from hibernation re-enumerates everything */
|
||||
if (hibernated)
|
||||
uhci_hc_died(uhci);
|
||||
|
||||
/* FIXME: Disable non-PME# remote wakeup? */
|
||||
|
||||
/* The firmware or a boot kernel may have changed the controller
|
||||
@@ -940,10 +940,11 @@ static struct pci_driver uhci_pci_driver = {
|
||||
.remove = usb_hcd_pci_remove,
|
||||
.shutdown = uhci_shutdown,
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = usb_hcd_pci_suspend,
|
||||
.resume = usb_hcd_pci_resume,
|
||||
#endif /* PM */
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.driver = {
|
||||
.pm = &usb_hcd_pci_pm_ops
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init uhci_hcd_init(void)
|
||||
@@ -961,7 +962,7 @@ static int __init uhci_hcd_init(void)
|
||||
errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
|
||||
if (!errbuf)
|
||||
goto errbuf_failed;
|
||||
uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
|
||||
uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root);
|
||||
if (!uhci_debugfs_root)
|
||||
goto debug_failed;
|
||||
}
|
||||
|
@@ -260,7 +260,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
|
||||
INIT_LIST_HEAD(&qh->node);
|
||||
|
||||
if (udev) { /* Normal QH */
|
||||
qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
||||
qh->type = usb_endpoint_type(&hep->desc);
|
||||
if (qh->type != USB_ENDPOINT_XFER_ISOC) {
|
||||
qh->dummy_td = uhci_alloc_td(uhci);
|
||||
if (!qh->dummy_td) {
|
||||
|
485
drivers/usb/host/xhci-dbg.c
Normal file
485
drivers/usb/host/xhci-dbg.c
Normal file
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* xHCI host controller driver
|
||||
*
|
||||
* Copyright (C) 2008 Intel Corp.
|
||||
*
|
||||
* Author: Sarah Sharp
|
||||
* Some code borrowed from the Linux EHCI driver.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "xhci.h"
|
||||
|
||||
#define XHCI_INIT_VALUE 0x0
|
||||
|
||||
/* Add verbose debugging later, just print everything for now */
|
||||
|
||||
void xhci_dbg_regs(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
xhci_dbg(xhci, "// xHCI capability registers at %p:\n",
|
||||
xhci->cap_regs);
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
|
||||
xhci_dbg(xhci, "// @%p = 0x%x (CAPLENGTH AND HCIVERSION)\n",
|
||||
&xhci->cap_regs->hc_capbase, temp);
|
||||
xhci_dbg(xhci, "// CAPLENGTH: 0x%x\n",
|
||||
(unsigned int) HC_LENGTH(temp));
|
||||
#if 0
|
||||
xhci_dbg(xhci, "// HCIVERSION: 0x%x\n",
|
||||
(unsigned int) HC_VERSION(temp));
|
||||
#endif
|
||||
|
||||
xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs);
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off);
|
||||
xhci_dbg(xhci, "// @%p = 0x%x RTSOFF\n",
|
||||
&xhci->cap_regs->run_regs_off,
|
||||
(unsigned int) temp & RTSOFF_MASK);
|
||||
xhci_dbg(xhci, "// xHCI runtime registers at %p:\n", xhci->run_regs);
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->db_off);
|
||||
xhci_dbg(xhci, "// @%p = 0x%x DBOFF\n", &xhci->cap_regs->db_off, temp);
|
||||
xhci_dbg(xhci, "// Doorbell array at %p:\n", xhci->dba);
|
||||
}
|
||||
|
||||
static void xhci_print_cap_regs(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs);
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
|
||||
xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n",
|
||||
(unsigned int) temp);
|
||||
xhci_dbg(xhci, "CAPLENGTH: 0x%x\n",
|
||||
(unsigned int) HC_LENGTH(temp));
|
||||
xhci_dbg(xhci, "HCIVERSION: 0x%x\n",
|
||||
(unsigned int) HC_VERSION(temp));
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params1);
|
||||
xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n",
|
||||
(unsigned int) temp);
|
||||
xhci_dbg(xhci, " Max device slots: %u\n",
|
||||
(unsigned int) HCS_MAX_SLOTS(temp));
|
||||
xhci_dbg(xhci, " Max interrupters: %u\n",
|
||||
(unsigned int) HCS_MAX_INTRS(temp));
|
||||
xhci_dbg(xhci, " Max ports: %u\n",
|
||||
(unsigned int) HCS_MAX_PORTS(temp));
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params2);
|
||||
xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n",
|
||||
(unsigned int) temp);
|
||||
xhci_dbg(xhci, " Isoc scheduling threshold: %u\n",
|
||||
(unsigned int) HCS_IST(temp));
|
||||
xhci_dbg(xhci, " Maximum allowed segments in event ring: %u\n",
|
||||
(unsigned int) HCS_ERST_MAX(temp));
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
|
||||
xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n",
|
||||
(unsigned int) temp);
|
||||
xhci_dbg(xhci, " Worst case U1 device exit latency: %u\n",
|
||||
(unsigned int) HCS_U1_LATENCY(temp));
|
||||
xhci_dbg(xhci, " Worst case U2 device exit latency: %u\n",
|
||||
(unsigned int) HCS_U2_LATENCY(temp));
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
|
||||
xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp);
|
||||
xhci_dbg(xhci, " HC generates %s bit addresses\n",
|
||||
HCC_64BIT_ADDR(temp) ? "64" : "32");
|
||||
/* FIXME */
|
||||
xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n");
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off);
|
||||
xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK);
|
||||
}
|
||||
|
||||
static void xhci_print_command_reg(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
xhci_dbg(xhci, "USBCMD 0x%x:\n", temp);
|
||||
xhci_dbg(xhci, " HC is %s\n",
|
||||
(temp & CMD_RUN) ? "running" : "being stopped");
|
||||
xhci_dbg(xhci, " HC has %sfinished hard reset\n",
|
||||
(temp & CMD_RESET) ? "not " : "");
|
||||
xhci_dbg(xhci, " Event Interrupts %s\n",
|
||||
(temp & CMD_EIE) ? "enabled " : "disabled");
|
||||
xhci_dbg(xhci, " Host System Error Interrupts %s\n",
|
||||
(temp & CMD_EIE) ? "enabled " : "disabled");
|
||||
xhci_dbg(xhci, " HC has %sfinished light reset\n",
|
||||
(temp & CMD_LRESET) ? "not " : "");
|
||||
}
|
||||
|
||||
static void xhci_print_status(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->status);
|
||||
xhci_dbg(xhci, "USBSTS 0x%x:\n", temp);
|
||||
xhci_dbg(xhci, " Event ring is %sempty\n",
|
||||
(temp & STS_EINT) ? "not " : "");
|
||||
xhci_dbg(xhci, " %sHost System Error\n",
|
||||
(temp & STS_FATAL) ? "WARNING: " : "No ");
|
||||
xhci_dbg(xhci, " HC is %s\n",
|
||||
(temp & STS_HALT) ? "halted" : "running");
|
||||
}
|
||||
|
||||
static void xhci_print_op_regs(struct xhci_hcd *xhci)
|
||||
{
|
||||
xhci_dbg(xhci, "xHCI operational registers at %p:\n", xhci->op_regs);
|
||||
xhci_print_command_reg(xhci);
|
||||
xhci_print_status(xhci);
|
||||
}
|
||||
|
||||
static void xhci_print_ports(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 __iomem *addr;
|
||||
int i, j;
|
||||
int ports;
|
||||
char *names[NUM_PORT_REGS] = {
|
||||
"status",
|
||||
"power",
|
||||
"link",
|
||||
"reserved",
|
||||
};
|
||||
|
||||
ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
addr = &xhci->op_regs->port_status_base;
|
||||
for (i = 0; i < ports; i++) {
|
||||
for (j = 0; j < NUM_PORT_REGS; ++j) {
|
||||
xhci_dbg(xhci, "%p port %s reg = 0x%x\n",
|
||||
addr, names[j],
|
||||
(unsigned int) xhci_readl(xhci, addr));
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num)
|
||||
{
|
||||
void *addr;
|
||||
u32 temp;
|
||||
|
||||
addr = &ir_set->irq_pending;
|
||||
temp = xhci_readl(xhci, addr);
|
||||
if (temp == XHCI_INIT_VALUE)
|
||||
return;
|
||||
|
||||
xhci_dbg(xhci, " %p: ir_set[%i]\n", ir_set, set_num);
|
||||
|
||||
xhci_dbg(xhci, " %p: ir_set.pending = 0x%x\n", addr,
|
||||
(unsigned int)temp);
|
||||
|
||||
addr = &ir_set->irq_control;
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, " %p: ir_set.control = 0x%x\n", addr,
|
||||
(unsigned int)temp);
|
||||
|
||||
addr = &ir_set->erst_size;
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, " %p: ir_set.erst_size = 0x%x\n", addr,
|
||||
(unsigned int)temp);
|
||||
|
||||
addr = &ir_set->rsvd;
|
||||
temp = xhci_readl(xhci, addr);
|
||||
if (temp != XHCI_INIT_VALUE)
|
||||
xhci_dbg(xhci, " WARN: %p: ir_set.rsvd = 0x%x\n",
|
||||
addr, (unsigned int)temp);
|
||||
|
||||
addr = &ir_set->erst_base[0];
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, " %p: ir_set.erst_base[0] = 0x%x\n",
|
||||
addr, (unsigned int) temp);
|
||||
|
||||
addr = &ir_set->erst_base[1];
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, " %p: ir_set.erst_base[1] = 0x%x\n",
|
||||
addr, (unsigned int) temp);
|
||||
|
||||
addr = &ir_set->erst_dequeue[0];
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, " %p: ir_set.erst_dequeue[0] = 0x%x\n",
|
||||
addr, (unsigned int) temp);
|
||||
|
||||
addr = &ir_set->erst_dequeue[1];
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, " %p: ir_set.erst_dequeue[1] = 0x%x\n",
|
||||
addr, (unsigned int) temp);
|
||||
}
|
||||
|
||||
void xhci_print_run_regs(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 temp;
|
||||
int i;
|
||||
|
||||
xhci_dbg(xhci, "xHCI runtime registers at %p:\n", xhci->run_regs);
|
||||
temp = xhci_readl(xhci, &xhci->run_regs->microframe_index);
|
||||
xhci_dbg(xhci, " %p: Microframe index = 0x%x\n",
|
||||
&xhci->run_regs->microframe_index,
|
||||
(unsigned int) temp);
|
||||
for (i = 0; i < 7; ++i) {
|
||||
temp = xhci_readl(xhci, &xhci->run_regs->rsvd[i]);
|
||||
if (temp != XHCI_INIT_VALUE)
|
||||
xhci_dbg(xhci, " WARN: %p: Rsvd[%i] = 0x%x\n",
|
||||
&xhci->run_regs->rsvd[i],
|
||||
i, (unsigned int) temp);
|
||||
}
|
||||
}
|
||||
|
||||
void xhci_print_registers(struct xhci_hcd *xhci)
|
||||
{
|
||||
xhci_print_cap_regs(xhci);
|
||||
xhci_print_op_regs(xhci);
|
||||
xhci_print_ports(xhci);
|
||||
}
|
||||
|
||||
void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
xhci_dbg(xhci, "Offset 0x%x = 0x%x\n",
|
||||
i*4, trb->generic.field[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug a transfer request block (TRB).
|
||||
*/
|
||||
void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
|
||||
{
|
||||
u64 address;
|
||||
u32 type = xhci_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK;
|
||||
|
||||
switch (type) {
|
||||
case TRB_TYPE(TRB_LINK):
|
||||
xhci_dbg(xhci, "Link TRB:\n");
|
||||
xhci_print_trb_offsets(xhci, trb);
|
||||
|
||||
address = trb->link.segment_ptr[0] +
|
||||
(((u64) trb->link.segment_ptr[1]) << 32);
|
||||
xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);
|
||||
|
||||
xhci_dbg(xhci, "Interrupter target = 0x%x\n",
|
||||
GET_INTR_TARGET(trb->link.intr_target));
|
||||
xhci_dbg(xhci, "Cycle bit = %u\n",
|
||||
(unsigned int) (trb->link.control & TRB_CYCLE));
|
||||
xhci_dbg(xhci, "Toggle cycle bit = %u\n",
|
||||
(unsigned int) (trb->link.control & LINK_TOGGLE));
|
||||
xhci_dbg(xhci, "No Snoop bit = %u\n",
|
||||
(unsigned int) (trb->link.control & TRB_NO_SNOOP));
|
||||
break;
|
||||
case TRB_TYPE(TRB_TRANSFER):
|
||||
address = trb->trans_event.buffer[0] +
|
||||
(((u64) trb->trans_event.buffer[1]) << 32);
|
||||
/*
|
||||
* FIXME: look at flags to figure out if it's an address or if
|
||||
* the data is directly in the buffer field.
|
||||
*/
|
||||
xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);
|
||||
break;
|
||||
case TRB_TYPE(TRB_COMPLETION):
|
||||
address = trb->event_cmd.cmd_trb[0] +
|
||||
(((u64) trb->event_cmd.cmd_trb[1]) << 32);
|
||||
xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
|
||||
xhci_dbg(xhci, "Completion status = %u\n",
|
||||
(unsigned int) GET_COMP_CODE(trb->event_cmd.status));
|
||||
xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) trb->event_cmd.flags);
|
||||
break;
|
||||
default:
|
||||
xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
|
||||
(unsigned int) type>>10);
|
||||
xhci_print_trb_offsets(xhci, trb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug a segment with an xHCI ring.
|
||||
*
|
||||
* @return The Link TRB of the segment, or NULL if there is no Link TRB
|
||||
* (which is a bug, since all segments must have a Link TRB).
|
||||
*
|
||||
* Prints out all TRBs in the segment, even those after the Link TRB.
|
||||
*
|
||||
* XXX: should we print out TRBs that the HC owns? As long as we don't
|
||||
* write, that should be fine... We shouldn't expect that the memory pointed to
|
||||
* by the TRB is valid at all. Do we care about ones the HC owns? Probably,
|
||||
* for HC debugging.
|
||||
*/
|
||||
void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
|
||||
{
|
||||
int i;
|
||||
u32 addr = (u32) seg->dma;
|
||||
union xhci_trb *trb = seg->trbs;
|
||||
|
||||
for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
|
||||
trb = &seg->trbs[i];
|
||||
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr,
|
||||
(unsigned int) trb->link.segment_ptr[0],
|
||||
(unsigned int) trb->link.segment_ptr[1],
|
||||
(unsigned int) trb->link.intr_target,
|
||||
(unsigned int) trb->link.control);
|
||||
addr += sizeof(*trb);
|
||||
}
|
||||
}
|
||||
|
||||
void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
||||
{
|
||||
xhci_dbg(xhci, "Ring deq = %p (virt), 0x%llx (dma)\n",
|
||||
ring->dequeue,
|
||||
(unsigned long long)xhci_trb_virt_to_dma(ring->deq_seg,
|
||||
ring->dequeue));
|
||||
xhci_dbg(xhci, "Ring deq updated %u times\n",
|
||||
ring->deq_updates);
|
||||
xhci_dbg(xhci, "Ring enq = %p (virt), 0x%llx (dma)\n",
|
||||
ring->enqueue,
|
||||
(unsigned long long)xhci_trb_virt_to_dma(ring->enq_seg,
|
||||
ring->enqueue));
|
||||
xhci_dbg(xhci, "Ring enq updated %u times\n",
|
||||
ring->enq_updates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging for an xHCI ring, which is a queue broken into multiple segments.
|
||||
*
|
||||
* Print out each segment in the ring. Check that the DMA address in
|
||||
* each link segment actually matches the segment's stored DMA address.
|
||||
* Check that the link end bit is only set at the end of the ring.
|
||||
* Check that the dequeue and enqueue pointers point to real data in this ring
|
||||
* (not some other ring).
|
||||
*/
|
||||
void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
||||
{
|
||||
/* FIXME: Throw an error if any segment doesn't have a Link TRB */
|
||||
struct xhci_segment *seg;
|
||||
struct xhci_segment *first_seg = ring->first_seg;
|
||||
xhci_debug_segment(xhci, first_seg);
|
||||
|
||||
if (!ring->enq_updates && !ring->deq_updates) {
|
||||
xhci_dbg(xhci, " Ring has not been updated\n");
|
||||
return;
|
||||
}
|
||||
for (seg = first_seg->next; seg != first_seg; seg = seg->next)
|
||||
xhci_debug_segment(xhci, seg);
|
||||
}
|
||||
|
||||
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
|
||||
{
|
||||
u32 addr = (u32) erst->erst_dma_addr;
|
||||
int i;
|
||||
struct xhci_erst_entry *entry;
|
||||
|
||||
for (i = 0; i < erst->num_entries; ++i) {
|
||||
entry = &erst->entries[i];
|
||||
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",
|
||||
(unsigned int) addr,
|
||||
(unsigned int) entry->seg_addr[0],
|
||||
(unsigned int) entry->seg_addr[1],
|
||||
(unsigned int) entry->seg_size,
|
||||
(unsigned int) entry->rsvd);
|
||||
addr += sizeof(*entry);
|
||||
}
|
||||
}
|
||||
|
||||
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
|
||||
xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val);
|
||||
val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]);
|
||||
xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val);
|
||||
}
|
||||
|
||||
void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep)
|
||||
{
|
||||
int i, j;
|
||||
int last_ep_ctx = 31;
|
||||
/* Fields are 32 bits wide, DMA addresses are in bytes */
|
||||
int field_size = 32 / 8;
|
||||
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
|
||||
&ctx->drop_flags, (unsigned long long)dma,
|
||||
ctx->drop_flags);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
|
||||
&ctx->add_flags, (unsigned long long)dma,
|
||||
ctx->add_flags);
|
||||
dma += field_size;
|
||||
for (i = 0; i > 6; ++i) {
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
|
||||
&ctx->rsvd[i], (unsigned long long)dma,
|
||||
ctx->rsvd[i], i);
|
||||
dma += field_size;
|
||||
}
|
||||
|
||||
xhci_dbg(xhci, "Slot Context:\n");
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n",
|
||||
&ctx->slot.dev_info,
|
||||
(unsigned long long)dma, ctx->slot.dev_info);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n",
|
||||
&ctx->slot.dev_info2,
|
||||
(unsigned long long)dma, ctx->slot.dev_info2);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n",
|
||||
&ctx->slot.tt_info,
|
||||
(unsigned long long)dma, ctx->slot.tt_info);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n",
|
||||
&ctx->slot.dev_state,
|
||||
(unsigned long long)dma, ctx->slot.dev_state);
|
||||
dma += field_size;
|
||||
for (i = 0; i > 4; ++i) {
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
|
||||
&ctx->slot.reserved[i], (unsigned long long)dma,
|
||||
ctx->slot.reserved[i], i);
|
||||
dma += field_size;
|
||||
}
|
||||
|
||||
if (last_ep < 31)
|
||||
last_ep_ctx = last_ep + 1;
|
||||
for (i = 0; i < last_ep_ctx; ++i) {
|
||||
xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",
|
||||
&ctx->ep[i].ep_info,
|
||||
(unsigned long long)dma, ctx->ep[i].ep_info);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n",
|
||||
&ctx->ep[i].ep_info2,
|
||||
(unsigned long long)dma, ctx->ep[i].ep_info2);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[0]\n",
|
||||
&ctx->ep[i].deq[0],
|
||||
(unsigned long long)dma, ctx->ep[i].deq[0]);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[1]\n",
|
||||
&ctx->ep[i].deq[1],
|
||||
(unsigned long long)dma, ctx->ep[i].deq[1]);
|
||||
dma += field_size;
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n",
|
||||
&ctx->ep[i].tx_info,
|
||||
(unsigned long long)dma, ctx->ep[i].tx_info);
|
||||
dma += field_size;
|
||||
for (j = 0; j < 3; ++j) {
|
||||
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
|
||||
&ctx->ep[i].reserved[j],
|
||||
(unsigned long long)dma,
|
||||
ctx->ep[i].reserved[j], j);
|
||||
dma += field_size;
|
||||
}
|
||||
}
|
||||
}
|
145
drivers/usb/host/xhci-ext-caps.h
Normal file
145
drivers/usb/host/xhci-ext-caps.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* xHCI host controller driver
|
||||
*
|
||||
* Copyright (C) 2008 Intel Corp.
|
||||
*
|
||||
* Author: Sarah Sharp
|
||||
* Some code borrowed from the Linux EHCI driver.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/* Up to 16 microframes to halt an HC - one microframe is 125 microsectonds */
|
||||
#define XHCI_MAX_HALT_USEC (16*125)
|
||||
/* HC not running - set to 1 when run/stop bit is cleared. */
|
||||
#define XHCI_STS_HALT (1<<0)
|
||||
|
||||
/* HCCPARAMS offset from PCI base address */
|
||||
#define XHCI_HCC_PARAMS_OFFSET 0x10
|
||||
/* HCCPARAMS contains the first extended capability pointer */
|
||||
#define XHCI_HCC_EXT_CAPS(p) (((p)>>16)&0xffff)
|
||||
|
||||
/* Command and Status registers offset from the Operational Registers address */
|
||||
#define XHCI_CMD_OFFSET 0x00
|
||||
#define XHCI_STS_OFFSET 0x04
|
||||
|
||||
#define XHCI_MAX_EXT_CAPS 50
|
||||
|
||||
/* Capability Register */
|
||||
/* bits 7:0 - how long is the Capabilities register */
|
||||
#define XHCI_HC_LENGTH(p) (((p)>>00)&0x00ff)
|
||||
|
||||
/* Extended capability register fields */
|
||||
#define XHCI_EXT_CAPS_ID(p) (((p)>>0)&0xff)
|
||||
#define XHCI_EXT_CAPS_NEXT(p) (((p)>>8)&0xff)
|
||||
#define XHCI_EXT_CAPS_VAL(p) ((p)>>16)
|
||||
/* Extended capability IDs - ID 0 reserved */
|
||||
#define XHCI_EXT_CAPS_LEGACY 1
|
||||
#define XHCI_EXT_CAPS_PROTOCOL 2
|
||||
#define XHCI_EXT_CAPS_PM 3
|
||||
#define XHCI_EXT_CAPS_VIRT 4
|
||||
#define XHCI_EXT_CAPS_ROUTE 5
|
||||
/* IDs 6-9 reserved */
|
||||
#define XHCI_EXT_CAPS_DEBUG 10
|
||||
/* USB Legacy Support Capability - section 7.1.1 */
|
||||
#define XHCI_HC_BIOS_OWNED (1 << 16)
|
||||
#define XHCI_HC_OS_OWNED (1 << 24)
|
||||
|
||||
/* USB Legacy Support Capability - section 7.1.1 */
|
||||
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
|
||||
#define XHCI_LEGACY_SUPPORT_OFFSET (0x00)
|
||||
|
||||
/* USB Legacy Support Control and Status Register - section 7.1.2 */
|
||||
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
|
||||
#define XHCI_LEGACY_CONTROL_OFFSET (0x04)
|
||||
/* 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))
|
||||
|
||||
/* 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)
|
||||
/* Event Interrupt Enable - get irq when EINT bit is set in USBSTS register */
|
||||
#define XHCI_CMD_EIE (1 << 2)
|
||||
/* Host System Error Interrupt Enable - get irq when HSEIE bit set in USBSTS */
|
||||
#define XHCI_CMD_HSEIE (1 << 3)
|
||||
/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */
|
||||
#define XHCI_CMD_EWE (1 << 10)
|
||||
|
||||
#define XHCI_IRQS (XHCI_CMD_EIE | XHCI_CMD_HSEIE | XHCI_CMD_EWE)
|
||||
|
||||
/* true: Controller Not Ready to accept doorbell or op reg writes after reset */
|
||||
#define XHCI_STS_CNR (1 << 11)
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
/**
|
||||
* Return the next extended capability pointer register.
|
||||
*
|
||||
* @base PCI register base address.
|
||||
*
|
||||
* @ext_offset Offset of the 32-bit register that contains the extended
|
||||
* capabilites pointer. If searching for the first extended capability, pass
|
||||
* in XHCI_HCC_PARAMS_OFFSET. If searching for the next extended capability,
|
||||
* pass in the offset of the current extended capability register.
|
||||
*
|
||||
* Returns 0 if there is no next extended capability register or returns the register offset
|
||||
* from the PCI registers base address.
|
||||
*/
|
||||
static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
|
||||
{
|
||||
u32 next;
|
||||
|
||||
next = readl(base + ext_offset);
|
||||
|
||||
if (ext_offset == XHCI_HCC_PARAMS_OFFSET)
|
||||
/* Find the first extended capability */
|
||||
next = XHCI_HCC_EXT_CAPS(next);
|
||||
else
|
||||
/* Find the next extended capability */
|
||||
next = XHCI_EXT_CAPS_NEXT(next);
|
||||
if (!next)
|
||||
return 0;
|
||||
/*
|
||||
* Address calculation from offset of extended capabilities
|
||||
* (or HCCPARAMS) register - see section 5.3.6 and section 7.
|
||||
*/
|
||||
return ext_offset + (next << 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the offset of the extended capabilities with capability ID id.
|
||||
*
|
||||
* @base PCI MMIO registers base address.
|
||||
* @ext_offset Offset from base of the first extended capability to look at,
|
||||
* or the address of HCCPARAMS.
|
||||
* @id Extended capability ID to search for.
|
||||
*
|
||||
* This uses an arbitrary limit of XHCI_MAX_EXT_CAPS extended capabilities
|
||||
* to make sure that the list doesn't contain a loop.
|
||||
*/
|
||||
static inline int xhci_find_ext_cap_by_id(void __iomem *base, int ext_offset, int id)
|
||||
{
|
||||
u32 val;
|
||||
int limit = XHCI_MAX_EXT_CAPS;
|
||||
|
||||
while (ext_offset && limit > 0) {
|
||||
val = readl(base + ext_offset);
|
||||
if (XHCI_EXT_CAPS_ID(val) == id)
|
||||
break;
|
||||
ext_offset = xhci_find_next_cap_offset(base, ext_offset);
|
||||
limit--;
|
||||
}
|
||||
if (limit > 0)
|
||||
return ext_offset;
|
||||
return 0;
|
||||
}
|
1274
drivers/usb/host/xhci-hcd.c
Normal file
1274
drivers/usb/host/xhci-hcd.c
Normal file
File diff suppressed because it is too large
Load Diff
308
drivers/usb/host/xhci-hub.c
Normal file
308
drivers/usb/host/xhci-hub.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* xHCI host controller driver
|
||||
*
|
||||
* Copyright (C) 2008 Intel Corp.
|
||||
*
|
||||
* Author: Sarah Sharp
|
||||
* Some code borrowed from the Linux EHCI driver.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "xhci.h"
|
||||
|
||||
static void xhci_hub_descriptor(struct xhci_hcd *xhci,
|
||||
struct usb_hub_descriptor *desc)
|
||||
{
|
||||
int ports;
|
||||
u16 temp;
|
||||
|
||||
ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
|
||||
/* USB 3.0 hubs have a different descriptor, but we fake this for now */
|
||||
desc->bDescriptorType = 0x29;
|
||||
desc->bPwrOn2PwrGood = 10; /* xhci section 5.4.9 says 20ms max */
|
||||
desc->bHubContrCurrent = 0;
|
||||
|
||||
desc->bNbrPorts = ports;
|
||||
temp = 1 + (ports / 8);
|
||||
desc->bDescLength = 7 + 2 * temp;
|
||||
|
||||
/* Why does core/hcd.h define bitmap? It's just confusing. */
|
||||
memset(&desc->DeviceRemovable[0], 0, temp);
|
||||
memset(&desc->DeviceRemovable[temp], 0xff, temp);
|
||||
|
||||
/* Ugh, these should be #defines, FIXME */
|
||||
/* Using table 11-13 in USB 2.0 spec. */
|
||||
temp = 0;
|
||||
/* Bits 1:0 - support port power switching, or power always on */
|
||||
if (HCC_PPC(xhci->hcc_params))
|
||||
temp |= 0x0001;
|
||||
else
|
||||
temp |= 0x0002;
|
||||
/* Bit 2 - root hubs are not part of a compound device */
|
||||
/* Bits 4:3 - individual port over current protection */
|
||||
temp |= 0x0008;
|
||||
/* Bits 6:5 - no TTs in root ports */
|
||||
/* Bit 7 - no port indicators */
|
||||
desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp);
|
||||
}
|
||||
|
||||
static unsigned int xhci_port_speed(unsigned int port_status)
|
||||
{
|
||||
if (DEV_LOWSPEED(port_status))
|
||||
return 1 << USB_PORT_FEAT_LOWSPEED;
|
||||
if (DEV_HIGHSPEED(port_status))
|
||||
return 1 << USB_PORT_FEAT_HIGHSPEED;
|
||||
if (DEV_SUPERSPEED(port_status))
|
||||
return 1 << USB_PORT_FEAT_SUPERSPEED;
|
||||
/*
|
||||
* FIXME: Yes, we should check for full speed, but the core uses that as
|
||||
* a default in portspeed() in usb/core/hub.c (which is the only place
|
||||
* USB_PORT_FEAT_*SPEED is used).
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* These bits are Read Only (RO) and should be saved and written to the
|
||||
* registers: 0, 3, 10:13, 30
|
||||
* connect status, over-current status, port speed, and device removable.
|
||||
* connect status and port speed are also sticky - meaning they're in
|
||||
* the AUX well and they aren't changed by a hot, warm, or cold reset.
|
||||
*/
|
||||
#define XHCI_PORT_RO ((1<<0) | (1<<3) | (0xf<<10) | (1<<30))
|
||||
/*
|
||||
* These bits are RW; writing a 0 clears the bit, writing a 1 sets the bit:
|
||||
* bits 5:8, 9, 14:15, 25:27
|
||||
* link state, port power, port indicator state, "wake on" enable state
|
||||
*/
|
||||
#define XHCI_PORT_RWS ((0xf<<5) | (1<<9) | (0x3<<14) | (0x7<<25))
|
||||
/*
|
||||
* These bits are RW; writing a 1 sets the bit, writing a 0 has no effect:
|
||||
* bit 4 (port reset)
|
||||
*/
|
||||
#define XHCI_PORT_RW1S ((1<<4))
|
||||
/*
|
||||
* These bits are RW; writing a 1 clears the bit, writing a 0 has no effect:
|
||||
* bits 1, 17, 18, 19, 20, 21, 22, 23
|
||||
* port enable/disable, and
|
||||
* change bits: connect, PED, warm port reset changed (reserved zero for USB 2.0 ports),
|
||||
* over-current, reset, link state, and L1 change
|
||||
*/
|
||||
#define XHCI_PORT_RW1CS ((1<<1) | (0x7f<<17))
|
||||
/*
|
||||
* Bit 16 is RW, and writing a '1' to it causes the link state control to be
|
||||
* latched in
|
||||
*/
|
||||
#define XHCI_PORT_RW ((1<<16))
|
||||
/*
|
||||
* These bits are Reserved Zero (RsvdZ) and zero should be written to them:
|
||||
* bits 2, 24, 28:31
|
||||
*/
|
||||
#define XHCI_PORT_RZ ((1<<2) | (1<<24) | (0xf<<28))
|
||||
|
||||
/*
|
||||
* Given a port state, this function returns a value that would result in the
|
||||
* port being in the same state, if the value was written to the port status
|
||||
* control register.
|
||||
* Save Read Only (RO) bits and save read/write bits where
|
||||
* writing a 0 clears the bit and writing a 1 sets the bit (RWS).
|
||||
* For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
|
||||
*/
|
||||
static u32 xhci_port_state_to_neutral(u32 state)
|
||||
{
|
||||
/* Save read-only status and port state */
|
||||
return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
|
||||
}
|
||||
|
||||
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 ports;
|
||||
unsigned long flags;
|
||||
u32 temp, status;
|
||||
int retval = 0;
|
||||
u32 __iomem *addr;
|
||||
char *port_change_bit;
|
||||
|
||||
ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
switch (typeReq) {
|
||||
case GetHubStatus:
|
||||
/* No power source, over-current reported per port */
|
||||
memset(buf, 0, 4);
|
||||
break;
|
||||
case GetHubDescriptor:
|
||||
xhci_hub_descriptor(xhci, (struct usb_hub_descriptor *) buf);
|
||||
break;
|
||||
case GetPortStatus:
|
||||
if (!wIndex || wIndex > ports)
|
||||
goto error;
|
||||
wIndex--;
|
||||
status = 0;
|
||||
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
|
||||
/* wPortChange bits */
|
||||
if (temp & PORT_CSC)
|
||||
status |= 1 << USB_PORT_FEAT_C_CONNECTION;
|
||||
if (temp & PORT_PEC)
|
||||
status |= 1 << USB_PORT_FEAT_C_ENABLE;
|
||||
if ((temp & PORT_OCC))
|
||||
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
|
||||
/*
|
||||
* FIXME ignoring suspend, reset, and USB 2.1/3.0 specific
|
||||
* changes
|
||||
*/
|
||||
if (temp & PORT_CONNECT) {
|
||||
status |= 1 << USB_PORT_FEAT_CONNECTION;
|
||||
status |= xhci_port_speed(temp);
|
||||
}
|
||||
if (temp & PORT_PE)
|
||||
status |= 1 << USB_PORT_FEAT_ENABLE;
|
||||
if (temp & PORT_OC)
|
||||
status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
|
||||
if (temp & PORT_RESET)
|
||||
status |= 1 << USB_PORT_FEAT_RESET;
|
||||
if (temp & PORT_POWER)
|
||||
status |= 1 << USB_PORT_FEAT_POWER;
|
||||
xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
|
||||
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
|
||||
break;
|
||||
case SetPortFeature:
|
||||
wIndex &= 0xff;
|
||||
if (!wIndex || wIndex > ports)
|
||||
goto error;
|
||||
wIndex--;
|
||||
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_POWER:
|
||||
/*
|
||||
* Turn on ports, even if there isn't per-port switching.
|
||||
* HC will report connect events even before this is set.
|
||||
* However, khubd will ignore the roothub events until
|
||||
* the roothub is registered.
|
||||
*/
|
||||
xhci_writel(xhci, temp | PORT_POWER, addr);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
break;
|
||||
case USB_PORT_FEAT_RESET:
|
||||
temp = (temp | PORT_RESET);
|
||||
xhci_writel(xhci, temp, addr);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
temp = xhci_readl(xhci, addr); /* unblock any posted writes */
|
||||
break;
|
||||
case ClearPortFeature:
|
||||
if (!wIndex || wIndex > ports)
|
||||
goto error;
|
||||
wIndex--;
|
||||
addr = &xhci->op_regs->port_status_base +
|
||||
NUM_PORT_REGS*(wIndex & 0xff);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_C_RESET:
|
||||
status = PORT_RC;
|
||||
port_change_bit = "reset";
|
||||
break;
|
||||
case USB_PORT_FEAT_C_CONNECTION:
|
||||
status = PORT_CSC;
|
||||
port_change_bit = "connect";
|
||||
break;
|
||||
case USB_PORT_FEAT_C_OVER_CURRENT:
|
||||
status = PORT_OCC;
|
||||
port_change_bit = "over-current";
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
/* Change bits are all write 1 to clear */
|
||||
xhci_writel(xhci, temp | status, addr);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
|
||||
port_change_bit, wIndex, temp);
|
||||
temp = xhci_readl(xhci, addr); /* unblock any posted writes */
|
||||
break;
|
||||
default:
|
||||
error:
|
||||
/* "stall" on error */
|
||||
retval = -EPIPE;
|
||||
}
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 0 if the status hasn't changed, or the number of bytes in buf.
|
||||
* Ports are 0-indexed from the HCD point of view,
|
||||
* and 1-indexed from the USB core pointer of view.
|
||||
* xHCI instances can have up to 127 ports, so FIXME if you see more than 15.
|
||||
*
|
||||
* Note that the status change bits will be cleared as soon as a port status
|
||||
* change event is generated, so we use the saved status from that event.
|
||||
*/
|
||||
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 temp, status;
|
||||
int i, retval;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int ports;
|
||||
u32 __iomem *addr;
|
||||
|
||||
ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
|
||||
/* Initial status is no changes */
|
||||
buf[0] = 0;
|
||||
status = 0;
|
||||
if (ports > 7) {
|
||||
buf[1] = 0;
|
||||
retval = 2;
|
||||
} else {
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
/* For each port, did anything change? If so, set that bit in buf. */
|
||||
for (i = 0; i < ports; i++) {
|
||||
addr = &xhci->op_regs->port_status_base +
|
||||
NUM_PORT_REGS*i;
|
||||
temp = xhci_readl(xhci, addr);
|
||||
if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) {
|
||||
if (i < 7)
|
||||
buf[0] |= 1 << (i + 1);
|
||||
else
|
||||
buf[1] |= 1 << (i - 7);
|
||||
status = 1;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return status ? retval : 0;
|
||||
}
|
769
drivers/usb/host/xhci-mem.c
Normal file
769
drivers/usb/host/xhci-mem.c
Normal file
@@ -0,0 +1,769 @@
|
||||
/*
|
||||
* xHCI host controller driver
|
||||
*
|
||||
* Copyright (C) 2008 Intel Corp.
|
||||
*
|
||||
* Author: Sarah Sharp
|
||||
* Some code borrowed from the Linux EHCI driver.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dmapool.h>
|
||||
|
||||
#include "xhci.h"
|
||||
|
||||
/*
|
||||
* Allocates a generic ring segment from the ring pool, sets the dma address,
|
||||
* initializes the segment to zero, and sets the private next pointer to NULL.
|
||||
*
|
||||
* Section 4.11.1.1:
|
||||
* "All components of all Command and Transfer TRBs shall be initialized to '0'"
|
||||
*/
|
||||
static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flags)
|
||||
{
|
||||
struct xhci_segment *seg;
|
||||
dma_addr_t dma;
|
||||
|
||||
seg = kzalloc(sizeof *seg, flags);
|
||||
if (!seg)
|
||||
return 0;
|
||||
xhci_dbg(xhci, "Allocating priv segment structure at %p\n", seg);
|
||||
|
||||
seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma);
|
||||
if (!seg->trbs) {
|
||||
kfree(seg);
|
||||
return 0;
|
||||
}
|
||||
xhci_dbg(xhci, "// Allocating segment at %p (virtual) 0x%llx (DMA)\n",
|
||||
seg->trbs, (unsigned long long)dma);
|
||||
|
||||
memset(seg->trbs, 0, SEGMENT_SIZE);
|
||||
seg->dma = dma;
|
||||
seg->next = NULL;
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
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);
|
||||
dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
|
||||
seg->trbs = NULL;
|
||||
}
|
||||
xhci_dbg(xhci, "Freeing priv segment structure at %p\n", seg);
|
||||
kfree(seg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the prev segment point to the next segment.
|
||||
*
|
||||
* Change the last TRB in the prev segment to be a Link TRB which points to the
|
||||
* DMA address of the next segment. The caller needs to set any Link TRB
|
||||
* 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)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!prev || !next)
|
||||
return;
|
||||
prev->next = next;
|
||||
if (link_trbs) {
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr[0] = next->dma;
|
||||
|
||||
/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
|
||||
val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
|
||||
val &= ~TRB_TYPE_BITMASK;
|
||||
val |= TRB_TYPE(TRB_LINK);
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.control = val;
|
||||
}
|
||||
xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
|
||||
(unsigned long long)prev->dma,
|
||||
(unsigned long long)next->dma);
|
||||
}
|
||||
|
||||
/* XXX: Do we need the hcd structure in all these functions? */
|
||||
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)
|
||||
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;
|
||||
}
|
||||
xhci_segment_free(xhci, first_seg);
|
||||
ring->first_seg = NULL;
|
||||
kfree(ring);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ring with zero or more segments.
|
||||
*
|
||||
* Link each segment together into a ring.
|
||||
* Set the end flag and the cycle toggle bit on the last segment.
|
||||
* 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)
|
||||
{
|
||||
struct xhci_ring *ring;
|
||||
struct xhci_segment *prev;
|
||||
|
||||
ring = kzalloc(sizeof *(ring), flags);
|
||||
xhci_dbg(xhci, "Allocating ring at %p\n", ring);
|
||||
if (!ring)
|
||||
return 0;
|
||||
|
||||
INIT_LIST_HEAD(&ring->td_list);
|
||||
INIT_LIST_HEAD(&ring->cancelled_td_list);
|
||||
if (num_segs == 0)
|
||||
return ring;
|
||||
|
||||
ring->first_seg = xhci_segment_alloc(xhci, flags);
|
||||
if (!ring->first_seg)
|
||||
goto fail;
|
||||
num_segs--;
|
||||
|
||||
prev = ring->first_seg;
|
||||
while (num_segs > 0) {
|
||||
struct xhci_segment *next;
|
||||
|
||||
next = xhci_segment_alloc(xhci, flags);
|
||||
if (!next)
|
||||
goto fail;
|
||||
xhci_link_segments(xhci, prev, next, link_trbs);
|
||||
|
||||
prev = next;
|
||||
num_segs--;
|
||||
}
|
||||
xhci_link_segments(xhci, prev, ring->first_seg, link_trbs);
|
||||
|
||||
if (link_trbs) {
|
||||
/* See section 4.9.2.1 and 6.4.4.1 */
|
||||
prev->trbs[TRBS_PER_SEGMENT-1].link.control |= (LINK_TOGGLE);
|
||||
xhci_dbg(xhci, "Wrote link toggle flag to"
|
||||
" segment %p (virtual), 0x%llx (DMA)\n",
|
||||
prev, (unsigned long long)prev->dma);
|
||||
}
|
||||
/* The ring is empty, so the enqueue pointer == dequeue pointer */
|
||||
ring->enqueue = ring->first_seg->trbs;
|
||||
ring->enq_seg = ring->first_seg;
|
||||
ring->dequeue = ring->enqueue;
|
||||
ring->deq_seg = ring->first_seg;
|
||||
/* The ring is initialized to 0. The producer must write 1 to the cycle
|
||||
* bit to handover ownership of the TRB, so PCS = 1. The consumer must
|
||||
* compare CCS to the cycle bit to check ownership, so CCS = 1.
|
||||
*/
|
||||
ring->cycle_state = 1;
|
||||
|
||||
return ring;
|
||||
|
||||
fail:
|
||||
xhci_ring_free(xhci, ring);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* All the xhci_tds in the ring's TD list should be freed at this point */
|
||||
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
|
||||
{
|
||||
struct xhci_virt_device *dev;
|
||||
int i;
|
||||
|
||||
/* Slot ID 0 is reserved */
|
||||
if (slot_id == 0 || !xhci->devs[slot_id])
|
||||
return;
|
||||
|
||||
dev = xhci->devs[slot_id];
|
||||
xhci->dcbaa->dev_context_ptrs[2*slot_id] = 0;
|
||||
xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 31; ++i)
|
||||
if (dev->ep_rings[i])
|
||||
xhci_ring_free(xhci, dev->ep_rings[i]);
|
||||
|
||||
if (dev->in_ctx)
|
||||
dma_pool_free(xhci->device_pool,
|
||||
dev->in_ctx, dev->in_ctx_dma);
|
||||
if (dev->out_ctx)
|
||||
dma_pool_free(xhci->device_pool,
|
||||
dev->out_ctx, dev->out_ctx_dma);
|
||||
kfree(xhci->devs[slot_id]);
|
||||
xhci->devs[slot_id] = 0;
|
||||
}
|
||||
|
||||
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
|
||||
struct usb_device *udev, gfp_t flags)
|
||||
{
|
||||
dma_addr_t dma;
|
||||
struct xhci_virt_device *dev;
|
||||
|
||||
/* Slot ID 0 is reserved */
|
||||
if (slot_id == 0 || xhci->devs[slot_id]) {
|
||||
xhci_warn(xhci, "Bad Slot ID %d\n", slot_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xhci->devs[slot_id] = kzalloc(sizeof(*xhci->devs[slot_id]), flags);
|
||||
if (!xhci->devs[slot_id])
|
||||
return 0;
|
||||
dev = xhci->devs[slot_id];
|
||||
|
||||
/* Allocate the (output) device context that will be used in the HC */
|
||||
dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
|
||||
if (!dev->out_ctx)
|
||||
goto fail;
|
||||
dev->out_ctx_dma = dma;
|
||||
xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id,
|
||||
(unsigned long long)dma);
|
||||
memset(dev->out_ctx, 0, sizeof(*dev->out_ctx));
|
||||
|
||||
/* Allocate the (input) device context for address device command */
|
||||
dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
|
||||
if (!dev->in_ctx)
|
||||
goto fail;
|
||||
dev->in_ctx_dma = dma;
|
||||
xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id,
|
||||
(unsigned long long)dma);
|
||||
memset(dev->in_ctx, 0, sizeof(*dev->in_ctx));
|
||||
|
||||
/* Allocate endpoint 0 ring */
|
||||
dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags);
|
||||
if (!dev->ep_rings[0])
|
||||
goto fail;
|
||||
|
||||
init_completion(&dev->cmd_completion);
|
||||
|
||||
/*
|
||||
* Point to output device context in dcbaa; skip the output control
|
||||
* context, which is eight 32 bit fields (or 32 bytes long)
|
||||
*/
|
||||
xhci->dcbaa->dev_context_ptrs[2*slot_id] =
|
||||
(u32) dev->out_ctx_dma + (32);
|
||||
xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
|
||||
slot_id,
|
||||
&xhci->dcbaa->dev_context_ptrs[2*slot_id],
|
||||
(unsigned long long)dev->out_ctx_dma);
|
||||
xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
xhci_free_virt_device(xhci, slot_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Setup an xHCI virtual device for a Set Address command */
|
||||
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev)
|
||||
{
|
||||
struct xhci_virt_device *dev;
|
||||
struct xhci_ep_ctx *ep0_ctx;
|
||||
struct usb_device *top_dev;
|
||||
|
||||
dev = xhci->devs[udev->slot_id];
|
||||
/* Slot ID 0 is reserved */
|
||||
if (udev->slot_id == 0 || !dev) {
|
||||
xhci_warn(xhci, "Slot ID %d is not assigned to this device\n",
|
||||
udev->slot_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
ep0_ctx = &dev->in_ctx->ep[0];
|
||||
|
||||
/* 2) New slot context and endpoint 0 context are valid*/
|
||||
dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
|
||||
|
||||
/* 3) Only the control endpoint is valid - one endpoint context */
|
||||
dev->in_ctx->slot.dev_info |= LAST_CTX(1);
|
||||
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
dev->in_ctx->slot.dev_info |= (u32) udev->route;
|
||||
dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS;
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS;
|
||||
break;
|
||||
case USB_SPEED_FULL:
|
||||
dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS;
|
||||
break;
|
||||
case USB_SPEED_LOW:
|
||||
dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS;
|
||||
break;
|
||||
case USB_SPEED_VARIABLE:
|
||||
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
/* Speed was set earlier, this shouldn't happen. */
|
||||
BUG();
|
||||
}
|
||||
/* Find the root hub port this device is under */
|
||||
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
|
||||
top_dev = top_dev->parent)
|
||||
/* Found device below root hub */;
|
||||
dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
|
||||
xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);
|
||||
|
||||
/* Is this a LS/FS device under a HS hub? */
|
||||
/*
|
||||
* FIXME: I don't think this is right, where does the TT info for the
|
||||
* roothub or parent hub come from?
|
||||
*/
|
||||
if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) &&
|
||||
udev->tt) {
|
||||
dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id;
|
||||
dev->in_ctx->slot.tt_info |= udev->ttport << 8;
|
||||
}
|
||||
xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);
|
||||
xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport);
|
||||
|
||||
/* Step 4 - ring already allocated */
|
||||
/* Step 5 */
|
||||
ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP);
|
||||
/*
|
||||
* See section 4.3 bullet 6:
|
||||
* The default Max Packet size for ep0 is "8 bytes for a USB2
|
||||
* LS/FS/HS device or 512 bytes for a USB3 SS device"
|
||||
* XXX: Not sure about wireless USB devices.
|
||||
*/
|
||||
if (udev->speed == USB_SPEED_SUPER)
|
||||
ep0_ctx->ep_info2 |= MAX_PACKET(512);
|
||||
else
|
||||
ep0_ctx->ep_info2 |= MAX_PACKET(8);
|
||||
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
|
||||
ep0_ctx->ep_info2 |= MAX_BURST(0);
|
||||
ep0_ctx->ep_info2 |= ERROR_COUNT(3);
|
||||
|
||||
ep0_ctx->deq[0] =
|
||||
dev->ep_rings[0]->first_seg->dma;
|
||||
ep0_ctx->deq[0] |= dev->ep_rings[0]->cycle_state;
|
||||
ep0_ctx->deq[1] = 0;
|
||||
|
||||
/* Steps 7 and 8 were done in xhci_alloc_virt_device() */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the polling or NAK interval.
|
||||
*
|
||||
* The polling interval is expressed in "microframes". If xHCI's Interval field
|
||||
* is set to N, it will service the endpoint every 2^(Interval)*125us.
|
||||
*
|
||||
* The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval
|
||||
* is set to 0.
|
||||
*/
|
||||
static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
unsigned int interval = 0;
|
||||
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_HIGH:
|
||||
/* Max NAK rate */
|
||||
if (usb_endpoint_xfer_control(&ep->desc) ||
|
||||
usb_endpoint_xfer_bulk(&ep->desc))
|
||||
interval = ep->desc.bInterval;
|
||||
/* Fall through - SS and HS isoc/int have same decoding */
|
||||
case USB_SPEED_SUPER:
|
||||
if (usb_endpoint_xfer_int(&ep->desc) ||
|
||||
usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||
if (ep->desc.bInterval == 0)
|
||||
interval = 0;
|
||||
else
|
||||
interval = ep->desc.bInterval - 1;
|
||||
if (interval > 15)
|
||||
interval = 15;
|
||||
if (interval != ep->desc.bInterval + 1)
|
||||
dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
|
||||
ep->desc.bEndpointAddress, 1 << interval);
|
||||
}
|
||||
break;
|
||||
/* Convert bInterval (in 1-255 frames) to microframes and round down to
|
||||
* nearest power of 2.
|
||||
*/
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_LOW:
|
||||
if (usb_endpoint_xfer_int(&ep->desc) ||
|
||||
usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||
interval = fls(8*ep->desc.bInterval) - 1;
|
||||
if (interval > 10)
|
||||
interval = 10;
|
||||
if (interval < 3)
|
||||
interval = 3;
|
||||
if ((1 << interval) != 8*ep->desc.bInterval)
|
||||
dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
|
||||
ep->desc.bEndpointAddress, 1 << interval);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
return EP_INTERVAL(interval);
|
||||
}
|
||||
|
||||
static inline u32 xhci_get_endpoint_type(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
int in;
|
||||
u32 type;
|
||||
|
||||
in = usb_endpoint_dir_in(&ep->desc);
|
||||
if (usb_endpoint_xfer_control(&ep->desc)) {
|
||||
type = EP_TYPE(CTRL_EP);
|
||||
} else if (usb_endpoint_xfer_bulk(&ep->desc)) {
|
||||
if (in)
|
||||
type = EP_TYPE(BULK_IN_EP);
|
||||
else
|
||||
type = EP_TYPE(BULK_OUT_EP);
|
||||
} else if (usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||
if (in)
|
||||
type = EP_TYPE(ISOC_IN_EP);
|
||||
else
|
||||
type = EP_TYPE(ISOC_OUT_EP);
|
||||
} else if (usb_endpoint_xfer_int(&ep->desc)) {
|
||||
if (in)
|
||||
type = EP_TYPE(INT_IN_EP);
|
||||
else
|
||||
type = EP_TYPE(INT_OUT_EP);
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
int xhci_endpoint_init(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep,
|
||||
gfp_t mem_flags)
|
||||
{
|
||||
unsigned int ep_index;
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
struct xhci_ring *ep_ring;
|
||||
unsigned int max_packet;
|
||||
unsigned int max_burst;
|
||||
|
||||
ep_index = xhci_get_endpoint_index(&ep->desc);
|
||||
ep_ctx = &virt_dev->in_ctx->ep[ep_index];
|
||||
|
||||
/* Set up the endpoint ring */
|
||||
virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags);
|
||||
if (!virt_dev->new_ep_rings[ep_index])
|
||||
return -ENOMEM;
|
||||
ep_ring = virt_dev->new_ep_rings[ep_index];
|
||||
ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state;
|
||||
ep_ctx->deq[1] = 0;
|
||||
|
||||
ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);
|
||||
|
||||
/* FIXME dig Mult and streams info out of ep companion desc */
|
||||
|
||||
/* Allow 3 retries for everything but isoc */
|
||||
if (!usb_endpoint_xfer_isoc(&ep->desc))
|
||||
ep_ctx->ep_info2 = ERROR_COUNT(3);
|
||||
else
|
||||
ep_ctx->ep_info2 = ERROR_COUNT(0);
|
||||
|
||||
ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep);
|
||||
|
||||
/* Set the max packet size and max burst */
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
max_packet = ep->desc.wMaxPacketSize;
|
||||
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
|
||||
/* dig out max burst from ep companion desc */
|
||||
max_packet = ep->ss_ep_comp->desc.bMaxBurst;
|
||||
ep_ctx->ep_info2 |= MAX_BURST(max_packet);
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
/* bits 11:12 specify the number of additional transaction
|
||||
* opportunities per microframe (USB 2.0, section 9.6.6)
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc) ||
|
||||
usb_endpoint_xfer_int(&ep->desc)) {
|
||||
max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
|
||||
ep_ctx->ep_info2 |= MAX_BURST(max_burst);
|
||||
}
|
||||
/* Fall through */
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_LOW:
|
||||
max_packet = ep->desc.wMaxPacketSize & 0x3ff;
|
||||
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
/* FIXME Debug endpoint context */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xhci_endpoint_zero(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
unsigned int ep_index;
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
|
||||
ep_index = xhci_get_endpoint_index(&ep->desc);
|
||||
ep_ctx = &virt_dev->in_ctx->ep[ep_index];
|
||||
|
||||
ep_ctx->ep_info = 0;
|
||||
ep_ctx->ep_info2 = 0;
|
||||
ep_ctx->deq[0] = 0;
|
||||
ep_ctx->deq[1] = 0;
|
||||
ep_ctx->tx_info = 0;
|
||||
/* Don't free the endpoint ring until the set interface or configuration
|
||||
* request succeeds.
|
||||
*/
|
||||
}
|
||||
|
||||
void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
|
||||
int size;
|
||||
int i;
|
||||
|
||||
/* Free the Event Ring Segment Table and the actual Event Ring */
|
||||
xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
|
||||
xhci_writel(xhci, 0, &xhci->ir_set->erst_base[0]);
|
||||
xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
|
||||
xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[0]);
|
||||
xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]);
|
||||
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
|
||||
if (xhci->erst.entries)
|
||||
pci_free_consistent(pdev, size,
|
||||
xhci->erst.entries, xhci->erst.erst_dma_addr);
|
||||
xhci->erst.entries = NULL;
|
||||
xhci_dbg(xhci, "Freed ERST\n");
|
||||
if (xhci->event_ring)
|
||||
xhci_ring_free(xhci, xhci->event_ring);
|
||||
xhci->event_ring = NULL;
|
||||
xhci_dbg(xhci, "Freed event ring\n");
|
||||
|
||||
xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[0]);
|
||||
xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[1]);
|
||||
if (xhci->cmd_ring)
|
||||
xhci_ring_free(xhci, xhci->cmd_ring);
|
||||
xhci->cmd_ring = NULL;
|
||||
xhci_dbg(xhci, "Freed command ring\n");
|
||||
|
||||
for (i = 1; i < MAX_HC_SLOTS; ++i)
|
||||
xhci_free_virt_device(xhci, i);
|
||||
|
||||
if (xhci->segment_pool)
|
||||
dma_pool_destroy(xhci->segment_pool);
|
||||
xhci->segment_pool = NULL;
|
||||
xhci_dbg(xhci, "Freed segment pool\n");
|
||||
|
||||
if (xhci->device_pool)
|
||||
dma_pool_destroy(xhci->device_pool);
|
||||
xhci->device_pool = NULL;
|
||||
xhci_dbg(xhci, "Freed device context pool\n");
|
||||
|
||||
xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[0]);
|
||||
xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[1]);
|
||||
if (xhci->dcbaa)
|
||||
pci_free_consistent(pdev, sizeof(*xhci->dcbaa),
|
||||
xhci->dcbaa, xhci->dcbaa->dma);
|
||||
xhci->dcbaa = NULL;
|
||||
|
||||
xhci->page_size = 0;
|
||||
xhci->page_shift = 0;
|
||||
}
|
||||
|
||||
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||
{
|
||||
dma_addr_t dma;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.controller;
|
||||
unsigned int val, val2;
|
||||
struct xhci_segment *seg;
|
||||
u32 page_size;
|
||||
int i;
|
||||
|
||||
page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
|
||||
xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size);
|
||||
for (i = 0; i < 16; i++) {
|
||||
if ((0x1 & page_size) != 0)
|
||||
break;
|
||||
page_size = page_size >> 1;
|
||||
}
|
||||
if (i < 16)
|
||||
xhci_dbg(xhci, "Supported page size of %iK\n", (1 << (i+12)) / 1024);
|
||||
else
|
||||
xhci_warn(xhci, "WARN: no supported page size\n");
|
||||
/* Use 4K pages, since that's common and the minimum the HC supports */
|
||||
xhci->page_shift = 12;
|
||||
xhci->page_size = 1 << xhci->page_shift;
|
||||
xhci_dbg(xhci, "HCD page size set to %iK\n", xhci->page_size / 1024);
|
||||
|
||||
/*
|
||||
* Program the Number of Device Slots Enabled field in the CONFIG
|
||||
* register with the max value of slots the HC can handle.
|
||||
*/
|
||||
val = HCS_MAX_SLOTS(xhci_readl(xhci, &xhci->cap_regs->hcs_params1));
|
||||
xhci_dbg(xhci, "// xHC can handle at most %d device slots.\n",
|
||||
(unsigned int) val);
|
||||
val2 = xhci_readl(xhci, &xhci->op_regs->config_reg);
|
||||
val |= (val2 & ~HCS_SLOTS_MASK);
|
||||
xhci_dbg(xhci, "// Setting Max device slots reg = 0x%x.\n",
|
||||
(unsigned int) val);
|
||||
xhci_writel(xhci, val, &xhci->op_regs->config_reg);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
if (!xhci->dcbaa)
|
||||
goto fail;
|
||||
memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
|
||||
xhci->dcbaa->dma = dma;
|
||||
xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n",
|
||||
(unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
|
||||
xhci_writel(xhci, dma, &xhci->op_regs->dcbaa_ptr[0]);
|
||||
xhci_writel(xhci, (u32) 0, &xhci->op_regs->dcbaa_ptr[1]);
|
||||
|
||||
/*
|
||||
* Initialize the ring segment pool. The ring must be a contiguous
|
||||
* structure comprised of TRBs. The TRBs must be 16 byte aligned,
|
||||
* however, the command ring segment needs 64-byte aligned segments,
|
||||
* so we pick the greater alignment need.
|
||||
*/
|
||||
xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
|
||||
SEGMENT_SIZE, 64, xhci->page_size);
|
||||
/* See Table 46 and Note on Figure 55 */
|
||||
/* FIXME support 64-byte contexts */
|
||||
xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev,
|
||||
sizeof(struct xhci_device_control),
|
||||
64, xhci->page_size);
|
||||
if (!xhci->segment_pool || !xhci->device_pool)
|
||||
goto fail;
|
||||
|
||||
/* Set up the command ring to have one segments for now. */
|
||||
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags);
|
||||
if (!xhci->cmd_ring)
|
||||
goto fail;
|
||||
xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
|
||||
xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
|
||||
(unsigned long long)xhci->cmd_ring->first_seg->dma);
|
||||
|
||||
/* Set the address in the Command Ring Control register */
|
||||
val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
|
||||
val = (val & ~CMD_RING_ADDR_MASK) |
|
||||
(xhci->cmd_ring->first_seg->dma & CMD_RING_ADDR_MASK) |
|
||||
xhci->cmd_ring->cycle_state;
|
||||
xhci_dbg(xhci, "// Setting command ring address low bits to 0x%x\n", val);
|
||||
xhci_writel(xhci, val, &xhci->op_regs->cmd_ring[0]);
|
||||
xhci_dbg(xhci, "// Setting command ring address high bits to 0x0\n");
|
||||
xhci_writel(xhci, (u32) 0, &xhci->op_regs->cmd_ring[1]);
|
||||
xhci_dbg_cmd_ptrs(xhci);
|
||||
|
||||
val = xhci_readl(xhci, &xhci->cap_regs->db_off);
|
||||
val &= DBOFF_MASK;
|
||||
xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
|
||||
" from cap regs base addr\n", val);
|
||||
xhci->dba = (void *) xhci->cap_regs + val;
|
||||
xhci_dbg_regs(xhci);
|
||||
xhci_print_run_regs(xhci);
|
||||
/* Set ir_set to interrupt register set 0 */
|
||||
xhci->ir_set = (void *) xhci->run_regs->ir_set;
|
||||
|
||||
/*
|
||||
* Event ring setup: Allocate a normal ring, but also setup
|
||||
* 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);
|
||||
if (!xhci->event_ring)
|
||||
goto fail;
|
||||
|
||||
xhci->erst.entries = pci_alloc_consistent(to_pci_dev(dev),
|
||||
sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS, &dma);
|
||||
if (!xhci->erst.entries)
|
||||
goto fail;
|
||||
xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n",
|
||||
(unsigned long long)dma);
|
||||
|
||||
memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS);
|
||||
xhci->erst.num_entries = ERST_NUM_SEGS;
|
||||
xhci->erst.erst_dma_addr = dma;
|
||||
xhci_dbg(xhci, "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx\n",
|
||||
xhci->erst.num_entries,
|
||||
xhci->erst.entries,
|
||||
(unsigned long long)xhci->erst.erst_dma_addr);
|
||||
|
||||
/* set ring base address and size for each segment table entry */
|
||||
for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) {
|
||||
struct xhci_erst_entry *entry = &xhci->erst.entries[val];
|
||||
entry->seg_addr[0] = seg->dma;
|
||||
entry->seg_addr[1] = 0;
|
||||
entry->seg_size = TRBS_PER_SEGMENT;
|
||||
entry->rsvd = 0;
|
||||
seg = seg->next;
|
||||
}
|
||||
|
||||
/* set ERST count with the number of entries in the segment table */
|
||||
val = xhci_readl(xhci, &xhci->ir_set->erst_size);
|
||||
val &= ERST_SIZE_MASK;
|
||||
val |= ERST_NUM_SEGS;
|
||||
xhci_dbg(xhci, "// Write ERST size = %i to ir_set 0 (some bits preserved)\n",
|
||||
val);
|
||||
xhci_writel(xhci, val, &xhci->ir_set->erst_size);
|
||||
|
||||
xhci_dbg(xhci, "// Set ERST entries to point to event ring.\n");
|
||||
/* set the segment table base address */
|
||||
xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n",
|
||||
(unsigned long long)xhci->erst.erst_dma_addr);
|
||||
val = xhci_readl(xhci, &xhci->ir_set->erst_base[0]);
|
||||
val &= ERST_PTR_MASK;
|
||||
val |= (xhci->erst.erst_dma_addr & ~ERST_PTR_MASK);
|
||||
xhci_writel(xhci, val, &xhci->ir_set->erst_base[0]);
|
||||
xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
|
||||
|
||||
/* Set the event ring dequeue address */
|
||||
xhci_set_hc_event_deq(xhci);
|
||||
xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n");
|
||||
xhci_print_ir_set(xhci, xhci->ir_set, 0);
|
||||
|
||||
/*
|
||||
* XXX: Might need to set the Interrupter Moderation Register to
|
||||
* something other than the default (~1ms minimum between interrupts).
|
||||
* See section 5.5.1.2.
|
||||
*/
|
||||
init_completion(&xhci->addr_dev);
|
||||
for (i = 0; i < MAX_HC_SLOTS; ++i)
|
||||
xhci->devs[i] = 0;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
xhci_warn(xhci, "Couldn't initialize memory\n");
|
||||
xhci_mem_cleanup(xhci);
|
||||
return -ENOMEM;
|
||||
}
|
166
drivers/usb/host/xhci-pci.c
Normal file
166
drivers/usb/host/xhci-pci.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* xHCI host controller driver PCI Bus Glue.
|
||||
*
|
||||
* Copyright (C) 2008 Intel Corp.
|
||||
*
|
||||
* Author: Sarah Sharp
|
||||
* Some code borrowed from the Linux EHCI driver.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "xhci.h"
|
||||
|
||||
static const char hcd_name[] = "xhci_hcd";
|
||||
|
||||
/* called after powerup, by probe or system-pm "wakeup" */
|
||||
static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev)
|
||||
{
|
||||
/*
|
||||
* TODO: Implement finding debug ports later.
|
||||
* TODO: see if there are any quirks that need to be added to handle
|
||||
* new extended capabilities.
|
||||
*/
|
||||
|
||||
/* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */
|
||||
if (!pci_set_mwi(pdev))
|
||||
xhci_dbg(xhci, "MWI active\n");
|
||||
|
||||
xhci_dbg(xhci, "Finished xhci_pci_reinit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
int retval;
|
||||
|
||||
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->hcc_params);
|
||||
xhci_print_registers(xhci);
|
||||
|
||||
/* Make sure the HC is halted. */
|
||||
retval = xhci_halt(xhci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
xhci_dbg(xhci, "Resetting HCD\n");
|
||||
/* Reset the internal HC memory state and registers. */
|
||||
retval = xhci_reset(xhci);
|
||||
if (retval)
|
||||
return retval;
|
||||
xhci_dbg(xhci, "Reset complete\n");
|
||||
|
||||
xhci_dbg(xhci, "Calling HCD init\n");
|
||||
/* Initialize HCD and host controller data structures. */
|
||||
retval = xhci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
xhci_dbg(xhci, "Called HCD init\n");
|
||||
|
||||
pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
|
||||
xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
|
||||
|
||||
/* Find any debug ports */
|
||||
return xhci_pci_reinit(xhci, pdev);
|
||||
}
|
||||
|
||||
static const struct hc_driver xhci_pci_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "xHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct xhci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = xhci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB3,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = xhci_pci_setup,
|
||||
.start = xhci_run,
|
||||
/* suspend and resume implemented later */
|
||||
.stop = xhci_stop,
|
||||
.shutdown = xhci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = xhci_urb_enqueue,
|
||||
.urb_dequeue = xhci_urb_dequeue,
|
||||
.alloc_dev = xhci_alloc_dev,
|
||||
.free_dev = xhci_free_dev,
|
||||
.add_endpoint = xhci_add_endpoint,
|
||||
.drop_endpoint = xhci_drop_endpoint,
|
||||
.check_bandwidth = xhci_check_bandwidth,
|
||||
.reset_bandwidth = xhci_reset_bandwidth,
|
||||
.address_device = xhci_address_device,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = xhci_get_frame,
|
||||
|
||||
/* Root hub support */
|
||||
.hub_control = xhci_hub_control,
|
||||
.hub_status_data = xhci_hub_status_data,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* PCI driver selection metadata; PCI hotplugging uses this */
|
||||
static const struct pci_device_id pci_ids[] = { {
|
||||
/* handle any USB 3.0 xHCI controller */
|
||||
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
|
||||
.driver_data = (unsigned long) &xhci_pci_hc_driver,
|
||||
},
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_ids);
|
||||
|
||||
/* pci driver glue; this is a "new style" PCI driver module */
|
||||
static struct pci_driver xhci_pci_driver = {
|
||||
.name = (char *) hcd_name,
|
||||
.id_table = pci_ids,
|
||||
|
||||
.probe = usb_hcd_pci_probe,
|
||||
.remove = usb_hcd_pci_remove,
|
||||
/* suspend and resume implemented later */
|
||||
|
||||
.shutdown = usb_hcd_pci_shutdown,
|
||||
};
|
||||
|
||||
int xhci_register_pci()
|
||||
{
|
||||
return pci_register_driver(&xhci_pci_driver);
|
||||
}
|
||||
|
||||
void xhci_unregister_pci()
|
||||
{
|
||||
pci_unregister_driver(&xhci_pci_driver);
|
||||
}
|
1648
drivers/usb/host/xhci-ring.c
Normal file
1648
drivers/usb/host/xhci-ring.c
Normal file
File diff suppressed because it is too large
Load Diff
1157
drivers/usb/host/xhci.h
Normal file
1157
drivers/usb/host/xhci.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user