Misc xHCI fixes for 3.9
Hi Greg, Here's a couple of fixes for the xHCI driver. Three patches are nothing major: build warning fix, macro field width fix, and removing some unnecessary log spam. The only interesting thing here is Tianyu's two patches to fix the USB port connection type discovery, for the USB port power off mechanism. This adds new USB host API, but as discussed, it's necessary to avoid powering off the wrong USB port. It's not marked for backport to stable kernels, since the sysfs mechanism to manually power off a port didn't go in until 3.9. I've smoke tested these, including system suspend, USB device suspend, and rocking out in my cube with a pair of USB headphones. They look fine to me. Hibernate is currently broken on my system, due to some nouveau MMIO read faults. I'll report that separately. Sarah Sharp -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJRUgiCAAoJEBMGWMLi1Gc5e5EQAIdnyu6hE0tfv08wHF/MX6f6 Rz2R9XrF2k5m7P0ILa3p1KLNCfOAXpEsnHZZKld+Idr3anNvSU9PlJ86DD3PlbMp OwFlMFO7mYIFoM9vGdTE91FQklhb2e6FOd6Fsev7MygZB6HofPeSB+4V7bRbeH9Z n6jZxwT8MUenixBUETilPBWvOwimloZzXa9C5gl/jYgUNcsEgcSZXGixO82hvZvq pPrC6ZyWkW2Nzpme6cQ6dWsAHWvy1vwXZe0RYxmRbXa/no+vIAEYG720BQou/xjc 89duRZNQFr+7z2MMkuMrqSVncqnt94Tmvf9CS4JKBdUyXpdeoxOMS+ZZM7w7EuFX uCT+p7oFmDGUXAdQPcpD49AjjGRgPFmTTKpuv4Mxdo95ZhurdEAbjeL3A9KjYM3P M5HH1ZZqJOd35EJvjT01a5/d5aauk+Hre65D7Lr4anJAlE/BgyKwJ3yug0RaoCeR fmQnlp/wcMxG0yU5mWfA2tJCOTQKZcGNX+ZxqL1s8Ru4o9SlBZ094ai8VK1Bdur2 u1Z3JwPexoowjH8azdndHlDN1/ehdOjY7j+kmcRj+IMP4SdLdYON+oN4djh738h6 bpkp0LyQMVBdT/YsAABYlqbbPpWtk2JmNf19V16rUXxpatZ5gOfhlBxd3lQxqHel KVm6tlGgSy+iGR3scEib =pF5D -----END PGP SIGNATURE----- Merge tag 'for-usb-linus-2013-03-26' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-linus Misc xHCI fixes for 3.9 Hi Greg, Here's a couple of fixes for the xHCI driver. Three patches are nothing major: build warning fix, macro field width fix, and removing some unnecessary log spam. The only interesting thing here is Tianyu's two patches to fix the USB port connection type discovery, for the USB port power off mechanism. This adds new USB host API, but as discussed, it's necessary to avoid powering off the wrong USB port. It's not marked for backport to stable kernels, since the sysfs mechanism to manually power off a port didn't go in until 3.9. I've smoke tested these, including system suspend, USB device suspend, and rocking out in my cube with a pair of USB headphones. They look fine to me. Hibernate is currently broken on my system, due to some nouveau MMIO read faults. I'll report that separately. Sarah Sharp
This commit is contained in:
commit
d78658d45e
8 changed files with 88 additions and 55 deletions
|
@ -2412,6 +2412,14 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
|
||||
|
||||
int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1)
|
||||
{
|
||||
if (!hcd->driver->find_raw_port_number)
|
||||
return port1;
|
||||
|
||||
return hcd->driver->find_raw_port_number(hcd, port1);
|
||||
}
|
||||
|
||||
static int usb_hcd_request_irqs(struct usb_hcd *hcd,
|
||||
unsigned int irqnum, unsigned long irqflags)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
|
||||
#include "usb.h"
|
||||
|
@ -188,8 +189,13 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
|
|||
* connected to.
|
||||
*/
|
||||
if (!udev->parent) {
|
||||
*handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev),
|
||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||
int raw_port_num;
|
||||
|
||||
raw_port_num = usb_hcd_find_raw_port_number(hcd,
|
||||
port_num);
|
||||
*handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev),
|
||||
raw_port_num);
|
||||
if (!*handle)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
|
|
|
@ -1022,44 +1022,24 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
|
|||
* is attached to (or the roothub port its ancestor hub is attached to). All we
|
||||
* know is the index of that port under either the USB 2.0 or the USB 3.0
|
||||
* roothub, but that doesn't give us the real index into the HW port status
|
||||
* registers. Scan through the xHCI roothub port array, looking for the Nth
|
||||
* entry of the correct port speed. Return the port number of that entry.
|
||||
* registers. Call xhci_find_raw_port_number() to get real index.
|
||||
*/
|
||||
static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
|
||||
struct usb_device *udev)
|
||||
{
|
||||
struct usb_device *top_dev;
|
||||
unsigned int num_similar_speed_ports;
|
||||
unsigned int faked_port_num;
|
||||
int i;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
if (udev->speed == USB_SPEED_SUPER)
|
||||
hcd = xhci->shared_hcd;
|
||||
else
|
||||
hcd = xhci->main_hcd;
|
||||
|
||||
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
|
||||
top_dev = top_dev->parent)
|
||||
/* Found device below root hub */;
|
||||
faked_port_num = top_dev->portnum;
|
||||
for (i = 0, num_similar_speed_ports = 0;
|
||||
i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
|
||||
u8 port_speed = xhci->port_array[i];
|
||||
|
||||
/*
|
||||
* Skip ports that don't have known speeds, or have duplicate
|
||||
* Extended Capabilities port speed entries.
|
||||
*/
|
||||
if (port_speed == 0 || port_speed == DUPLICATE_ENTRY)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* USB 3.0 ports are always under a USB 3.0 hub. USB 2.0 and
|
||||
* 1.1 ports are under the USB 2.0 hub. If the port speed
|
||||
* matches the device speed, it's a similar speed port.
|
||||
*/
|
||||
if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER))
|
||||
num_similar_speed_ports++;
|
||||
if (num_similar_speed_ports == faked_port_num)
|
||||
/* Roothub ports are numbered from 1 to N */
|
||||
return i+1;
|
||||
}
|
||||
return 0;
|
||||
return xhci_find_raw_port_number(hcd, top_dev->portnum);
|
||||
}
|
||||
|
||||
/* Setup an xHCI virtual device for a Set Address command */
|
||||
|
|
|
@ -313,6 +313,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
|
|||
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
|
||||
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
|
||||
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
|
||||
.find_raw_port_number = xhci_find_raw_port_number,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
|
@ -1599,14 +1599,20 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
if ((port_id <= 0) || (port_id > max_ports)) {
|
||||
xhci_warn(xhci, "Invalid port id %d\n", port_id);
|
||||
bogus_port_status = true;
|
||||
goto cleanup;
|
||||
inc_deq(xhci, xhci->event_ring);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Figure out which usb_hcd this port is attached to:
|
||||
* is it a USB 3.0 port or a USB 2.0/1.1 port?
|
||||
*/
|
||||
major_revision = xhci->port_array[port_id - 1];
|
||||
|
||||
/* Find the right roothub. */
|
||||
hcd = xhci_to_hcd(xhci);
|
||||
if ((major_revision == 0x03) != (hcd->speed == HCD_USB3))
|
||||
hcd = xhci->shared_hcd;
|
||||
|
||||
if (major_revision == 0) {
|
||||
xhci_warn(xhci, "Event for port %u not in "
|
||||
"Extended Capabilities, ignoring.\n",
|
||||
|
@ -1629,10 +1635,6 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
* into the index into the ports on the correct split roothub, and the
|
||||
* correct bus_state structure.
|
||||
*/
|
||||
/* Find the right roothub. */
|
||||
hcd = xhci_to_hcd(xhci);
|
||||
if ((major_revision == 0x03) != (hcd->speed == HCD_USB3))
|
||||
hcd = xhci->shared_hcd;
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
if (hcd->speed == HCD_USB3)
|
||||
port_array = xhci->usb3_ports;
|
||||
|
@ -2027,8 +2029,8 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
if (event_trb != ep_ring->dequeue &&
|
||||
event_trb != td->last_trb)
|
||||
td->urb->actual_length =
|
||||
td->urb->transfer_buffer_length
|
||||
- TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
td->urb->transfer_buffer_length -
|
||||
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
else
|
||||
td->urb->actual_length = 0;
|
||||
|
||||
|
@ -2060,7 +2062,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
/* Maybe the event was for the data stage? */
|
||||
td->urb->actual_length =
|
||||
td->urb->transfer_buffer_length -
|
||||
TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
xhci_dbg(xhci, "Waiting for status "
|
||||
"stage event\n");
|
||||
return 0;
|
||||
|
@ -2096,7 +2098,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
/* handle completion code */
|
||||
switch (trb_comp_code) {
|
||||
case COMP_SUCCESS:
|
||||
if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
|
||||
if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
|
||||
frame->status = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -2141,7 +2143,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
|
||||
}
|
||||
len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
|
||||
TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
|
||||
if (trb_comp_code != COMP_STOP_INVAL) {
|
||||
frame->actual_length = len;
|
||||
|
@ -2199,7 +2201,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
case COMP_SUCCESS:
|
||||
/* Double check that the HW transferred everything. */
|
||||
if (event_trb != td->last_trb ||
|
||||
TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
|
||||
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
|
||||
xhci_warn(xhci, "WARN Successful completion "
|
||||
"on short TX\n");
|
||||
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
|
||||
|
@ -2227,18 +2229,18 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
"%d bytes untransferred\n",
|
||||
td->urb->ep->desc.bEndpointAddress,
|
||||
td->urb->transfer_buffer_length,
|
||||
TRB_LEN(le32_to_cpu(event->transfer_len)));
|
||||
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));
|
||||
/* Fast path - was this the last TRB in the TD for this URB? */
|
||||
if (event_trb == td->last_trb) {
|
||||
if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
|
||||
if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
|
||||
td->urb->actual_length =
|
||||
td->urb->transfer_buffer_length -
|
||||
TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
if (td->urb->transfer_buffer_length <
|
||||
td->urb->actual_length) {
|
||||
xhci_warn(xhci, "HC gave bad length "
|
||||
"of %d bytes left\n",
|
||||
TRB_LEN(le32_to_cpu(event->transfer_len)));
|
||||
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));
|
||||
td->urb->actual_length = 0;
|
||||
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
|
||||
*status = -EREMOTEIO;
|
||||
|
@ -2280,7 +2282,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
if (trb_comp_code != COMP_STOP_INVAL)
|
||||
td->urb->actual_length +=
|
||||
TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
|
||||
TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
}
|
||||
|
||||
return finish_td(xhci, td, event_trb, event, ep, status, false);
|
||||
|
@ -2368,7 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
* transfer type
|
||||
*/
|
||||
case COMP_SUCCESS:
|
||||
if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
|
||||
if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
|
||||
break;
|
||||
if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
|
||||
trb_comp_code = COMP_SHORT_TX;
|
||||
|
@ -2461,14 +2463,21 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|||
* TD list.
|
||||
*/
|
||||
if (list_empty(&ep_ring->td_list)) {
|
||||
xhci_warn(xhci, "WARN Event TRB for slot %d ep %d "
|
||||
"with no TDs queued?\n",
|
||||
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
|
||||
ep_index);
|
||||
xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
|
||||
(le32_to_cpu(event->flags) &
|
||||
TRB_TYPE_BITMASK)>>10);
|
||||
xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
|
||||
/*
|
||||
* A stopped endpoint may generate an extra completion
|
||||
* event if the device was suspended. Don't print
|
||||
* warnings.
|
||||
*/
|
||||
if (!(trb_comp_code == COMP_STOP ||
|
||||
trb_comp_code == COMP_STOP_INVAL)) {
|
||||
xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",
|
||||
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
|
||||
ep_index);
|
||||
xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
|
||||
(le32_to_cpu(event->flags) &
|
||||
TRB_TYPE_BITMASK)>>10);
|
||||
xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
|
||||
}
|
||||
if (ep->skip) {
|
||||
ep->skip = false;
|
||||
xhci_dbg(xhci, "td_list is empty while skip "
|
||||
|
|
|
@ -3779,6 +3779,28 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transfer the port index into real index in the HW port status
|
||||
* registers. Caculate offset between the port's PORTSC register
|
||||
* and port status base. Divide the number of per port register
|
||||
* to get the real index. The raw port number bases 1.
|
||||
*/
|
||||
int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
__le32 __iomem *base_addr = &xhci->op_regs->port_status_base;
|
||||
__le32 __iomem *addr;
|
||||
int raw_port;
|
||||
|
||||
if (hcd->speed != HCD_USB3)
|
||||
addr = xhci->usb2_ports[port1 - 1];
|
||||
else
|
||||
addr = xhci->usb3_ports[port1 - 1];
|
||||
|
||||
raw_port = (addr - base_addr)/NUM_PORT_REGS + 1;
|
||||
return raw_port;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
|
||||
/* BESL to HIRD Encoding array for USB2 LPM */
|
||||
|
|
|
@ -972,6 +972,10 @@ struct xhci_transfer_event {
|
|||
__le32 flags;
|
||||
};
|
||||
|
||||
/* Transfer event TRB length bit mask */
|
||||
/* bits 0:23 */
|
||||
#define EVENT_TRB_LEN(p) ((p) & 0xffffff)
|
||||
|
||||
/** Transfer Event bit fields **/
|
||||
#define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f)
|
||||
|
||||
|
@ -1829,6 +1833,7 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
|||
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
|
||||
char *buf, u16 wLength);
|
||||
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
|
||||
int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int xhci_bus_suspend(struct usb_hcd *hcd);
|
||||
|
|
|
@ -357,6 +357,7 @@ struct hc_driver {
|
|||
*/
|
||||
int (*disable_usb3_lpm_timeout)(struct usb_hcd *,
|
||||
struct usb_device *, enum usb3_link_state state);
|
||||
int (*find_raw_port_number)(struct usb_hcd *, int);
|
||||
};
|
||||
|
||||
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
|
||||
|
@ -396,6 +397,7 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd);
|
|||
extern int usb_add_hcd(struct usb_hcd *hcd,
|
||||
unsigned int irqnum, unsigned long irqflags);
|
||||
extern void usb_remove_hcd(struct usb_hcd *hcd);
|
||||
extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
|
||||
|
||||
struct platform_device;
|
||||
extern void usb_hcd_platform_shutdown(struct platform_device *dev);
|
||||
|
|
Loading…
Reference in a new issue