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>
This commit is contained in:
parent
f3572db823
commit
6a113ddc03
|
@ -172,6 +172,15 @@ static bool pci_iommuv2_capable(struct pci_dev *pdev)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool pdev_pri_erratum(struct pci_dev *pdev, u32 erratum)
|
||||
{
|
||||
struct iommu_dev_data *dev_data;
|
||||
|
||||
dev_data = get_dev_data(&pdev->dev);
|
||||
|
||||
return dev_data->errata & (1 << erratum) ? true : false;
|
||||
}
|
||||
|
||||
/*
|
||||
* In this function the list of preallocated protection domains is traversed to
|
||||
* find the domain for a specific device
|
||||
|
@ -1934,9 +1943,33 @@ static void pdev_iommuv2_disable(struct pci_dev *pdev)
|
|||
pci_disable_pasid(pdev);
|
||||
}
|
||||
|
||||
/* FIXME: Change generic reset-function to do the same */
|
||||
static int pri_reset_while_enabled(struct pci_dev *pdev)
|
||||
{
|
||||
u16 control;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
control |= PCI_PRI_RESET;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pdev_iommuv2_enable(struct pci_dev *pdev)
|
||||
{
|
||||
int ret;
|
||||
bool reset_enable;
|
||||
int reqs, ret;
|
||||
|
||||
/* FIXME: Hardcode number of outstanding requests for now */
|
||||
reqs = 32;
|
||||
if (pdev_pri_erratum(pdev, AMD_PRI_DEV_ERRATUM_LIMIT_REQ_ONE))
|
||||
reqs = 1;
|
||||
reset_enable = pdev_pri_erratum(pdev, AMD_PRI_DEV_ERRATUM_ENABLE_RESET);
|
||||
|
||||
/* Only allow access to user-accessible pages */
|
||||
ret = pci_enable_pasid(pdev, 0);
|
||||
|
@ -1948,11 +1981,17 @@ static int pdev_iommuv2_enable(struct pci_dev *pdev)
|
|||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
/* FIXME: Hardcode number of outstanding requests for now */
|
||||
ret = pci_enable_pri(pdev, 32);
|
||||
/* Enable PRI */
|
||||
ret = pci_enable_pri(pdev, reqs);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
if (reset_enable) {
|
||||
ret = pri_reset_while_enabled(pdev);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
ret = pci_enable_ats(pdev, PAGE_SHIFT);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
@ -3481,3 +3520,15 @@ struct iommu_domain *amd_iommu_get_v2_domain(struct pci_dev *pdev)
|
|||
return domain->iommu_domain;
|
||||
}
|
||||
EXPORT_SYMBOL(amd_iommu_get_v2_domain);
|
||||
|
||||
void amd_iommu_enable_device_erratum(struct pci_dev *pdev, u32 erratum)
|
||||
{
|
||||
struct iommu_dev_data *dev_data;
|
||||
|
||||
if (!amd_iommu_v2_supported())
|
||||
return;
|
||||
|
||||
dev_data = get_dev_data(&pdev->dev);
|
||||
dev_data->errata |= (1 << erratum);
|
||||
}
|
||||
EXPORT_SYMBOL(amd_iommu_enable_device_erratum);
|
||||
|
|
|
@ -404,6 +404,7 @@ struct iommu_dev_data {
|
|||
} ats; /* ATS state */
|
||||
bool pri_tlp; /* PASID TLB required for
|
||||
PPR completions */
|
||||
u32 errata; /* Bitmap for errata to apply */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -26,6 +26,24 @@
|
|||
|
||||
extern int amd_iommu_detect(void);
|
||||
|
||||
|
||||
/**
|
||||
* amd_iommu_enable_device_erratum() - Enable erratum workaround for device
|
||||
* in the IOMMUv2 driver
|
||||
* @pdev: The PCI device the workaround is necessary for
|
||||
* @erratum: The erratum workaround to enable
|
||||
*
|
||||
* Possible values for the erratum number are for now:
|
||||
* - AMD_PRI_DEV_ERRATUM_ENABLE_RESET - Reset PRI capability when PRI
|
||||
* is enabled
|
||||
* - AMD_PRI_DEV_ERRATUM_LIMIT_REQ_ONE - Limit number of outstanding PRI
|
||||
* requests to one
|
||||
*/
|
||||
#define AMD_PRI_DEV_ERRATUM_ENABLE_RESET 0
|
||||
#define AMD_PRI_DEV_ERRATUM_LIMIT_REQ_ONE 1
|
||||
|
||||
extern void amd_iommu_enable_device_erratum(struct pci_dev *pdev, u32 erratum);
|
||||
|
||||
#else
|
||||
|
||||
static inline int amd_iommu_detect(void) { return -ENODEV; }
|
||||
|
|
Loading…
Reference in New Issue