aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2016-09-26 15:52:16 -0400
committerAlex Williamson <alex.williamson@redhat.com>2016-09-26 15:52:16 -0400
commitddf9dc0eb5314d6dac8b19b1cc37c739c6896e7e (patch)
treee3ef8314ebd2c84bb0cded5fae5fff0204e5e78a
parent2e06285655b59362847b610a7cfad204fee9640b (diff)
vfio-pci: Virtualize PCIe & AF FLR
We use a BAR restore trick to try to detect when a user has performed a device reset, possibly through FLR or other backdoors, to put things back into a working state. This is important for backdoor resets, but we can actually just virtualize the "front door" resets provided via PCIe and AF FLR. Set these bits as virtualized + writable, allowing the default write to set them in vconfig, then we can simply check the bit, perform an FLR of our own, and clear the bit. We don't actually have the granularity in PCI to specify the type of reset we want to do, but generally devices don't implement both PCIe and AF FLR and we'll favor these over other types of reset, so we should generally lineup. We do test whether the device provides the requested FLR type to stay consistent with hardware capabilities though. This seems to fix several instance of devices getting into bad states with userspace drivers, like dpdk, running inside a VM. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Reviewed-by: Greg Rose <grose@lightfleet.com>
-rw-r--r--drivers/vfio/pci/vfio_pci_config.c82
1 files changed, 77 insertions, 5 deletions
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index c4f235452d81..65d4a3015542 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -804,6 +804,40 @@ static int __init init_pci_cap_pcix_perm(struct perm_bits *perm)
804 return 0; 804 return 0;
805} 805}
806 806
807static int vfio_exp_config_write(struct vfio_pci_device *vdev, int pos,
808 int count, struct perm_bits *perm,
809 int offset, __le32 val)
810{
811 __le16 *ctrl = (__le16 *)(vdev->vconfig + pos -
812 offset + PCI_EXP_DEVCTL);
813
814 count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
815 if (count < 0)
816 return count;
817
818 /*
819 * The FLR bit is virtualized, if set and the device supports PCIe
820 * FLR, issue a reset_function. Regardless, clear the bit, the spec
821 * requires it to be always read as zero. NB, reset_function might
822 * not use a PCIe FLR, we don't have that level of granularity.
823 */
824 if (*ctrl & cpu_to_le16(PCI_EXP_DEVCTL_BCR_FLR)) {
825 u32 cap;
826 int ret;
827
828 *ctrl &= ~cpu_to_le16(PCI_EXP_DEVCTL_BCR_FLR);
829
830 ret = pci_user_read_config_dword(vdev->pdev,
831 pos - offset + PCI_EXP_DEVCAP,
832 &cap);
833
834 if (!ret && (cap & PCI_EXP_DEVCAP_FLR))
835 pci_try_reset_function(vdev->pdev);
836 }
837
838 return count;
839}
840
807/* Permissions for PCI Express capability */ 841/* Permissions for PCI Express capability */
808static int __init init_pci_cap_exp_perm(struct perm_bits *perm) 842static int __init init_pci_cap_exp_perm(struct perm_bits *perm)
809{ 843{
@@ -811,26 +845,64 @@ static int __init init_pci_cap_exp_perm(struct perm_bits *perm)
811 if (alloc_perm_bits(perm, PCI_CAP_EXP_ENDPOINT_SIZEOF_V2)) 845 if (alloc_perm_bits(perm, PCI_CAP_EXP_ENDPOINT_SIZEOF_V2))
812 return -ENOMEM; 846 return -ENOMEM;
813 847
848 perm->writefn = vfio_exp_config_write;
849
814 p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE); 850 p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
815 851
816 /* 852 /*
817 * Allow writes to device control fields (includes FLR!) 853 * Allow writes to device control fields, except devctl_phantom,
818 * but not to devctl_phantom which could confuse IOMMU 854 * which could confuse IOMMU, and the ARI bit in devctl2, which
819 * or to the ARI bit in devctl2 which is set at probe time 855 * is set at probe time. FLR gets virtualized via our writefn.
820 */ 856 */
821 p_setw(perm, PCI_EXP_DEVCTL, NO_VIRT, ~PCI_EXP_DEVCTL_PHANTOM); 857 p_setw(perm, PCI_EXP_DEVCTL,
858 PCI_EXP_DEVCTL_BCR_FLR, ~PCI_EXP_DEVCTL_PHANTOM);
822 p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI); 859 p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI);
823 return 0; 860 return 0;
824} 861}
825 862
863static int vfio_af_config_write(struct vfio_pci_device *vdev, int pos,
864 int count, struct perm_bits *perm,
865 int offset, __le32 val)
866{
867 u8 *ctrl = vdev->vconfig + pos - offset + PCI_AF_CTRL;
868
869 count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
870 if (count < 0)
871 return count;
872
873 /*
874 * The FLR bit is virtualized, if set and the device supports AF
875 * FLR, issue a reset_function. Regardless, clear the bit, the spec
876 * requires it to be always read as zero. NB, reset_function might
877 * not use an AF FLR, we don't have that level of granularity.
878 */
879 if (*ctrl & PCI_AF_CTRL_FLR) {
880 u8 cap;
881 int ret;
882
883 *ctrl &= ~PCI_AF_CTRL_FLR;
884
885 ret = pci_user_read_config_byte(vdev->pdev,
886 pos - offset + PCI_AF_CAP,
887 &cap);
888
889 if (!ret && (cap & PCI_AF_CAP_FLR) && (cap & PCI_AF_CAP_TP))
890 pci_try_reset_function(vdev->pdev);
891 }
892
893 return count;
894}
895
826/* Permissions for Advanced Function capability */ 896/* Permissions for Advanced Function capability */
827static int __init init_pci_cap_af_perm(struct perm_bits *perm) 897static int __init init_pci_cap_af_perm(struct perm_bits *perm)
828{ 898{
829 if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_AF])) 899 if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_AF]))
830 return -ENOMEM; 900 return -ENOMEM;
831 901
902 perm->writefn = vfio_af_config_write;
903
832 p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE); 904 p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
833 p_setb(perm, PCI_AF_CTRL, NO_VIRT, PCI_AF_CTRL_FLR); 905 p_setb(perm, PCI_AF_CTRL, PCI_AF_CTRL_FLR, PCI_AF_CTRL_FLR);
834 return 0; 906 return 0;
835} 907}
836 908