diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-25 06:23:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-25 06:23:15 -0400 |
commit | 1be025d3cb40cd295123af2c394f7229ef9b30ca (patch) | |
tree | 5dc14e1ea412cc7fdc3e563ad23187059fe8bfb5 /drivers/usb/host/xhci-hub.c | |
parent | 2d03423b2319cc854adeb28a03f65de5b5e0ab63 (diff) | |
parent | a2c76b83fdd763c826f38a55127ccf25708099ce (diff) |
Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (260 commits)
usb: renesas_usbhs: fixup inconsistent return from usbhs_pkt_push()
usb/isp1760: Allow to optionally trigger low-level chip reset via GPIOLIB.
USB: gadget: midi: memory leak in f_midi_bind_config()
USB: gadget: midi: fix range check in f_midi_out_open()
QE/FHCI: fixed the CONTROL bug
usb: renesas_usbhs: tidyup for smatch warnings
USB: Fix USB Kconfig dependency problem on 85xx/QoirQ platforms
EHCI: workaround for MosChip controller bug
usb: gadget: file_storage: fix race on unloading
USB: ftdi_sio.c: Use ftdi async_icount structure for TIOCMIWAIT, as in other drivers
USB: ftdi_sio.c:Fill MSR fields of the ftdi async_icount structure
USB: ftdi_sio.c: Fill LSR fields of the ftdi async_icount structure
USB: ftdi_sio.c:Fill TX field of the ftdi async_icount structure
USB: ftdi_sio.c: Fill the RX field of the ftdi async_icount structure
USB: ftdi_sio.c: Basic icount infrastructure for ftdi_sio
usb/isp1760: Let OF bindings depend on general CONFIG_OF instead of PPC_OF .
USB: ftdi_sio: Support TI/Luminary Micro Stellaris BD-ICDI Board
USB: Fix runtime wakeup on OHCI
xHCI/USB: Make xHCI driver have a BOS descriptor.
usb: gadget: add new usb gadget for ACM and mass storage
...
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 139 |
1 files changed, 89 insertions, 50 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 723f8231193d..431efe72b1f7 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -28,6 +28,25 @@ | |||
28 | #define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ | 28 | #define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ |
29 | PORT_RC | PORT_PLC | PORT_PE) | 29 | PORT_RC | PORT_PLC | PORT_PE) |
30 | 30 | ||
31 | /* usb 1.1 root hub device descriptor */ | ||
32 | static u8 usb_bos_descriptor [] = { | ||
33 | USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */ | ||
34 | USB_DT_BOS, /* __u8 bDescriptorType */ | ||
35 | 0x0F, 0x00, /* __le16 wTotalLength, 15 bytes */ | ||
36 | 0x1, /* __u8 bNumDeviceCaps */ | ||
37 | /* First device capability */ | ||
38 | USB_DT_USB_SS_CAP_SIZE, /* __u8 bLength, 10 bytes */ | ||
39 | USB_DT_DEVICE_CAPABILITY, /* Device Capability */ | ||
40 | USB_SS_CAP_TYPE, /* bDevCapabilityType, SUPERSPEED_USB */ | ||
41 | 0x00, /* bmAttributes, LTM off by default */ | ||
42 | USB_5GBPS_OPERATION, 0x00, /* wSpeedsSupported, 5Gbps only */ | ||
43 | 0x03, /* bFunctionalitySupport, | ||
44 | USB 3.0 speed only */ | ||
45 | 0x00, /* bU1DevExitLat, set later. */ | ||
46 | 0x00, 0x00 /* __le16 bU2DevExitLat, set later. */ | ||
47 | }; | ||
48 | |||
49 | |||
31 | static void xhci_common_hub_descriptor(struct xhci_hcd *xhci, | 50 | static void xhci_common_hub_descriptor(struct xhci_hcd *xhci, |
32 | struct usb_hub_descriptor *desc, int ports) | 51 | struct usb_hub_descriptor *desc, int ports) |
33 | { | 52 | { |
@@ -232,7 +251,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, | |||
232 | continue; | 251 | continue; |
233 | speed = xhci->devs[i]->udev->speed; | 252 | speed = xhci->devs[i]->udev->speed; |
234 | if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3)) | 253 | if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3)) |
235 | && xhci->devs[i]->port == port) { | 254 | && xhci->devs[i]->fake_port == port) { |
236 | slot_id = i; | 255 | slot_id = i; |
237 | break; | 256 | break; |
238 | } | 257 | } |
@@ -392,13 +411,39 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array) | |||
392 | return max_ports; | 411 | return max_ports; |
393 | } | 412 | } |
394 | 413 | ||
414 | void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, | ||
415 | int port_id, u32 link_state) | ||
416 | { | ||
417 | u32 temp; | ||
418 | |||
419 | temp = xhci_readl(xhci, port_array[port_id]); | ||
420 | temp = xhci_port_state_to_neutral(temp); | ||
421 | temp &= ~PORT_PLS_MASK; | ||
422 | temp |= PORT_LINK_STROBE | link_state; | ||
423 | xhci_writel(xhci, temp, port_array[port_id]); | ||
424 | } | ||
425 | |||
426 | /* Test and clear port RWC bit */ | ||
427 | void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, | ||
428 | int port_id, u32 port_bit) | ||
429 | { | ||
430 | u32 temp; | ||
431 | |||
432 | temp = xhci_readl(xhci, port_array[port_id]); | ||
433 | if (temp & port_bit) { | ||
434 | temp = xhci_port_state_to_neutral(temp); | ||
435 | temp |= port_bit; | ||
436 | xhci_writel(xhci, temp, port_array[port_id]); | ||
437 | } | ||
438 | } | ||
439 | |||
395 | int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | 440 | int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, |
396 | u16 wIndex, char *buf, u16 wLength) | 441 | u16 wIndex, char *buf, u16 wLength) |
397 | { | 442 | { |
398 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 443 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
399 | int max_ports; | 444 | int max_ports; |
400 | unsigned long flags; | 445 | unsigned long flags; |
401 | u32 temp, temp1, status; | 446 | u32 temp, status; |
402 | int retval = 0; | 447 | int retval = 0; |
403 | __le32 __iomem **port_array; | 448 | __le32 __iomem **port_array; |
404 | int slot_id; | 449 | int slot_id; |
@@ -429,6 +474,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
429 | xhci_hub_descriptor(hcd, xhci, | 474 | xhci_hub_descriptor(hcd, xhci, |
430 | (struct usb_hub_descriptor *) buf); | 475 | (struct usb_hub_descriptor *) buf); |
431 | break; | 476 | break; |
477 | case DeviceRequest | USB_REQ_GET_DESCRIPTOR: | ||
478 | if ((wValue & 0xff00) != (USB_DT_BOS << 8)) | ||
479 | goto error; | ||
480 | |||
481 | if (hcd->speed != HCD_USB3) | ||
482 | goto error; | ||
483 | |||
484 | memcpy(buf, &usb_bos_descriptor, | ||
485 | USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); | ||
486 | temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); | ||
487 | buf[12] = HCS_U1_LATENCY(temp); | ||
488 | put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); | ||
489 | |||
490 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
491 | return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; | ||
432 | case GetPortStatus: | 492 | case GetPortStatus: |
433 | if (!wIndex || wIndex > max_ports) | 493 | if (!wIndex || wIndex > max_ports) |
434 | goto error; | 494 | goto error; |
@@ -472,11 +532,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
472 | xhci_dbg(xhci, "Resume USB2 port %d\n", | 532 | xhci_dbg(xhci, "Resume USB2 port %d\n", |
473 | wIndex + 1); | 533 | wIndex + 1); |
474 | bus_state->resume_done[wIndex] = 0; | 534 | bus_state->resume_done[wIndex] = 0; |
475 | temp1 = xhci_port_state_to_neutral(temp); | 535 | xhci_set_link_state(xhci, port_array, wIndex, |
476 | temp1 &= ~PORT_PLS_MASK; | 536 | XDEV_U0); |
477 | temp1 |= PORT_LINK_STROBE | XDEV_U0; | ||
478 | xhci_writel(xhci, temp1, port_array[wIndex]); | ||
479 | |||
480 | xhci_dbg(xhci, "set port %d resume\n", | 537 | xhci_dbg(xhci, "set port %d resume\n", |
481 | wIndex + 1); | 538 | wIndex + 1); |
482 | slot_id = xhci_find_slot_id_by_port(hcd, xhci, | 539 | slot_id = xhci_find_slot_id_by_port(hcd, xhci, |
@@ -551,10 +608,19 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
551 | switch (wValue) { | 608 | switch (wValue) { |
552 | case USB_PORT_FEAT_SUSPEND: | 609 | case USB_PORT_FEAT_SUSPEND: |
553 | temp = xhci_readl(xhci, port_array[wIndex]); | 610 | temp = xhci_readl(xhci, port_array[wIndex]); |
611 | if ((temp & PORT_PLS_MASK) != XDEV_U0) { | ||
612 | /* Resume the port to U0 first */ | ||
613 | xhci_set_link_state(xhci, port_array, wIndex, | ||
614 | XDEV_U0); | ||
615 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
616 | msleep(10); | ||
617 | spin_lock_irqsave(&xhci->lock, flags); | ||
618 | } | ||
554 | /* In spec software should not attempt to suspend | 619 | /* In spec software should not attempt to suspend |
555 | * a port unless the port reports that it is in the | 620 | * a port unless the port reports that it is in the |
556 | * enabled (PED = ‘1’,PLS < ‘3’) state. | 621 | * enabled (PED = ‘1’,PLS < ‘3’) state. |
557 | */ | 622 | */ |
623 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
558 | if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) | 624 | if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) |
559 | || (temp & PORT_PLS_MASK) >= XDEV_U3) { | 625 | || (temp & PORT_PLS_MASK) >= XDEV_U3) { |
560 | xhci_warn(xhci, "USB core suspending device " | 626 | xhci_warn(xhci, "USB core suspending device " |
@@ -573,10 +639,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
573 | xhci_stop_device(xhci, slot_id, 1); | 639 | xhci_stop_device(xhci, slot_id, 1); |
574 | spin_lock_irqsave(&xhci->lock, flags); | 640 | spin_lock_irqsave(&xhci->lock, flags); |
575 | 641 | ||
576 | temp = xhci_port_state_to_neutral(temp); | 642 | xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3); |
577 | temp &= ~PORT_PLS_MASK; | ||
578 | temp |= PORT_LINK_STROBE | XDEV_U3; | ||
579 | xhci_writel(xhci, temp, port_array[wIndex]); | ||
580 | 643 | ||
581 | spin_unlock_irqrestore(&xhci->lock, flags); | 644 | spin_unlock_irqrestore(&xhci->lock, flags); |
582 | msleep(10); /* wait device to enter */ | 645 | msleep(10); /* wait device to enter */ |
@@ -610,10 +673,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
610 | } | 673 | } |
611 | } | 674 | } |
612 | 675 | ||
613 | temp = xhci_port_state_to_neutral(temp); | 676 | xhci_set_link_state(xhci, port_array, wIndex, |
614 | temp &= ~PORT_PLS_MASK; | 677 | link_state); |
615 | temp |= PORT_LINK_STROBE | link_state; | ||
616 | xhci_writel(xhci, temp, port_array[wIndex]); | ||
617 | 678 | ||
618 | spin_unlock_irqrestore(&xhci->lock, flags); | 679 | spin_unlock_irqrestore(&xhci->lock, flags); |
619 | msleep(20); /* wait device to enter */ | 680 | msleep(20); /* wait device to enter */ |
@@ -677,24 +738,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
677 | if ((temp & PORT_PE) == 0) | 738 | if ((temp & PORT_PE) == 0) |
678 | goto error; | 739 | goto error; |
679 | 740 | ||
680 | temp = xhci_port_state_to_neutral(temp); | 741 | xhci_set_link_state(xhci, port_array, wIndex, |
681 | temp &= ~PORT_PLS_MASK; | 742 | XDEV_RESUME); |
682 | temp |= PORT_LINK_STROBE | XDEV_RESUME; | 743 | spin_unlock_irqrestore(&xhci->lock, flags); |
683 | xhci_writel(xhci, temp, | ||
684 | port_array[wIndex]); | ||
685 | |||
686 | spin_unlock_irqrestore(&xhci->lock, | ||
687 | flags); | ||
688 | msleep(20); | 744 | msleep(20); |
689 | spin_lock_irqsave(&xhci->lock, flags); | 745 | spin_lock_irqsave(&xhci->lock, flags); |
690 | 746 | xhci_set_link_state(xhci, port_array, wIndex, | |
691 | temp = xhci_readl(xhci, | 747 | XDEV_U0); |
692 | port_array[wIndex]); | ||
693 | temp = xhci_port_state_to_neutral(temp); | ||
694 | temp &= ~PORT_PLS_MASK; | ||
695 | temp |= PORT_LINK_STROBE | XDEV_U0; | ||
696 | xhci_writel(xhci, temp, | ||
697 | port_array[wIndex]); | ||
698 | } | 748 | } |
699 | bus_state->port_c_suspend |= 1 << wIndex; | 749 | bus_state->port_c_suspend |= 1 << wIndex; |
700 | 750 | ||
@@ -910,25 +960,18 @@ int xhci_bus_resume(struct usb_hcd *hcd) | |||
910 | if (test_bit(port_index, &bus_state->bus_suspended) && | 960 | if (test_bit(port_index, &bus_state->bus_suspended) && |
911 | (temp & PORT_PLS_MASK)) { | 961 | (temp & PORT_PLS_MASK)) { |
912 | if (DEV_SUPERSPEED(temp)) { | 962 | if (DEV_SUPERSPEED(temp)) { |
913 | temp = xhci_port_state_to_neutral(temp); | 963 | xhci_set_link_state(xhci, port_array, |
914 | temp &= ~PORT_PLS_MASK; | 964 | port_index, XDEV_U0); |
915 | temp |= PORT_LINK_STROBE | XDEV_U0; | ||
916 | xhci_writel(xhci, temp, port_array[port_index]); | ||
917 | } else { | 965 | } else { |
918 | temp = xhci_port_state_to_neutral(temp); | 966 | xhci_set_link_state(xhci, port_array, |
919 | temp &= ~PORT_PLS_MASK; | 967 | port_index, XDEV_RESUME); |
920 | temp |= PORT_LINK_STROBE | XDEV_RESUME; | ||
921 | xhci_writel(xhci, temp, port_array[port_index]); | ||
922 | 968 | ||
923 | spin_unlock_irqrestore(&xhci->lock, flags); | 969 | spin_unlock_irqrestore(&xhci->lock, flags); |
924 | msleep(20); | 970 | msleep(20); |
925 | spin_lock_irqsave(&xhci->lock, flags); | 971 | spin_lock_irqsave(&xhci->lock, flags); |
926 | 972 | ||
927 | temp = xhci_readl(xhci, port_array[port_index]); | 973 | xhci_set_link_state(xhci, port_array, |
928 | temp = xhci_port_state_to_neutral(temp); | 974 | port_index, XDEV_U0); |
929 | temp &= ~PORT_PLS_MASK; | ||
930 | temp |= PORT_LINK_STROBE | XDEV_U0; | ||
931 | xhci_writel(xhci, temp, port_array[port_index]); | ||
932 | } | 975 | } |
933 | /* wait for the port to enter U0 and report port link | 976 | /* wait for the port to enter U0 and report port link |
934 | * state change. | 977 | * state change. |
@@ -938,12 +981,8 @@ int xhci_bus_resume(struct usb_hcd *hcd) | |||
938 | spin_lock_irqsave(&xhci->lock, flags); | 981 | spin_lock_irqsave(&xhci->lock, flags); |
939 | 982 | ||
940 | /* Clear PLC */ | 983 | /* Clear PLC */ |
941 | temp = xhci_readl(xhci, port_array[port_index]); | 984 | xhci_test_and_clear_bit(xhci, port_array, port_index, |
942 | if (temp & PORT_PLC) { | 985 | PORT_PLC); |
943 | temp = xhci_port_state_to_neutral(temp); | ||
944 | temp |= PORT_PLC; | ||
945 | xhci_writel(xhci, temp, port_array[port_index]); | ||
946 | } | ||
947 | 986 | ||
948 | slot_id = xhci_find_slot_id_by_port(hcd, | 987 | slot_id = xhci_find_slot_id_by_port(hcd, |
949 | xhci, port_index + 1); | 988 | xhci, port_index + 1); |