summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-sched.c13
-rw-r--r--drivers/usb/host/isp1362-hcd.c18
-rw-r--r--drivers/usb/host/isp1362.h12
-rw-r--r--drivers/usb/host/pci-quirks.c2
-rw-r--r--drivers/usb/host/whci/asl.c23
-rw-r--r--drivers/usb/host/whci/pzl.c24
-rw-r--r--drivers/usb/host/xhci-hcd.c29
7 files changed, 84 insertions, 37 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 3ea0593..b25cdea 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1400,6 +1400,10 @@ iso_stream_schedule (
goto fail;
}
+ period = urb->interval;
+ if (!stream->highspeed)
+ period <<= 3;
+
now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
/* when's the last uframe this urb could start? */
@@ -1417,14 +1421,15 @@ iso_stream_schedule (
/* Fell behind (by up to twice the slop amount)? */
if (start >= max - 2 * 8 * SCHEDULE_SLOP)
- start += stream->interval * DIV_ROUND_UP(
- max - start, stream->interval) - mod;
+ start += period * DIV_ROUND_UP(
+ max - start, period) - mod;
/* Tried to schedule too far into the future? */
if (unlikely((start + sched->span) >= max)) {
status = -EFBIG;
goto fail;
}
+ stream->next_uframe = start;
goto ready;
}
@@ -1440,10 +1445,6 @@ iso_stream_schedule (
/* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
- period = urb->interval;
- if (!stream->highspeed)
- period <<= 3;
-
/* find a uframe slot with enough bandwidth */
for (; start < (stream->next_uframe + period); start++) {
int enough_space;
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index e35d828..5c774ab 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -2284,10 +2284,10 @@ static int isp1362_mem_config(struct usb_hcd *hcd)
dev_info(hcd->self.controller, "ISP1362 Memory usage:\n");
dev_info(hcd->self.controller, " ISTL: 2 * %4d: %4d @ $%04x:$%04x\n",
istl_size / 2, istl_size, 0, istl_size / 2);
- dev_info(hcd->self.controller, " INTL: %4d * (%3u+8): %4d @ $%04x\n",
+ dev_info(hcd->self.controller, " INTL: %4d * (%3lu+8): %4d @ $%04x\n",
ISP1362_INTL_BUFFERS, intl_blksize - PTD_HEADER_SIZE,
intl_size, istl_size);
- dev_info(hcd->self.controller, " ATL : %4d * (%3u+8): %4d @ $%04x\n",
+ dev_info(hcd->self.controller, " ATL : %4d * (%3lu+8): %4d @ $%04x\n",
atl_buffers, atl_blksize - PTD_HEADER_SIZE,
atl_size, istl_size + intl_size);
dev_info(hcd->self.controller, " USED/FREE: %4d %4d\n", total,
@@ -2677,12 +2677,12 @@ static int __devexit isp1362_remove(struct platform_device *pdev)
DBG(0, "%s: Removing HCD\n", __func__);
usb_remove_hcd(hcd);
- DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__,
- (u32)isp1362_hcd->data_reg);
+ DBG(0, "%s: Unmapping data_reg @ %p\n", __func__,
+ isp1362_hcd->data_reg);
iounmap(isp1362_hcd->data_reg);
- DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__,
- (u32)isp1362_hcd->addr_reg);
+ DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__,
+ isp1362_hcd->addr_reg);
iounmap(isp1362_hcd->addr_reg);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -2810,16 +2810,16 @@ static int __init isp1362_probe(struct platform_device *pdev)
return 0;
err6:
- DBG(0, "%s: Freeing dev %08x\n", __func__, (u32)isp1362_hcd);
+ DBG(0, "%s: Freeing dev %p\n", __func__, isp1362_hcd);
usb_put_hcd(hcd);
err5:
- DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__, (u32)data_reg);
+ DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, data_reg);
iounmap(data_reg);
err4:
DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)data->start);
release_mem_region(data->start, resource_len(data));
err3:
- DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__, (u32)addr_reg);
+ DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, addr_reg);
iounmap(addr_reg);
err2:
DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)addr->start);
diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h
index fe60f62..1a253eb 100644
--- a/drivers/usb/host/isp1362.h
+++ b/drivers/usb/host/isp1362.h
@@ -580,7 +580,7 @@ static inline const char *ISP1362_INT_NAME(int n)
static inline void ALIGNSTAT(struct isp1362_hcd *isp1362_hcd, void *ptr)
{
- unsigned p = (unsigned)ptr;
+ unsigned long p = (unsigned long)ptr;
if (!(p & 0xf))
isp1362_hcd->stat16++;
else if (!(p & 0x7))
@@ -770,7 +770,7 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
if (!len)
return;
- if ((unsigned)dp & 0x1) {
+ if ((unsigned long)dp & 0x1) {
/* not aligned */
for (; len > 1; len -= 2) {
data = *dp++;
@@ -962,8 +962,8 @@ static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16
isp1362_write_diraddr(isp1362_hcd, offset, len);
- DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %08x\n", __func__,
- len, offset, (u32)buf);
+ DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n",
+ __func__, len, offset, buf);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
@@ -982,8 +982,8 @@ static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16
isp1362_write_diraddr(isp1362_hcd, offset, len);
- DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %08x\n", __func__,
- len, offset, (u32)buf);
+ DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n",
+ __func__, len, offset, buf);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 23cf3bd..83b5f9c 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -475,4 +475,4 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
quirk_usb_handoff_xhci(pdev);
}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c
index c632437..562eba1 100644
--- a/drivers/usb/host/whci/asl.c
+++ b/drivers/usb/host/whci/asl.c
@@ -115,6 +115,10 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
if (status & QTD_STS_HALTED) {
/* Ug, an error. */
process_halted_qtd(whc, qset, td);
+ /* A halted qTD always triggers an update
+ because the qset was either removed or
+ reactivated. */
+ update |= WHC_UPDATE_UPDATED;
goto done;
}
@@ -305,6 +309,7 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
struct whc_urb *wurb = urb->hcpriv;
struct whc_qset *qset = wurb->qset;
struct whc_std *std, *t;
+ bool has_qtd = false;
int ret;
unsigned long flags;
@@ -315,17 +320,21 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
goto out;
list_for_each_entry_safe(std, t, &qset->stds, list_node) {
- if (std->urb == urb)
+ if (std->urb == urb) {
+ if (std->qtd)
+ has_qtd = true;
qset_free_std(whc, std);
- else
+ } else
std->qtd = NULL; /* so this std is re-added when the qset is */
}
- asl_qset_remove(whc, qset);
- wurb->status = status;
- wurb->is_async = true;
- queue_work(whc->workqueue, &wurb->dequeue_work);
-
+ if (has_qtd) {
+ asl_qset_remove(whc, qset);
+ wurb->status = status;
+ wurb->is_async = true;
+ queue_work(whc->workqueue, &wurb->dequeue_work);
+ } else
+ qset_remove_urb(whc, qset, urb, status);
out:
spin_unlock_irqrestore(&whc->lock, flags);
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c
index a9e05ba..0db3fb2 100644
--- a/drivers/usb/host/whci/pzl.c
+++ b/drivers/usb/host/whci/pzl.c
@@ -121,6 +121,10 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
if (status & QTD_STS_HALTED) {
/* Ug, an error. */
process_halted_qtd(whc, qset, td);
+ /* A halted qTD always triggers an update
+ because the qset was either removed or
+ reactivated. */
+ update |= WHC_UPDATE_UPDATED;
goto done;
}
@@ -333,6 +337,7 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
struct whc_urb *wurb = urb->hcpriv;
struct whc_qset *qset = wurb->qset;
struct whc_std *std, *t;
+ bool has_qtd = false;
int ret;
unsigned long flags;
@@ -343,17 +348,22 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
goto out;
list_for_each_entry_safe(std, t, &qset->stds, list_node) {
- if (std->urb == urb)
+ if (std->urb == urb) {
+ if (std->qtd)
+ has_qtd = true;
qset_free_std(whc, std);
- else
+ } else
std->qtd = NULL; /* so this std is re-added when the qset is */
}
- pzl_qset_remove(whc, qset);
- wurb->status = status;
- wurb->is_async = false;
- queue_work(whc->workqueue, &wurb->dequeue_work);
-
+ if (has_qtd) {
+ pzl_qset_remove(whc, qset);
+ update_pzl_hw_view(whc);
+ wurb->status = status;
+ wurb->is_async = false;
+ queue_work(whc->workqueue, &wurb->dequeue_work);
+ } else
+ qset_remove_urb(whc, qset, urb, status);
out:
spin_unlock_irqrestore(&whc->lock, flags);
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 99911e7..932f999 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -335,6 +335,12 @@ void xhci_event_ring_work(unsigned long arg)
spin_lock_irqsave(&xhci->lock, flags);
temp = xhci_readl(xhci, &xhci->op_regs->status);
xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
+ if (temp == 0xffffffff) {
+ xhci_dbg(xhci, "HW died, polling stopped.\n");
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return;
+ }
+
temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp);
xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled);
@@ -776,6 +782,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
unsigned long flags;
int ret;
+ u32 temp;
struct xhci_hcd *xhci;
struct xhci_td *td;
unsigned int ep_index;
@@ -788,6 +795,17 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
if (ret || !urb->hcpriv)
goto done;
+ temp = xhci_readl(xhci, &xhci->op_regs->status);
+ if (temp == 0xffffffff) {
+ xhci_dbg(xhci, "HW died, freeing TD.\n");
+ td = (struct xhci_td *) urb->hcpriv;
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN);
+ kfree(td);
+ return ret;
+ }
xhci_dbg(xhci, "Cancel URB %p\n", urb);
xhci_dbg(xhci, "Event ring:\n");
@@ -877,7 +895,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
ctrl_ctx->drop_flags |= drop_flag;
new_drop_flags = ctrl_ctx->drop_flags;
- ctrl_ctx->add_flags = ~drop_flag;
+ ctrl_ctx->add_flags &= ~drop_flag;
new_add_flags = ctrl_ctx->add_flags;
last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags);
@@ -1410,11 +1428,20 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
unsigned long flags;
+ u32 state;
if (udev->slot_id == 0)
return;
spin_lock_irqsave(&xhci->lock, flags);
+ /* Don't disable the slot if the host controller is dead. */
+ state = xhci_readl(xhci, &xhci->op_regs->status);
+ if (state == 0xffffffff) {
+ xhci_free_virt_device(xhci, udev->slot_id);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return;
+ }
+
if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
OpenPOWER on IntegriCloud