Skip to content

Commit b58b133

Browse files
pran005joergroedel
authored andcommitted
iommu: Handle iommu faults for a bad iopf setup
The iommu_report_device_fault function was updated to return void while assuming that drivers only need to call iommu_report_device_fault() for reporting an iopf. This implementation causes following problems: 1. The drivers rely on the core code to call it's page_reponse, however, when a fault is received and no fault capable domain is attached / iopf_param is NULL, the ops->page_response is NOT called causing the device to stall in case the fault type was PAGE_REQ. 2. The arm_smmu_v3 driver relies on the returned value to log errors returning void from iommu_report_device_fault causes these events to be missed while logging. Modify the iommu_report_device_fault function to return -EINVAL for cases where no fault capable domain is attached or iopf_param was NULL and calls back to the driver (ops->page_response) in case the fault type was IOMMU_FAULT_PAGE_REQ. The returned value can be used by the drivers to log the fault/event as needed. Reported-by: Kunkun Jiang <[email protected]> Closes: https://lore.kernel.org/all/[email protected]/ Fixes: 3dfa64a ("iommu: Make iommu_report_device_fault() return void") Signed-off-by: Jason Gunthorpe <[email protected]> Signed-off-by: Pranjal Shrivastava <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Reviewed-by: Lu Baolu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 47ac09b commit b58b133

File tree

3 files changed

+87
-41
lines changed

3 files changed

+87
-41
lines changed

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1777,7 +1777,7 @@ static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
17771777
goto out_unlock;
17781778
}
17791779

1780-
iommu_report_device_fault(master->dev, &fault_evt);
1780+
ret = iommu_report_device_fault(master->dev, &fault_evt);
17811781
out_unlock:
17821782
mutex_unlock(&smmu->streams_mutex);
17831783
return ret;

drivers/iommu/io-pgfault.c

Lines changed: 83 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,59 @@ static struct iopf_group *iopf_group_alloc(struct iommu_fault_param *iopf_param,
115115
return group;
116116
}
117117

118+
static struct iommu_attach_handle *find_fault_handler(struct device *dev,
119+
struct iopf_fault *evt)
120+
{
121+
struct iommu_fault *fault = &evt->fault;
122+
struct iommu_attach_handle *attach_handle;
123+
124+
if (fault->prm.flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID) {
125+
attach_handle = iommu_attach_handle_get(dev->iommu_group,
126+
fault->prm.pasid, 0);
127+
if (IS_ERR(attach_handle)) {
128+
const struct iommu_ops *ops = dev_iommu_ops(dev);
129+
130+
if (!ops->user_pasid_table)
131+
return NULL;
132+
/*
133+
* The iommu driver for this device supports user-
134+
* managed PASID table. Therefore page faults for
135+
* any PASID should go through the NESTING domain
136+
* attached to the device RID.
137+
*/
138+
attach_handle = iommu_attach_handle_get(
139+
dev->iommu_group, IOMMU_NO_PASID,
140+
IOMMU_DOMAIN_NESTED);
141+
if (IS_ERR(attach_handle))
142+
return NULL;
143+
}
144+
} else {
145+
attach_handle = iommu_attach_handle_get(dev->iommu_group,
146+
IOMMU_NO_PASID, 0);
147+
148+
if (IS_ERR(attach_handle))
149+
return NULL;
150+
}
151+
152+
if (!attach_handle->domain->iopf_handler)
153+
return NULL;
154+
155+
return attach_handle;
156+
}
157+
158+
static void iopf_error_response(struct device *dev, struct iopf_fault *evt)
159+
{
160+
const struct iommu_ops *ops = dev_iommu_ops(dev);
161+
struct iommu_fault *fault = &evt->fault;
162+
struct iommu_page_response resp = {
163+
.pasid = fault->prm.pasid,
164+
.grpid = fault->prm.grpid,
165+
.code = IOMMU_PAGE_RESP_INVALID
166+
};
167+
168+
ops->page_response(dev, evt, &resp);
169+
}
170+
118171
/**
119172
* iommu_report_device_fault() - Report fault event to device driver
120173
* @dev: the device
@@ -153,24 +206,39 @@ static struct iopf_group *iopf_group_alloc(struct iommu_fault_param *iopf_param,
153206
* handling framework should guarantee that the iommu domain could only be
154207
* freed after the device has stopped generating page faults (or the iommu
155208
* hardware has been set to block the page faults) and the pending page faults
156-
* have been flushed.
209+
* have been flushed. In case no page fault handler is attached or no iopf params
210+
* are setup, then the ops->page_response() is called to complete the evt.
211+
*
212+
* Returns 0 on success, or an error in case of a bad/failed iopf setup.
157213
*/
158-
void iommu_report_device_fault(struct device *dev, struct iopf_fault *evt)
214+
int iommu_report_device_fault(struct device *dev, struct iopf_fault *evt)
159215
{
216+
struct iommu_attach_handle *attach_handle;
160217
struct iommu_fault *fault = &evt->fault;
161218
struct iommu_fault_param *iopf_param;
162219
struct iopf_group abort_group = {};
163220
struct iopf_group *group;
164221

222+
attach_handle = find_fault_handler(dev, evt);
223+
if (!attach_handle)
224+
goto err_bad_iopf;
225+
226+
/*
227+
* Something has gone wrong if a fault capable domain is attached but no
228+
* iopf_param is setup
229+
*/
165230
iopf_param = iopf_get_dev_fault_param(dev);
166231
if (WARN_ON(!iopf_param))
167-
return;
232+
goto err_bad_iopf;
168233

169234
if (!(fault->prm.flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE)) {
170-
report_partial_fault(iopf_param, fault);
235+
int ret;
236+
237+
ret = report_partial_fault(iopf_param, fault);
171238
iopf_put_dev_fault_param(iopf_param);
172239
/* A request that is not the last does not need to be ack'd */
173-
return;
240+
241+
return ret;
174242
}
175243

176244
/*
@@ -185,38 +253,7 @@ void iommu_report_device_fault(struct device *dev, struct iopf_fault *evt)
185253
if (group == &abort_group)
186254
goto err_abort;
187255

188-
if (fault->prm.flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID) {
189-
group->attach_handle = iommu_attach_handle_get(dev->iommu_group,
190-
fault->prm.pasid,
191-
0);
192-
if (IS_ERR(group->attach_handle)) {
193-
const struct iommu_ops *ops = dev_iommu_ops(dev);
194-
195-
if (!ops->user_pasid_table)
196-
goto err_abort;
197-
198-
/*
199-
* The iommu driver for this device supports user-
200-
* managed PASID table. Therefore page faults for
201-
* any PASID should go through the NESTING domain
202-
* attached to the device RID.
203-
*/
204-
group->attach_handle =
205-
iommu_attach_handle_get(dev->iommu_group,
206-
IOMMU_NO_PASID,
207-
IOMMU_DOMAIN_NESTED);
208-
if (IS_ERR(group->attach_handle))
209-
goto err_abort;
210-
}
211-
} else {
212-
group->attach_handle =
213-
iommu_attach_handle_get(dev->iommu_group, IOMMU_NO_PASID, 0);
214-
if (IS_ERR(group->attach_handle))
215-
goto err_abort;
216-
}
217-
218-
if (!group->attach_handle->domain->iopf_handler)
219-
goto err_abort;
256+
group->attach_handle = attach_handle;
220257

