aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Rui <ray.huang@amd.com>2013-09-16 11:47:28 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-25 20:24:37 -0400
commit7868943db1668fba898cf71bed1506c19d6958aa (patch)
tree39592951e8e9fc2eddf7828cc3a53ca40e38fbd3
parent22b4f0cd1d4d98f50213e9a37ead654e80b54b9d (diff)
usb: core: implement AMD remote wakeup quirk
The following patch is required to resolve remote wake issues with certain devices. Issue description: If the remote wake is issued from the device in a specific timing condition while the system is entering sleep state then it may cause system to auto wake on subsequent sleep cycle. Root cause: Host controller rebroadcasts the Resume signal > 100 µseconds after receiving the original resume event from the device. For proper function, some devices may require the rebroadcast of resume event within the USB spec of 100µS. Workaroud: 1. Filter the AMD platforms with Yangtze chipset, then judge of all the usb devices are mouse or not. And get out the port id which attached a mouse with Pixart controller. 2. Then reset the port which attached issue device during system resume from S3. [Q] Why the special devices are only mice? Would high speed devices such as 3G modem or USB Bluetooth adapter trigger this issue? - Current this sensitivity is only confined to devices that use Pixart controllers. This controller is designed for use with LS mouse devices only. We have not observed any other devices failing. There may be a small risk for other devices also but this patch (reset device in resume phase) will cover the cases if required. [Q] Shouldn’t the resume signal be sent within 100 us for every device? - The Host controller may not send the resume signal within 100us, this our host controller specification change. This is why we require the patch to prevent side effects on certain known devices. [Q] Why would clicking mouse INTENSELY to wake the system up trigger this issue? - This behavior is specific to the devices that use Pixart controller. It is timing dependent on when the resume event is triggered during the sleep state. [Q] Is it a host controller issue or mouse? - It is the host controller behavior during resume that triggers the device incorrect behavior on the next resume. This patch sets USB_QUIRK_RESET_RESUME flag for these Pixart-based mice when they attached to platforms with AMD Yangtze chipset. Signed-off-by: Huang Rui <ray.huang@amd.com> Suggested-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/core/hcd-pci.c3
-rw-r--r--drivers/usb/core/quirks.c37
-rw-r--r--drivers/usb/host/pci-quirks.c12
-rw-r--r--include/linux/usb/hcd.h3
4 files changed, 55 insertions, 0 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index b9d3c43e3859..dfe9d0f22978 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -215,6 +215,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
215 goto disable_pci; 215 goto disable_pci;
216 } 216 }
217 217
218 hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) &&
219 driver->flags & (HCD_USB11 | HCD_USB3)) ? 1 : 0;
220
218 if (driver->flags & HCD_MEMORY) { 221 if (driver->flags & HCD_MEMORY) {
219 /* EHCI, OHCI */ 222 /* EHCI, OHCI */
220 hcd->rsrc_start = pci_resource_start(dev, 0); 223 hcd->rsrc_start = pci_resource_start(dev, 0);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 5b44cd47da5b..74d18c8b7a88 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -13,6 +13,7 @@
13 13
14#include <linux/usb.h> 14#include <linux/usb.h>
15#include <linux/usb/quirks.h> 15#include <linux/usb/quirks.h>
16#include <linux/usb/hcd.h>
16#include "usb.h" 17#include "usb.h"
17 18
18/* Lists of quirky USB devices, split in device quirks and interface quirks. 19/* Lists of quirky USB devices, split in device quirks and interface quirks.
@@ -155,6 +156,21 @@ static const struct usb_device_id usb_interface_quirk_list[] = {
155 { } /* terminating entry must be last */ 156 { } /* terminating entry must be last */
156}; 157};
157 158
159static const struct usb_device_id usb_amd_resume_quirk_list[] = {
160 /* Lenovo Mouse with Pixart controller */
161 { USB_DEVICE(0x17ef, 0x602e), .driver_info = USB_QUIRK_RESET_RESUME },
162
163 /* Pixart Mouse */
164 { USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME },
165 { USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME },
166 { USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME },
167
168 /* Logitech Optical Mouse M90/M100 */
169 { USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME },
170
171 { } /* terminating entry must be last */
172};
173
158static bool usb_match_any_interface(struct usb_device *udev, 174static bool usb_match_any_interface(struct usb_device *udev,
159 const struct usb_device_id *id) 175 const struct usb_device_id *id)
160{ 176{
@@ -181,6 +197,18 @@ static bool usb_match_any_interface(struct usb_device *udev,
181 return false; 197 return false;
182} 198}
183 199
200int usb_amd_resume_quirk(struct usb_device *udev)
201{
202 struct usb_hcd *hcd;
203
204 hcd = bus_to_hcd(udev->bus);
205 /* The device should be attached directly to root hub */
206 if (udev->level == 1 && hcd->amd_resume_bug == 1)
207 return 1;
208
209 return 0;
210}
211
184static u32 __usb_detect_quirks(struct usb_device *udev, 212static u32 __usb_detect_quirks(struct usb_device *udev,
185 const struct usb_device_id *id) 213 const struct usb_device_id *id)
186{ 214{
@@ -206,6 +234,15 @@ static u32 __usb_detect_quirks(struct usb_device *udev,
206void usb_detect_quirks(struct usb_device *udev) 234void usb_detect_quirks(struct usb_device *udev)
207{ 235{
208 udev->quirks = __usb_detect_quirks(udev, usb_quirk_list); 236 udev->quirks = __usb_detect_quirks(udev, usb_quirk_list);
237
238 /*
239 * Pixart-based mice would trigger remote wakeup issue on AMD
240 * Yangtze chipset, so set them as RESET_RESUME flag.
241 */
242 if (usb_amd_resume_quirk(udev))
243 udev->quirks |= __usb_detect_quirks(udev,
244 usb_amd_resume_quirk_list);
245
209 if (udev->quirks) 246 if (udev->quirks)
210 dev_dbg(&udev->dev, "USB quirks for this device: %x\n", 247 dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
211 udev->quirks); 248 udev->quirks);
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index d1e68d887f6e..17eb1916e65e 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -250,6 +250,18 @@ commit:
250} 250}
251EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info); 251EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
252 252
253int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev)
254{
255 /* Make sure amd chipset type has already been initialized */
256 usb_amd_find_chipset_info();
257 if (amd_chipset.sb_type.gen != AMD_CHIPSET_YANGTZE)
258 return 0;
259
260 dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n");
261 return 1;
262}
263EXPORT_SYMBOL_GPL(usb_hcd_amd_remote_wakeup_quirk);
264
253/* 265/*
254 * The hardware normally enables the A-link power management feature, which 266 * The hardware normally enables the A-link power management feature, which
255 * lets the system lower the power consumption in idle states. 267 * lets the system lower the power consumption in idle states.
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 8c865134c881..fc64b6825f5e 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -141,6 +141,7 @@ struct usb_hcd {
141 unsigned wireless:1; /* Wireless USB HCD */ 141 unsigned wireless:1; /* Wireless USB HCD */
142 unsigned authorized_default:1; 142 unsigned authorized_default:1;
143 unsigned has_tt:1; /* Integrated TT in root hub */ 143 unsigned has_tt:1; /* Integrated TT in root hub */
144 unsigned amd_resume_bug:1; /* AMD remote wakeup quirk */
144 145
145 unsigned int irq; /* irq allocated */ 146 unsigned int irq; /* irq allocated */
146 void __iomem *regs; /* device memory/io */ 147 void __iomem *regs; /* device memory/io */
@@ -435,6 +436,8 @@ extern int usb_hcd_pci_probe(struct pci_dev *dev,
435extern void usb_hcd_pci_remove(struct pci_dev *dev); 436extern void usb_hcd_pci_remove(struct pci_dev *dev);
436extern void usb_hcd_pci_shutdown(struct pci_dev *dev); 437extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
437 438
439extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev);
440
438#ifdef CONFIG_PM 441#ifdef CONFIG_PM
439extern const struct dev_pm_ops usb_hcd_pci_pm_ops; 442extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
440#endif 443#endif