aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c150
1 files changed, 104 insertions, 46 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index f8074525267c..20e28077b96d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -404,67 +404,56 @@ static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
404} 404}
405 405
406/** 406/**
407 * pci_set_power_state - Set the power state of a PCI device 407 * pci_raw_set_power_state - Use PCI PM registers to set the power state of
408 * @dev: PCI device to be suspended 408 * given PCI device
409 * @state: PCI power state (D0, D1, D2, D3hot, D3cold) we're entering 409 * @dev: PCI device to handle.
410 * @pm: PCI PM capability offset of the device.
411 * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
410 * 412 *
411 * Transition a device to a new power state, using the Power Management 413 * RETURN VALUE:
412 * Capabilities in the device's config space. 414 * -EINVAL if the requested state is invalid.
413 * 415 * -EIO if device does not support PCI PM or its PM capabilities register has a
414 * RETURN VALUE: 416 * wrong version, or device doesn't support the requested state.
415 * -EINVAL if trying to enter a lower state than we're already in. 417 * 0 if device already is in the requested state.
416 * 0 if we're already in the requested state. 418 * 0 if device's power state has been successfully changed.
417 * -EIO if device does not support PCI PM.
418 * 0 if we can successfully change the power state.
419 */ 419 */
420int 420static int
421pci_set_power_state(struct pci_dev *dev, pci_power_t state) 421pci_raw_set_power_state(struct pci_dev *dev, int pm, pci_power_t state)
422{ 422{
423 int pm, need_restore = 0;
424 u16 pmcsr, pmc; 423 u16 pmcsr, pmc;
424 bool need_restore = false;
425 425
426 /* bound the state we're entering */
427 if (state > PCI_D3hot)
428 state = PCI_D3hot;
429
430 /*
431 * If the device or the parent bridge can't support PCI PM, ignore
432 * the request if we're doing anything besides putting it into D0
433 * (which would only happen on boot).
434 */
435 if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
436 return 0;
437
438 /* find PCI PM capability in list */
439 pm = pci_find_capability(dev, PCI_CAP_ID_PM);
440
441 /* abort if the device doesn't support PM capabilities */
442 if (!pm) 426 if (!pm)
443 return -EIO; 427 return -EIO;
444 428
429 if (state < PCI_D0 || state > PCI_D3hot)
430 return -EINVAL;
431
445 /* Validate current state: 432 /* Validate current state:
446 * Can enter D0 from any state, but if we can only go deeper 433 * Can enter D0 from any state, but if we can only go deeper
447 * to sleep if we're already in a low power state 434 * to sleep if we're already in a low power state
448 */ 435 */
449 if (state != PCI_D0 && dev->current_state > state) { 436 if (dev->current_state == state) {
437 /* we're already there */
438 return 0;
439 } else if (state != PCI_D0 && dev->current_state <= PCI_D3cold
440 && dev->current_state > state) {
450 dev_err(&dev->dev, "invalid power transition " 441 dev_err(&dev->dev, "invalid power transition "
451 "(from state %d to %d)\n", dev->current_state, state); 442 "(from state %d to %d)\n", dev->current_state, state);
452 return -EINVAL; 443 return -EINVAL;
453 } else if (dev->current_state == state) 444 }
454 return 0; /* we're already there */
455 445
446 pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
456 447
457 pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc);
458 if ((pmc & PCI_PM_CAP_VER_MASK) > 3) { 448 if ((pmc & PCI_PM_CAP_VER_MASK) > 3) {
459 dev_printk(KERN_DEBUG, &dev->dev, "unsupported PM cap regs " 449 dev_err(&dev->dev, "unsupported PM cap regs version (%u)\n",
460 "version (%u)\n", pmc & PCI_PM_CAP_VER_MASK); 450 pmc & PCI_PM_CAP_VER_MASK);
461 return -EIO; 451 return -EIO;
462 } 452 }
463 453
464 /* check if this device supports the desired state */ 454 /* check if this device supports the desired state */
465 if (state == PCI_D1 && !(pmc & PCI_PM_CAP_D1)) 455 if ((state == PCI_D1 && !(pmc & PCI_PM_CAP_D1))
466 return -EIO; 456 || (state == PCI_D2 && !(pmc & PCI_PM_CAP_D2)))
467 else if (state == PCI_D2 && !(pmc & PCI_PM_CAP_D2))
468 return -EIO; 457 return -EIO;
469 458
470 pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); 459 pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
@@ -483,7 +472,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
483 case PCI_UNKNOWN: /* Boot-up */ 472 case PCI_UNKNOWN: /* Boot-up */
484 if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot 473 if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
485 && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) 474 && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
486 need_restore = 1; 475 need_restore = true;
487 /* Fall-through: force to D0 */ 476 /* Fall-through: force to D0 */
488 default: 477 default:
489 pmcsr = 0; 478 pmcsr = 0;
@@ -500,12 +489,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
500 else if (state == PCI_D2 || dev->current_state == PCI_D2) 489 else if (state == PCI_D2 || dev->current_state == PCI_D2)
501 udelay(200); 490 udelay(200);
502 491
503 /*
504 * Give firmware a chance to be called, such as ACPI _PRx, _PSx
505 * Firmware method after native method ?
506 */
507 platform_pci_set_power_state(dev, state);
508
509 dev->current_state = state; 492 dev->current_state = state;
510 493
511 /* According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT 494 /* According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT
@@ -530,6 +513,81 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
530} 513}
531 514
532/** 515/**
516 * pci_update_current_state - Read PCI power state of given device from its
517 * PCI PM registers and cache it
518 * @dev: PCI device to handle.
519 * @pm: PCI PM capability offset of the device.
520 */
521static void pci_update_current_state(struct pci_dev *dev, int pm)
522{
523 if (pm) {
524 u16 pmcsr;
525
526 pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
527 dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
528 }
529}
530
531/**
532 * pci_set_power_state - Set the power state of a PCI device
533 * @dev: PCI device to handle.
534 * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
535 *
536 * Transition a device to a new power state, using the platform formware and/or
537 * the device's PCI PM registers.
538 *
539 * RETURN VALUE:
540 * -EINVAL if the requested state is invalid.
541 * -EIO if device does not support PCI PM or its PM capabilities register has a
542 * wrong version, or device doesn't support the requested state.
543 * 0 if device already is in the requested state.
544 * 0 if device's power state has been successfully changed.
545 */
546int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
547{
548 int pm, error;
549
550 /* bound the state we're entering */
551 if (state > PCI_D3hot)
552 state = PCI_D3hot;
553 else if (state < PCI_D0)
554 state = PCI_D0;
555 else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
556 /*
557 * If the device or the parent bridge do not support PCI PM,
558 * ignore the request if we're doing anything other than putting
559 * it into D0 (which would only happen on boot).
560 */
561 return 0;
562
563 /* Find PCI PM capability in the list */
564 pm = pci_find_capability(dev, PCI_CAP_ID_PM);
565
566 if (state == PCI_D0 && platform_pci_power_manageable(dev)) {
567 /*
568 * Allow the platform to change the state, for example via ACPI
569 * _PR0, _PS0 and some such, but do not trust it.
570 */
571 int ret = platform_pci_set_power_state(dev, PCI_D0);
572 if (!ret)
573 pci_update_current_state(dev, pm);
574 }
575
576 error = pci_raw_set_power_state(dev, pm, state);
577
578 if (state > PCI_D0 && platform_pci_power_manageable(dev)) {
579 /* Allow the platform to finalize the transition */
580 int ret = platform_pci_set_power_state(dev, state);
581 if (!ret) {
582 pci_update_current_state(dev, pm);
583 error = 0;
584 }
585 }
586
587 return error;
588}
589
590/**
533 * pci_choose_state - Choose the power state of a PCI device 591 * pci_choose_state - Choose the power state of a PCI device
534 * @dev: PCI device to be suspended 592 * @dev: PCI device to be suspended
535 * @state: target sleep state for the whole system. This is the value 593 * @state: target sleep state for the whole system. This is the value