diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2011-12-01 06:04:58 -0500 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2011-12-12 09:19:06 -0500 |
commit | 6a113ddc03bcc32d3d440dce42b445868d5be093 (patch) | |
tree | 2788087070898e12721ea94ddcde336f748ce7ff | |
parent | f3572db823decfd747e6afd4c4ddfd67e8af8b6d (diff) |
iommu/amd: Add device errata handling
Add infrastructure for errata-handling and handle two known
erratas in the IOMMUv2 code.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
-rw-r--r-- | drivers/iommu/amd_iommu.c | 57 | ||||
-rw-r--r-- | drivers/iommu/amd_iommu_types.h | 1 | ||||
-rw-r--r-- | include/linux/amd-iommu.h | 18 |
3 files changed, 73 insertions, 3 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 71773d0fb76..e453bbd0944 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
@@ -172,6 +172,15 @@ static bool pci_iommuv2_capable(struct pci_dev *pdev) | |||
172 | return true; | 172 | return true; |
173 | } | 173 | } |
174 | 174 | ||
175 | static bool pdev_pri_erratum(struct pci_dev *pdev, u32 erratum) | ||
176 | { | ||
177 | struct iommu_dev_data *dev_data; | ||
178 | |||
179 | dev_data = get_dev_data(&pdev->dev); | ||
180 | |||
181 | return dev_data->errata & (1 << erratum) ? true : false; | ||
182 | } | ||
183 | |||
175 | /* | 184 | /* |
176 | * In this function the list of preallocated protection domains is traversed to | 185 | * In this function the list of preallocated protection domains is traversed to |
177 | * find the domain for a specific device | 186 | * find the domain for a specific device |
@@ -1934,9 +1943,33 @@ static void pdev_iommuv2_disable(struct pci_dev *pdev) | |||
1934 | pci_disable_pasid(pdev); | 1943 | pci_disable_pasid(pdev); |
1935 | } | 1944 | } |
1936 | 1945 | ||
1946 | /* FIXME: Change generic reset-function to do the same */ | ||
1947 | static int pri_reset_while_enabled(struct pci_dev *pdev) | ||
1948 | { | ||
1949 | u16 control; | ||
1950 | int pos; | ||
1951 | |||
1952 | pos = pci_find_ext_capability(pdev, PCI_PRI_CAP); | ||
1953 | if (!pos) | ||
1954 | return -EINVAL; | ||
1955 | |||
1956 | pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control); | ||
1957 | control |= PCI_PRI_RESET; | ||
1958 | pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control); | ||
1959 | |||
1960 | return 0; | ||
1961 | } | ||
1962 | |||
1937 | static int pdev_iommuv2_enable(struct pci_dev *pdev) | 1963 | static int pdev_iommuv2_enable(struct pci_dev *pdev) |
1938 | { | 1964 | { |
1939 | int ret; | 1965 | bool reset_enable; |
1966 | int reqs, ret; | ||
1967 | |||
1968 | /* FIXME: Hardcode number of outstanding requests for now */ | ||
1969 | reqs = 32; | ||
1970 | if (pdev_pri_erratum(pdev, AMD_PRI_DEV_ERRATUM_LIMIT_REQ_ONE)) | ||
1971 | reqs = 1; | ||
1972 | reset_enable = pdev_pri_erratum(pdev, AMD_PRI_DEV_ERRATUM_ENABLE_RESET); | ||
1940 | 1973 | ||
1941 | /* Only allow access to user-accessible pages */ | 1974 | /* Only allow access to user-accessible pages */ |
1942 | ret = pci_enable_pasid(pdev, 0); | 1975 | ret = pci_enable_pasid(pdev, 0); |
@@ -1948,11 +1981,17 @@ static int pdev_iommuv2_enable(struct pci_dev *pdev) | |||
1948 | if (ret) | 1981 | if (ret) |
1949 | goto out_err; | 1982 | goto out_err; |
1950 | 1983 | ||
1951 | /* FIXME: Hardcode number of outstanding requests for now */ | 1984 | /* Enable PRI */ |
1952 | ret = pci_enable_pri(pdev, 32); | 1985 | ret = pci_enable_pri(pdev, reqs); |
1953 | if (ret) | 1986 | if (ret) |
1954 | goto out_err; | 1987 | goto out_err; |
1955 | 1988 | ||
1989 | if (reset_enable) { | ||
1990 | ret = pri_reset_while_enabled(pdev); | ||
1991 | if (ret) | ||
1992 | goto out_err; | ||
1993 | } | ||
1994 | |||
1956 | ret = pci_enable_ats(pdev, PAGE_SHIFT); | 1995 | ret = pci_enable_ats(pdev, PAGE_SHIFT); |
1957 | if (ret) | 1996 | if (ret) |
1958 | goto out_err; | 1997 | goto out_err; |
@@ -3481,3 +3520,15 @@ struct iommu_domain *amd_iommu_get_v2_domain(struct pci_dev *pdev) | |||
3481 | return domain->iommu_domain; | 3520 | return domain->iommu_domain; |
3482 | } | 3521 | } |
3483 | EXPORT_SYMBOL(amd_iommu_get_v2_domain); | 3522 | EXPORT_SYMBOL(amd_iommu_get_v2_domain); |
3523 | |||
3524 | void amd_iommu_enable_device_erratum(struct pci_dev *pdev, u32 erratum) | ||
3525 | { | ||
3526 | struct iommu_dev_data *dev_data; | ||
3527 | |||
3528 | if (!amd_iommu_v2_supported()) | ||
3529 | return; | ||
3530 | |||
3531 | dev_data = get_dev_data(&pdev->dev); | ||
3532 | dev_data->errata |= (1 << erratum); | ||
3533 | } | ||
3534 | EXPORT_SYMBOL(amd_iommu_enable_device_erratum); | ||
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index c39988fbcbb..6ad8b10b313 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h | |||
@@ -404,6 +404,7 @@ struct iommu_dev_data { | |||
404 | } ats; /* ATS state */ | 404 | } ats; /* ATS state */ |
405 | bool pri_tlp; /* PASID TLB required for | 405 | bool pri_tlp; /* PASID TLB required for |
406 | PPR completions */ | 406 | PPR completions */ |
407 | u32 errata; /* Bitmap for errata to apply */ | ||
407 | }; | 408 | }; |
408 | 409 | ||
409 | /* | 410 | /* |
diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h index a6863a2dec1..4152c3073db 100644 --- a/include/linux/amd-iommu.h +++ b/include/linux/amd-iommu.h | |||
@@ -26,6 +26,24 @@ | |||
26 | 26 | ||
27 | extern int amd_iommu_detect(void); | 27 | extern int amd_iommu_detect(void); |
28 | 28 | ||
29 | |||
30 | /** | ||
31 | * amd_iommu_enable_device_erratum() - Enable erratum workaround for device | ||
32 | * in the IOMMUv2 driver | ||
33 | * @pdev: The PCI device the workaround is necessary for | ||
34 | * @erratum: The erratum workaround to enable | ||
35 | * | ||
36 | * Possible values for the erratum number are for now: | ||
37 | * - AMD_PRI_DEV_ERRATUM_ENABLE_RESET - Reset PRI capability when PRI | ||
38 | * is enabled | ||
39 | * - AMD_PRI_DEV_ERRATUM_LIMIT_REQ_ONE - Limit number of outstanding PRI | ||
40 | * requests to one | ||
41 | */ | ||
42 | #define AMD_PRI_DEV_ERRATUM_ENABLE_RESET 0 | ||
43 | #define AMD_PRI_DEV_ERRATUM_LIMIT_REQ_ONE 1 | ||
44 | |||
45 | extern void amd_iommu_enable_device_erratum(struct pci_dev *pdev, u32 erratum); | ||
46 | |||
29 | #else | 47 | #else |
30 | 48 | ||
31 | static inline int amd_iommu_detect(void) { return -ENODEV; } | 49 | static inline int amd_iommu_detect(void) { return -ENODEV; } |