Skip to content

Commit

Permalink
Merge tag 'usb-3.5-rc6' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Linus Torvalds committed Jul 11, 2012
2 parents 5f351f0 + dbf0e4c commit 1e032dc
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 56 deletions.
12 changes: 12 additions & 0 deletions drivers/pci/pci-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,18 @@ static int pci_pm_suspend_noirq(struct device *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;
}

Expand Down
5 changes: 0 additions & 5 deletions drivers/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1744,11 +1744,6 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
if (target_state == PCI_POWER_ERROR)
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));

error = pci_set_power_state(dev, target_state);
Expand Down
26 changes: 0 additions & 26 deletions drivers/pci/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, 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,
struct pci_fixup *end)
{
Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/class/cdc-wdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,8 @@ static ssize_t wdm_read
goto retry;
}
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);
goto retry;
}
Expand Down
18 changes: 10 additions & 8 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -2324,12 +2324,16 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
static int hub_port_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay, bool warm);

/* Is a USB 3.0 port in the Inactive state? */
static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus)
/* Is a USB 3.0 port in the Inactive or Complinance Mode state?
* 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) &&
(portstatus & USB_PORT_STAT_LINK_STATE) ==
USB_SS_PORT_LS_SS_INACTIVE;
(((portstatus & USB_PORT_STAT_LINK_STATE) ==
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,
Expand Down Expand Up @@ -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
*/
if (hub_port_inactive(hub, portstatus)) {
if (hub_port_warm_reset_required(hub, portstatus)) {
int ret;

if ((portchange & USB_PORT_STAT_C_CONNECTION))
Expand Down Expand Up @@ -4408,9 +4412,7 @@ static void hub_events(void)
/* Warm reset a USB3 protocol port if it's in
* SS.Inactive state.
*/
if (hub_is_superspeed(hub->hdev) &&
(portstatus & USB_PORT_STAT_LINK_STATE)
== USB_SS_PORT_LS_SS_INACTIVE) {
if (hub_port_warm_reset_required(hub, portstatus)) {
dev_dbg(hub_dev, "warm reset port %d\n", i);
hub_port_reset(hub, i, NULL,
HUB_BH_RESET_TIME, true);
Expand Down
44 changes: 38 additions & 6 deletions drivers/usb/host/xhci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
u16 wIndex, char *buf, u16 wLength)
{
Expand Down Expand Up @@ -606,13 +642,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
else
status |= USB_PORT_STAT_POWER;
}
/* Port Link State */
/* Update Port Link State for super speed ports*/
if (hcd->speed == HCD_USB3) {
/* resume state is a xHCI internal state.
* Do not report it to usb core.
*/
if ((temp & PORT_PLS_MASK) != XDEV_RESUME)
status |= (temp & PORT_PLS_MASK);
xhci_hub_report_link_state(&status, temp);
}
if (bus_state->port_c_suspend & (1 << wIndex))
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
Expand Down
11 changes: 11 additions & 0 deletions drivers/usb/host/xhci-ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
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) {
/* We have more usable TRBs */
ep_ring->num_trbs_free++;
Expand Down
6 changes: 5 additions & 1 deletion drivers/usb/host/xhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,11 @@ struct xhci_op_regs {
#define PORT_PLC (1 << 22)
/* port configure error change - port failed to configure its link partner */
#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) */
#define PORT_WKCONN_E (1 << 25)
/* wake on disconnect (enable) */
Expand Down
8 changes: 0 additions & 8 deletions drivers/usb/serial/metro-usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
metro_priv->throttled = 0;
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. */
usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe);

Expand Down
26 changes: 26 additions & 0 deletions drivers/usb/serial/option.c
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,15 @@ static void option_instat_callback(struct urb *urb);

/* MediaTek products */
#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 */
#define CELLIENT_VENDOR_ID 0x2692
Expand Down Expand Up @@ -554,6 +563,10 @@ static const struct option_blacklist_info net_intf1_blacklist = {
.reserved = BIT(1),
};

static const struct option_blacklist_info net_intf2_blacklist = {
.reserved = BIT(2),
};

static const struct option_blacklist_info net_intf3_blacklist = {
.reserved = BIT(3),
};
Expand Down Expand Up @@ -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, 0x1299, 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,
0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
Expand Down Expand Up @@ -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, 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, 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) },
{ } /* Terminating entry */
};
Expand Down
2 changes: 0 additions & 2 deletions include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ enum pci_dev_flags {
PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
/* Provide indication device is assigned by a Virtual Machine Manager */
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 {
Expand Down

0 comments on commit 1e032dc

Please sign in to comment.