Merge branch 'for-usb-linus' of git+ssh://master.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-linus
* 'for-usb-linus' of git+ssh://master.kernel.org/pub/scm/linux/kernel/git/sarah/xhci: USB: Fix up URB error codes to reflect implementation. xhci: Always set urb->status to zero for isoc endpoints. xhci: Add reset on resume quirk for asrock p67 host xHCI 1.0: Incompatible Device Error xHCI 1.0: Force Stopped Event(FSE) xhci: Don't warn about zeroed bMaxBurst descriptor field. USB: Free bandwidth when usb_disable_device is called. xhci: Reject double add of active endpoints.
This commit is contained in:
Коммит
95a2424ff9
|
@ -76,6 +76,13 @@ A transfer's actual_length may be positive even when an error has been
|
|||
reported. That's because transfers often involve several packets, so that
|
||||
one or more packets could finish before an error stops further endpoint I/O.
|
||||
|
||||
For isochronous URBs, the urb status value is non-zero only if the URB is
|
||||
unlinked, the device is removed, the host controller is disabled, or the total
|
||||
transferred length is less than the requested length and the URB_SHORT_NOT_OK
|
||||
flag is set. Completion handlers for isochronous URBs should only see
|
||||
urb->status set to zero, -ENOENT, -ECONNRESET, -ESHUTDOWN, or -EREMOTEIO.
|
||||
Individual frame descriptor status fields may report more status codes.
|
||||
|
||||
|
||||
0 Transfer completed successfully
|
||||
|
||||
|
@ -132,7 +139,7 @@ one or more packets could finish before an error stops further endpoint I/O.
|
|||
device removal events immediately.
|
||||
|
||||
-EXDEV ISO transfer only partially completed
|
||||
look at individual frame status for details
|
||||
(only set in iso_frame_desc[n].status, not urb->status)
|
||||
|
||||
-EINVAL ISO madness, if this happens: Log off and go home
|
||||
|
||||
|
|
|
@ -1634,6 +1634,7 @@ void usb_disconnect(struct usb_device **pdev)
|
|||
{
|
||||
struct usb_device *udev = *pdev;
|
||||
int i;
|
||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||
|
||||
if (!udev) {
|
||||
pr_debug ("%s nodev\n", __func__);
|
||||
|
@ -1661,7 +1662,9 @@ void usb_disconnect(struct usb_device **pdev)
|
|||
* so that the hardware is now fully quiesced.
|
||||
*/
|
||||
dev_dbg (&udev->dev, "unregistering device\n");
|
||||
mutex_lock(hcd->bandwidth_mutex);
|
||||
usb_disable_device(udev, 0);
|
||||
mutex_unlock(hcd->bandwidth_mutex);
|
||||
usb_hcd_synchronize_unlinks(udev);
|
||||
|
||||
usb_remove_ep_devs(&udev->ep0);
|
||||
|
|
|
@ -1135,10 +1135,13 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf,
|
|||
* Deallocates hcd/hardware state for the endpoints (nuking all or most
|
||||
* pending urbs) and usbcore state for the interfaces, so that usbcore
|
||||
* must usb_set_configuration() before any interfaces could be used.
|
||||
*
|
||||
* Must be called with hcd->bandwidth_mutex held.
|
||||
*/
|
||||
void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
||||
{
|
||||
int i;
|
||||
struct usb_hcd *hcd = bus_to_hcd(dev->bus);
|
||||
|
||||
/* getting rid of interfaces will disconnect
|
||||
* any drivers bound to them (a key side effect)
|
||||
|
@ -1172,6 +1175,16 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
|||
|
||||
dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
|
||||
skip_ep0 ? "non-ep0" : "all");
|
||||
if (hcd->driver->check_bandwidth) {
|
||||
/* First pass: Cancel URBs, leave endpoint pointers intact. */
|
||||
for (i = skip_ep0; i < 16; ++i) {
|
||||
usb_disable_endpoint(dev, i, false);
|
||||
usb_disable_endpoint(dev, i + USB_DIR_IN, false);
|
||||
}
|
||||
/* Remove endpoints from the host controller internal state */
|
||||
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
|
||||
/* Second pass: remove endpoint pointers */
|
||||
}
|
||||
for (i = skip_ep0; i < 16; ++i) {
|
||||
usb_disable_endpoint(dev, i, true);
|
||||
usb_disable_endpoint(dev, i + USB_DIR_IN, true);
|
||||
|
@ -1727,6 +1740,7 @@ free_interfaces:
|
|||
/* if it's already configured, clear out old state first.
|
||||
* getting rid of old interfaces means unbinding their drivers.
|
||||
*/
|
||||
mutex_lock(hcd->bandwidth_mutex);
|
||||
if (dev->state != USB_STATE_ADDRESS)
|
||||
usb_disable_device(dev, 1); /* Skip ep0 */
|
||||
|
||||
|
@ -1739,7 +1753,6 @@ free_interfaces:
|
|||
* host controller will not allow submissions to dropped endpoints. If
|
||||
* this call fails, the device state is unchanged.
|
||||
*/
|
||||
mutex_lock(hcd->bandwidth_mutex);
|
||||
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(hcd->bandwidth_mutex);
|
||||
|
|
|
@ -1215,8 +1215,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
|||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
|
||||
/* dig out max burst from ep companion desc */
|
||||
max_packet = ep->ss_ep_comp.bMaxBurst;
|
||||
if (!max_packet)
|
||||
xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n");
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet));
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
|
||||
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
|
||||
|
||||
#define PCI_VENDOR_ID_ETRON 0x1b6f
|
||||
#define PCI_DEVICE_ID_ASROCK_P67 0x7023
|
||||
|
||||
static const char hcd_name[] = "xhci_hcd";
|
||||
|
||||
/* called after powerup, by probe or system-pm "wakeup" */
|
||||
|
@ -134,6 +137,11 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
|||
xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
|
||||
xhci->limit_active_eps = 64;
|
||||
}
|
||||
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
|
||||
pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
|
||||
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||||
xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
|
||||
}
|
||||
|
||||
/* Make sure the HC is halted. */
|
||||
retval = xhci_halt(xhci);
|
||||
|
|
|
@ -1733,6 +1733,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
frame->status = -EOVERFLOW;
|
||||
skip_td = true;
|
||||
break;
|
||||
case COMP_DEV_ERR:
|
||||
case COMP_STALL:
|
||||
frame->status = -EPROTO;
|
||||
skip_td = true;
|
||||
|
@ -1767,9 +1768,6 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
}
|
||||
}
|
||||
|
||||
if ((idx == urb_priv->length - 1) && *status == -EINPROGRESS)
|
||||
*status = 0;
|
||||
|
||||
return finish_td(xhci, td, event_trb, event, ep, status, false);
|
||||
}
|
||||
|
||||
|
@ -1787,8 +1785,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
idx = urb_priv->td_cnt;
|
||||
frame = &td->urb->iso_frame_desc[idx];
|
||||
|
||||
/* The transfer is partly done */
|
||||
*status = -EXDEV;
|
||||
/* The transfer is partly done. */
|
||||
frame->status = -EXDEV;
|
||||
|
||||
/* calc actual length */
|
||||
|
@ -2016,6 +2013,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
|
||||
ep_index);
|
||||
goto cleanup;
|
||||
case COMP_DEV_ERR:
|
||||
xhci_warn(xhci, "WARN: detect an incompatible device");
|
||||
status = -EPROTO;
|
||||
break;
|
||||
case COMP_MISSED_INT:
|
||||
/*
|
||||
* When encounter missed service error, one or more isoc tds
|
||||
|
@ -2063,6 +2064,20 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
/* Is this a TRB in the currently executing TD? */
|
||||
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
|
||||
td->last_trb, event_dma);
|
||||
|
||||
/*
|
||||
* Skip the Force Stopped Event. The event_trb(event_dma) of FSE
|
||||
* is not in the current TD pointed by ep_ring->dequeue because
|
||||
* that the hardware dequeue pointer still at the previous TRB
|
||||
* of the current TD. The previous TRB maybe a Link TD or the
|
||||
* last TRB of the previous TD. The command completion handle
|
||||
* will take care the rest.
|
||||
*/
|
||||
if (!event_seg && trb_comp_code == COMP_STOP_INVAL) {
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!event_seg) {
|
||||
if (!ep->skip ||
|
||||
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
|
||||
|
@ -2158,6 +2173,11 @@ cleanup:
|
|||
urb->transfer_buffer_length,
|
||||
status);
|
||||
spin_unlock(&xhci->lock);
|
||||
/* EHCI, UHCI, and OHCI always unconditionally set the
|
||||
* urb->status of an isochronous endpoint to 0.
|
||||
*/
|
||||
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
|
||||
status = 0;
|
||||
usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status);
|
||||
spin_lock(&xhci->lock);
|
||||
}
|
||||
|
|
|
@ -759,6 +759,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||
msleep(100);
|
||||
|
||||
spin_lock_irq(&xhci->lock);
|
||||
if (xhci->quirks & XHCI_RESET_ON_RESUME)
|
||||
hibernated = true;
|
||||
|
||||
if (!hibernated) {
|
||||
/* step 1: restore register */
|
||||
|
@ -1401,6 +1403,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
u32 added_ctxs;
|
||||
unsigned int last_ctx;
|
||||
u32 new_add_flags, new_drop_flags, new_slot_info;
|
||||
struct xhci_virt_device *virt_dev;
|
||||
int ret = 0;
|
||||
|
||||
ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
|
||||
|
@ -1425,11 +1428,25 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
|
||||
out_ctx = xhci->devs[udev->slot_id]->out_ctx;
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
in_ctx = virt_dev->in_ctx;
|
||||
out_ctx = virt_dev->out_ctx;
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
||||
ep_index = xhci_get_endpoint_index(&ep->desc);
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
|
||||
|
||||
/* If this endpoint is already in use, and the upper layers are trying
|
||||
* to add it again without dropping it, reject the addition.
|
||||
*/
|
||||
if (virt_dev->eps[ep_index].ring &&
|
||||
!(le32_to_cpu(ctrl_ctx->drop_flags) &
|
||||
xhci_get_endpoint_flag(&ep->desc))) {
|
||||
xhci_warn(xhci, "Trying to add endpoint 0x%x "
|
||||
"without dropping it.\n",
|
||||
(unsigned int) ep->desc.bEndpointAddress);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If the HCD has already noted the endpoint is enabled,
|
||||
* ignore this request.
|
||||
*/
|
||||
|
@ -1445,8 +1462,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
* process context, not interrupt context (or so documenation
|
||||
* for usb_set_interface() and usb_set_configuration() claim).
|
||||
*/
|
||||
if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id],
|
||||
udev, ep, GFP_NOIO) < 0) {
|
||||
if (xhci_endpoint_init(xhci, virt_dev, udev, ep, GFP_NOIO) < 0) {
|
||||
dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
|
||||
__func__, ep->desc.bEndpointAddress);
|
||||
return -ENOMEM;
|
||||
|
@ -1537,6 +1553,11 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
|
|||
"and endpoint is not disabled.\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case COMP_DEV_ERR:
|
||||
dev_warn(&udev->dev, "ERROR: Incompatible device for endpoint "
|
||||
"configure command.\n");
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
case COMP_SUCCESS:
|
||||
dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
|
||||
ret = 0;
|
||||
|
@ -1571,6 +1592,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
|
|||
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case COMP_DEV_ERR:
|
||||
dev_warn(&udev->dev, "ERROR: Incompatible device for evaluate "
|
||||
"context command.\n");
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
case COMP_MEL_ERR:
|
||||
/* Max Exit Latency too large error */
|
||||
dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n");
|
||||
|
@ -2853,6 +2879,11 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
dev_warn(&udev->dev, "Device not responding to set address.\n");
|
||||
ret = -EPROTO;
|
||||
break;
|
||||
case COMP_DEV_ERR:
|
||||
dev_warn(&udev->dev, "ERROR: Incompatible device for address "
|
||||
"device command.\n");
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
case COMP_SUCCESS:
|
||||
xhci_dbg(xhci, "Successful Address Device command\n");
|
||||
break;
|
||||
|
|
|
@ -874,6 +874,8 @@ struct xhci_transfer_event {
|
|||
#define COMP_PING_ERR 20
|
||||
/* Event Ring is full */
|
||||
#define COMP_ER_FULL 21
|
||||
/* Incompatible Device Error */
|
||||
#define COMP_DEV_ERR 22
|
||||
/* Missed Service Error - HC couldn't service an isoc ep within interval */
|
||||
#define COMP_MISSED_INT 23
|
||||
/* Successfully stopped command ring */
|
||||
|
@ -1308,6 +1310,7 @@ struct xhci_hcd {
|
|||
*/
|
||||
#define XHCI_EP_LIMIT_QUIRK (1 << 5)
|
||||
#define XHCI_BROKEN_MSI (1 << 6)
|
||||
#define XHCI_RESET_ON_RESUME (1 << 7)
|
||||
unsigned int num_active_eps;
|
||||
unsigned int limit_active_eps;
|
||||
/* There are two roothubs to keep track of bus suspend info for */
|
||||
|
|
Загрузка…
Ссылка в новой задаче