mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
iommu/amd: Fix missing CMD_COMPLETE_PPR response for invalid PPR requests
The AMD IOMMU spec, requires the host to respond with a CMD_COMPLETE_PPR command when an EVENT_TYPE_INV_PPR_REQ event is received with the RX bit cleared. This response was missing in the current implementation, leaving invalid PPR requests unacknowledged. Introduce amd_iommu_report_ppr_err() to handle EVENT_TYPE_INV_PPR_REQ events. The new function logs the invalid PPR request and when the RX bit is cleared, sends CMD_COMPLETE_PPR response. Reported-by: Gaultier Delbarre <Gaultier.Delbarre@amd.com> Co-developed-by: Wei Huang <wei.huang2@amd.com> Signed-off-by: Wei Huang <wei.huang2@amd.com> Signed-off-by: Vasant Hegde <vasant.hegde@amd.com> Reviewed-by: Ankit Soni <Ankit.Soni@amd.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
parent
589f0cc1e0
commit
bc1f5ec826
|
|
@ -159,6 +159,7 @@
|
|||
#define EVENT_FLAGS_SHIFT 0x10
|
||||
#define EVENT_FLAG_RW 0x020
|
||||
#define EVENT_FLAG_I 0x008
|
||||
#define EVENT_FLAG_PPR_RX 0x001
|
||||
|
||||
/* feature control bits */
|
||||
#define CONTROL_IOMMU_EN 0
|
||||
|
|
|
|||
|
|
@ -905,10 +905,40 @@ static void amd_iommu_report_page_fault(struct amd_iommu *iommu,
|
|||
pci_dev_put(pdev);
|
||||
}
|
||||
|
||||
static void amd_iommu_report_ppr_err(struct amd_iommu *iommu, volatile u32 *event,
|
||||
u16 devid, u64 address, int flags)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
struct device *dev = iommu->iommu.dev;
|
||||
u32 pasid = PPR_PASID(*((u64 *)event));
|
||||
int tag = event[1] & 0x03FF;
|
||||
|
||||
dev_err(dev, "Event logged [INVALID_PPR_REQUEST device=%04x:%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x tag=0x%03x]\n",
|
||||
iommu->pci_seg->id, PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
|
||||
pasid, address, flags, tag);
|
||||
|
||||
/* Skip COMPLETE_PPR_REQUEST response if RX=1 */
|
||||
if (flags & EVENT_FLAG_PPR_RX)
|
||||
return;
|
||||
|
||||
pdev = pci_get_domain_bus_and_slot(iommu->pci_seg->id, PCI_BUS_NUM(devid),
|
||||
devid & 0xff);
|
||||
if (!pdev)
|
||||
return;
|
||||
|
||||
if (!dev_iommu_priv_get(&pdev->dev)) {
|
||||
pci_dev_put(pdev);
|
||||
return;
|
||||
}
|
||||
|
||||
amd_iommu_complete_ppr(&pdev->dev, pasid, IOMMU_PAGE_RESP_FAILURE, tag);
|
||||
pci_dev_put(pdev);
|
||||
}
|
||||
|
||||
static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
|
||||
{
|
||||
struct device *dev = iommu->iommu.dev;
|
||||
int type, devid, flags, tag;
|
||||
int type, devid, flags;
|
||||
volatile u32 *event = __evt;
|
||||
int count = 0;
|
||||
u64 address, ctrl;
|
||||
|
|
@ -982,11 +1012,7 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
|
|||
amd_iommu_report_rmp_hw_error(iommu, event);
|
||||
break;
|
||||
case EVENT_TYPE_INV_PPR_REQ:
|
||||
pasid = PPR_PASID(*((u64 *)__evt));
|
||||
tag = event[1] & 0x03FF;
|
||||
dev_err(dev, "Event logged [INVALID_PPR_REQUEST device=%04x:%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x tag=0x%03x]\n",
|
||||
iommu->pci_seg->id, PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
|
||||
pasid, address, flags, tag);
|
||||
amd_iommu_report_ppr_err(iommu, event, devid, address, flags);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Event logged [UNKNOWN event[0]=0x%08x event[1]=0x%08x event[2]=0x%08x event[3]=0x%08x\n",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user