diff options
Diffstat (limited to 'drivers/vfio/pci')
-rw-r--r-- | drivers/vfio/pci/vfio_pci_config.c | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index f1dde2c0fe99..964ff22bf281 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c | |||
@@ -587,12 +587,46 @@ static int __init init_pci_cap_basic_perm(struct perm_bits *perm) | |||
587 | return 0; | 587 | return 0; |
588 | } | 588 | } |
589 | 589 | ||
590 | static int vfio_pm_config_write(struct vfio_pci_device *vdev, int pos, | ||
591 | int count, struct perm_bits *perm, | ||
592 | int offset, __le32 val) | ||
593 | { | ||
594 | count = vfio_default_config_write(vdev, pos, count, perm, offset, val); | ||
595 | if (count < 0) | ||
596 | return count; | ||
597 | |||
598 | if (offset == PCI_PM_CTRL) { | ||
599 | pci_power_t state; | ||
600 | |||
601 | switch (le32_to_cpu(val) & PCI_PM_CTRL_STATE_MASK) { | ||
602 | case 0: | ||
603 | state = PCI_D0; | ||
604 | break; | ||
605 | case 1: | ||
606 | state = PCI_D1; | ||
607 | break; | ||
608 | case 2: | ||
609 | state = PCI_D2; | ||
610 | break; | ||
611 | case 3: | ||
612 | state = PCI_D3hot; | ||
613 | break; | ||
614 | } | ||
615 | |||
616 | pci_set_power_state(vdev->pdev, state); | ||
617 | } | ||
618 | |||
619 | return count; | ||
620 | } | ||
621 | |||
590 | /* Permissions for the Power Management capability */ | 622 | /* Permissions for the Power Management capability */ |
591 | static int __init init_pci_cap_pm_perm(struct perm_bits *perm) | 623 | static int __init init_pci_cap_pm_perm(struct perm_bits *perm) |
592 | { | 624 | { |
593 | if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_PM])) | 625 | if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_PM])) |
594 | return -ENOMEM; | 626 | return -ENOMEM; |
595 | 627 | ||
628 | perm->writefn = vfio_pm_config_write; | ||
629 | |||
596 | /* | 630 | /* |
597 | * We always virtualize the next field so we can remove | 631 | * We always virtualize the next field so we can remove |
598 | * capabilities from the chain if we want to. | 632 | * capabilities from the chain if we want to. |
@@ -600,10 +634,11 @@ static int __init init_pci_cap_pm_perm(struct perm_bits *perm) | |||
600 | p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE); | 634 | p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE); |
601 | 635 | ||
602 | /* | 636 | /* |
603 | * Power management is defined *per function*, | 637 | * Power management is defined *per function*, so we can let |
604 | * so we let the user write this | 638 | * the user change power state, but we trap and initiate the |
639 | * change ourselves, so the state bits are read-only. | ||
605 | */ | 640 | */ |
606 | p_setd(perm, PCI_PM_CTRL, NO_VIRT, ALL_WRITE); | 641 | p_setd(perm, PCI_PM_CTRL, NO_VIRT, ~PCI_PM_CTRL_STATE_MASK); |
607 | return 0; | 642 | return 0; |
608 | } | 643 | } |
609 | 644 | ||