Skip to content

Commit

Permalink
iommu/amd: Add device errata handling
Browse files Browse the repository at this point in the history
Add infrastructure for errata-handling and handle two known
erratas in the IOMMUv2 code.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
  • Loading branch information
Joerg Roedel committed Dec 12, 2011
1 parent f3572db commit 6a113dd
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 3 deletions.
57 changes: 54 additions & 3 deletions drivers/iommu/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
1 change: 1 addition & 0 deletions drivers/iommu/amd_iommu_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
};

/*
Expand Down
18 changes: 18 additions & 0 deletions include/linux/amd-iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down

0 comments on commit 6a113dd

Please sign in to comment.