Skip to content

Commit 978d626

Browse files
weihuang-amdjoergroedel
authored andcommitted
iommu/amd: Add IO page fault notifier handler
Whenever there is a page fault IOMMU logs entry to ppr log and sends interrupt to host. We have to handle the page fault and respond to IOMMU. Add support to validate page fault request and hook it to core iommu page fault handler. Signed-off-by: Wei Huang <[email protected]> Co-developed-by: Suravee Suthikulpanit <[email protected]> Signed-off-by: Suravee Suthikulpanit <[email protected]> Co-developed-by: Vasant Hegde <[email protected]> Signed-off-by: Vasant Hegde <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 405e2f1 commit 978d626

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

drivers/iommu/amd/amd_iommu_types.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,14 @@
251251
#define PPR_ENTRY_SIZE 16
252252
#define PPR_LOG_SIZE (PPR_ENTRY_SIZE * PPR_LOG_ENTRIES)
253253

254+
/* PAGE_SERVICE_REQUEST PPR Log Buffer Entry flags */
255+
#define PPR_FLAG_EXEC 0x002 /* Execute permission requested */
256+
#define PPR_FLAG_READ 0x004 /* Read permission requested */
257+
#define PPR_FLAG_WRITE 0x020 /* Write permission requested */
258+
#define PPR_FLAG_US 0x040 /* 1: User, 0: Supervisor */
259+
#define PPR_FLAG_RVSD 0x080 /* Reserved bit not zero */
260+
#define PPR_FLAG_GN 0x100 /* GVA and PASID is valid */
261+
254262
#define PPR_REQ_TYPE(x) (((x) >> 60) & 0xfULL)
255263
#define PPR_FLAGS(x) (((x) >> 48) & 0xfffULL)
256264
#define PPR_DEVID(x) ((x) & 0xffffULL)

drivers/iommu/amd/ppr.c

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,103 @@ void amd_iommu_restart_ppr_log(struct amd_iommu *iommu)
6060
MMIO_STATUS_PPR_OVERFLOW_MASK);
6161
}
6262

63+
static inline u32 ppr_flag_to_fault_perm(u16 flag)
64+
{
65+
int perm = 0;
66+
67+
if (flag & PPR_FLAG_READ)
68+
perm |= IOMMU_FAULT_PERM_READ;
69+
if (flag & PPR_FLAG_WRITE)
70+
perm |= IOMMU_FAULT_PERM_WRITE;
71+
if (flag & PPR_FLAG_EXEC)
72+
perm |= IOMMU_FAULT_PERM_EXEC;
73+
if (!(flag & PPR_FLAG_US))
74+
perm |= IOMMU_FAULT_PERM_PRIV;
75+
76+
return perm;
77+
}
78+
79+
static bool ppr_is_valid(struct amd_iommu *iommu, u64 *raw)
80+
{
81+
struct device *dev = iommu->iommu.dev;
82+
u16 devid = PPR_DEVID(raw[0]);
83+
84+
if (!(PPR_FLAGS(raw[0]) & PPR_FLAG_GN)) {
85+
dev_dbg(dev, "PPR logged [Request ignored due to GN=0 (device=%04x:%02x:%02x.%x "
86+
"pasid=0x%05llx address=0x%llx flags=0x%04llx tag=0x%03llx]\n",
87+
iommu->pci_seg->id, PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
88+
PPR_PASID(raw[0]), raw[1], PPR_FLAGS(raw[0]), PPR_TAG(raw[0]));
89+
return false;
90+
}
91+
92+
if (PPR_FLAGS(raw[0]) & PPR_FLAG_RVSD) {
93+
dev_dbg(dev, "PPR logged [Invalid request format (device=%04x:%02x:%02x.%x "
94+
"pasid=0x%05llx address=0x%llx flags=0x%04llx tag=0x%03llx]\n",
95+
iommu->pci_seg->id, PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
96+
PPR_PASID(raw[0]), raw[1], PPR_FLAGS(raw[0]), PPR_TAG(raw[0]));
97+
return false;
98+
}
99+
100+
return true;
101+
}
102+
103+
static void iommu_call_iopf_notifier(struct amd_iommu *iommu, u64 *raw)
104+
{
105+
struct iommu_dev_data *dev_data;
106+
struct iopf_fault event;
107+
struct pci_dev *pdev;
108+
u16 devid = PPR_DEVID(raw[0]);
109+
110+
if (PPR_REQ_TYPE(raw[0]) != PPR_REQ_FAULT) {
111+
pr_info_ratelimited("Unknown PPR request received\n");
112+
return;
113+
}
114+
115+
pdev = pci_get_domain_bus_and_slot(iommu->pci_seg->id,
116+
PCI_BUS_NUM(devid), devid & 0xff);
117+
if (!pdev)
118+
return;
119+
120+
if (!ppr_is_valid(iommu, raw))
121+
goto out;
122+
123+
memset(&event, 0, sizeof(struct iopf_fault));
124+
125+
event.fault.type = IOMMU_FAULT_PAGE_REQ;
126+
event.fault.prm.perm = ppr_flag_to_fault_perm(PPR_FLAGS(raw[0]));
127+
event.fault.prm.addr = (u64)(raw[1] & PAGE_MASK);
128+
event.fault.prm.pasid = PPR_PASID(raw[0]);
129+
event.fault.prm.grpid = PPR_TAG(raw[0]) & 0x1FF;
130+
131+
/*
132+
* PASID zero is used for requests from the I/O device without
133+
* a PASID
134+
*/
135+
dev_data = dev_iommu_priv_get(&pdev->dev);
136+
if (event.fault.prm.pasid == 0 ||
137+
event.fault.prm.pasid >= dev_data->max_pasids) {
138+
pr_info_ratelimited("Invalid PASID : 0x%x, device : 0x%x\n",
139+
event.fault.prm.pasid, pdev->dev.id);
140+
goto out;
141+
}
142+
143+
event.fault.prm.flags |= IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID;
144+
event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
145+
if (PPR_TAG(raw[0]) & 0x200)
146+
event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
147+
148+
/* Submit event */
149+
iommu_report_device_fault(&pdev->dev, &event);
150+
151+
return;
152+
153+
out:
154+
/* Nobody cared, abort */
155+
amd_iommu_complete_ppr(&pdev->dev, PPR_PASID(raw[0]),
156+
IOMMU_PAGE_RESP_FAILURE,
157+
PPR_TAG(raw[0]) & 0x1FF);
158+
}
159+
63160
void amd_iommu_poll_ppr_log(struct amd_iommu *iommu)
64161
{
65162
u32 head, tail;
@@ -105,7 +202,8 @@ void amd_iommu_poll_ppr_log(struct amd_iommu *iommu)
105202
head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE;
106203
writel(head, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
107204

108-
/* TODO: PPR Handler will be added when we add IOPF support */
205+
/* Handle PPR entry */
206+
iommu_call_iopf_notifier(iommu, entry);
109207
}
110208
}
111209

0 commit comments

Comments
 (0)