Commit 9afcdb10 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'for-usb-next-2013-10-17' of...

Merge tag 'for-usb-next-2013-10-17' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-next

Sarah writes:

xhci: Final patches for 3.13

Hi Greg,

Here's my pull request for usb-next and 3.13.  My xHCI tree is closed
after this point, since I won't be able to run my full tests while I'm in
Scotland.  After Kernel Summit, I'll be on vacation with access to email
from Oct 26th to Nov 6th.

Here's what's in this request:

 - Patches to fix USB 2.0 Link PM issues that cause USB 3.0 devices to not
   enumerate or misbehave when plugged into a USB 2.0 port.  Those are
   marked for stable.

 - A msec vs jiffies bug fix by xiao jin, which results in fairly harmless
   behavior, and thus isn't marked for stable.

 - Xenia's patches to refactor the xHCI command handling code, which makes
   it much more readable and consistent.

 - Misc cleanup patches, one by Sachin Kamat and three from Dan Williams.

Here's what's not in this request:

 - Dan's two patches to allow the xHCI host to use the "Windows" or "new"
   enumeration scheme.  I did not have time to test those, and I want to
   run them with as many USB devices as I can get a hold of.  That will
   have to wait for 3.14.

 - Xenia's patches to remove xhci_readl in favor of readl.  I'll queue
   those for 3.14 after I test them.

 - The xHCI streams update, UAS fixes, and usbfs streams support.  I'm not
   comfortable with changes and fixes to that patchset coming in this late.
   I would rather wait for 3.14 and be really sure the streams support is
   stable before we add new userspace API and remove CONFIG_BROKEN from the
   uas driver.

 - Julius' patch to clear the port reset bit on hub resume that came in
   a couple days ago.  It looks harmless, but I would rather take the time
   to test and queue it for usb-linus and the stable trees once 3.13-rc1
   is out.

