Blame view
drivers/pci/pci-driver.c
30.7 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 |
/* * drivers/pci/pci-driver.c * |
2b9373031 PCI: remove fooli... |
4 5 6 7 8 |
* (C) Copyright 2002-2004, 2007 Greg Kroah-Hartman <greg@kroah.com> * (C) Copyright 2007 Novell Inc. * * Released under the GPL v2 only. * |
1da177e4c Linux-2.6.12-rc2 |
9 10 11 12 13 14 |
*/ #include <linux/pci.h> #include <linux/module.h> #include <linux/init.h> #include <linux/device.h> |
d42c69972 [PATCH] PCI: Run ... |
15 |
#include <linux/mempolicy.h> |
4e57b6817 [PATCH] fix missi... |
16 17 |
#include <linux/string.h> #include <linux/slab.h> |
8c65b4a60 [PATCH] fix remai... |
18 |
#include <linux/sched.h> |
873392ca5 PCI: work_on_cpu:... |
19 |
#include <linux/cpu.h> |
6cbf82148 PCI PM: Run-time ... |
20 |
#include <linux/pm_runtime.h> |
eea3fc035 PCI / PM: Detect ... |
21 |
#include <linux/suspend.h> |
1da177e4c Linux-2.6.12-rc2 |
22 |
#include "pci.h" |
758658589 [PATCH] PCI: clea... |
23 24 25 26 |
struct pci_dynid { struct list_head node; struct pci_device_id id; }; |
1da177e4c Linux-2.6.12-rc2 |
27 |
|
9dba910e9 PCI: separate out... |
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
/** * pci_add_dynid - add a new PCI device ID to this driver and re-probe devices * @drv: target pci driver * @vendor: PCI vendor ID * @device: PCI device ID * @subvendor: PCI subvendor ID * @subdevice: PCI subdevice ID * @class: PCI class * @class_mask: PCI class mask * @driver_data: private driver data * * Adds a new dynamic pci device ID to this driver and causes the * driver to probe for all devices again. @drv must have been * registered prior to calling this function. * * CONTEXT: * Does GFP_KERNEL allocation. * * RETURNS: * 0 on success, -errno on failure. */ int pci_add_dynid(struct pci_driver *drv, unsigned int vendor, unsigned int device, unsigned int subvendor, unsigned int subdevice, unsigned int class, unsigned int class_mask, unsigned long driver_data) { struct pci_dynid *dynid; int retval; dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); if (!dynid) return -ENOMEM; dynid->id.vendor = vendor; dynid->id.device = device; dynid->id.subvendor = subvendor; dynid->id.subdevice = subdevice; dynid->id.class = class; dynid->id.class_mask = class_mask; dynid->id.driver_data = driver_data; |
3d3c2ae11 [PATCH] PCI: fix ... |
69 |
|
9dba910e9 PCI: separate out... |
70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
spin_lock(&drv->dynids.lock); list_add_tail(&dynid->node, &drv->dynids.list); spin_unlock(&drv->dynids.lock); get_driver(&drv->driver); retval = driver_attach(&drv->driver); put_driver(&drv->driver); return retval; } static void pci_free_dynids(struct pci_driver *drv) { struct pci_dynid *dynid, *n; |
3d3c2ae11 [PATCH] PCI: fix ... |
84 |
|
9dba910e9 PCI: separate out... |
85 86 87 88 89 90 91 92 93 94 95 96 |
spin_lock(&drv->dynids.lock); list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { list_del(&dynid->node); kfree(dynid); } spin_unlock(&drv->dynids.lock); } /* * Dynamic device ID manipulation via sysfs is disabled for !CONFIG_HOTPLUG */ #ifdef CONFIG_HOTPLUG |
1da177e4c Linux-2.6.12-rc2 |
97 |
/** |
9dba910e9 PCI: separate out... |
98 |
* store_new_id - sysfs frontend to pci_add_dynid() |
8f7020d36 [PATCH] kernel-do... |
99 100 101 |
* @driver: target device driver * @buf: buffer for scanning device ID data * @count: input size |
1da177e4c Linux-2.6.12-rc2 |
102 |
* |
9dba910e9 PCI: separate out... |
103 |
* Allow PCI IDs to be added to an existing driver via sysfs. |
1da177e4c Linux-2.6.12-rc2 |
104 |
*/ |
f8eb1005a [PATCH] pci-drive... |
105 |
static ssize_t |
1da177e4c Linux-2.6.12-rc2 |
106 107 |
store_new_id(struct device_driver *driver, const char *buf, size_t count) { |
1da177e4c Linux-2.6.12-rc2 |
108 |
struct pci_driver *pdrv = to_pci_driver(driver); |
b41d6cf38 PCI: Check dynids... |
109 |
const struct pci_device_id *ids = pdrv->id_table; |
6ba186361 PCI: Require vend... |
110 |
__u32 vendor, device, subvendor=PCI_ANY_ID, |
1da177e4c Linux-2.6.12-rc2 |
111 112 113 |
subdevice=PCI_ANY_ID, class=0, class_mask=0; unsigned long driver_data=0; int fields=0; |
9dba910e9 PCI: separate out... |
114 |
int retval; |
1da177e4c Linux-2.6.12-rc2 |
115 |
|
b41d6cf38 PCI: Check dynids... |
116 |
fields = sscanf(buf, "%x %x %x %x %x %x %lx", |
1da177e4c Linux-2.6.12-rc2 |
117 118 |
&vendor, &device, &subvendor, &subdevice, &class, &class_mask, &driver_data); |
6ba186361 PCI: Require vend... |
119 |
if (fields < 2) |
1da177e4c Linux-2.6.12-rc2 |
120 |
return -EINVAL; |
b41d6cf38 PCI: Check dynids... |
121 122 |
/* Only accept driver_data values that match an existing id_table entry */ |
2debb4d20 PCI: allow pci dr... |
123 124 125 126 127 128 129 130 |
if (ids) { retval = -EINVAL; while (ids->vendor || ids->subvendor || ids->class_mask) { if (driver_data == ids->driver_data) { retval = 0; break; } ids++; |
b41d6cf38 PCI: Check dynids... |
131 |
} |
2debb4d20 PCI: allow pci dr... |
132 133 |
if (retval) /* No match */ return retval; |
b41d6cf38 PCI: Check dynids... |
134 |
} |
b41d6cf38 PCI: Check dynids... |
135 |
|
9dba910e9 PCI: separate out... |
136 137 |
retval = pci_add_dynid(pdrv, vendor, device, subvendor, subdevice, class, class_mask, driver_data); |
b19441af1 PCI: fix __must_c... |
138 139 |
if (retval) return retval; |
1da177e4c Linux-2.6.12-rc2 |
140 141 |
return count; } |
1da177e4c Linux-2.6.12-rc2 |
142 |
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); |
1da177e4c Linux-2.6.12-rc2 |
143 |
|
0994375e9 PCI: add remove_i... |
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
/** * store_remove_id - remove a PCI device ID from this driver * @driver: target device driver * @buf: buffer for scanning device ID data * @count: input size * * Removes a dynamic pci device ID to this driver. */ static ssize_t store_remove_id(struct device_driver *driver, const char *buf, size_t count) { struct pci_dynid *dynid, *n; struct pci_driver *pdrv = to_pci_driver(driver); __u32 vendor, device, subvendor = PCI_ANY_ID, subdevice = PCI_ANY_ID, class = 0, class_mask = 0; int fields = 0; int retval = -ENODEV; fields = sscanf(buf, "%x %x %x %x %x %x", &vendor, &device, &subvendor, &subdevice, &class, &class_mask); if (fields < 2) return -EINVAL; spin_lock(&pdrv->dynids.lock); list_for_each_entry_safe(dynid, n, &pdrv->dynids.list, node) { struct pci_device_id *id = &dynid->id; if ((id->vendor == vendor) && (id->device == device) && (subvendor == PCI_ANY_ID || id->subvendor == subvendor) && (subdevice == PCI_ANY_ID || id->subdevice == subdevice) && !((id->class ^ class) & class_mask)) { list_del(&dynid->node); kfree(dynid); retval = 0; break; } } spin_unlock(&pdrv->dynids.lock); if (retval) return retval; return count; } static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); |
1da177e4c Linux-2.6.12-rc2 |
189 190 191 192 193 |
static int pci_create_newid_file(struct pci_driver *drv) { int error = 0; if (drv->probe != NULL) |
03d43b19b PCI: use proper c... |
194 |
error = driver_create_file(&drv->driver, &driver_attr_new_id); |
1da177e4c Linux-2.6.12-rc2 |
195 196 |
return error; } |
03d43b19b PCI: use proper c... |
197 198 199 200 |
static void pci_remove_newid_file(struct pci_driver *drv) { driver_remove_file(&drv->driver, &driver_attr_new_id); } |
0994375e9 PCI: add remove_i... |
201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
static int pci_create_removeid_file(struct pci_driver *drv) { int error = 0; if (drv->probe != NULL) error = driver_create_file(&drv->driver,&driver_attr_remove_id); return error; } static void pci_remove_removeid_file(struct pci_driver *drv) { driver_remove_file(&drv->driver, &driver_attr_remove_id); } |
1da177e4c Linux-2.6.12-rc2 |
215 |
#else /* !CONFIG_HOTPLUG */ |
1da177e4c Linux-2.6.12-rc2 |
216 217 218 219 |
static inline int pci_create_newid_file(struct pci_driver *drv) { return 0; } |
03d43b19b PCI: use proper c... |
220 |
static inline void pci_remove_newid_file(struct pci_driver *drv) {} |
0994375e9 PCI: add remove_i... |
221 222 223 224 225 |
static inline int pci_create_removeid_file(struct pci_driver *drv) { return 0; } static inline void pci_remove_removeid_file(struct pci_driver *drv) {} |
1da177e4c Linux-2.6.12-rc2 |
226 227 228 |
#endif /** |
758658589 [PATCH] PCI: clea... |
229 |
* pci_match_id - See if a pci device matches a given pci_id table |
1da177e4c Linux-2.6.12-rc2 |
230 |
* @ids: array of PCI device id structures to search in |
758658589 [PATCH] PCI: clea... |
231 232 |
* @dev: the PCI device structure to match against. * |
1da177e4c Linux-2.6.12-rc2 |
233 |
* Used by a driver to check whether a PCI device present in the |
758658589 [PATCH] PCI: clea... |
234 |
* system is in its list of supported devices. Returns the matching |
1da177e4c Linux-2.6.12-rc2 |
235 |
* pci_device_id structure or %NULL if there is no match. |
758658589 [PATCH] PCI: clea... |
236 |
* |
8b60756a6 Fix more "depreca... |
237 |
* Deprecated, don't use this as it will not catch any dynamic ids |
758658589 [PATCH] PCI: clea... |
238 |
* that a driver might want to check for. |
1da177e4c Linux-2.6.12-rc2 |
239 |
*/ |
758658589 [PATCH] PCI: clea... |
240 241 |
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev) |
1da177e4c Linux-2.6.12-rc2 |
242 |
{ |
758658589 [PATCH] PCI: clea... |
243 244 245 246 247 248 |
if (ids) { while (ids->vendor || ids->subvendor || ids->class_mask) { if (pci_match_one_device(ids, dev)) return ids; ids++; } |
1da177e4c Linux-2.6.12-rc2 |
249 250 251 252 253 |
} return NULL; } /** |
ae9608af9 PCI: fix pci-driv... |
254 |
* pci_match_device - Tell if a PCI device structure has a matching PCI device id structure |
758658589 [PATCH] PCI: clea... |
255 |
* @drv: the PCI driver to match against |
39ba487fe [PATCH] PCI: kern... |
256 |
* @dev: the PCI device structure to match against |
758658589 [PATCH] PCI: clea... |
257 258 259 260 |
* * Used by a driver to check whether a PCI device present in the * system is in its list of supported devices. Returns the matching * pci_device_id structure or %NULL if there is no match. |
1da177e4c Linux-2.6.12-rc2 |
261 |
*/ |
d73460d79 PCI: make pci_mat... |
262 263 |
static const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_dev *dev) |
758658589 [PATCH] PCI: clea... |
264 |
{ |
758658589 [PATCH] PCI: clea... |
265 |
struct pci_dynid *dynid; |
1da177e4c Linux-2.6.12-rc2 |
266 |
|
7461b60af PCI: use /sys/bus... |
267 |
/* Look at the dynamic ids first, before the static ones */ |
758658589 [PATCH] PCI: clea... |
268 269 270 271 272 273 |
spin_lock(&drv->dynids.lock); list_for_each_entry(dynid, &drv->dynids.list, node) { if (pci_match_one_device(&dynid->id, dev)) { spin_unlock(&drv->dynids.lock); return &dynid->id; } |
1da177e4c Linux-2.6.12-rc2 |
274 |
} |
758658589 [PATCH] PCI: clea... |
275 |
spin_unlock(&drv->dynids.lock); |
7461b60af PCI: use /sys/bus... |
276 277 |
return pci_match_id(drv->id_table, dev); |
1da177e4c Linux-2.6.12-rc2 |
278 |
} |
873392ca5 PCI: work_on_cpu:... |
279 280 281 282 283 284 285 286 287 |
struct drv_dev_and_id { struct pci_driver *drv; struct pci_dev *dev; const struct pci_device_id *id; }; static long local_pci_probe(void *_ddi) { struct drv_dev_and_id *ddi = _ddi; |
f3ec4f87d PCI: change devic... |
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
struct device *dev = &ddi->dev->dev; int rc; /* Unbound PCI devices are always set to disabled and suspended. * During probe, the device is set to enabled and active and the * usage count is incremented. If the driver supports runtime PM, * it should call pm_runtime_put_noidle() in its probe routine and * pm_runtime_get_noresume() in its remove routine. */ pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); rc = ddi->drv->probe(ddi->dev, ddi->id); if (rc) { pm_runtime_disable(dev); pm_runtime_set_suspended(dev); pm_runtime_put_noidle(dev); } return rc; |
873392ca5 PCI: work_on_cpu:... |
308 |
} |
d42c69972 [PATCH] PCI: Run ... |
309 310 311 |
static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, const struct pci_device_id *id) { |
873392ca5 PCI: work_on_cpu:... |
312 313 314 315 316 317 318 319 |
int error, node; struct drv_dev_and_id ddi = { drv, dev, id }; /* Execute driver initialization on node where the device's bus is attached to. This way the driver likely allocates its local memory on the right node without any need to change it. */ node = dev_to_node(&dev->dev); |
f70316dac generic: use new ... |
320 |
if (node >= 0) { |
873392ca5 PCI: work_on_cpu:... |
321 |
int cpu; |
873392ca5 PCI: work_on_cpu:... |
322 323 |
get_online_cpus(); |
a70f73028 cpumask: replace ... |
324 |
cpu = cpumask_any_and(cpumask_of_node(node), cpu_online_mask); |
873392ca5 PCI: work_on_cpu:... |
325 326 327 328 329 330 331 |
if (cpu < nr_cpu_ids) error = work_on_cpu(cpu, local_pci_probe, &ddi); else error = local_pci_probe(&ddi); put_online_cpus(); } else error = local_pci_probe(&ddi); |
d42c69972 [PATCH] PCI: Run ... |
332 333 |
return error; } |
1da177e4c Linux-2.6.12-rc2 |
334 |
/** |
23ea3793f PCI: fix __pci_de... |
335 |
* __pci_device_probe - check if a driver wants to claim a specific PCI device |
8f7020d36 [PATCH] kernel-do... |
336 337 |
* @drv: driver to call to check if it wants the PCI device * @pci_dev: PCI device being probed |
1da177e4c Linux-2.6.12-rc2 |
338 |
* |
8f7020d36 [PATCH] kernel-do... |
339 |
* returns 0 on success, else error. |
1da177e4c Linux-2.6.12-rc2 |
340 341 342 343 |
* side-effect: pci_dev->driver is set to drv when drv claims pci_dev. */ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) |
758658589 [PATCH] PCI: clea... |
344 345 |
{ const struct pci_device_id *id; |
1da177e4c Linux-2.6.12-rc2 |
346 347 348 |
int error = 0; if (!pci_dev->driver && drv->probe) { |
758658589 [PATCH] PCI: clea... |
349 350 351 352 |
error = -ENODEV; id = pci_match_device(drv, pci_dev); if (id) |
d42c69972 [PATCH] PCI: Run ... |
353 |
error = pci_call_probe(drv, pci_dev, id); |
758658589 [PATCH] PCI: clea... |
354 355 356 357 |
if (error >= 0) { pci_dev->driver = drv; error = 0; } |
1da177e4c Linux-2.6.12-rc2 |
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
} return error; } static int pci_device_probe(struct device * dev) { int error = 0; struct pci_driver *drv; struct pci_dev *pci_dev; drv = to_pci_driver(dev->driver); pci_dev = to_pci_dev(dev); pci_dev_get(pci_dev); error = __pci_device_probe(drv, pci_dev); if (error) pci_dev_put(pci_dev); return error; } static int pci_device_remove(struct device * dev) { struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; if (drv) { |
f3ec4f87d PCI: change devic... |
384 385 |
if (drv->remove) { pm_runtime_get_sync(dev); |
1da177e4c Linux-2.6.12-rc2 |
386 |
drv->remove(pci_dev); |
f3ec4f87d PCI: change devic... |
387 388 |
pm_runtime_put_noidle(dev); } |
1da177e4c Linux-2.6.12-rc2 |
389 390 |
pci_dev->driver = NULL; } |
f3ec4f87d PCI: change devic... |
391 392 393 394 |
/* Undo the runtime PM settings in local_pci_probe() */ pm_runtime_disable(dev); pm_runtime_set_suspended(dev); pm_runtime_put_noidle(dev); |
1da177e4c Linux-2.6.12-rc2 |
395 |
/* |
2449e06a5 PCI: reset pci de... |
396 397 398 399 400 401 402 |
* If the device is still on, set the power state as "unknown", * since it might change by the next time we load the driver. */ if (pci_dev->current_state == PCI_D0) pci_dev->current_state = PCI_UNKNOWN; /* |
1da177e4c Linux-2.6.12-rc2 |
403 404 405 406 407 408 409 410 411 412 413 |
* We would love to complain here if pci_dev->is_enabled is set, that * the driver should have called pci_disable_device(), but the * unfortunate fact is there are too many odd BIOS and bridge setups * that don't like drivers doing that all of the time. * Oh well, we can dream of sane hardware when we sleep, no matter how * horrible the crap we have to deal with is when we are awake... */ pci_dev_put(pci_dev); return 0; } |
bbb44d9f2 PCI: implement ne... |
414 415 416 417 418 419 420 421 422 423 |
static void pci_device_shutdown(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_driver *drv = pci_dev->driver; if (drv && drv->shutdown) drv->shutdown(pci_dev); pci_msi_shutdown(pci_dev); pci_msix_shutdown(pci_dev); } |
aa3386015 PM: Remove CONFIG... |
424 |
#ifdef CONFIG_PM |
6cbf82148 PCI PM: Run-time ... |
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 |
/* Auxiliary functions used for system resume and run-time resume. */ /** * pci_restore_standard_config - restore standard config registers of PCI device * @pci_dev: PCI device to handle */ static int pci_restore_standard_config(struct pci_dev *pci_dev) { pci_update_current_state(pci_dev, PCI_UNKNOWN); if (pci_dev->current_state != PCI_D0) { int error = pci_set_power_state(pci_dev, PCI_D0); if (error) return error; } |
1d3c16a81 PCI: make pci_res... |
441 442 |
pci_restore_state(pci_dev); return 0; |
6cbf82148 PCI PM: Run-time ... |
443 444 445 446 447 448 449 450 451 |
} static void pci_pm_default_resume_early(struct pci_dev *pci_dev) { pci_restore_standard_config(pci_dev); pci_fixup_device(pci_fixup_resume_early, pci_dev); } #endif |
bbb44d9f2 PCI: implement ne... |
452 453 454 455 |
#ifdef CONFIG_PM_SLEEP /* * Default "suspend" method for devices that have no driver provided suspend, |
fa58d305d PCI PM: Add suspe... |
456 |
* or not even a driver at all (second part). |
bbb44d9f2 PCI: implement ne... |
457 |
*/ |
bb8089454 PCI PM: Rearrange... |
458 |
static void pci_pm_set_unknown_state(struct pci_dev *pci_dev) |
bbb44d9f2 PCI: implement ne... |
459 |
{ |
bbb44d9f2 PCI: implement ne... |
460 461 462 463 464 465 466 467 468 469 |
/* * mark its power state as "unknown", since we don't know if * e.g. the BIOS will change its device state when we suspend. */ if (pci_dev->current_state == PCI_D0) pci_dev->current_state = PCI_UNKNOWN; } /* * Default "resume" method for devices that have no driver provided resume, |
355a72d75 PCI: Rework defau... |
470 471 |
* or not even a driver at all (second part). */ |
bb8089454 PCI PM: Rearrange... |
472 |
static int pci_pm_reenable_device(struct pci_dev *pci_dev) |
355a72d75 PCI: Rework defau... |
473 474 |
{ int retval; |
bbb44d9f2 PCI: implement ne... |
475 476 477 478 479 480 481 482 483 484 485 486 487 |
/* if the device was enabled before suspend, reenable */ retval = pci_reenable_device(pci_dev); /* * if the device was busmaster before the suspend, make it busmaster * again */ if (pci_dev->is_busmaster) pci_set_master(pci_dev); return retval; } static int pci_legacy_suspend(struct device *dev, pm_message_t state) |
1da177e4c Linux-2.6.12-rc2 |
488 489 490 |
{ struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; |
46939f8b1 PCI PM: Put devic... |
491 |
|
026694920 [PATCH] pm: print... |
492 |
if (drv && drv->suspend) { |
99dadce87 PCI PM: Fix savin... |
493 |
pci_power_t prev = pci_dev->current_state; |
46939f8b1 PCI PM: Put devic... |
494 |
int error; |
aa8c6c937 PCI PM: Restore s... |
495 |
|
57ef80266 PCI PM: Consisten... |
496 497 498 499 |
error = drv->suspend(pci_dev, state); suspend_report_result(drv->suspend, error); if (error) return error; |
aa8c6c937 PCI PM: Restore s... |
500 |
|
46939f8b1 PCI PM: Put devic... |
501 |
if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 |
99dadce87 PCI PM: Fix savin... |
502 503 504 505 506 |
&& pci_dev->current_state != PCI_UNKNOWN) { WARN_ONCE(pci_dev->current_state != prev, "PCI PM: Device state not saved by %pF ", drv->suspend); |
99dadce87 PCI PM: Fix savin... |
507 |
} |
026694920 [PATCH] pm: print... |
508 |
} |
ad8cfa1de PCI PM: Call pci_... |
509 510 |
pci_fixup_device(pci_fixup_suspend, pci_dev); |
46939f8b1 PCI PM: Put devic... |
511 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
512 |
} |
bbb44d9f2 PCI: implement ne... |
513 |
static int pci_legacy_suspend_late(struct device *dev, pm_message_t state) |
cbd69dbbf Suspend changes f... |
514 515 516 |
{ struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; |
cbd69dbbf Suspend changes f... |
517 518 |
if (drv && drv->suspend_late) { |
46939f8b1 PCI PM: Put devic... |
519 520 |
pci_power_t prev = pci_dev->current_state; int error; |
57ef80266 PCI PM: Consisten... |
521 522 |
error = drv->suspend_late(pci_dev, state); suspend_report_result(drv->suspend_late, error); |
46939f8b1 PCI PM: Put devic... |
523 524 525 526 527 528 529 530 531 532 533 |
if (error) return error; if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 && pci_dev->current_state != PCI_UNKNOWN) { WARN_ONCE(pci_dev->current_state != prev, "PCI PM: Device state not saved by %pF ", drv->suspend_late); return 0; } |
cbd69dbbf Suspend changes f... |
534 |
} |
46939f8b1 PCI PM: Put devic... |
535 536 537 538 539 540 541 |
if (!pci_dev->state_saved) pci_save_state(pci_dev); pci_pm_set_unknown_state(pci_dev); return 0; |
cbd69dbbf Suspend changes f... |
542 |
} |
1da177e4c Linux-2.6.12-rc2 |
543 |
|
f6dc1e5e3 PCI PM: Put PM ca... |
544 545 |
static int pci_legacy_resume_early(struct device *dev) { |
f6dc1e5e3 PCI PM: Put PM ca... |
546 547 |
struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; |
aa8c6c937 PCI PM: Restore s... |
548 549 |
return drv && drv->resume_early ? drv->resume_early(pci_dev) : 0; |
f6dc1e5e3 PCI PM: Put PM ca... |
550 |
} |
bbb44d9f2 PCI: implement ne... |
551 |
static int pci_legacy_resume(struct device *dev) |
1da177e4c Linux-2.6.12-rc2 |
552 553 554 |
{ struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; |
ad8cfa1de PCI PM: Call pci_... |
555 |
pci_fixup_device(pci_fixup_resume, pci_dev); |
aa8c6c937 PCI PM: Restore s... |
556 557 |
return drv && drv->resume ? drv->resume(pci_dev) : pci_pm_reenable_device(pci_dev); |
1da177e4c Linux-2.6.12-rc2 |
558 |
} |
571ff7584 PCI PM: Power-man... |
559 |
/* Auxiliary functions used by the new power management framework */ |
5294e2567 PCI PM: make the ... |
560 |
static void pci_pm_default_resume(struct pci_dev *pci_dev) |
571ff7584 PCI PM: Power-man... |
561 |
{ |
734104292 PCI PM: Avoid tou... |
562 |
pci_fixup_device(pci_fixup_resume, pci_dev); |
5294e2567 PCI PM: make the ... |
563 564 |
if (!pci_is_bridge(pci_dev)) pci_enable_wake(pci_dev, PCI_D0, false); |
571ff7584 PCI PM: Power-man... |
565 |
} |
5294e2567 PCI PM: make the ... |
566 |
static void pci_pm_default_suspend(struct pci_dev *pci_dev) |
734104292 PCI PM: Avoid tou... |
567 |
{ |
5294e2567 PCI PM: make the ... |
568 |
/* Disable non-bridge devices without PM support */ |
cbbc2f6b0 PCI PM: Do not di... |
569 570 |
if (!pci_is_bridge(pci_dev)) pci_disable_enabled_device(pci_dev); |
734104292 PCI PM: Avoid tou... |
571 |
} |
07e836e8d PCI PM: Move pci_... |
572 573 574 |
static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) { struct pci_driver *drv = pci_dev->driver; |
bb8089454 PCI PM: Rearrange... |
575 |
bool ret = drv && (drv->suspend || drv->suspend_late || drv->resume |
07e836e8d PCI PM: Move pci_... |
576 |
|| drv->resume_early); |
bb8089454 PCI PM: Rearrange... |
577 578 579 580 581 582 |
/* * Legacy PM support is used by default, so warn if the new framework is * supported as well. Drivers are supposed to support either the * former, or the latter, but not both at the same time. */ |
82440a825 PCI: pci_has_lega... |
583 584 585 |
WARN(ret && drv->driver.pm, "driver %s device %04x:%04x ", drv->name, pci_dev->vendor, pci_dev->device); |
bb8089454 PCI PM: Rearrange... |
586 587 |
return ret; |
07e836e8d PCI PM: Move pci_... |
588 |
} |
571ff7584 PCI PM: Power-man... |
589 |
/* New power management framework */ |
bbb44d9f2 PCI: implement ne... |
590 591 592 593 |
static int pci_pm_prepare(struct device *dev) { struct device_driver *drv = dev->driver; int error = 0; |
6cbf82148 PCI PM: Run-time ... |
594 |
/* |
eea3fc035 PCI / PM: Detect ... |
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 |
* If a PCI device configured to wake up the system from sleep states * has been suspended at run time and there's a resume request pending * for it, this is equivalent to the device signaling wakeup, so the * system suspend operation should be aborted. */ pm_runtime_get_noresume(dev); if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) pm_wakeup_event(dev, 0); if (pm_wakeup_pending()) { pm_runtime_put_sync(dev); return -EBUSY; } /* |
6cbf82148 PCI PM: Run-time ... |
610 611 612 613 614 615 616 617 |
* PCI devices suspended at run time need to be resumed at this * point, because in general it is necessary to reconfigure them for * system suspend. Namely, if the device is supposed to wake up the * system from the sleep state, we may need to reconfigure it for this * purpose. In turn, if the device is not supposed to wake up the * system from the sleep state, we'll have to prevent it from signaling * wake-up. */ |
eea3fc035 PCI / PM: Detect ... |
618 |
pm_runtime_resume(dev); |
6cbf82148 PCI PM: Run-time ... |
619 |
|
bbb44d9f2 PCI: implement ne... |
620 621 622 623 624 625 626 627 628 629 630 631 |
if (drv && drv->pm && drv->pm->prepare) error = drv->pm->prepare(dev); return error; } static void pci_pm_complete(struct device *dev) { struct device_driver *drv = dev->driver; if (drv && drv->pm && drv->pm->complete) drv->pm->complete(dev); |
a5f76d5eb PCI / PM: Block r... |
632 633 |
pm_runtime_put_sync(dev); |
bbb44d9f2 PCI: implement ne... |
634 |
} |
6cbf82148 PCI PM: Run-time ... |
635 636 637 638 639 640 |
#else /* !CONFIG_PM_SLEEP */ #define pci_pm_prepare NULL #define pci_pm_complete NULL #endif /* !CONFIG_PM_SLEEP */ |
bbb44d9f2 PCI: implement ne... |
641 642 643 644 645 |
#ifdef CONFIG_SUSPEND static int pci_pm_suspend(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); |
8150f32b9 Driver Core: Make... |
646 |
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
bbb44d9f2 PCI: implement ne... |
647 |
|
ad8cfa1de PCI PM: Call pci_... |
648 649 |
if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend(dev, PMSG_SUSPEND); |
bb8089454 PCI PM: Rearrange... |
650 |
|
5294e2567 PCI PM: make the ... |
651 652 653 654 |
if (!pm) { pci_pm_default_suspend(pci_dev); goto Fixup; } |
5294e2567 PCI PM: make the ... |
655 656 657 |
if (pm->suspend) { pci_power_t prev = pci_dev->current_state; int error; |
ddb7c9d29 PCI PM: Fix handl... |
658 659 |
error = pm->suspend(dev); suspend_report_result(pm->suspend, error); |
5294e2567 PCI PM: make the ... |
660 661 |
if (error) return error; |
46939f8b1 PCI PM: Put devic... |
662 |
if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 |
5294e2567 PCI PM: make the ... |
663 664 665 666 667 |
&& pci_dev->current_state != PCI_UNKNOWN) { WARN_ONCE(pci_dev->current_state != prev, "PCI PM: State of device not saved by %pF ", pm->suspend); |
5294e2567 PCI PM: make the ... |
668 |
} |
bbb44d9f2 PCI: implement ne... |
669 |
} |
fa58d305d PCI PM: Add suspe... |
670 |
|
5294e2567 PCI PM: make the ... |
671 672 673 674 |
Fixup: pci_fixup_device(pci_fixup_suspend, pci_dev); return 0; |
bbb44d9f2 PCI: implement ne... |
675 676 677 |
} static int pci_pm_suspend_noirq(struct device *dev) |
c89581772 [PATCH] PCI: Add ... |
678 |
{ |
355a72d75 PCI: Rework defau... |
679 |
struct pci_dev *pci_dev = to_pci_dev(dev); |
8150f32b9 Driver Core: Make... |
680 |
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
c89581772 [PATCH] PCI: Add ... |
681 |
|
bb8089454 PCI PM: Rearrange... |
682 683 |
if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend_late(dev, PMSG_SUSPEND); |
931ff68a5 PCI PM: Restore c... |
684 685 |
if (!pm) { pci_save_state(pci_dev); |
46939f8b1 PCI PM: Put devic... |
686 |
return 0; |
931ff68a5 PCI PM: Restore c... |
687 |
} |
46939f8b1 PCI PM: Put devic... |
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
if (pm->suspend_noirq) { pci_power_t prev = pci_dev->current_state; int error; error = pm->suspend_noirq(dev); suspend_report_result(pm->suspend_noirq, error); if (error) return error; if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 && pci_dev->current_state != PCI_UNKNOWN) { WARN_ONCE(pci_dev->current_state != prev, "PCI PM: State of device not saved by %pF ", pm->suspend_noirq); return 0; } |
bbb44d9f2 PCI: implement ne... |
706 |
} |
46939f8b1 PCI PM: Put devic... |
707 708 709 710 711 |
if (!pci_dev->state_saved) { pci_save_state(pci_dev); if (!pci_is_bridge(pci_dev)) pci_prepare_to_sleep(pci_dev); } |
d67e37d79 PCI PM: Run defau... |
712 |
|
46939f8b1 PCI PM: Put devic... |
713 714 715 |
pci_pm_set_unknown_state(pci_dev); return 0; |
c89581772 [PATCH] PCI: Add ... |
716 |
} |
1da177e4c Linux-2.6.12-rc2 |
717 |
|
f6dc1e5e3 PCI PM: Put PM ca... |
718 |
static int pci_pm_resume_noirq(struct device *dev) |
bbb44d9f2 PCI: implement ne... |
719 720 721 |
{ struct pci_dev *pci_dev = to_pci_dev(dev); struct device_driver *drv = dev->driver; |
355a72d75 PCI: Rework defau... |
722 |
int error = 0; |
bbb44d9f2 PCI: implement ne... |
723 |
|
6cbf82148 PCI PM: Run-time ... |
724 |
pci_pm_default_resume_early(pci_dev); |
aa8c6c937 PCI PM: Restore s... |
725 |
|
ad8cfa1de PCI PM: Call pci_... |
726 |
if (pci_has_legacy_pm_support(pci_dev)) |
f6dc1e5e3 PCI PM: Put PM ca... |
727 |
return pci_legacy_resume_early(dev); |
bb8089454 PCI PM: Rearrange... |
728 |
|
f6dc1e5e3 PCI PM: Put PM ca... |
729 730 |
if (drv && drv->pm && drv->pm->resume_noirq) error = drv->pm->resume_noirq(dev); |
bbb44d9f2 PCI: implement ne... |
731 732 733 |
return error; } |
f6dc1e5e3 PCI PM: Put PM ca... |
734 |
static int pci_pm_resume(struct device *dev) |
bbb44d9f2 PCI: implement ne... |
735 |
{ |
355a72d75 PCI: Rework defau... |
736 |
struct pci_dev *pci_dev = to_pci_dev(dev); |
8150f32b9 Driver Core: Make... |
737 |
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
bbb44d9f2 PCI: implement ne... |
738 |
int error = 0; |
418e4da33 PCI PM: Fix suspe... |
739 740 741 742 743 744 |
/* * This is necessary for the suspend error path in which resume is * called without restoring the standard config registers of the device. */ if (pci_dev->state_saved) pci_restore_standard_config(pci_dev); |
ad8cfa1de PCI PM: Call pci_... |
745 |
if (pci_has_legacy_pm_support(pci_dev)) |
f6dc1e5e3 PCI PM: Put PM ca... |
746 |
return pci_legacy_resume(dev); |
bb8089454 PCI PM: Rearrange... |
747 |
|
5294e2567 PCI PM: make the ... |
748 |
pci_pm_default_resume(pci_dev); |
734104292 PCI PM: Avoid tou... |
749 |
|
5294e2567 PCI PM: make the ... |
750 751 752 753 754 755 |
if (pm) { if (pm->resume) error = pm->resume(dev); } else { pci_pm_reenable_device(pci_dev); } |
bbb44d9f2 PCI: implement ne... |
756 |
|
999cce4a5 PCI PM: Return er... |
757 |
return error; |
bbb44d9f2 PCI: implement ne... |
758 759 760 761 762 763 764 765 766 767 |
} #else /* !CONFIG_SUSPEND */ #define pci_pm_suspend NULL #define pci_pm_suspend_noirq NULL #define pci_pm_resume NULL #define pci_pm_resume_noirq NULL #endif /* !CONFIG_SUSPEND */ |
1f112cee0 PM / Hibernate: I... |
768 |
#ifdef CONFIG_HIBERNATE_CALLBACKS |
bbb44d9f2 PCI: implement ne... |
769 770 771 772 |
static int pci_pm_freeze(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); |
8150f32b9 Driver Core: Make... |
773 |
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
bbb44d9f2 PCI: implement ne... |
774 |
|
ad8cfa1de PCI PM: Call pci_... |
775 776 |
if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend(dev, PMSG_FREEZE); |
bb8089454 PCI PM: Rearrange... |
777 |
|
5294e2567 PCI PM: make the ... |
778 779 780 |
if (!pm) { pci_pm_default_suspend(pci_dev); return 0; |
bbb44d9f2 PCI: implement ne... |
781 |
} |
5294e2567 PCI PM: make the ... |
782 783 784 785 786 787 788 789 |
if (pm->freeze) { int error; error = pm->freeze(dev); suspend_report_result(pm->freeze, error); if (error) return error; } |
5294e2567 PCI PM: make the ... |
790 |
return 0; |
bbb44d9f2 PCI: implement ne... |
791 792 793 794 |
} static int pci_pm_freeze_noirq(struct device *dev) { |
355a72d75 PCI: Rework defau... |
795 |
struct pci_dev *pci_dev = to_pci_dev(dev); |
adf094931 PM: Simplify the ... |
796 |
struct device_driver *drv = dev->driver; |
bbb44d9f2 PCI: implement ne... |
797 |
|
bb8089454 PCI PM: Rearrange... |
798 799 |
if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend_late(dev, PMSG_FREEZE); |
d67e37d79 PCI PM: Run defau... |
800 |
if (drv && drv->pm && drv->pm->freeze_noirq) { |
46939f8b1 PCI PM: Put devic... |
801 |
int error; |
d67e37d79 PCI PM: Run defau... |
802 803 |
error = drv->pm->freeze_noirq(dev); suspend_report_result(drv->pm->freeze_noirq, error); |
46939f8b1 PCI PM: Put devic... |
804 805 |
if (error) return error; |
bbb44d9f2 PCI: implement ne... |
806 |
} |
46939f8b1 PCI PM: Put devic... |
807 808 |
if (!pci_dev->state_saved) pci_save_state(pci_dev); |
d67e37d79 PCI PM: Run defau... |
809 |
|
46939f8b1 PCI PM: Put devic... |
810 811 812 |
pci_pm_set_unknown_state(pci_dev); return 0; |
bbb44d9f2 PCI: implement ne... |
813 |
} |
f6dc1e5e3 PCI PM: Put PM ca... |
814 |
static int pci_pm_thaw_noirq(struct device *dev) |
bbb44d9f2 PCI: implement ne... |
815 |
{ |
355a72d75 PCI: Rework defau... |
816 |
struct pci_dev *pci_dev = to_pci_dev(dev); |
bbb44d9f2 PCI: implement ne... |
817 818 |
struct device_driver *drv = dev->driver; int error = 0; |
ad8cfa1de PCI PM: Call pci_... |
819 |
if (pci_has_legacy_pm_support(pci_dev)) |
f6dc1e5e3 PCI PM: Put PM ca... |
820 |
return pci_legacy_resume_early(dev); |
bb8089454 PCI PM: Rearrange... |
821 |
|
f6dc1e5e3 PCI PM: Put PM ca... |
822 |
pci_update_current_state(pci_dev, PCI_D0); |
d67e37d79 PCI PM: Run defau... |
823 |
|
f6dc1e5e3 PCI PM: Put PM ca... |
824 825 |
if (drv && drv->pm && drv->pm->thaw_noirq) error = drv->pm->thaw_noirq(dev); |
bbb44d9f2 PCI: implement ne... |
826 827 828 |
return error; } |
f6dc1e5e3 PCI PM: Put PM ca... |
829 |
static int pci_pm_thaw(struct device *dev) |
bbb44d9f2 PCI: implement ne... |
830 |
{ |
355a72d75 PCI: Rework defau... |
831 |
struct pci_dev *pci_dev = to_pci_dev(dev); |
8150f32b9 Driver Core: Make... |
832 |
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
bbb44d9f2 PCI: implement ne... |
833 |
int error = 0; |
ad8cfa1de PCI PM: Call pci_... |
834 |
if (pci_has_legacy_pm_support(pci_dev)) |
f6dc1e5e3 PCI PM: Put PM ca... |
835 |
return pci_legacy_resume(dev); |
bb8089454 PCI PM: Rearrange... |
836 |
|
5294e2567 PCI PM: make the ... |
837 838 839 840 841 842 |
if (pm) { if (pm->thaw) error = pm->thaw(dev); } else { pci_pm_reenable_device(pci_dev); } |
bbb44d9f2 PCI: implement ne... |
843 |
|
4b77b0a2b PCI: Clear saved_... |
844 |
pci_dev->state_saved = false; |
bbb44d9f2 PCI: implement ne... |
845 846 847 848 849 |
return error; } static int pci_pm_poweroff(struct device *dev) { |
355a72d75 PCI: Rework defau... |
850 |
struct pci_dev *pci_dev = to_pci_dev(dev); |
8150f32b9 Driver Core: Make... |
851 |
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
bbb44d9f2 PCI: implement ne... |
852 |
|
ad8cfa1de PCI PM: Call pci_... |
853 854 |
if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend(dev, PMSG_HIBERNATE); |
bb8089454 PCI PM: Rearrange... |
855 |
|
5294e2567 PCI PM: make the ... |
856 857 858 859 |
if (!pm) { pci_pm_default_suspend(pci_dev); goto Fixup; } |
5294e2567 PCI PM: make the ... |
860 |
if (pm->poweroff) { |
46939f8b1 PCI PM: Put devic... |
861 |
int error; |
ddb7c9d29 PCI PM: Fix handl... |
862 863 |
error = pm->poweroff(dev); suspend_report_result(pm->poweroff, error); |
46939f8b1 PCI PM: Put devic... |
864 865 |
if (error) return error; |
bbb44d9f2 PCI: implement ne... |
866 |
} |
5294e2567 PCI PM: make the ... |
867 868 |
Fixup: pci_fixup_device(pci_fixup_suspend, pci_dev); |
c9b9972b3 PCI PM: Fix power... |
869 |
|
46939f8b1 PCI PM: Put devic... |
870 |
return 0; |
bbb44d9f2 PCI: implement ne... |
871 872 873 874 |
} static int pci_pm_poweroff_noirq(struct device *dev) { |
46939f8b1 PCI PM: Put devic... |
875 |
struct pci_dev *pci_dev = to_pci_dev(dev); |
adf094931 PM: Simplify the ... |
876 |
struct device_driver *drv = dev->driver; |
bbb44d9f2 PCI: implement ne... |
877 |
|
bb8089454 PCI PM: Rearrange... |
878 879 |
if (pci_has_legacy_pm_support(to_pci_dev(dev))) return pci_legacy_suspend_late(dev, PMSG_HIBERNATE); |
46939f8b1 PCI PM: Put devic... |
880 881 882 883 884 |
if (!drv || !drv->pm) return 0; if (drv->pm->poweroff_noirq) { int error; |
d67e37d79 PCI PM: Run defau... |
885 886 |
error = drv->pm->poweroff_noirq(dev); suspend_report_result(drv->pm->poweroff_noirq, error); |
46939f8b1 PCI PM: Put devic... |
887 888 |
if (error) return error; |
bbb44d9f2 PCI: implement ne... |
889 |
} |
46939f8b1 PCI PM: Put devic... |
890 891 892 893 |
if (!pci_dev->state_saved && !pci_is_bridge(pci_dev)) pci_prepare_to_sleep(pci_dev); return 0; |
bbb44d9f2 PCI: implement ne... |
894 |
} |
f6dc1e5e3 PCI PM: Put PM ca... |
895 |
static int pci_pm_restore_noirq(struct device *dev) |
bbb44d9f2 PCI: implement ne... |
896 897 898 |
{ struct pci_dev *pci_dev = to_pci_dev(dev); struct device_driver *drv = dev->driver; |
355a72d75 PCI: Rework defau... |
899 |
int error = 0; |
bbb44d9f2 PCI: implement ne... |
900 |
|
6cbf82148 PCI PM: Run-time ... |
901 |
pci_pm_default_resume_early(pci_dev); |
aa8c6c937 PCI PM: Restore s... |
902 |
|
ad8cfa1de PCI PM: Call pci_... |
903 |
if (pci_has_legacy_pm_support(pci_dev)) |
f6dc1e5e3 PCI PM: Put PM ca... |
904 |
return pci_legacy_resume_early(dev); |
bb8089454 PCI PM: Rearrange... |
905 |
|
f6dc1e5e3 PCI PM: Put PM ca... |
906 907 |
if (drv && drv->pm && drv->pm->restore_noirq) error = drv->pm->restore_noirq(dev); |
bbb44d9f2 PCI: implement ne... |
908 909 910 |
return error; } |
f6dc1e5e3 PCI PM: Put PM ca... |
911 |
static int pci_pm_restore(struct device *dev) |
bbb44d9f2 PCI: implement ne... |
912 913 |
{ struct pci_dev *pci_dev = to_pci_dev(dev); |
8150f32b9 Driver Core: Make... |
914 |
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
bbb44d9f2 PCI: implement ne... |
915 |
int error = 0; |
418e4da33 PCI PM: Fix suspe... |
916 917 918 919 920 921 |
/* * This is necessary for the hibernation error path in which restore is * called without restoring the standard config registers of the device. */ if (pci_dev->state_saved) pci_restore_standard_config(pci_dev); |
ad8cfa1de PCI PM: Call pci_... |
922 |
if (pci_has_legacy_pm_support(pci_dev)) |
f6dc1e5e3 PCI PM: Put PM ca... |
923 |
return pci_legacy_resume(dev); |
bb8089454 PCI PM: Rearrange... |
924 |
|
5294e2567 PCI PM: make the ... |
925 |
pci_pm_default_resume(pci_dev); |
734104292 PCI PM: Avoid tou... |
926 |
|
5294e2567 PCI PM: make the ... |
927 928 929 930 931 932 |
if (pm) { if (pm->restore) error = pm->restore(dev); } else { pci_pm_reenable_device(pci_dev); } |
bbb44d9f2 PCI: implement ne... |
933 934 |
return error; |
c89581772 [PATCH] PCI: Add ... |
935 |
} |
1da177e4c Linux-2.6.12-rc2 |
936 |
|
1f112cee0 PM / Hibernate: I... |
937 |
#else /* !CONFIG_HIBERNATE_CALLBACKS */ |
bbb44d9f2 PCI: implement ne... |
938 939 940 941 942 943 944 945 946 |
#define pci_pm_freeze NULL #define pci_pm_freeze_noirq NULL #define pci_pm_thaw NULL #define pci_pm_thaw_noirq NULL #define pci_pm_poweroff NULL #define pci_pm_poweroff_noirq NULL #define pci_pm_restore NULL #define pci_pm_restore_noirq NULL |
1f112cee0 PM / Hibernate: I... |
947 |
#endif /* !CONFIG_HIBERNATE_CALLBACKS */ |
bbb44d9f2 PCI: implement ne... |
948 |
|
6cbf82148 PCI PM: Run-time ... |
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
#ifdef CONFIG_PM_RUNTIME static int pci_pm_runtime_suspend(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; pci_power_t prev = pci_dev->current_state; int error; if (!pm || !pm->runtime_suspend) return -ENOSYS; error = pm->runtime_suspend(dev); suspend_report_result(pm->runtime_suspend, error); if (error) return error; pci_fixup_device(pci_fixup_suspend, pci_dev); if (!pci_dev->state_saved && pci_dev->current_state != PCI_D0 && pci_dev->current_state != PCI_UNKNOWN) { WARN_ONCE(pci_dev->current_state != prev, "PCI PM: State of device not saved by %pF ", pm->runtime_suspend); return 0; } if (!pci_dev->state_saved) pci_save_state(pci_dev); pci_finish_runtime_suspend(pci_dev); return 0; } static int pci_pm_runtime_resume(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (!pm || !pm->runtime_resume) return -ENOSYS; pci_pm_default_resume_early(pci_dev); __pci_enable_wake(pci_dev, PCI_D0, true, false); pci_fixup_device(pci_fixup_resume, pci_dev); return pm->runtime_resume(dev); } static int pci_pm_runtime_idle(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (!pm) return -ENOSYS; if (pm->runtime_idle) { int ret = pm->runtime_idle(dev); if (ret) return ret; } pm_runtime_suspend(dev); return 0; } #else /* !CONFIG_PM_RUNTIME */ #define pci_pm_runtime_suspend NULL #define pci_pm_runtime_resume NULL #define pci_pm_runtime_idle NULL #endif /* !CONFIG_PM_RUNTIME */ |
aa3386015 PM: Remove CONFIG... |
1025 |
#ifdef CONFIG_PM |
6cbf82148 PCI PM: Run-time ... |
1026 |
|
8150f32b9 Driver Core: Make... |
1027 |
const struct dev_pm_ops pci_dev_pm_ops = { |
adf094931 PM: Simplify the ... |
1028 1029 1030 1031 1032 1033 1034 1035 |
.prepare = pci_pm_prepare, .complete = pci_pm_complete, .suspend = pci_pm_suspend, .resume = pci_pm_resume, .freeze = pci_pm_freeze, .thaw = pci_pm_thaw, .poweroff = pci_pm_poweroff, .restore = pci_pm_restore, |
bbb44d9f2 PCI: implement ne... |
1036 1037 1038 1039 1040 1041 |
.suspend_noirq = pci_pm_suspend_noirq, .resume_noirq = pci_pm_resume_noirq, .freeze_noirq = pci_pm_freeze_noirq, .thaw_noirq = pci_pm_thaw_noirq, .poweroff_noirq = pci_pm_poweroff_noirq, .restore_noirq = pci_pm_restore_noirq, |
6cbf82148 PCI PM: Run-time ... |
1042 1043 1044 |
.runtime_suspend = pci_pm_runtime_suspend, .runtime_resume = pci_pm_runtime_resume, .runtime_idle = pci_pm_runtime_idle, |
bbb44d9f2 PCI: implement ne... |
1045 |
}; |
adf094931 PM: Simplify the ... |
1046 |
#define PCI_PM_OPS_PTR (&pci_dev_pm_ops) |
bbb44d9f2 PCI: implement ne... |
1047 |
|
6cbf82148 PCI PM: Run-time ... |
1048 |
#else /* !COMFIG_PM_OPS */ |
bbb44d9f2 PCI: implement ne... |
1049 1050 |
#define PCI_PM_OPS_PTR NULL |
6cbf82148 PCI PM: Run-time ... |
1051 |
#endif /* !COMFIG_PM_OPS */ |
bbb44d9f2 PCI: implement ne... |
1052 |
|
1da177e4c Linux-2.6.12-rc2 |
1053 |
/** |
863b18f4b [PATCH] PCI: auto... |
1054 |
* __pci_register_driver - register a new pci driver |
1da177e4c Linux-2.6.12-rc2 |
1055 |
* @drv: the driver structure to register |
863b18f4b [PATCH] PCI: auto... |
1056 |
* @owner: owner module of drv |
f95d882d8 PCI/sysfs/kobject... |
1057 |
* @mod_name: module name string |
1da177e4c Linux-2.6.12-rc2 |
1058 1059 1060 |
* * Adds the driver structure to the list of registered drivers. * Returns a negative value on error, otherwise 0. |
eaae4b3a8 [PATCH] PCI: Spel... |
1061 |
* If no error occurred, the driver remains registered even if |
1da177e4c Linux-2.6.12-rc2 |
1062 1063 |
* no device was claimed during registration. */ |
725522b54 PCI: add the sysf... |
1064 1065 |
int __pci_register_driver(struct pci_driver *drv, struct module *owner, const char *mod_name) |
1da177e4c Linux-2.6.12-rc2 |
1066 1067 1068 1069 1070 1071 |
{ int error; /* initialize common driver fields */ drv->driver.name = drv->name; drv->driver.bus = &pci_bus_type; |
863b18f4b [PATCH] PCI: auto... |
1072 |
drv->driver.owner = owner; |
725522b54 PCI: add the sysf... |
1073 |
drv->driver.mod_name = mod_name; |
50b007552 PCI: Multiprobe s... |
1074 |
|
758658589 [PATCH] PCI: clea... |
1075 1076 |
spin_lock_init(&drv->dynids.lock); INIT_LIST_HEAD(&drv->dynids.list); |
1da177e4c Linux-2.6.12-rc2 |
1077 1078 1079 |
/* register with core */ error = driver_register(&drv->driver); |
50bf14b3f pci: fix __pci_re... |
1080 |
if (error) |
0994375e9 PCI: add remove_i... |
1081 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
1082 |
|
50bf14b3f pci: fix __pci_re... |
1083 1084 |
error = pci_create_newid_file(drv); if (error) |
0994375e9 PCI: add remove_i... |
1085 |
goto out_newid; |
1da177e4c Linux-2.6.12-rc2 |
1086 |
|
0994375e9 PCI: add remove_i... |
1087 1088 1089 1090 |
error = pci_create_removeid_file(drv); if (error) goto out_removeid; out: |
1da177e4c Linux-2.6.12-rc2 |
1091 |
return error; |
0994375e9 PCI: add remove_i... |
1092 1093 1094 1095 1096 1097 |
out_removeid: pci_remove_newid_file(drv); out_newid: driver_unregister(&drv->driver); goto out; |
1da177e4c Linux-2.6.12-rc2 |
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 |
} /** * pci_unregister_driver - unregister a pci driver * @drv: the driver structure to unregister * * Deletes the driver structure from the list of registered PCI drivers, * gives it a chance to clean up by calling its remove() function for * each device it was responsible for, and marks those devices as * driverless. */ void pci_unregister_driver(struct pci_driver *drv) { |
0994375e9 PCI: add remove_i... |
1113 |
pci_remove_removeid_file(drv); |
03d43b19b PCI: use proper c... |
1114 |
pci_remove_newid_file(drv); |
1da177e4c Linux-2.6.12-rc2 |
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 |
driver_unregister(&drv->driver); pci_free_dynids(drv); } static struct pci_driver pci_compat_driver = { .name = "compat" }; /** * pci_dev_driver - get the pci_driver of a device * @dev: the device to query * * Returns the appropriate pci_driver structure or %NULL if there is no * registered driver for the device. */ struct pci_driver * pci_dev_driver(const struct pci_dev *dev) { if (dev->driver) return dev->driver; else { int i; for(i=0; i<=PCI_ROM_RESOURCE; i++) if (dev->resource[i].flags & IORESOURCE_BUSY) return &pci_compat_driver; } return NULL; } /** * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure |
1da177e4c Linux-2.6.12-rc2 |
1146 |
* @dev: the PCI device structure to match against |
8f7020d36 [PATCH] kernel-do... |
1147 |
* @drv: the device driver to search for matching PCI device id structures |
1da177e4c Linux-2.6.12-rc2 |
1148 1149 |
* * Used by a driver to check whether a PCI device present in the |
8f7020d36 [PATCH] kernel-do... |
1150 |
* system is in its list of supported devices. Returns the matching |
1da177e4c Linux-2.6.12-rc2 |
1151 1152 |
* pci_device_id structure or %NULL if there is no match. */ |
758658589 [PATCH] PCI: clea... |
1153 |
static int pci_bus_match(struct device *dev, struct device_driver *drv) |
1da177e4c Linux-2.6.12-rc2 |
1154 |
{ |
758658589 [PATCH] PCI: clea... |
1155 1156 |
struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_driver *pci_drv = to_pci_driver(drv); |
1da177e4c Linux-2.6.12-rc2 |
1157 |
const struct pci_device_id *found_id; |
758658589 [PATCH] PCI: clea... |
1158 |
found_id = pci_match_device(pci_drv, pci_dev); |
1da177e4c Linux-2.6.12-rc2 |
1159 1160 |
if (found_id) return 1; |
758658589 [PATCH] PCI: clea... |
1161 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 |
} /** * pci_dev_get - increments the reference count of the pci device structure * @dev: the device being referenced * * Each live reference to a device should be refcounted. * * Drivers for PCI devices should normally record such references in * their probe() methods, when they bind to a device, and release * them by calling pci_dev_put(), in their disconnect() methods. * * A pointer to the device with the incremented reference counter is returned. */ struct pci_dev *pci_dev_get(struct pci_dev *dev) { if (dev) get_device(&dev->dev); return dev; } /** * pci_dev_put - release a use of the pci device structure * @dev: device that's been disconnected * * Must be called when a user of a device is finished with it. When the last * user of the device calls this function, the memory of the device is freed. */ void pci_dev_put(struct pci_dev *dev) { if (dev) put_device(&dev->dev); } #ifndef CONFIG_HOTPLUG |
7eff2e7a8 Driver core: chan... |
1197 |
int pci_uevent(struct device *dev, struct kobj_uevent_env *env) |
1da177e4c Linux-2.6.12-rc2 |
1198 1199 1200 1201 1202 1203 1204 1205 |
{ return -ENODEV; } #endif struct bus_type pci_bus_type = { .name = "pci", .match = pci_bus_match, |
312c004d3 [PATCH] driver co... |
1206 |
.uevent = pci_uevent, |
b15d686a2 [PATCH] Add pci_b... |
1207 1208 |
.probe = pci_device_probe, .remove = pci_device_remove, |
cbd69dbbf Suspend changes f... |
1209 |
.shutdown = pci_device_shutdown, |
1da177e4c Linux-2.6.12-rc2 |
1210 |
.dev_attrs = pci_dev_attrs, |
705b1aaa8 PCI: Introduce /s... |
1211 |
.bus_attrs = pci_bus_attrs, |
bbb44d9f2 PCI: implement ne... |
1212 |
.pm = PCI_PM_OPS_PTR, |
1da177e4c Linux-2.6.12-rc2 |
1213 1214 1215 1216 1217 1218 1219 1220 |
}; static int __init pci_driver_init(void) { return bus_register(&pci_bus_type); } postcore_initcall(pci_driver_init); |
9dba910e9 PCI: separate out... |
1221 |
EXPORT_SYMBOL_GPL(pci_add_dynid); |
758658589 [PATCH] PCI: clea... |
1222 |
EXPORT_SYMBOL(pci_match_id); |
863b18f4b [PATCH] PCI: auto... |
1223 |
EXPORT_SYMBOL(__pci_register_driver); |
1da177e4c Linux-2.6.12-rc2 |
1224 1225 1226 1227 1228 |
EXPORT_SYMBOL(pci_unregister_driver); EXPORT_SYMBOL(pci_dev_driver); EXPORT_SYMBOL(pci_bus_type); EXPORT_SYMBOL(pci_dev_get); EXPORT_SYMBOL(pci_dev_put); |