221258
/*
222259
* On success iopf_handler must call iopf_group_response() and
@@ -225,7 +262,7 @@ void iommu_report_device_fault(struct device *dev, struct iopf_fault *evt)
225262
if (group->attach_handle->domain->iopf_handler(group))
226263
goto err_abort;
227264

228-
return;
265+
return 0;
229266

230267
err_abort:
231268
dev_warn_ratelimited(dev, "iopf with pasid %d aborted\n",
@@ -235,6 +272,14 @@ void iommu_report_device_fault(struct device *dev, struct iopf_fault *evt)
235272
__iopf_free_group(group);
236273
else
237274
iopf_free_group(group);
275+
276+
return 0;
277+
278+
err_bad_iopf:
279+
if (fault->type == IOMMU_FAULT_PAGE_REQ)
280+
iopf_error_response(dev, evt);
281+
282+
return -EINVAL;
238283
}
239284
EXPORT_SYMBOL_GPL(iommu_report_device_fault);
240285

include/linux/iommu.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,7 +1563,7 @@ struct iopf_queue *iopf_queue_alloc(const char *name);
15631563
void iopf_queue_free(struct iopf_queue *queue);
15641564
int iopf_queue_discard_partial(struct iopf_queue *queue);
15651565
void iopf_free_group(struct iopf_group *group);
1566-
void iommu_report_device_fault(struct device *dev, struct iopf_fault *evt);
1566+
int iommu_report_device_fault(struct device *dev, struct iopf_fault *evt);
15671567
void iopf_group_response(struct iopf_group *group,
15681568
enum iommu_page_response_code status);
15691569
#else
@@ -1601,9 +1601,10 @@ static inline void iopf_free_group(struct iopf_group *group)
16011601
{
16021602
}
16031603

1604-
static inline void
1604+
static inline int
16051605
iommu_report_device_fault(struct device *dev, struct iopf_fault *evt)
16061606
{
1607+
return -ENODEV;
16071608
}
16081609

16091610
static inline void iopf_group_response(struct iopf_group *group,

0 commit comments

Comments
 (0)