aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-09-23 01:38:16 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 19:47:40 -0400
commit5f827ea3c3820cd8e0a1a35e4d275c8b78ee94e1 (patch)
tree7bd8a0f12f83c219cab6da7e30e8d0e1d94df57d
parentf3f3253d644d36a2ea5464005a9c2cf28804d200 (diff)
[PATCH] usbcore PCI glue updates for PM
This updates the PCI glue to address the new and simplified usbcore suspend semantics, where CONFIG_USB_SUSPEND becomes irrelevant to HCDs because hcd->hub_suspend() will always be called. - Removes now-unneeded recursion support - Go back to ignoring faults reported by the wakeup calls; we expect them to fail sometimes, and that's just fine. The PCI HCDs will need simple changes to catch up to this, like being able to ignore the setting of CONFIG_USB_SUSPEND. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> drivers/usb/core/hcd-pci.c | 106 +++++++++++++++++++++------------------------ drivers/usb/core/hcd.h | 6 +- 2 files changed, 53 insertions(+), 59 deletions(-)
-rw-r--r--drivers/usb/core/hcd-pci.c106
-rw-r--r--drivers/usb/core/hcd.h6
2 files changed, 53 insertions, 59 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 6385d1a99b60..84d9e69329bb 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -30,6 +30,8 @@
30#include <asm/io.h> 30#include <asm/io.h>
31#include <asm/irq.h> 31#include <asm/irq.h>
32#include <linux/usb.h> 32#include <linux/usb.h>
33
34#include "usb.h"
33#include "hcd.h" 35#include "hcd.h"
34 36
35 37
@@ -197,6 +199,26 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
197 199
198 hcd = pci_get_drvdata(dev); 200 hcd = pci_get_drvdata(dev);
199 201
202 /* Root hub suspend should have stopped all downstream traffic,
203 * and all bus master traffic. And done so for both the interface
204 * and the stub usb_device (which we check here). But maybe it
205 * didn't; writing sysfs power/state files ignores such rules...
206 *
207 * We must ignore the FREEZE vs SUSPEND distinction here, because
208 * otherwise the swsusp will save (and restore) garbage state.
209 */
210 if (hcd->self.root_hub->dev.power.power_state.event == PM_EVENT_ON)
211 return -EBUSY;
212
213 if (hcd->driver->suspend) {
214 retval = hcd->driver->suspend(hcd, message);
215 if (retval) {
216 dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n",
217 retval);
218 goto done;
219 }
220 }
221
200 /* FIXME until the generic PM interfaces change a lot more, this 222 /* FIXME until the generic PM interfaces change a lot more, this
201 * can't use PCI D1 and D2 states. For example, the confusion 223 * can't use PCI D1 and D2 states. For example, the confusion
202 * between messages and states will need to vanish, and messages 224 * between messages and states will need to vanish, and messages
@@ -215,31 +237,13 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
215 */ 237 */
216 has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM); 238 has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
217 239
218 switch (hcd->state) { 240 /* Downstream ports from this root hub should already be quiesced, so
219 241 * there will be no DMA activity. Now we can shut down the upstream
220 /* entry if root hub wasn't yet suspended ... from sysfs, 242 * link (except maybe for PME# resume signaling) and enter some PCI
221 * without autosuspend, or if USB_SUSPEND isn't configured. 243 * low power state, if the hardware allows.
222 */ 244 */
223 case HC_STATE_RUNNING: 245 if (hcd->state == HC_STATE_SUSPENDED) {
224 hcd->state = HC_STATE_QUIESCING;
225 retval = hcd->driver->suspend (hcd, message);
226 if (retval) {
227 dev_dbg (hcd->self.controller,
228 "suspend fail, retval %d\n",
229 retval);
230 break;
231 }
232 hcd->state = HC_STATE_SUSPENDED;
233 /* FALLTHROUGH */
234 246
235 /* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the
236 * controller and/or root hub will already have been suspended,
237 * but it won't be ready for a PCI resume call.
238 *
239 * FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will
240 * have been called, otherwise root hub timers still run ...
241 */
242 case HC_STATE_SUSPENDED:
243 /* no DMA or IRQs except when HC is active */ 247 /* no DMA or IRQs except when HC is active */
244 if (dev->current_state == PCI_D0) { 248 if (dev->current_state == PCI_D0) {
245 pci_save_state (dev); 249 pci_save_state (dev);
@@ -248,7 +252,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
248 252
249 if (!has_pci_pm) { 253 if (!has_pci_pm) {
250 dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n"); 254 dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
251 break; 255 goto done;
252 } 256 }
253 257
254 /* NOTE: dev->current_state becomes nonzero only here, and 258 /* NOTE: dev->current_state becomes nonzero only here, and
@@ -259,28 +263,29 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
259 retval = pci_set_power_state (dev, PCI_D3hot); 263 retval = pci_set_power_state (dev, PCI_D3hot);
260 if (retval == 0) { 264 if (retval == 0) {
261 dev_dbg (hcd->self.controller, "--> PCI D3\n"); 265 dev_dbg (hcd->self.controller, "--> PCI D3\n");
262 retval = pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup); 266
263 if (retval) 267 /* Ignore these return values. We rely on pci code to
264 break; 268 * reject requests the hardware can't implement, rather
265 retval = pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup); 269 * than coding the same thing.
266 } else if (retval < 0) { 270 */
271 (void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
272 (void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
273 } else {
267 dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n", 274 dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
268 retval); 275 retval);
269 (void) usb_hcd_pci_resume (dev); 276 (void) usb_hcd_pci_resume (dev);
270 break;
271 } 277 }
272 break; 278
273 default: 279 } else {
274 dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n", 280 dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
275 hcd->state); 281 hcd->state);
276 WARN_ON(1); 282 WARN_ON(1);
277 retval = -EINVAL; 283 retval = -EINVAL;
278 break;
279 } 284 }
280 285
281 /* update power_state **ONLY** to make sysfs happier */ 286done:
282 if (retval == 0) 287 if (retval == 0)
283 dev->dev.power.power_state = message; 288 dev->dev.power.power_state = PMSG_SUSPEND;
284 return retval; 289 return retval;
285} 290}
286EXPORT_SYMBOL (usb_hcd_pci_suspend); 291EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -336,20 +341,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
336 dev->current_state); 341 dev->current_state);
337 } 342 }
338#endif 343#endif
339 retval = pci_enable_wake (dev, dev->current_state, 0); 344 /* yes, ignore these results too... */
340 if (retval) { 345 (void) pci_enable_wake (dev, dev->current_state, 0);
341 dev_err(hcd->self.controller, 346 (void) pci_enable_wake (dev, PCI_D3cold, 0);
342 "can't enable_wake to %d, %d!\n",
343 dev->current_state, retval);
344 return retval;
345 }
346 retval = pci_enable_wake (dev, PCI_D3cold, 0);
347 if (retval) {
348 dev_err(hcd->self.controller,
349 "can't enable_wake to %d, %d!\n",
350 PCI_D3cold, retval);
351 return retval;
352 }
353 } else { 347 } else {
354 /* Same basic cases: clean (powered/not), dirty */ 348 /* Same basic cases: clean (powered/not), dirty */
355 dev_dbg(hcd->self.controller, "PCI legacy resume\n"); 349 dev_dbg(hcd->self.controller, "PCI legacy resume\n");
@@ -371,17 +365,17 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
371 365
372 dev->dev.power.power_state = PMSG_ON; 366 dev->dev.power.power_state = PMSG_ON;
373 367
374 hcd->state = HC_STATE_RESUMING;
375 hcd->saw_irq = 0; 368 hcd->saw_irq = 0;
376 369
377 retval = hcd->driver->resume (hcd); 370 if (hcd->driver->resume) {
378 if (!HC_IS_RUNNING (hcd->state)) { 371 retval = hcd->driver->resume(hcd);
379 dev_dbg (hcd->self.controller, 372 if (retval) {
380 "resume fail, retval %d\n", retval); 373 dev_err (hcd->self.controller,
381 usb_hc_died (hcd); 374 "PCI post-resume error %d!\n", retval);
375 usb_hc_died (hcd);
376 }
382 } 377 }
383 378
384 retval = pci_enable_device(dev);
385 return retval; 379 return retval;
386} 380}
387EXPORT_SYMBOL (usb_hcd_pci_resume); 381EXPORT_SYMBOL (usb_hcd_pci_resume);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index eb21f13c5c74..74757fc1a99f 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -182,12 +182,12 @@ struct hc_driver {
182 int (*start) (struct usb_hcd *hcd); 182 int (*start) (struct usb_hcd *hcd);
183 183
184 /* NOTE: these suspend/resume calls relate to the HC as 184 /* NOTE: these suspend/resume calls relate to the HC as
185 * a whole, not just the root hub; they're for bus glue. 185 * a whole, not just the root hub; they're for PCI bus glue.
186 */ 186 */
187 /* called after all devices were suspended */ 187 /* called after suspending the hub, before entering D3 etc */
188 int (*suspend) (struct usb_hcd *hcd, pm_message_t message); 188 int (*suspend) (struct usb_hcd *hcd, pm_message_t message);
189 189
190 /* called before any devices get resumed */ 190 /* called after entering D0 (etc), before resuming the hub */
191 int (*resume) (struct usb_hcd *hcd); 191 int (*resume) (struct usb_hcd *hcd);
192 192
193 /* cleanly make HCD stop writing memory and doing I/O */ 193 /* cleanly make HCD stop writing memory and doing I/O */