aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/vfio/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/vfio/pci')
-rw-r--r--drivers/vfio/pci/vfio_pci_config.c41
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
590static 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 */
591static int __init init_pci_cap_pm_perm(struct perm_bits *perm) 623static 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