Commit 1e032dc5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-3.5-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg Kroah-Hartman:
 "Here are a few fixes and new device ids for the 3.5-rc6 tree.

  The PCI changes resolve a long-standing issue with resuming some EHCI
  controllers.  It has been acked by the PCI maintainer, and he asked
  for it to go through my USB tree instead of his.

  The xhci patches also resolve a number of reported issues.

  Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"

* tag 'usb-3.5-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  PCI: EHCI: fix crash during suspend on ASUS computers
  USB: cdc-wdm: fix lockup on error in wdm_read
  USB: metro-usb: fix tty_flip_buffer_push use
  USB: option: Add MEDIATEK product ids
  USB: option: add ZTE MF60
  xhci: Fix hang on back-to-back Set TR Deq Ptr commands.
  usb: Add support for root hub port status CAS
parents 5f351f06 dbf0e4c7
...@@ -748,6 +748,18 @@ static int pci_pm_suspend_noirq(struct device *dev) ...@@ -748,6 +748,18 @@ static int pci_pm_suspend_noirq(struct device *dev)
pci_pm_set_unknown_state(pci_dev); pci_pm_set_unknown_state(pci_dev);
/*
* Some BIOSes from ASUS have a bug: If a USB EHCI host controller's
* PCI COMMAND register isn't 0, the BIOS assumes that the controller
* hasn't been quiesced and tries to turn it off. If the controller
* is already in D3, this can hang or cause memory corruption.
*
* Since the value of the COMMAND register doesn't matter once the
* device has been suspended, we can safely set it to 0 here.
*/
if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
pci_write_config_word(pci_dev, PCI_COMMAND, 0);
return 0; return 0;
} }
......
...@@ -1744,11 +1744,6 @@ int pci_prepare_to_sleep(struct pci_dev *dev) ...@@ -1744,11 +1744,6 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
if (target_state == PCI_POWER_ERROR) if (target_state == PCI_POWER_ERROR)
return -EIO; return -EIO;
/* Some devices mustn't be in D3 during system sleep */
if (target_state == PCI_D3hot &&
(dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP))
return 0;
pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev)); pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev));
error = pci_set_power_state(dev, target_state); error = pci_set_power_state(dev, target_state);
......
...@@ -2929,32 +2929,6 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev) ...@@ -2929,32 +2929,6 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
/*
* The Intel 6 Series/C200 Series chipset's EHCI controllers on many
* ASUS motherboards will cause memory corruption or a system crash
* if they are in D3 while the system is put into S3 sleep.
*/
static void __devinit asus_ehci_no_d3(struct pci_dev *dev)
{
const char *sys_info;
static const char good_Asus_board[] = "P8Z68-V";
if (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP)
return;
if (dev->subsystem_vendor != PCI_VENDOR_ID_ASUSTEK)
return;
sys_info = dmi_get_system_info(DMI_BOARD_NAME);
if (sys_info && memcmp(sys_info, good_Asus_board,
sizeof(good_Asus_board) - 1) == 0)
return;
dev_info(&dev->dev, "broken D3 during system sleep on ASUS\n");
dev->dev_flags |= PCI_DEV_FLAGS_NO_D3_DURING_SLEEP;
device_set_wakeup_capable(&dev->dev, false);
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3);
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
struct pci_fixup *end) struct pci_fixup *end)
{ {
......
...@@ -500,6 +500,8 @@ static ssize_t wdm_read ...@@ -500,6 +500,8 @@ static ssize_t wdm_read
goto retry; goto retry;
} }
if (!desc->reslength) { /* zero length read */ if (!desc->reslength) { /* zero length read */
dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__);
clear_bit(WDM_READ, &desc->flags);
spin_unlock_irq(&desc->iuspin); spin_unlock_irq(&desc->iuspin);
goto retry; goto retry;
} }
......
...@@ -2324,12 +2324,16 @@ static unsigned hub_is_wusb(struct usb_hub *hub) ...@@ -2324,12 +2324,16 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
static int hub_port_reset(struct usb_hub *hub, int port1, static int hub_port_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay, bool warm); struct usb_device *udev, unsigned int delay, bool warm);
/* Is a USB 3.0 port in the Inactive state? */ /* Is a USB 3.0 port in the Inactive or Complinance Mode state?
static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus) * Port worm reset is required to recover
*/
static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus)
{ {
return hub_is_superspeed(hub->hdev) && return hub_is_superspeed(hub->hdev) &&
(portstatus & USB_PORT_STAT_LINK_STATE) == (((portstatus & USB_PORT_STAT_LINK_STATE) ==
USB_SS_PORT_LS_SS_INACTIVE; USB_SS_PORT_LS_SS_INACTIVE) ||
((portstatus & USB_PORT_STAT_LINK_STATE) ==
USB_SS_PORT_LS_COMP_MOD)) ;
} }
static int hub_port_wait_reset(struct usb_hub *hub, int port1, static int hub_port_wait_reset(struct usb_hub *hub, int port1,
...@@ -2365,7 +2369,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, ...@@ -2365,7 +2369,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
* *
* See https://bugzilla.kernel.org/show_bug.cgi?id=41752 * See https://bugzilla.kernel.org/show_bug.cgi?id=41752
*/ */
if (hub_port_inactive(hub, portstatus)) { if (hub_port_warm_reset_required(hub, portstatus)) {
int ret; int ret;
if ((portchange & USB_PORT_STAT_C_CONNECTION)) if ((portchange & USB_PORT_STAT_C_CONNECTION))
...@@ -4408,9 +4412,7 @@ static void hub_events(void) ...@@ -4408,9 +4412,7 @@ static void hub_events(void)
/* Warm reset a USB3 protocol port if it's in /* Warm reset a USB3 protocol port if it's in
* SS.Inactive state. * SS.Inactive state.
*/ */
if (hub_is_superspeed(hub->hdev) && if (hub_port_warm_reset_required(hub, portstatus)) {
(portstatus & USB_PORT_STAT_LINK_STATE)
== USB_SS_PORT_LS_SS_INACTIVE) {
dev_dbg(hub_dev, "warm reset port %d\n", i); dev_dbg(hub_dev, "warm reset port %d\n", i);
hub_port_reset(hub, i, NULL, hub_port_reset(hub, i, NULL,
HUB_BH_RESET_TIME, true); HUB_BH_RESET_TIME, true);
......
...@@ -462,6 +462,42 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, ...@@ -462,6 +462,42 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
} }
} }
/* Updates Link Status for super Speed port */
static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
{
u32 pls = status_reg & PORT_PLS_MASK;
/* resume state is a xHCI internal state.
* Do not report it to usb core.
*/
if (pls == XDEV_RESUME)
return;
/* When the CAS bit is set then warm reset
* should be performed on port
*/
if (status_reg & PORT_CAS) {
/* The CAS bit can be set while the port is
* in any link state.
* Only roothubs have CAS bit, so we
* pretend to be in compliance mode
* unless we're already in compliance
* or the inactive state.
*/
if (pls != USB_SS_PORT_LS_COMP_MOD &&
pls != USB_SS_PORT_LS_SS_INACTIVE) {
pls = USB_SS_PORT_LS_COMP_MOD;
}
/* Return also connection bit -
* hub state machine resets port
* when this bit is set.
*/
pls |= USB_PORT_STAT_CONNECTION;
}
/* update status field */
*status |= pls;
}
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength) u16 wIndex, char *buf, u16 wLength)
{ {
...@@ -606,13 +642,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -606,13 +642,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
else else
status |= USB_PORT_STAT_POWER; status |= USB_PORT_STAT_POWER;
} }
/* Port Link State */ /* Update Port Link State for super speed ports*/
if (hcd->speed == HCD_USB3) { if (hcd->speed == HCD_USB3) {
/* resume state is a xHCI internal state. xhci_hub_report_link_state(&status, temp);
* Do not report it to usb core.
*/
if ((temp & PORT_PLS_MASK) != XDEV_RESUME)
status |= (temp & PORT_PLS_MASK);
} }
if (bus_state->port_c_suspend & (1 << wIndex)) if (bus_state->port_c_suspend & (1 << wIndex))
status |= 1 << USB_PORT_FEAT_C_SUSPEND; status |= 1 << USB_PORT_FEAT_C_SUSPEND;
......
...@@ -885,6 +885,17 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, ...@@ -885,6 +885,17 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
num_trbs_free_temp = ep_ring->num_trbs_free; num_trbs_free_temp = ep_ring->num_trbs_free;
dequeue_temp = ep_ring->dequeue; dequeue_temp = ep_ring->dequeue;
/* If we get two back-to-back stalls, and the first stalled transfer
* ends just before a link TRB, the dequeue pointer will be left on
* the link TRB by the code in the while loop. So we have to update
* the dequeue pointer one segment further, or we'll jump off
* the segment into la-la-land.
*/
if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) {
ep_ring->deq_seg = ep_ring->deq_seg->next;
ep_ring->dequeue = ep_ring->deq_seg->trbs;
}
while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) { while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
/* We have more usable TRBs */ /* We have more usable TRBs */
ep_ring->num_trbs_free++; ep_ring->num_trbs_free++;
......
...@@ -341,7 +341,11 @@ struct xhci_op_regs { ...@@ -341,7 +341,11 @@ struct xhci_op_regs {
#define PORT_PLC (1 << 22) #define PORT_PLC (1 << 22)
/* port configure error change - port failed to configure its link partner */ /* port configure error change - port failed to configure its link partner */
#define PORT_CEC (1 << 23) #define PORT_CEC (1 << 23)
/* bit 24 reserved */ /* Cold Attach Status - xHC can set this bit to report device attached during
* Sx state. Warm port reset should be perfomed to clear this bit and move port
* to connected state.
*/
#define PORT_CAS (1 << 24)
/* wake on connect (enable) */ /* wake on connect (enable) */
#define PORT_WKCONN_E (1 << 25) #define PORT_WKCONN_E (1 << 25)
/* wake on disconnect (enable) */ /* wake on disconnect (enable) */
......
...@@ -222,14 +222,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -222,14 +222,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
metro_priv->throttled = 0; metro_priv->throttled = 0;
spin_unlock_irqrestore(&metro_priv->lock, flags); spin_unlock_irqrestore(&metro_priv->lock, flags);
/*
* Force low_latency on so that our tty_push actually forces the data
* through, otherwise it is scheduled, and with high data rates (like
* with OHCI) data can get lost.
*/
if (tty)
tty->low_latency = 1;
/* Clear the urb pipe. */ /* Clear the urb pipe. */
usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe); usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe);
......
...@@ -497,6 +497,15 @@ static void option_instat_callback(struct urb *urb); ...@@ -497,6 +497,15 @@ static void option_instat_callback(struct urb *urb);
/* MediaTek products */ /* MediaTek products */
#define MEDIATEK_VENDOR_ID 0x0e8d #define MEDIATEK_VENDOR_ID 0x0e8d
#define MEDIATEK_PRODUCT_DC_1COM 0x00a0
#define MEDIATEK_PRODUCT_DC_4COM 0x00a5
#define MEDIATEK_PRODUCT_DC_5COM 0x00a4
#define MEDIATEK_PRODUCT_7208_1COM 0x7101
#define MEDIATEK_PRODUCT_7208_2COM 0x7102
#define MEDIATEK_PRODUCT_FP_1COM 0x0003
#define MEDIATEK_PRODUCT_FP_2COM 0x0023
#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043
#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033
/* Cellient products */ /* Cellient products */
#define CELLIENT_VENDOR_ID 0x2692 #define CELLIENT_VENDOR_ID 0x2692
...@@ -554,6 +563,10 @@ static const struct option_blacklist_info net_intf1_blacklist = { ...@@ -554,6 +563,10 @@ static const struct option_blacklist_info net_intf1_blacklist = {
.reserved = BIT(1), .reserved = BIT(1),
}; };
static const struct option_blacklist_info net_intf2_blacklist = {
.reserved = BIT(2),
};
static const struct option_blacklist_info net_intf3_blacklist = { static const struct option_blacklist_info net_intf3_blacklist = {
.reserved = BIT(3), .reserved = BIT(3),
}; };
...@@ -1099,6 +1112,8 @@ static const struct usb_device_id option_ids[] = { ...@@ -1099,6 +1112,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,
0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
...@@ -1240,6 +1255,17 @@ static const struct usb_device_id option_ids[] = { ...@@ -1240,6 +1255,17 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) },
{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -176,8 +176,6 @@ enum pci_dev_flags { ...@@ -176,8 +176,6 @@ enum pci_dev_flags {
PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2, PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
/* Provide indication device is assigned by a Virtual Machine Manager */ /* Provide indication device is assigned by a Virtual Machine Manager */
PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4, PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4,
/* Device causes system crash if in D3 during S3 sleep */
PCI_DEV_FLAGS_NO_D3_DURING_SLEEP = (__force pci_dev_flags_t) 8,
}; };
enum pci_irq_reroute_variant { enum pci_irq_reroute_variant {
......
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