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:
Vasant Hegde 2026-08-11 04:08:58 +00:00 committed by Joerg Roedel
parent 589f0cc1e0
commit bc1f5ec826
2 changed files with 33 additions and 6 deletions

View File

@ -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

View File

@ -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",