Sarah Sharp
parents 5584cfba a2cdc343
...@@ -1790,6 +1790,9 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) ...@@ -1790,6 +1790,9 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
struct usb_hcd *hcd = bus_to_hcd(udev->bus); struct usb_hcd *hcd = bus_to_hcd(udev->bus);
int ret = -EPERM; int ret = -EPERM;
if (enable && !udev->usb2_hw_lpm_allowed)
return 0;
if (hcd->driver->set_usb2_hw_lpm) { if (hcd->driver->set_usb2_hw_lpm) {
ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);
if (!ret) if (!ret)
......
...@@ -1112,16 +1112,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) ...@@ -1112,16 +1112,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
/* /*
* USB3 protocol ports will automatically transition * USB3 protocol ports will automatically transition
* to Enabled state when detect an USB3.0 device attach. * to Enabled state when detect an USB3.0 device attach.
* Do not disable USB3 protocol ports. * Do not disable USB3 protocol ports, just pretend
* power was lost
*/ */
if (!hub_is_superspeed(hdev)) { portstatus &= ~USB_PORT_STAT_ENABLE;
if (!hub_is_superspeed(hdev))
usb_clear_port_feature(hdev, port1, usb_clear_port_feature(hdev, port1,
USB_PORT_FEAT_ENABLE); USB_PORT_FEAT_ENABLE);
portstatus &= ~USB_PORT_STAT_ENABLE;
} else {
/* Pretend that power was lost for USB3 devs */
portstatus &= ~USB_PORT_STAT_ENABLE;
}
} }
/* Clear status-change flags; we'll debounce later */ /* Clear status-change flags; we'll debounce later */
...@@ -3958,6 +3955,32 @@ static int hub_set_address(struct usb_device *udev, int devnum) ...@@ -3958,6 +3955,32 @@ static int hub_set_address(struct usb_device *udev, int devnum)
return retval; return retval;
} }
/*
* There are reports of USB 3.0 devices that say they support USB 2.0 Link PM
* when they're plugged into a USB 2.0 port, but they don't work when LPM is
* enabled.
*
* Only enable USB 2.0 Link PM if the port is internal (hardwired), or the
* device says it supports the new USB 2.0 Link PM errata by setting the BESL
* support bit in the BOS descriptor.
*/
static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev)
{
int connect_type;
if (!udev->usb2_hw_lpm_capable)
return;
connect_type = usb_get_hub_port_connect_type(udev->parent,
udev->portnum);
if ((udev->bos->ext_cap->bmAttributes & USB_BESL_SUPPORT) ||
connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
udev->usb2_hw_lpm_allowed = 1;
usb_set_usb2_hardware_lpm(udev, 1);
}
}
/* Reset device, (re)assign address, get device descriptor. /* Reset device, (re)assign address, get device descriptor.
* Device connection must be stable, no more debouncing needed. * Device connection must be stable, no more debouncing needed.
* Returns device in USB_STATE_ADDRESS, except on error. * Returns device in USB_STATE_ADDRESS, except on error.
...@@ -4251,6 +4274,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, ...@@ -4251,6 +4274,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
/* notify HCD that we have a device connected and addressed */ /* notify HCD that we have a device connected and addressed */
if (hcd->driver->update_device) if (hcd->driver->update_device)
hcd->driver->update_device(hcd, udev); hcd->driver->update_device(hcd, udev);
hub_set_initial_usb2_lpm_policy(udev);
fail: fail:
if (retval) { if (retval) {
hub_port_disable(hub, port1, 0); hub_port_disable(hub, port1, 0);
...@@ -5095,6 +5119,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev) ...@@ -5095,6 +5119,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
} }
parent_hub = usb_hub_to_struct_hub(parent_hdev); parent_hub = usb_hub_to_struct_hub(parent_hdev);
/* Disable USB2 hardware LPM.
* It will be re-enabled by the enumeration process.
*/
if (udev->usb2_hw_lpm_enabled == 1)
usb_set_usb2_hardware_lpm(udev, 0);
bos = udev->bos; bos = udev->bos;
udev->bos = NULL; udev->bos = NULL;
...@@ -5202,6 +5232,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) ...@@ -5202,6 +5232,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
done: done:
/* Now that the alt settings are re-installed, enable LTM and LPM. */ /* Now that the alt settings are re-installed, enable LTM and LPM. */
usb_set_usb2_hardware_lpm(udev, 1);
usb_unlocked_enable_lpm(udev); usb_unlocked_enable_lpm(udev);
usb_enable_ltm(udev); usb_enable_ltm(udev);
usb_release_bos_descriptor(udev); usb_release_bos_descriptor(udev);
......
...@@ -1182,8 +1182,12 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) ...@@ -1182,8 +1182,12 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
put_device(&dev->actconfig->interface[i]->dev); put_device(&dev->actconfig->interface[i]->dev);
dev->actconfig->interface[i] = NULL; dev->actconfig->interface[i] = NULL;
} }
if (dev->usb2_hw_lpm_enabled == 1)
usb_set_usb2_hardware_lpm(dev, 0);
usb_unlocked_disable_lpm(dev); usb_unlocked_disable_lpm(dev);
usb_disable_ltm(dev); usb_disable_ltm(dev);
dev->actconfig = NULL; dev->actconfig = NULL;
if (dev->state == USB_STATE_CONFIGURED) if (dev->state == USB_STATE_CONFIGURED)
usb_set_device_state(dev, USB_STATE_ADDRESS); usb_set_device_state(dev, USB_STATE_ADDRESS);
......
...@@ -458,7 +458,7 @@ static ssize_t usb2_hardware_lpm_show(struct device *dev, ...@@ -458,7 +458,7 @@ static ssize_t usb2_hardware_lpm_show(struct device *dev,
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
const char *p; const char *p;
if (udev->usb2_hw_lpm_enabled == 1) if (udev->usb2_hw_lpm_allowed == 1)
p = "enabled"; p = "enabled";
else else
p = "disabled"; p = "disabled";
...@@ -478,8 +478,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, ...@@ -478,8 +478,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev,
ret = strtobool(buf, &value); ret = strtobool(buf, &value);
if (!ret) if (!ret) {
udev->usb2_hw_lpm_allowed = value;
ret = usb_set_usb2_hardware_lpm(udev, value); ret = usb_set_usb2_hardware_lpm(udev, value);
}
usb_unlock_device(udev); usb_unlock_device(udev);
......
...@@ -296,7 +296,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) ...@@ -296,7 +296,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
/* Wait for last stop endpoint command to finish */ /* Wait for last stop endpoint command to finish */
timeleft = wait_for_completion_interruptible_timeout( timeleft = wait_for_completion_interruptible_timeout(
cmd->completion, cmd->completion,
USB_CTRL_SET_TIMEOUT); XHCI_CMD_DEFAULT_TIMEOUT);
if (timeleft <= 0) { if (timeleft <= 0) {
xhci_warn(xhci, "%s while waiting for stop endpoint command\n", xhci_warn(xhci, "%s while waiting for stop endpoint command\n",
timeleft == 0 ? "Timeout" : "Signal"); timeleft == 0 ? "Timeout" : "Signal");
...@@ -524,7 +524,8 @@ static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg) ...@@ -524,7 +524,8 @@ static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg)
* the compliance mode timer is deleted. A port won't enter * the compliance mode timer is deleted. A port won't enter
* compliance mode if it has previously entered U0. * compliance mode if it has previously entered U0.
*/ */
void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status,
u16 wIndex)
{ {
u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1); u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1);
bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0); bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0);
......
...@@ -1693,9 +1693,7 @@ void xhci_free_command(struct xhci_hcd *xhci, ...@@ -1693,9 +1693,7 @@ void xhci_free_command(struct xhci_hcd *xhci,
void xhci_mem_cleanup(struct xhci_hcd *xhci) void xhci_mem_cleanup(struct xhci_hcd *xhci)
{ {
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
struct dev_info *dev_info, *next;
struct xhci_cd *cur_cd, *next_cd; struct xhci_cd *cur_cd, *next_cd;
unsigned long flags;
int size; int size;
int i, j, num_ports; int i, j, num_ports;
...@@ -1756,13 +1754,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) ...@@ -1756,13 +1754,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
scratchpad_free(xhci); scratchpad_free(xhci);
spin_lock_irqsave(&xhci->lock, flags);
list_for_each_entry_safe(dev_info, next, &xhci->lpm_failed_devs, list) {
list_del(&dev_info->list);
kfree(dev_info);
}
spin_unlock_irqrestore(&xhci->lock, flags);
if (!xhci->rh_bw) if (!xhci->rh_bw)
goto no_bw; goto no_bw;
...@@ -2231,7 +2222,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) ...@@ -2231,7 +2222,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
u32 page_size, temp; u32 page_size, temp;
int i; int i;
INIT_LIST_HEAD(&xhci->lpm_failed_devs);
INIT_LIST_HEAD(&xhci->cancel_cmd_list); INIT_LIST_HEAD(&xhci->cancel_cmd_list);
page_size = xhci_readl(xhci, &xhci->op_regs->page_size); page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
......
This diff is collapsed.
...@@ -3459,7 +3459,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -3459,7 +3459,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
/* Wait for the Reset Device command to finish */ /* Wait for the Reset Device command to finish */
timeleft = wait_for_completion_interruptible_timeout( timeleft = wait_for_completion_interruptible_timeout(
reset_device_cmd->completion, reset_device_cmd->completion,
USB_CTRL_SET_TIMEOUT); XHCI_CMD_DEFAULT_TIMEOUT);
if (timeleft <= 0) { if (timeleft <= 0) {
xhci_warn(xhci, "%s while waiting for reset device command\n", xhci_warn(xhci, "%s while waiting for reset device command\n",
timeleft == 0 ? "Timeout" : "Signal"); timeleft == 0 ? "Timeout" : "Signal");
...@@ -3583,11 +3583,6 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -3583,11 +3583,6 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
} }
if (udev->usb2_hw_lpm_enabled) {
xhci_set_usb2_hardware_lpm(hcd, udev, 0);
udev->usb2_hw_lpm_enabled = 0;
}
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
/* Don't disable the slot if the host controller is dead. */ /* Don't disable the slot if the host controller is dead. */
state = xhci_readl(xhci, &xhci->op_regs->status); state = xhci_readl(xhci, &xhci->op_regs->status);
...@@ -3721,9 +3716,6 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -3721,9 +3716,6 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
* the device). * the device).
* We should be protected by the usb_address0_mutex in khubd's hub_port_init, so * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so
* we should only issue and wait on one address command at the same time. * we should only issue and wait on one address command at the same time.
*
* We add one to the device address issued by the hardware because the USB core
* uses address 1 for the root hubs (even though they're not really devices).
*/ */
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
{ {
...@@ -3868,16 +3860,13 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) ...@@ -3868,16 +3860,13 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
trace_xhci_address_ctx(xhci, virt_dev->out_ctx, trace_xhci_address_ctx(xhci, virt_dev->out_ctx,
slot_ctx->dev_info >> 27); slot_ctx->dev_info >> 27);
/* Use kernel assigned address for devices; store xHC assigned
* address locally. */
virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK)
+ 1;
/* Zero the input context control for later use */ /* Zero the input context control for later use */
ctrl_ctx->add_flags = 0; ctrl_ctx->add_flags = 0;
ctrl_ctx->drop_flags = 0; ctrl_ctx->drop_flags = 0;
xhci_dbg_trace(xhci, trace_xhci_dbg_address, xhci_dbg_trace(xhci, trace_xhci_dbg_address,
"Internal device address = %d", virt_dev->address); "Internal device address = %d",
le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK);
return 0; return 0;
} }
...@@ -4025,133 +4014,6 @@ static int xhci_calculate_usb2_hw_lpm_params(struct usb_device *udev) ...@@ -4025,133 +4014,6 @@ static int xhci_calculate_usb2_hw_lpm_params(struct usb_device *udev)
return PORT_BESLD(besld) | PORT_L1_TIMEOUT(l1) | PORT_HIRDM(hirdm); return PORT_BESLD(besld) | PORT_L1_TIMEOUT(l1) | PORT_HIRDM(hirdm);
} }
static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
struct usb_device *udev)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct dev_info *dev_info;
__le32 __iomem **port_array;
__le32 __iomem *addr, *pm_addr;
u32 temp, dev_id;
unsigned int port_num;
unsigned long flags;
int hird;
int ret;
if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
!udev->lpm_capable)
return -EINVAL;
/* we only support lpm for non-hub device connected to root hub yet */
if (!udev->parent || udev->parent->parent ||
udev->descriptor.bDeviceClass == USB_CLASS_HUB)
return -EINVAL;
spin_lock_irqsave(&xhci->lock, flags);
/* Look for devices in lpm_failed_devs list */
dev_id = le16_to_cpu(udev->descriptor.idVendor) << 16 |
le16_to_cpu(udev->descriptor.idProduct);
list_for_each_entry(dev_info, &xhci->lpm_failed_devs, list) {
if (dev_info->dev_id == dev_id) {
ret = -EINVAL;
goto finish;
}
}
port_array = xhci->usb2_ports;
port_num = udev->portnum - 1;
if (port_num > HCS_MAX_PORTS(xhci->hcs_params1)) {
xhci_dbg(xhci, "invalid port number %d\n", udev->portnum);
ret = -EINVAL;
goto finish;
}
/*
* Test USB 2.0 software LPM.
* FIXME: some xHCI 1.0 hosts may implement a new register to set up
* hardware-controlled USB 2.0 LPM. See section 5.4.11 and 4.23.5.1.1.1
* in the June 2011 errata release.
*/
xhci_dbg(xhci, "test port %d software LPM\n", port_num);
/*
* Set L1 Device Slot and HIRD/BESL.
* Check device's USB 2.0 extension descriptor to determine whether
* HIRD or BESL shoule be used. See USB2.0 LPM errata.
*/
pm_addr = port_array[port_num] + PORTPMSC;
hird = xhci_calculate_hird_besl(xhci, udev);
temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
xhci_writel(xhci, temp, pm_addr);
/* Set port link state to U2(L1) */
addr = port_array[port_num];
xhci_set_link_state(xhci, port_array, port_num, XDEV_U2);
/* wait for ACK */
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(10);
spin_lock_irqsave(&xhci->lock, flags);
/* Check L1 Status */
ret = xhci_handshake(xhci, pm_addr,
PORT_L1S_MASK, PORT_L1S_SUCCESS, 125);
if (ret != -ETIMEDOUT) {
/* enter L1 successfully */
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, "port %d entered L1 state, port status 0x%x\n",
port_num, temp);
ret = 0;
} else {
temp = xhci_readl(xhci, pm_addr);
xhci_dbg(xhci, "port %d software lpm failed, L1 status %d\n",
port_num, temp & PORT_L1S_MASK);
ret = -EINVAL;
}
/* Resume the port */
xhci_set_link_state(xhci, port_array, port_num, XDEV_U0);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(10);
spin_lock_irqsave(&xhci->lock, flags);
/* Clear PLC */
xhci_test_and_clear_bit(xhci, port_array, port_num, PORT_PLC);
/* Check PORTSC to make sure the device is in the right state */
if (!ret) {
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, "resumed port %d status 0x%x\n", port_num, temp);
if (!(temp & PORT_CONNECT) || !(temp & PORT_PE) ||
(temp & PORT_PLS_MASK) != XDEV_U0) {
xhci_dbg(xhci, "port L1 resume fail\n");
ret = -EINVAL;
}
}
if (ret) {
/* Insert dev to lpm_failed_devs list */
xhci_warn(xhci, "device LPM test failed, may disconnect and "
"re-enumerate\n");
dev_info = kzalloc(sizeof(struct dev_info), GFP_ATOMIC);
if (!dev_info) {
ret = -ENOMEM;
goto finish;
}
dev_info->dev_id = dev_id;
INIT_LIST_HEAD(&dev_info->list);
list_add(&dev_info->list, &xhci->lpm_failed_devs);
} else {
xhci_ring_device(xhci, udev->slot_id);
}
finish:
spin_unlock_irqrestore(&xhci->lock, flags);
return ret;
}
int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
struct usb_device *udev, int enable) struct usb_device *udev, int enable)
{ {
...@@ -4228,7 +4090,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, ...@@ -4228,7 +4090,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
} }
pm_val &= ~PORT_HIRD_MASK; pm_val &= ~PORT_HIRD_MASK;
pm_val |= PORT_HIRD(hird) | PORT_RWE; pm_val |= PORT_HIRD(hird) | PORT_RWE | PORT_L1DS(udev->slot_id);
xhci_writel(xhci, pm_val, pm_addr); xhci_writel(xhci, pm_val, pm_addr);
pm_val = xhci_readl(xhci, pm_addr); pm_val = xhci_readl(xhci, pm_addr);
pm_val |= PORT_HLE; pm_val |= PORT_HLE;
...@@ -4236,7 +4098,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, ...@@ -4236,7 +4098,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
/* flush write */ /* flush write */
xhci_readl(xhci, pm_addr); xhci_readl(xhci, pm_addr);
} else { } else {
pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK); pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK | PORT_L1DS_MASK);
xhci_writel(xhci, pm_val, pm_addr); xhci_writel(xhci, pm_val, pm_addr);
/* flush write */ /* flush write */
xhci_readl(xhci, pm_addr); xhci_readl(xhci, pm_addr);
...@@ -4279,24 +4141,26 @@ static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port, ...@@ -4279,24 +4141,26 @@ static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port,
int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
{ {
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int ret;
int portnum = udev->portnum - 1; int portnum = udev->portnum - 1;
ret = xhci_usb2_software_lpm_test(hcd, udev); if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
if (!ret) { !udev->lpm_capable)
xhci_dbg(xhci, "software LPM test succeed\n"); return 0;
if (xhci->hw_lpm_support == 1 &&
xhci_check_usb2_port_capability(xhci, portnum, XHCI_HLC)) { /* we only support lpm for non-hub device connected to root hub yet */
udev->usb2_hw_lpm_capable = 1; if (!udev->parent || udev->parent->parent ||
udev->l1_params.timeout = XHCI_L1_TIMEOUT; udev->descriptor.bDeviceClass == USB_CLASS_HUB)
udev->l1_params.besl = XHCI_DEFAULT_BESL; return 0;
if (xhci_check_usb2_port_capability(xhci, portnum,
XHCI_BLC)) if (xhci->hw_lpm_support == 1 &&
udev->usb2_hw_lpm_besl_capable = 1; xhci_check_usb2_port_capability(
ret = xhci_set_usb2_hardware_lpm(hcd, udev, 1); xhci, portnum, XHCI_HLC)) {
if (!ret) udev->usb2_hw_lpm_capable = 1;
udev->usb2_hw_lpm_enabled = 1; udev->l1_params.timeout = XHCI_L1_TIMEOUT;
} udev->l1_params.besl = XHCI_DEFAULT_BESL;
if (xhci_check_usb2_port_capability(xhci, portnum,
XHCI_BLC))
udev->usb2_hw_lpm_besl_capable = 1;
} }
return 0; return 0;
......
...@@ -383,6 +383,7 @@ struct xhci_op_regs { ...@@ -383,6 +383,7 @@ struct xhci_op_regs {
#define PORT_RWE (1 << 3) #define PORT_RWE (1 << 3)
#define PORT_HIRD(p) (((p) & 0xf) << 4) #define PORT_HIRD(p) (((p) & 0xf) << 4)
#define PORT_HIRD_MASK (0xf << 4) #define PORT_HIRD_MASK (0xf << 4)
#define PORT_L1DS_MASK (0xff << 8)
#define PORT_L1DS(p) (((p) & 0xff) << 8) #define PORT_L1DS(p) (((p) & 0xff) << 8)
#define PORT_HLE (1 << 16) #define PORT_HLE (1 << 16)
...@@ -934,8 +935,6 @@ struct xhci_virt_device { ...@@ -934,8 +935,6 @@ struct xhci_virt_device {
/* Rings saved to ensure old alt settings can be re-instated */ /* Rings saved to ensure old alt settings can be re-instated */
struct xhci_ring **ring_cache; struct xhci_ring **ring_cache;
int num_rings_cached; int num_rings_cached;
/* Store xHC assigned device address */
int address;
#define XHCI_MAX_RINGS_CACHED 31 #define XHCI_MAX_RINGS_CACHED 31
struct xhci_virt_ep eps[31]; struct xhci_virt_ep eps[31];
struct completion cmd_completion; struct completion cmd_completion;
......
...@@ -475,7 +475,8 @@ struct usb3_lpm_parameters { ...@@ -475,7 +475,8 @@ struct usb3_lpm_parameters {
* @lpm_capable: device supports LPM * @lpm_capable: device supports LPM
* @usb2_hw_lpm_capable: device can perform USB2 hardware LPM * @usb2_hw_lpm_capable: device can perform USB2 hardware LPM
* @usb2_hw_lpm_besl_capable: device can perform USB2 hardware BESL LPM * @usb2_hw_lpm_besl_capable: device can perform USB2 hardware BESL LPM
* @usb2_hw_lpm_enabled: USB2 hardware LPM enabled * @usb2_hw_lpm_enabled: USB2 hardware LPM is enabled
* @usb2_hw_lpm_allowed: Userspace allows USB 2.0 LPM to be enabled
* @usb3_lpm_enabled: USB3 hardware LPM enabled * @usb3_lpm_enabled: USB3 hardware LPM enabled
* @string_langid: language ID for strings * @string_langid: language ID for strings
* @product: iProduct string, if present (static) * @product: iProduct string, if present (static)
...@@ -548,6 +549,7 @@ struct usb_device { ...@@ -548,6 +549,7 @@ struct usb_device {
unsigned usb2_hw_lpm_capable:1; unsigned usb2_hw_lpm_capable:1;
unsigned usb2_hw_lpm_besl_capable:1; unsigned usb2_hw_lpm_besl_capable:1;
unsigned usb2_hw_lpm_enabled:1; unsigned usb2_hw_lpm_enabled:1;
unsigned usb2_hw_lpm_allowed:1;
unsigned usb3_lpm_enabled:1; unsigned usb3_lpm_enabled:1;
int string_langid; int string_langid;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment