mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
Merge branch 'for-usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci
* 'for-usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci: Intel xhci: Limit number of active endpoints to 64. Intel xhci: Ignore spurious successful event. Intel xhci: Support EHCI/xHCI port switching. Intel xhci: Add PCI id for Panther Point xHCI host. xhci: STFU: Be quieter during URB submission and completion. xhci: STFU: Don't print event ring dequeue pointer. xhci: STFU: Remove function tracing. xhci: Don't submit commands when the host is dead. xhci: Clear stopped_td when Stop Endpoint command completes.
This commit is contained in:
commit
87367a0b71
8 changed files with 413 additions and 69 deletions
|
@ -348,11 +348,50 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
|
||||||
|
pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||||
|
pdev->device == 0x1E26;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ehci_enable_xhci_companion(void)
|
||||||
|
{
|
||||||
|
struct pci_dev *companion = NULL;
|
||||||
|
|
||||||
|
/* The xHCI and EHCI controllers are not on the same PCI slot */
|
||||||
|
for_each_pci_dev(companion) {
|
||||||
|
if (!usb_is_intel_switchable_xhci(companion))
|
||||||
|
continue;
|
||||||
|
usb_enable_xhci_ports(companion);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||||
{
|
{
|
||||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||||
|
|
||||||
|
/* The BIOS on systems with the Intel Panther Point chipset may or may
|
||||||
|
* not support xHCI natively. That means that during system resume, it
|
||||||
|
* may switch the ports back to EHCI so that users can use their
|
||||||
|
* keyboard to select a kernel from GRUB after resume from hibernate.
|
||||||
|
*
|
||||||
|
* The BIOS is supposed to remember whether the OS had xHCI ports
|
||||||
|
* enabled before resume, and switch the ports back to xHCI when the
|
||||||
|
* BIOS/OS semaphore is written, but we all know we can't trust BIOS
|
||||||
|
* writers.
|
||||||
|
*
|
||||||
|
* Unconditionally switch the ports back to xHCI after a system resume.
|
||||||
|
* We can't tell whether the EHCI or xHCI controller will be resumed
|
||||||
|
* first, so we have to do the port switchover in both drivers. Writing
|
||||||
|
* a '1' to the port switchover registers should have no effect if the
|
||||||
|
* port was already switched over.
|
||||||
|
*/
|
||||||
|
if (usb_is_intel_switchable_ehci(pdev))
|
||||||
|
ehci_enable_xhci_companion();
|
||||||
|
|
||||||
// maybe restore FLADJ
|
// maybe restore FLADJ
|
||||||
|
|
||||||
if (time_before(jiffies, ehci->next_statechange))
|
if (time_before(jiffies, ehci->next_statechange))
|
||||||
|
|
|
@ -69,6 +69,9 @@
|
||||||
#define NB_PIF0_PWRDOWN_0 0x01100012
|
#define NB_PIF0_PWRDOWN_0 0x01100012
|
||||||
#define NB_PIF0_PWRDOWN_1 0x01100013
|
#define NB_PIF0_PWRDOWN_1 0x01100013
|
||||||
|
|
||||||
|
#define USB_INTEL_XUSB2PR 0xD0
|
||||||
|
#define USB_INTEL_USB3_PSSEN 0xD8
|
||||||
|
|
||||||
static struct amd_chipset_info {
|
static struct amd_chipset_info {
|
||||||
struct pci_dev *nb_dev;
|
struct pci_dev *nb_dev;
|
||||||
struct pci_dev *smbus_dev;
|
struct pci_dev *smbus_dev;
|
||||||
|
@ -673,6 +676,64 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
|
||||||
|
pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||||
|
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that
|
||||||
|
* share some number of ports. These ports can be switched between either
|
||||||
|
* controller. Not all of the ports under the EHCI host controller may be
|
||||||
|
* switchable.
|
||||||
|
*
|
||||||
|
* The ports should be switched over to xHCI before PCI probes for any device
|
||||||
|
* start. This avoids active devices under EHCI being disconnected during the
|
||||||
|
* port switchover, which could cause loss of data on USB storage devices, or
|
||||||
|
* failed boot when the root file system is on a USB mass storage device and is
|
||||||
|
* enumerated under EHCI first.
|
||||||
|
*
|
||||||
|
* We write into the xHC's PCI configuration space in some Intel-specific
|
||||||
|
* registers to switch the ports over. The USB 3.0 terminations and the USB
|
||||||
|
* 2.0 data wires are switched separately. We want to enable the SuperSpeed
|
||||||
|
* terminations before switching the USB 2.0 wires over, so that USB 3.0
|
||||||
|
* devices connect at SuperSpeed, rather than at USB 2.0 speeds.
|
||||||
|
*/
|
||||||
|
void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
|
||||||
|
{
|
||||||
|
u32 ports_available;
|
||||||
|
|
||||||
|
ports_available = 0xffffffff;
|
||||||
|
/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
|
||||||
|
* Register, to turn on SuperSpeed terminations for all
|
||||||
|
* available ports.
|
||||||
|
*/
|
||||||
|
pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
|
||||||
|
cpu_to_le32(ports_available));
|
||||||
|
|
||||||
|
pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
|
||||||
|
&ports_available);
|
||||||
|
dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled "
|
||||||
|
"under xHCI: 0x%x\n", ports_available);
|
||||||
|
|
||||||
|
ports_available = 0xffffffff;
|
||||||
|
/* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to
|
||||||
|
* switch the USB 2.0 power and data lines over to the xHCI
|
||||||
|
* host.
|
||||||
|
*/
|
||||||
|
pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
|
||||||
|
cpu_to_le32(ports_available));
|
||||||
|
|
||||||
|
pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
|
||||||
|
&ports_available);
|
||||||
|
dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over "
|
||||||
|
"to xHCI: 0x%x\n", ports_available);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PCI Quirks for xHCI.
|
* PCI Quirks for xHCI.
|
||||||
*
|
*
|
||||||
|
@ -732,6 +793,8 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
||||||
writel(XHCI_LEGACY_DISABLE_SMI,
|
writel(XHCI_LEGACY_DISABLE_SMI,
|
||||||
base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
||||||
|
|
||||||
|
if (usb_is_intel_switchable_xhci(pdev))
|
||||||
|
usb_enable_xhci_ports(pdev);
|
||||||
hc_init:
|
hc_init:
|
||||||
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
|
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ int usb_amd_find_chipset_info(void);
|
||||||
void usb_amd_dev_put(void);
|
void usb_amd_dev_put(void);
|
||||||
void usb_amd_quirk_pll_disable(void);
|
void usb_amd_quirk_pll_disable(void);
|
||||||
void usb_amd_quirk_pll_enable(void);
|
void usb_amd_quirk_pll_enable(void);
|
||||||
|
bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
|
||||||
|
void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
|
||||||
#else
|
#else
|
||||||
static inline void usb_amd_quirk_pll_disable(void) {}
|
static inline void usb_amd_quirk_pll_disable(void) {}
|
||||||
static inline void usb_amd_quirk_pll_enable(void) {}
|
static inline void usb_amd_quirk_pll_enable(void) {}
|
||||||
|
|
|
@ -118,6 +118,12 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||||
/* AMD PLL quirk */
|
/* AMD PLL quirk */
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
|
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
|
||||||
xhci->quirks |= XHCI_AMD_PLL_FIX;
|
xhci->quirks |= XHCI_AMD_PLL_FIX;
|
||||||
|
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||||
|
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
|
||||||
|
xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
|
||||||
|
xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
|
||||||
|
xhci->limit_active_eps = 64;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure the HC is halted. */
|
/* Make sure the HC is halted. */
|
||||||
retval = xhci_halt(xhci);
|
retval = xhci_halt(xhci);
|
||||||
|
@ -242,8 +248,28 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
|
||||||
static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||||
{
|
{
|
||||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||||
|
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
|
/* The BIOS on systems with the Intel Panther Point chipset may or may
|
||||||
|
* not support xHCI natively. That means that during system resume, it
|
||||||
|
* may switch the ports back to EHCI so that users can use their
|
||||||
|
* keyboard to select a kernel from GRUB after resume from hibernate.
|
||||||
|
*
|
||||||
|
* The BIOS is supposed to remember whether the OS had xHCI ports
|
||||||
|
* enabled before resume, and switch the ports back to xHCI when the
|
||||||
|
* BIOS/OS semaphore is written, but we all know we can't trust BIOS
|
||||||
|
* writers.
|
||||||
|
*
|
||||||
|
* Unconditionally switch the ports back to xHCI after a system resume.
|
||||||
|
* We can't tell whether the EHCI or xHCI controller will be resumed
|
||||||
|
* first, so we have to do the port switchover in both drivers. Writing
|
||||||
|
* a '1' to the port switchover registers should have no effect if the
|
||||||
|
* port was already switched over.
|
||||||
|
*/
|
||||||
|
if (usb_is_intel_switchable_xhci(pdev))
|
||||||
|
usb_enable_xhci_ports(pdev);
|
||||||
|
|
||||||
retval = xhci_resume(xhci, hibernated);
|
retval = xhci_resume(xhci, hibernated);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,12 +167,6 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
|
||||||
next = ring->dequeue;
|
next = ring->dequeue;
|
||||||
}
|
}
|
||||||
addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
|
addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
|
||||||
if (ring == xhci->event_ring)
|
|
||||||
xhci_dbg(xhci, "Event ring deq = 0x%llx (DMA)\n", addr);
|
|
||||||
else if (ring == xhci->cmd_ring)
|
|
||||||
xhci_dbg(xhci, "Command ring deq = 0x%llx (DMA)\n", addr);
|
|
||||||
else
|
|
||||||
xhci_dbg(xhci, "Ring deq = 0x%llx (DMA)\n", addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -248,12 +242,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||||
next = ring->enqueue;
|
next = ring->enqueue;
|
||||||
}
|
}
|
||||||
addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);
|
addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);
|
||||||
if (ring == xhci->event_ring)
|
|
||||||
xhci_dbg(xhci, "Event ring enq = 0x%llx (DMA)\n", addr);
|
|
||||||
else if (ring == xhci->cmd_ring)
|
|
||||||
xhci_dbg(xhci, "Command ring enq = 0x%llx (DMA)\n", addr);
|
|
||||||
else
|
|
||||||
xhci_dbg(xhci, "Ring enq = 0x%llx (DMA)\n", addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -636,13 +624,11 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||||
xhci_dbg(xhci, "Giveback %s URB %p\n", adjective, urb);
|
|
||||||
|
|
||||||
spin_unlock(&xhci->lock);
|
spin_unlock(&xhci->lock);
|
||||||
usb_hcd_giveback_urb(hcd, urb, status);
|
usb_hcd_giveback_urb(hcd, urb, status);
|
||||||
xhci_urb_free_priv(xhci, urb_priv);
|
xhci_urb_free_priv(xhci, urb_priv);
|
||||||
spin_lock(&xhci->lock);
|
spin_lock(&xhci->lock);
|
||||||
xhci_dbg(xhci, "%s URB given back\n", adjective);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,6 +678,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
|
||||||
|
|
||||||
if (list_empty(&ep->cancelled_td_list)) {
|
if (list_empty(&ep->cancelled_td_list)) {
|
||||||
xhci_stop_watchdog_timer_in_irq(xhci, ep);
|
xhci_stop_watchdog_timer_in_irq(xhci, ep);
|
||||||
|
ep->stopped_td = NULL;
|
||||||
|
ep->stopped_trb = NULL;
|
||||||
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
|
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1093,8 +1081,13 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
||||||
complete(&xhci->addr_dev);
|
complete(&xhci->addr_dev);
|
||||||
break;
|
break;
|
||||||
case TRB_TYPE(TRB_DISABLE_SLOT):
|
case TRB_TYPE(TRB_DISABLE_SLOT):
|
||||||
if (xhci->devs[slot_id])
|
if (xhci->devs[slot_id]) {
|
||||||
|
if (xhci->quirks & XHCI_EP_LIMIT_QUIRK)
|
||||||
|
/* Delete default control endpoint resources */
|
||||||
|
xhci_free_device_endpoint_resources(xhci,
|
||||||
|
xhci->devs[slot_id], true);
|
||||||
xhci_free_virt_device(xhci, slot_id);
|
xhci_free_virt_device(xhci, slot_id);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TRB_TYPE(TRB_CONFIG_EP):
|
case TRB_TYPE(TRB_CONFIG_EP):
|
||||||
virt_dev = xhci->devs[slot_id];
|
virt_dev = xhci->devs[slot_id];
|
||||||
|
@ -1630,7 +1623,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
"without IOC set??\n");
|
"without IOC set??\n");
|
||||||
*status = -ESHUTDOWN;
|
*status = -ESHUTDOWN;
|
||||||
} else {
|
} else {
|
||||||
xhci_dbg(xhci, "Successful control transfer!\n");
|
|
||||||
*status = 0;
|
*status = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1727,7 +1719,6 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
switch (trb_comp_code) {
|
switch (trb_comp_code) {
|
||||||
case COMP_SUCCESS:
|
case COMP_SUCCESS:
|
||||||
frame->status = 0;
|
frame->status = 0;
|
||||||
xhci_dbg(xhci, "Successful isoc transfer!\n");
|
|
||||||
break;
|
break;
|
||||||
case COMP_SHORT_TX:
|
case COMP_SHORT_TX:
|
||||||
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
|
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
|
||||||
|
@ -1837,12 +1828,6 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
else
|
else
|
||||||
*status = 0;
|
*status = 0;
|
||||||
} else {
|
} else {
|
||||||
if (usb_endpoint_xfer_bulk(&td->urb->ep->desc))
|
|
||||||
xhci_dbg(xhci, "Successful bulk "
|
|
||||||
"transfer!\n");
|
|
||||||
else
|
|
||||||
xhci_dbg(xhci, "Successful interrupt "
|
|
||||||
"transfer!\n");
|
|
||||||
*status = 0;
|
*status = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1856,11 +1841,12 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
/* Others already handled above */
|
/* Others already handled above */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
xhci_dbg(xhci, "ep %#x - asked for %d bytes, "
|
if (trb_comp_code == COMP_SHORT_TX)
|
||||||
"%d bytes untransferred\n",
|
xhci_dbg(xhci, "ep %#x - asked for %d bytes, "
|
||||||
td->urb->ep->desc.bEndpointAddress,
|
"%d bytes untransferred\n",
|
||||||
td->urb->transfer_buffer_length,
|
td->urb->ep->desc.bEndpointAddress,
|
||||||
TRB_LEN(le32_to_cpu(event->transfer_len)));
|
td->urb->transfer_buffer_length,
|
||||||
|
TRB_LEN(le32_to_cpu(event->transfer_len)));
|
||||||
/* Fast path - was this the last TRB in the TD for this URB? */
|
/* Fast path - was this the last TRB in the TD for this URB? */
|
||||||
if (event_trb == td->last_trb) {
|
if (event_trb == td->last_trb) {
|
||||||
if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
|
if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
|
||||||
|
@ -1954,7 +1940,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
|
|
||||||
/* Endpoint ID is 1 based, our index is zero based */
|
/* Endpoint ID is 1 based, our index is zero based */
|
||||||
ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
|
ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
|
||||||
xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index);
|
|
||||||
ep = &xdev->eps[ep_index];
|
ep = &xdev->eps[ep_index];
|
||||||
ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
|
ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
|
||||||
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
|
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
|
||||||
|
@ -2081,6 +2066,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
if (!event_seg) {
|
if (!event_seg) {
|
||||||
if (!ep->skip ||
|
if (!ep->skip ||
|
||||||
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
|
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
|
||||||
|
/* Some host controllers give a spurious
|
||||||
|
* successful event after a short transfer.
|
||||||
|
* Ignore it.
|
||||||
|
*/
|
||||||
|
if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&
|
||||||
|
ep_ring->last_td_was_short) {
|
||||||
|
ep_ring->last_td_was_short = false;
|
||||||
|
ret = 0;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
/* HC is busted, give up! */
|
/* HC is busted, give up! */
|
||||||
xhci_err(xhci,
|
xhci_err(xhci,
|
||||||
"ERROR Transfer event TRB DMA ptr not "
|
"ERROR Transfer event TRB DMA ptr not "
|
||||||
|
@ -2091,6 +2086,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
ret = skip_isoc_td(xhci, td, event, ep, &status);
|
ret = skip_isoc_td(xhci, td, event, ep, &status);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
if (trb_comp_code == COMP_SHORT_TX)
|
||||||
|
ep_ring->last_td_was_short = true;
|
||||||
|
else
|
||||||
|
ep_ring->last_td_was_short = false;
|
||||||
|
|
||||||
if (ep->skip) {
|
if (ep->skip) {
|
||||||
xhci_dbg(xhci, "Found td. Clear skip flag.\n");
|
xhci_dbg(xhci, "Found td. Clear skip flag.\n");
|
||||||
|
@ -2149,9 +2148,15 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
xhci_urb_free_priv(xhci, urb_priv);
|
xhci_urb_free_priv(xhci, urb_priv);
|
||||||
|
|
||||||
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
|
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
|
||||||
xhci_dbg(xhci, "Giveback URB %p, len = %d, "
|
if ((urb->actual_length != urb->transfer_buffer_length &&
|
||||||
"status = %d\n",
|
(urb->transfer_flags &
|
||||||
urb, urb->actual_length, status);
|
URB_SHORT_NOT_OK)) ||
|
||||||
|
status != 0)
|
||||||
|
xhci_dbg(xhci, "Giveback URB %p, len = %d, "
|
||||||
|
"expected = %x, status = %d\n",
|
||||||
|
urb, urb->actual_length,
|
||||||
|
urb->transfer_buffer_length,
|
||||||
|
status);
|
||||||
spin_unlock(&xhci->lock);
|
spin_unlock(&xhci->lock);
|
||||||
usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status);
|
usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status);
|
||||||
spin_lock(&xhci->lock);
|
spin_lock(&xhci->lock);
|
||||||
|
@ -2180,7 +2185,6 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
|
||||||
int update_ptrs = 1;
|
int update_ptrs = 1;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
xhci_dbg(xhci, "In %s\n", __func__);
|
|
||||||
if (!xhci->event_ring || !xhci->event_ring->dequeue) {
|
if (!xhci->event_ring || !xhci->event_ring->dequeue) {
|
||||||
xhci->error_bitmask |= 1 << 1;
|
xhci->error_bitmask |= 1 << 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2193,7 +2197,6 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
|
||||||
xhci->error_bitmask |= 1 << 2;
|
xhci->error_bitmask |= 1 << 2;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
xhci_dbg(xhci, "%s - OS owns TRB\n", __func__);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Barrier between reading the TRB_CYCLE (valid) flag above and any
|
* Barrier between reading the TRB_CYCLE (valid) flag above and any
|
||||||
|
@ -2203,20 +2206,14 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
|
||||||
/* FIXME: Handle more event types. */
|
/* FIXME: Handle more event types. */
|
||||||
switch ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK)) {
|
switch ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK)) {
|
||||||
case TRB_TYPE(TRB_COMPLETION):
|
case TRB_TYPE(TRB_COMPLETION):
|
||||||
xhci_dbg(xhci, "%s - calling handle_cmd_completion\n", __func__);
|
|
||||||
handle_cmd_completion(xhci, &event->event_cmd);
|
handle_cmd_completion(xhci, &event->event_cmd);
|
||||||
xhci_dbg(xhci, "%s - returned from handle_cmd_completion\n", __func__);
|
|
||||||
break;
|
break;
|
||||||
case TRB_TYPE(TRB_PORT_STATUS):
|
case TRB_TYPE(TRB_PORT_STATUS):
|
||||||
xhci_dbg(xhci, "%s - calling handle_port_status\n", __func__);
|
|
||||||
handle_port_status(xhci, event);
|
handle_port_status(xhci, event);
|
||||||
xhci_dbg(xhci, "%s - returned from handle_port_status\n", __func__);
|
|
||||||
update_ptrs = 0;
|
update_ptrs = 0;
|
||||||
break;
|
break;
|
||||||
case TRB_TYPE(TRB_TRANSFER):
|
case TRB_TYPE(TRB_TRANSFER):
|
||||||
xhci_dbg(xhci, "%s - calling handle_tx_event\n", __func__);
|
|
||||||
ret = handle_tx_event(xhci, &event->trans_event);
|
ret = handle_tx_event(xhci, &event->trans_event);
|
||||||
xhci_dbg(xhci, "%s - returned from handle_tx_event\n", __func__);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
xhci->error_bitmask |= 1 << 9;
|
xhci->error_bitmask |= 1 << 9;
|
||||||
else
|
else
|
||||||
|
@ -2273,16 +2270,6 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||||
spin_unlock(&xhci->lock);
|
spin_unlock(&xhci->lock);
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
xhci_dbg(xhci, "op reg status = %08x\n", status);
|
|
||||||
xhci_dbg(xhci, "Event ring dequeue ptr:\n");
|
|
||||||
xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
|
|
||||||
(unsigned long long)
|
|
||||||
xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
|
|
||||||
lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
|
||||||
upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
|
|
||||||
(unsigned int) le32_to_cpu(trb->link.intr_target),
|
|
||||||
(unsigned int) le32_to_cpu(trb->link.control));
|
|
||||||
|
|
||||||
if (status & STS_FATAL) {
|
if (status & STS_FATAL) {
|
||||||
xhci_warn(xhci, "WARNING: Host System Error\n");
|
xhci_warn(xhci, "WARNING: Host System Error\n");
|
||||||
xhci_halt(xhci);
|
xhci_halt(xhci);
|
||||||
|
@ -2397,7 +2384,6 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||||
u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
|
u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
|
||||||
{
|
{
|
||||||
/* Make sure the endpoint has been added to xHC schedule */
|
/* Make sure the endpoint has been added to xHC schedule */
|
||||||
xhci_dbg(xhci, "Endpoint state = 0x%x\n", ep_state);
|
|
||||||
switch (ep_state) {
|
switch (ep_state) {
|
||||||
case EP_STATE_DISABLED:
|
case EP_STATE_DISABLED:
|
||||||
/*
|
/*
|
||||||
|
@ -2434,7 +2420,6 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||||
struct xhci_ring *ring = ep_ring;
|
struct xhci_ring *ring = ep_ring;
|
||||||
union xhci_trb *next;
|
union xhci_trb *next;
|
||||||
|
|
||||||
xhci_dbg(xhci, "prepare_ring: pointing to link trb\n");
|
|
||||||
next = ring->enqueue;
|
next = ring->enqueue;
|
||||||
|
|
||||||
while (last_trb(xhci, ring, ring->enq_seg, next)) {
|
while (last_trb(xhci, ring, ring->enq_seg, next)) {
|
||||||
|
|
|
@ -1314,8 +1314,10 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
return ret;
|
return ret;
|
||||||
xhci = hcd_to_xhci(hcd);
|
xhci = hcd_to_xhci(hcd);
|
||||||
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
|
if (xhci->xhc_state & XHCI_STATE_DYING)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
|
||||||
drop_flag = xhci_get_endpoint_flag(&ep->desc);
|
drop_flag = xhci_get_endpoint_flag(&ep->desc);
|
||||||
if (drop_flag == SLOT_FLAG || drop_flag == EP0_FLAG) {
|
if (drop_flag == SLOT_FLAG || drop_flag == EP0_FLAG) {
|
||||||
xhci_dbg(xhci, "xHCI %s - can't drop slot or ep 0 %#x\n",
|
xhci_dbg(xhci, "xHCI %s - can't drop slot or ep 0 %#x\n",
|
||||||
|
@ -1401,6 +1403,8 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
xhci = hcd_to_xhci(hcd);
|
xhci = hcd_to_xhci(hcd);
|
||||||
|
if (xhci->xhc_state & XHCI_STATE_DYING)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
added_ctxs = xhci_get_endpoint_flag(&ep->desc);
|
added_ctxs = xhci_get_endpoint_flag(&ep->desc);
|
||||||
last_ctx = xhci_last_valid_endpoint(added_ctxs);
|
last_ctx = xhci_last_valid_endpoint(added_ctxs);
|
||||||
|
@ -1578,6 +1582,113 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 xhci_count_num_new_endpoints(struct xhci_hcd *xhci,
|
||||||
|
struct xhci_container_ctx *in_ctx)
|
||||||
|
{
|
||||||
|
struct xhci_input_control_ctx *ctrl_ctx;
|
||||||
|
u32 valid_add_flags;
|
||||||
|
u32 valid_drop_flags;
|
||||||
|
|
||||||
|
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
||||||
|
/* Ignore the slot flag (bit 0), and the default control endpoint flag
|
||||||
|
* (bit 1). The default control endpoint is added during the Address
|
||||||
|
* Device command and is never removed until the slot is disabled.
|
||||||
|
*/
|
||||||
|
valid_add_flags = ctrl_ctx->add_flags >> 2;
|
||||||
|
valid_drop_flags = ctrl_ctx->drop_flags >> 2;
|
||||||
|
|
||||||
|
/* Use hweight32 to count the number of ones in the add flags, or
|
||||||
|
* number of endpoints added. Don't count endpoints that are changed
|
||||||
|
* (both added and dropped).
|
||||||
|
*/
|
||||||
|
return hweight32(valid_add_flags) -
|
||||||
|
hweight32(valid_add_flags & valid_drop_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int xhci_count_num_dropped_endpoints(struct xhci_hcd *xhci,
|
||||||
|
struct xhci_container_ctx *in_ctx)
|
||||||
|
{
|
||||||
|
struct xhci_input_control_ctx *ctrl_ctx;
|
||||||
|
u32 valid_add_flags;
|
||||||
|
u32 valid_drop_flags;
|
||||||
|
|
||||||
|
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
||||||
|
valid_add_flags = ctrl_ctx->add_flags >> 2;
|
||||||
|
valid_drop_flags = ctrl_ctx->drop_flags >> 2;
|
||||||
|
|
||||||
|
return hweight32(valid_drop_flags) -
|
||||||
|
hweight32(valid_add_flags & valid_drop_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to reserve the new number of endpoints before the configure endpoint
|
||||||
|
* command completes. We can't subtract the dropped endpoints from the number
|
||||||
|
* of active endpoints until the command completes because we can oversubscribe
|
||||||
|
* the host in this case:
|
||||||
|
*
|
||||||
|
* - the first configure endpoint command drops more endpoints than it adds
|
||||||
|
* - a second configure endpoint command that adds more endpoints is queued
|
||||||
|
* - the first configure endpoint command fails, so the config is unchanged
|
||||||
|
* - the second command may succeed, even though there isn't enough resources
|
||||||
|
*
|
||||||
|
* Must be called with xhci->lock held.
|
||||||
|
*/
|
||||||
|
static int xhci_reserve_host_resources(struct xhci_hcd *xhci,
|
||||||
|
struct xhci_container_ctx *in_ctx)
|
||||||
|
{
|
||||||
|
u32 added_eps;
|
||||||
|
|
||||||
|
added_eps = xhci_count_num_new_endpoints(xhci, in_ctx);
|
||||||
|
if (xhci->num_active_eps + added_eps > xhci->limit_active_eps) {
|
||||||
|
xhci_dbg(xhci, "Not enough ep ctxs: "
|
||||||
|
"%u active, need to add %u, limit is %u.\n",
|
||||||
|
xhci->num_active_eps, added_eps,
|
||||||
|
xhci->limit_active_eps);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
xhci->num_active_eps += added_eps;
|
||||||
|
xhci_dbg(xhci, "Adding %u ep ctxs, %u now active.\n", added_eps,
|
||||||
|
xhci->num_active_eps);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The configure endpoint was failed by the xHC for some other reason, so we
|
||||||
|
* need to revert the resources that failed configuration would have used.
|
||||||
|
*
|
||||||
|
* Must be called with xhci->lock held.
|
||||||
|
*/
|
||||||
|
static void xhci_free_host_resources(struct xhci_hcd *xhci,
|
||||||
|
struct xhci_container_ctx *in_ctx)
|
||||||
|
{
|
||||||
|
u32 num_failed_eps;
|
||||||
|
|
||||||
|
num_failed_eps = xhci_count_num_new_endpoints(xhci, in_ctx);
|
||||||
|
xhci->num_active_eps -= num_failed_eps;
|
||||||
|
xhci_dbg(xhci, "Removing %u failed ep ctxs, %u now active.\n",
|
||||||
|
num_failed_eps,
|
||||||
|
xhci->num_active_eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that the command has completed, clean up the active endpoint count by
|
||||||
|
* subtracting out the endpoints that were dropped (but not changed).
|
||||||
|
*
|
||||||
|
* Must be called with xhci->lock held.
|
||||||
|
*/
|
||||||
|
static void xhci_finish_resource_reservation(struct xhci_hcd *xhci,
|
||||||
|
struct xhci_container_ctx *in_ctx)
|
||||||
|
{
|
||||||
|
u32 num_dropped_eps;
|
||||||
|
|
||||||
|
num_dropped_eps = xhci_count_num_dropped_endpoints(xhci, in_ctx);
|
||||||
|
xhci->num_active_eps -= num_dropped_eps;
|
||||||
|
if (num_dropped_eps)
|
||||||
|
xhci_dbg(xhci, "Removing %u dropped ep ctxs, %u now active.\n",
|
||||||
|
num_dropped_eps,
|
||||||
|
xhci->num_active_eps);
|
||||||
|
}
|
||||||
|
|
||||||
/* Issue a configure endpoint command or evaluate context command
|
/* Issue a configure endpoint command or evaluate context command
|
||||||
* and wait for it to finish.
|
* and wait for it to finish.
|
||||||
*/
|
*/
|
||||||
|
@ -1598,6 +1709,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||||||
virt_dev = xhci->devs[udev->slot_id];
|
virt_dev = xhci->devs[udev->slot_id];
|
||||||
if (command) {
|
if (command) {
|
||||||
in_ctx = command->in_ctx;
|
in_ctx = command->in_ctx;
|
||||||
|
if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK) &&
|
||||||
|
xhci_reserve_host_resources(xhci, in_ctx)) {
|
||||||
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
|
xhci_warn(xhci, "Not enough host resources, "
|
||||||
|
"active endpoint contexts = %u\n",
|
||||||
|
xhci->num_active_eps);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
cmd_completion = command->completion;
|
cmd_completion = command->completion;
|
||||||
cmd_status = &command->status;
|
cmd_status = &command->status;
|
||||||
command->command_trb = xhci->cmd_ring->enqueue;
|
command->command_trb = xhci->cmd_ring->enqueue;
|
||||||
|
@ -1613,6 +1733,14 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||||||
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
|
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
|
||||||
} else {
|
} else {
|
||||||
in_ctx = virt_dev->in_ctx;
|
in_ctx = virt_dev->in_ctx;
|
||||||
|
if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK) &&
|
||||||
|
xhci_reserve_host_resources(xhci, in_ctx)) {
|
||||||
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
|
xhci_warn(xhci, "Not enough host resources, "
|
||||||
|
"active endpoint contexts = %u\n",
|
||||||
|
xhci->num_active_eps);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
cmd_completion = &virt_dev->cmd_completion;
|
cmd_completion = &virt_dev->cmd_completion;
|
||||||
cmd_status = &virt_dev->cmd_status;
|
cmd_status = &virt_dev->cmd_status;
|
||||||
}
|
}
|
||||||
|
@ -1627,6 +1755,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (command)
|
if (command)
|
||||||
list_del(&command->cmd_list);
|
list_del(&command->cmd_list);
|
||||||
|
if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK))
|
||||||
|
xhci_free_host_resources(xhci, in_ctx);
|
||||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
|
xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1649,8 +1779,22 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx_change)
|
if (!ctx_change)
|
||||||
return xhci_configure_endpoint_result(xhci, udev, cmd_status);
|
ret = xhci_configure_endpoint_result(xhci, udev, cmd_status);
|
||||||
return xhci_evaluate_context_result(xhci, udev, cmd_status);
|
else
|
||||||
|
ret = xhci_evaluate_context_result(xhci, udev, cmd_status);
|
||||||
|
|
||||||
|
if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) {
|
||||||
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
|
/* If the command failed, remove the reserved resources.
|
||||||
|
* Otherwise, clean up the estimate to include dropped eps.
|
||||||
|
*/
|
||||||
|
if (ret)
|
||||||
|
xhci_free_host_resources(xhci, in_ctx);
|
||||||
|
else
|
||||||
|
xhci_finish_resource_reservation(xhci, in_ctx);
|
||||||
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called after one or more calls to xhci_add_endpoint() or
|
/* Called after one or more calls to xhci_add_endpoint() or
|
||||||
|
@ -1676,6 +1820,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
return ret;
|
return ret;
|
||||||
xhci = hcd_to_xhci(hcd);
|
xhci = hcd_to_xhci(hcd);
|
||||||
|
if (xhci->xhc_state & XHCI_STATE_DYING)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
|
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
|
||||||
virt_dev = xhci->devs[udev->slot_id];
|
virt_dev = xhci->devs[udev->slot_id];
|
||||||
|
@ -2265,6 +2411,34 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deletes endpoint resources for endpoints that were active before a Reset
|
||||||
|
* Device command, or a Disable Slot command. The Reset Device command leaves
|
||||||
|
* the control endpoint intact, whereas the Disable Slot command deletes it.
|
||||||
|
*
|
||||||
|
* Must be called with xhci->lock held.
|
||||||
|
*/
|
||||||
|
void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
|
||||||
|
struct xhci_virt_device *virt_dev, bool drop_control_ep)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int num_dropped_eps = 0;
|
||||||
|
unsigned int drop_flags = 0;
|
||||||
|
|
||||||
|
for (i = (drop_control_ep ? 0 : 1); i < 31; i++) {
|
||||||
|
if (virt_dev->eps[i].ring) {
|
||||||
|
drop_flags |= 1 << i;
|
||||||
|
num_dropped_eps++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhci->num_active_eps -= num_dropped_eps;
|
||||||
|
if (num_dropped_eps)
|
||||||
|
xhci_dbg(xhci, "Dropped %u ep ctxs, flags = 0x%x, "
|
||||||
|
"%u now active.\n",
|
||||||
|
num_dropped_eps, drop_flags,
|
||||||
|
xhci->num_active_eps);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This submits a Reset Device Command, which will set the device state to 0,
|
* This submits a Reset Device Command, which will set the device state to 0,
|
||||||
* set the device address to 0, and disable all the endpoints except the default
|
* set the device address to 0, and disable all the endpoints except the default
|
||||||
|
@ -2406,6 +2580,14 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||||
goto command_cleanup;
|
goto command_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free up host controller endpoint resources */
|
||||||
|
if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) {
|
||||||
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
|
/* Don't delete the default control endpoint resources */
|
||||||
|
xhci_free_device_endpoint_resources(xhci, virt_dev, false);
|
||||||
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/* Everything but endpoint 0 is disabled, so free or cache the rings. */
|
/* Everything but endpoint 0 is disabled, so free or cache the rings. */
|
||||||
last_freed_endpoint = 1;
|
last_freed_endpoint = 1;
|
||||||
for (i = 1; i < 31; ++i) {
|
for (i = 1; i < 31; ++i) {
|
||||||
|
@ -2478,6 +2660,27 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks if we have enough host controller resources for the default control
|
||||||
|
* endpoint.
|
||||||
|
*
|
||||||
|
* Must be called with xhci->lock held.
|
||||||
|
*/
|
||||||
|
static int xhci_reserve_host_control_ep_resources(struct xhci_hcd *xhci)
|
||||||
|
{
|
||||||
|
if (xhci->num_active_eps + 1 > xhci->limit_active_eps) {
|
||||||
|
xhci_dbg(xhci, "Not enough ep ctxs: "
|
||||||
|
"%u active, need to add 1, limit is %u.\n",
|
||||||
|
xhci->num_active_eps, xhci->limit_active_eps);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
xhci->num_active_eps += 1;
|
||||||
|
xhci_dbg(xhci, "Adding 1 ep ctx, %u now active.\n",
|
||||||
|
xhci->num_active_eps);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 0 if the xHC ran out of device slots, the Enable Slot command
|
* Returns 0 if the xHC ran out of device slots, the Enable Slot command
|
||||||
* timed out, or allocating memory failed. Returns 1 on success.
|
* timed out, or allocating memory failed. Returns 1 on success.
|
||||||
|
@ -2513,24 +2716,39 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||||
xhci_err(xhci, "Error while assigning device slot ID\n");
|
xhci_err(xhci, "Error while assigning device slot ID\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* xhci_alloc_virt_device() does not touch rings; no need to lock.
|
|
||||||
* Use GFP_NOIO, since this function can be called from
|
if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) {
|
||||||
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
|
ret = xhci_reserve_host_control_ep_resources(xhci);
|
||||||
|
if (ret) {
|
||||||
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
|
xhci_warn(xhci, "Not enough host resources, "
|
||||||
|
"active endpoint contexts = %u\n",
|
||||||
|
xhci->num_active_eps);
|
||||||
|
goto disable_slot;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
|
}
|
||||||
|
/* Use GFP_NOIO, since this function can be called from
|
||||||
* xhci_discover_or_reset_device(), which may be called as part of
|
* xhci_discover_or_reset_device(), which may be called as part of
|
||||||
* mass storage driver error handling.
|
* mass storage driver error handling.
|
||||||
*/
|
*/
|
||||||
if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_NOIO)) {
|
if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_NOIO)) {
|
||||||
/* Disable slot, if we can do it without mem alloc */
|
|
||||||
xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
|
xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
|
||||||
spin_lock_irqsave(&xhci->lock, flags);
|
goto disable_slot;
|
||||||
if (!xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id))
|
|
||||||
xhci_ring_cmd_db(xhci);
|
|
||||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
udev->slot_id = xhci->slot_id;
|
udev->slot_id = xhci->slot_id;
|
||||||
/* Is this a LS or FS device under a HS hub? */
|
/* Is this a LS or FS device under a HS hub? */
|
||||||
/* Hub or peripherial? */
|
/* Hub or peripherial? */
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
disable_slot:
|
||||||
|
/* Disable slot, if we can do it without mem alloc */
|
||||||
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
|
if (!xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id))
|
||||||
|
xhci_ring_cmd_db(xhci);
|
||||||
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1123,6 +1123,7 @@ struct xhci_ring {
|
||||||
*/
|
*/
|
||||||
u32 cycle_state;
|
u32 cycle_state;
|
||||||
unsigned int stream_id;
|
unsigned int stream_id;
|
||||||
|
bool last_td_was_short;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xhci_erst_entry {
|
struct xhci_erst_entry {
|
||||||
|
@ -1290,6 +1291,19 @@ struct xhci_hcd {
|
||||||
#define XHCI_RESET_EP_QUIRK (1 << 1)
|
#define XHCI_RESET_EP_QUIRK (1 << 1)
|
||||||
#define XHCI_NEC_HOST (1 << 2)
|
#define XHCI_NEC_HOST (1 << 2)
|
||||||
#define XHCI_AMD_PLL_FIX (1 << 3)
|
#define XHCI_AMD_PLL_FIX (1 << 3)
|
||||||
|
#define XHCI_SPURIOUS_SUCCESS (1 << 4)
|
||||||
|
/*
|
||||||
|
* Certain Intel host controllers have a limit to the number of endpoint
|
||||||
|
* contexts they can handle. Ideally, they would signal that they can't handle
|
||||||
|
* anymore endpoint contexts by returning a Resource Error for the Configure
|
||||||
|
* Endpoint command, but they don't. Instead they expect software to keep track
|
||||||
|
* of the number of active endpoints for them, across configure endpoint
|
||||||
|
* commands, reset device commands, disable slot commands, and address device
|
||||||
|
* commands.
|
||||||
|
*/
|
||||||
|
#define XHCI_EP_LIMIT_QUIRK (1 << 5)
|
||||||
|
unsigned int num_active_eps;
|
||||||
|
unsigned int limit_active_eps;
|
||||||
/* There are two roothubs to keep track of bus suspend info for */
|
/* There are two roothubs to keep track of bus suspend info for */
|
||||||
struct xhci_bus_state bus_state[2];
|
struct xhci_bus_state bus_state[2];
|
||||||
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
|
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
|
||||||
|
@ -1338,9 +1352,6 @@ static inline unsigned int xhci_readl(const struct xhci_hcd *xhci,
|
||||||
static inline void xhci_writel(struct xhci_hcd *xhci,
|
static inline void xhci_writel(struct xhci_hcd *xhci,
|
||||||
const unsigned int val, __le32 __iomem *regs)
|
const unsigned int val, __le32 __iomem *regs)
|
||||||
{
|
{
|
||||||
xhci_dbg(xhci,
|
|
||||||
"`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n",
|
|
||||||
regs, val);
|
|
||||||
writel(val, regs);
|
writel(val, regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1368,9 +1379,6 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
|
||||||
u32 val_lo = lower_32_bits(val);
|
u32 val_lo = lower_32_bits(val);
|
||||||
u32 val_hi = upper_32_bits(val);
|
u32 val_hi = upper_32_bits(val);
|
||||||
|
|
||||||
xhci_dbg(xhci,
|
|
||||||
"`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n",
|
|
||||||
regs, (long unsigned int) val);
|
|
||||||
writel(val_lo, ptr);
|
writel(val_lo, ptr);
|
||||||
writel(val_hi, ptr + 1);
|
writel(val_hi, ptr + 1);
|
||||||
}
|
}
|
||||||
|
@ -1439,6 +1447,8 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
|
||||||
void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
|
void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
|
||||||
struct xhci_ep_ctx *ep_ctx,
|
struct xhci_ep_ctx *ep_ctx,
|
||||||
struct xhci_virt_ep *ep);
|
struct xhci_virt_ep *ep);
|
||||||
|
void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
|
||||||
|
struct xhci_virt_device *virt_dev, bool drop_control_ep);
|
||||||
struct xhci_ring *xhci_dma_to_transfer_ring(
|
struct xhci_ring *xhci_dma_to_transfer_ring(
|
||||||
struct xhci_virt_ep *ep,
|
struct xhci_virt_ep *ep,
|
||||||
u64 address);
|
u64 address);
|
||||||
|
|
|
@ -2483,6 +2483,7 @@
|
||||||
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f
|
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f
|
||||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40
|
#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40
|
||||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41
|
#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41
|
||||||
|
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI 0x1e31
|
||||||
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN 0x1e40
|
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN 0x1e40
|
||||||
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX 0x1e5f
|
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX 0x1e5f
|
||||||
#define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN 0x2310
|
#define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN 0x2310
|
||||||
|
|
Loading…
Reference in a new issue