mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 05:39:54 -04:00
Merge "usb: host: xhci: Change L1 timeout default to 128us"
This commit is contained in:
commit
68ab595cfd
5 changed files with 345 additions and 28 deletions
|
|
@ -8,7 +8,7 @@
|
|||
* Some code borrowed from the Linux EHCI driver.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
|
@ -1065,6 +1065,151 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|||
return status;
|
||||
}
|
||||
|
||||
static void xhci_single_step_completion(struct urb *urb)
|
||||
{
|
||||
struct completion *done = urb->context;
|
||||
|
||||
complete(done);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a URB and initialize the various fields of it.
|
||||
* This API is used by the single_step_set_feature test of
|
||||
* EHSET where IN packet of the GetDescriptor request is
|
||||
* sent 15secs after the SETUP packet.
|
||||
* Return NULL if failed.
|
||||
*/
|
||||
static struct urb *xhci_request_single_step_set_feature_urb(
|
||||
struct usb_device *udev,
|
||||
void *dr,
|
||||
void *buf,
|
||||
struct completion *done)
|
||||
{
|
||||
struct urb *urb;
|
||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||
struct usb_host_endpoint *ep;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return NULL;
|
||||
|
||||
urb->pipe = usb_rcvctrlpipe(udev, 0);
|
||||
ep = udev->ep_in[usb_pipeendpoint(urb->pipe)];
|
||||
if (!ep) {
|
||||
usb_free_urb(urb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the various URB fields as these are used by the HCD
|
||||
* driver to queue it and as well as when completion happens.
|
||||
*/
|
||||
urb->ep = ep;
|
||||
urb->dev = udev;
|
||||
urb->setup_packet = dr;
|
||||
urb->transfer_buffer = buf;
|
||||
urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
|
||||
urb->complete = xhci_single_step_completion;
|
||||
urb->status = -EINPROGRESS;
|
||||
urb->actual_length = 0;
|
||||
urb->transfer_flags = URB_DIR_IN;
|
||||
usb_get_urb(urb);
|
||||
atomic_inc(&urb->use_count);
|
||||
atomic_inc(&urb->dev->urbnum);
|
||||
usb_hcd_map_urb_for_dma(hcd, urb, GFP_KERNEL);
|
||||
urb->context = done;
|
||||
return urb;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function implements the USB_PORT_FEAT_TEST handling of the
|
||||
* SINGLE_STEP_SET_FEATURE test mode as defined in the Embedded
|
||||
* High-Speed Electrical Test (EHSET) specification. This simply
|
||||
* issues a GetDescriptor control transfer, with an inserted 15-second
|
||||
* delay after the end of the SETUP stage and before the IN token of
|
||||
* the DATA stage is set. The idea is that this gives the test operator
|
||||
* enough time to configure the oscilloscope to perform a measurement
|
||||
* of the response time between the DATA and ACK packets that follow.
|
||||
*/
|
||||
static int xhci_ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
|
||||
{
|
||||
int retval;
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
struct usb_device *udev;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct usb_device_descriptor *buf;
|
||||
unsigned long flags;
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
|
||||
/* Obtain udev of the rhub's child port */
|
||||
udev = usb_hub_find_child(hcd->self.root_hub, port);
|
||||
if (!udev) {
|
||||
xhci_err(xhci, "No device attached to the RootHub\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
|
||||
if (!dr) {
|
||||
kfree(buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Fill Setup packet for GetDescriptor */
|
||||
dr->bRequestType = USB_DIR_IN;
|
||||
dr->bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
|
||||
dr->wIndex = 0;
|
||||
dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
|
||||
urb = xhci_request_single_step_set_feature_urb(udev, dr, buf, &done);
|
||||
if (!urb) {
|
||||
retval = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Now complete just the SETUP stage */
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
retval = xhci_submit_single_step_set_feature(hcd, urb, 1);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
if (retval)
|
||||
goto out1;
|
||||
|
||||
if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
|
||||
usb_kill_urb(urb);
|
||||
retval = -ETIMEDOUT;
|
||||
xhci_err(xhci, "%s SETUP stage timed out on ep0\n", __func__);
|
||||
goto out1;
|
||||
}
|
||||
|
||||
/* Sleep for 15 seconds; HC will send SOFs during this period */
|
||||
msleep(15 * 1000);
|
||||
|
||||
/* Complete remaining DATA and status stages. Re-use same URB */
|
||||
urb->status = -EINPROGRESS;
|
||||
usb_get_urb(urb);
|
||||
atomic_inc(&urb->use_count);
|
||||
atomic_inc(&urb->dev->urbnum);
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
retval = xhci_submit_single_step_set_feature(hcd, urb, 0);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
if (!retval && !wait_for_completion_timeout(&done,
|
||||
msecs_to_jiffies(2000))) {
|
||||
usb_kill_urb(urb);
|
||||
retval = -ETIMEDOUT;
|
||||
xhci_err(xhci, "%s IN stage timed out on ep0\n", __func__);
|
||||
}
|
||||
out1:
|
||||
usb_free_urb(urb);
|
||||
cleanup:
|
||||
kfree(dr);
|
||||
kfree(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
u16 wIndex, char *buf, u16 wLength)
|
||||
{
|
||||
|
|
@ -1359,6 +1504,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
/* 4.19.6 Port Test Modes (USB2 Test Mode) */
|
||||
if (hcd->speed != HCD_USB2)
|
||||
goto error;
|
||||
if (test_mode == 6) { /* TEST_SINGLE_STEP_SET_FEATURE */
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
retval = xhci_ehset_single_step_set_feature(hcd,
|
||||
wIndex);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
break;
|
||||
}
|
||||
if (test_mode > TEST_FORCE_EN || test_mode < TEST_J)
|
||||
goto error;
|
||||
retval = xhci_enter_test_mode(xhci, test_mode, wIndex,
|
||||
|
|
|
|||
|
|
@ -193,6 +193,14 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|||
if (!sysdev)
|
||||
sysdev = &pdev->dev;
|
||||
|
||||
/*
|
||||
* If sysdev dev is having parent i.e. "linux,sysdev_is_parent" is true,
|
||||
* then use sysdev->parent device.
|
||||
*/
|
||||
if (sysdev->parent && sysdev->parent->of_node &&
|
||||
device_property_read_bool(sysdev, "linux,sysdev_is_parent"))
|
||||
sysdev = sysdev->parent;
|
||||
|
||||
/* Try to set 64-bit DMA first */
|
||||
if (WARN_ON(!sysdev->dma_mask))
|
||||
/* Platform did not initialize dma_mask */
|
||||
|
|
@ -382,33 +390,21 @@ static int xhci_plat_remove(struct platform_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused xhci_plat_suspend(struct device *dev)
|
||||
static int __maybe_unused xhci_plat_runtime_idle(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
||||
/*
|
||||
* xhci_suspend() needs `do_wakeup` to know whether host is allowed
|
||||
* to do wakeup during suspend. Since xhci_plat_suspend is currently
|
||||
* only designed for system suspend, device_may_wakeup() is enough
|
||||
* to dertermine whether host is allowed to do wakeup. Need to
|
||||
* reconsider this when xhci_plat_suspend enlarges its scope, e.g.,
|
||||
* also applies to runtime suspend.
|
||||
* When pm_runtime_put_autosuspend() is called on this device,
|
||||
* after this idle callback returns the PM core will schedule the
|
||||
* autosuspend if there is any remaining time until expiry. However,
|
||||
* when reaching this point because the child_count becomes 0, the
|
||||
* core does not honor autosuspend in that case and results in
|
||||
* idle/suspend happening immediately. In order to have a delay
|
||||
* before suspend we have to call pm_runtime_autosuspend() manually.
|
||||
*/
|
||||
return xhci_suspend(xhci, device_may_wakeup(dev));
|
||||
}
|
||||
|
||||
static int __maybe_unused xhci_plat_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int ret;
|
||||
|
||||
ret = xhci_priv_resume_quirk(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return xhci_resume(xhci, 0);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_autosuspend(dev);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev)
|
||||
|
|
@ -423,12 +419,25 @@ static int __maybe_unused xhci_plat_runtime_resume(struct device *dev)
|
|||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int ret;
|
||||
|
||||
return xhci_resume(xhci, 0);
|
||||
if (!xhci)
|
||||
return 0;
|
||||
|
||||
dev_dbg(dev, "xhci-plat runtime resume\n");
|
||||
|
||||
ret = xhci_priv_resume_quirk(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xhci_resume(xhci, false);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops xhci_plat_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(NULL, NULL)
|
||||
|
||||
SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend,
|
||||
xhci_plat_runtime_resume,
|
||||
|
|
|
|||
|
|
@ -3519,6 +3519,150 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Variant of xhci_queue_ctrl_tx() used to implement EHSET
|
||||
* SINGLE_STEP_SET_FEATURE test mode. It differs in that the control
|
||||
* transfer is broken up so that the SETUP stage can happen and call
|
||||
* the URB's completion handler before the DATA/STATUS stages are
|
||||
* executed by the xHC hardware. This assumes the control transfer is a
|
||||
* GetDescriptor, with a DATA stage in the IN direction, and an OUT
|
||||
* STATUS stage.
|
||||
*
|
||||
* This function is called twice, usually with a 15-second delay in between.
|
||||
* - with is_setup==true, the SETUP stage for the control request
|
||||
* (GetDescriptor) is queued in the TRB ring and sent to HW immediately
|
||||
* - with is_setup==false, the DATA and STATUS TRBs are queued and exceuted
|
||||
*
|
||||
* Caller must have locked xhci->lock
|
||||
*/
|
||||
int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb,
|
||||
int is_setup)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct xhci_ring *ep_ring;
|
||||
int num_trbs;
|
||||
int ret;
|
||||
unsigned int slot_id, ep_index;
|
||||
struct usb_ctrlrequest *setup;
|
||||
struct xhci_generic_trb *start_trb;
|
||||
int start_cycle;
|
||||
u32 field, length_field, remainder;
|
||||
struct urb_priv *urb_priv;
|
||||
struct xhci_td *td;
|
||||
|
||||
ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
|
||||
if (!ep_ring)
|
||||
return -EINVAL;
|
||||
|
||||
/* Need buffer for data stage */
|
||||
if (urb->transfer_buffer_length <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Need to copy setup packet into setup TRB, so we can't use the setup
|
||||
* DMA address.
|
||||
*/
|
||||
if (!urb->setup_packet)
|
||||
return -EINVAL;
|
||||
setup = (struct usb_ctrlrequest *) urb->setup_packet;
|
||||
|
||||
slot_id = urb->dev->slot_id;
|
||||
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
|
||||
|
||||
urb_priv = kzalloc(sizeof(struct urb_priv) +
|
||||
sizeof(struct xhci_td *), GFP_ATOMIC);
|
||||
if (!urb_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
td = &urb_priv->td[0];
|
||||
urb_priv->num_tds = 1;
|
||||
urb_priv->num_tds_done = 0;
|
||||
urb->hcpriv = urb_priv;
|
||||
|
||||
num_trbs = is_setup ? 1 : 2;
|
||||
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
num_trbs, urb, 0, GFP_ATOMIC);
|
||||
if (ret < 0) {
|
||||
kfree(urb_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't give the first TRB to the hardware (by toggling the cycle bit)
|
||||
* until we've finished creating all the other TRBs. The ring's cycle
|
||||
* state may change as we enqueue the other TRBs, so save it too.
|
||||
*/
|
||||
start_trb = &ep_ring->enqueue->generic;
|
||||
start_cycle = ep_ring->cycle_state;
|
||||
|
||||
if (is_setup) {
|
||||
/* Queue only the setup TRB */
|
||||
field = TRB_IDT | TRB_IOC | TRB_TYPE(TRB_SETUP);
|
||||
if (start_cycle == 0)
|
||||
field |= 0x1;
|
||||
|
||||
/* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
|
||||
if (xhci->hci_version >= 0x100) {
|
||||
if (setup->bRequestType & USB_DIR_IN)
|
||||
field |= TRB_TX_TYPE(TRB_DATA_IN);
|
||||
else
|
||||
field |= TRB_TX_TYPE(TRB_DATA_OUT);
|
||||
}
|
||||
|
||||
/* Save the DMA address of the last TRB in the TD */
|
||||
td->last_trb = ep_ring->enqueue;
|
||||
|
||||
queue_trb(xhci, ep_ring, false,
|
||||
setup->bRequestType | setup->bRequest << 8 |
|
||||
le16_to_cpu(setup->wValue) << 16,
|
||||
le16_to_cpu(setup->wIndex) |
|
||||
le16_to_cpu(setup->wLength) << 16,
|
||||
TRB_LEN(8) | TRB_INTR_TARGET(0),
|
||||
field);
|
||||
} else {
|
||||
/* Queue data TRB */
|
||||
field = TRB_ISP | TRB_TYPE(TRB_DATA);
|
||||
if (start_cycle == 0)
|
||||
field |= 0x1;
|
||||
if (setup->bRequestType & USB_DIR_IN)
|
||||
field |= TRB_DIR_IN;
|
||||
|
||||
remainder = xhci_td_remainder(xhci, 0,
|
||||
urb->transfer_buffer_length,
|
||||
urb->transfer_buffer_length,
|
||||
urb, 1);
|
||||
|
||||
length_field = TRB_LEN(urb->transfer_buffer_length) |
|
||||
TRB_TD_SIZE(remainder) |
|
||||
TRB_INTR_TARGET(0);
|
||||
|
||||
queue_trb(xhci, ep_ring, true,
|
||||
lower_32_bits(urb->transfer_dma),
|
||||
upper_32_bits(urb->transfer_dma),
|
||||
length_field,
|
||||
field);
|
||||
|
||||
/* Save the DMA address of the last TRB in the TD */
|
||||
td->last_trb = ep_ring->enqueue;
|
||||
|
||||
/* Queue status TRB */
|
||||
field = TRB_IOC | TRB_TYPE(TRB_STATUS);
|
||||
if (!(setup->bRequestType & USB_DIR_IN))
|
||||
field |= TRB_DIR_IN;
|
||||
|
||||
queue_trb(xhci, ep_ring, false,
|
||||
0,
|
||||
0,
|
||||
TRB_INTR_TARGET(0),
|
||||
field | ep_ring->cycle_state);
|
||||
}
|
||||
|
||||
giveback_first_trb(xhci, slot_id, ep_index, 0, start_cycle, start_trb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The transfer burst count field of the isochronous TRB defines the number of
|
||||
* bursts that are required to move all packets in this TD. Only SuperSpeed
|
||||
|
|
|
|||
|
|
@ -132,7 +132,13 @@ int xhci_start(struct xhci_hcd *xhci)
|
|||
{
|
||||
u32 temp;
|
||||
int ret;
|
||||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||||
|
||||
/*
|
||||
* disable irq to avoid xhci_irq flooding due to unhandeled port
|
||||
* change event in halt state, as soon as xhci_start clears halt bit
|
||||
*/
|
||||
disable_irq(hcd->irq);
|
||||
temp = readl(&xhci->op_regs->command);
|
||||
temp |= (CMD_RUN);
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.",
|
||||
|
|
@ -153,6 +159,8 @@ int xhci_start(struct xhci_hcd *xhci)
|
|||
/* clear state flags. Including dying, halted or removing */
|
||||
xhci->xhc_state = 0;
|
||||
|
||||
enable_irq(hcd->irq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -437,8 +437,8 @@ struct xhci_op_regs {
|
|||
#define PORT_L1_TIMEOUT(p)(((p) & 0xff) << 2)
|
||||
#define PORT_BESLD(p)(((p) & 0xf) << 10)
|
||||
|
||||
/* use 512 microseconds as USB2 LPM L1 default timeout. */
|
||||
#define XHCI_L1_TIMEOUT 512
|
||||
/* use 128 microseconds as USB2 LPM L1 default timeout. */
|
||||
#define XHCI_L1_TIMEOUT 128
|
||||
|
||||
/* Set default HIRD/BESL value to 4 (350/400us) for USB2 L1 LPM resume latency.
|
||||
* Safe to use with mixed HIRD and BESL systems (host and device) and is used
|
||||
|
|
@ -2674,4 +2674,8 @@ static inline const char *xhci_decode_ep_context(u32 info, u32 info2, u64 deq,
|
|||
return str;
|
||||
}
|
||||
|
||||
/* EHSET */
|
||||
int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb,
|
||||
int is_setup);
|
||||
|
||||
#endif /* __LINUX_XHCI_HCD_H */
|
||||
|
|
|
|||
Loading…
Reference in a new issue