Skip to content

Commit d1b7526

Browse files
jannaumarcan
authored andcommitted
drm/apple: Use iommu domain for piodma maps
The current use of of dma_get_sgtable/dma_map_sgtable is deemed unsafe. Replace it with an unmanaged iommu domain for the piodma iommu to map the buffers. Signed-off-by: Janne Grunau <[email protected]>
1 parent f672a1a commit d1b7526

3 files changed

Lines changed: 38 additions & 21 deletions

File tree

drivers/gpu/drm/apple/dcp-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ struct dcp_panel {
9797
struct apple_dcp {
9898
struct device *dev;
9999
struct platform_device *piodma;
100+
struct iommu_domain *iommu_dom;
100101
struct apple_rtkit *rtk;
101102
struct apple_crtc *crtc;
102103
struct apple_connector *connector;

drivers/gpu/drm/apple/dcp.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,22 @@ static int dcp_create_piodma_iommu_dev(struct apple_dcp *dcp)
342342
goto err_destroy_pdev;
343343
}
344344

345-
return 0;
345+
dcp->iommu_dom = iommu_domain_alloc(&platform_bus_type);
346+
if (!dcp->iommu_dom) {
347+
ret = -ENOMEM;
348+
goto err_destroy_pdev;
349+
}
350+
351+
ret = iommu_attach_device(dcp->iommu_dom, &dcp->piodma->dev);
352+
if (ret) {
353+
ret = dev_err_probe(dcp->dev, ret,
354+
"Failed to attach IOMMU child domain\n");
355+
goto err_free_domain;
356+
}
346357

358+
return 0;
359+
err_free_domain:
360+
iommu_domain_free(dcp->iommu_dom);
347361
err_destroy_pdev:
348362
of_platform_device_destroy(&dcp->piodma->dev, NULL);
349363
return ret;
@@ -556,6 +570,8 @@ static void dcp_comp_unbind(struct device *dev, struct device *main, void *data)
556570
iomfb_shutdown(dcp);
557571

558572
if (dcp->piodma) {
573+
iommu_detach_device(dcp->iommu_dom, &dcp->piodma->dev);
574+
iommu_domain_free(dcp->iommu_dom);
559575
of_platform_device_destroy(&dcp->piodma->dev, NULL);
560576
dcp->piodma = NULL;
561577
}

drivers/gpu/drm/apple/iomfb_template.c

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -258,32 +258,33 @@ static void iomfbep_cb_set_fx_prop(struct apple_dcp *dcp, struct iomfb_set_fx_pr
258258
* Callback to map a buffer allocated with allocate_buf for PIODMA usage.
259259
* PIODMA is separate from the main DCP and uses own IOVA space on a dedicated
260260
* stream of the display DART, rather than the expected DCP DART.
261-
*
262-
* XXX: This relies on dma_get_sgtable in concert with dma_map_sgtable, which
263-
* is a "fundamentally unsafe" operation according to the docs. And yet
264-
* everyone does it...
265261
*/
266262
static struct dcp_map_buf_resp dcpep_cb_map_piodma(struct apple_dcp *dcp,
267263
struct dcp_map_buf_req *req)
268264
{
265+
struct dcp_mem_descriptor *memdesc;
269266
struct sg_table *map;
270-
int ret;
267+
ssize_t ret;
271268

272269
if (req->buffer >= ARRAY_SIZE(dcp->memdesc))
273270
goto reject;
274271

275-
map = &dcp->memdesc[req->buffer].map;
272+
memdesc = &dcp->memdesc[req->buffer];
273+
map = &memdesc->map;
276274

277275
if (!map->sgl)
278276
goto reject;
279277

280-
/* Use PIODMA device instead of DCP to map against the right IOMMU. */
281-
ret = dma_map_sgtable(&dcp->piodma->dev, map, DMA_BIDIRECTIONAL, 0);
278+
/* use the piodma iommu domain to map against the right IOMMU */
279+
ret = iommu_map_sgtable(dcp->iommu_dom, memdesc->dva, map,
280+
IOMMU_READ | IOMMU_WRITE);
282281

283-
if (ret)
282+
if (ret != memdesc->size) {
283+
dev_err(dcp->dev, "iommu_map_sgtable() returned %zd instead of expected buffer size of %zu\n", ret, memdesc->size);
284284
goto reject;
285+
}
285286

286-
return (struct dcp_map_buf_resp){ .dva = sg_dma_address(map->sgl) };
287+
return (struct dcp_map_buf_resp){ .dva = memdesc->dva };
287288

288289
reject:
289290
dev_err(dcp->dev, "denying map of invalid buffer %llx for pidoma\n",
@@ -294,33 +295,32 @@ static struct dcp_map_buf_resp dcpep_cb_map_piodma(struct apple_dcp *dcp,
294295
static void dcpep_cb_unmap_piodma(struct apple_dcp *dcp,
295296
struct dcp_unmap_buf_resp *resp)
296297
{
297-
struct sg_table *map;
298-
dma_addr_t dma_addr;
298+
struct dcp_mem_descriptor *memdesc;
299299

300300
if (resp->buffer >= ARRAY_SIZE(dcp->memdesc)) {
301301
dev_warn(dcp->dev, "unmap request for out of range buffer %llu",
302302
resp->buffer);
303303
return;
304304
}
305305

306-
map = &dcp->memdesc[resp->buffer].map;
306+
memdesc = &dcp->memdesc[resp->buffer];
307307

308-
if (!map->sgl) {
308+
if (!memdesc->buf) {
309309
dev_warn(dcp->dev,
310310
"unmap for non-mapped buffer %llu iova:0x%08llx",
311311
resp->buffer, resp->dva);
312312
return;
313313
}
314314

315-
dma_addr = sg_dma_address(map->sgl);
316-
if (dma_addr != resp->dva) {
317-
dev_warn(dcp->dev, "unmap buffer %llu address mismatch dma_addr:%llx dva:%llx",
318-
resp->buffer, dma_addr, resp->dva);
315+
if (memdesc->dva != resp->dva) {
316+
dev_warn(dcp->dev, "unmap buffer %llu address mismatch "
317+
"memdesc.dva:%llx dva:%llx", resp->buffer,
318+
memdesc->dva, resp->dva);
319319
return;
320320
}
321321

322-
/* Use PIODMA device instead of DCP to unmap from the right IOMMU. */
323-
dma_unmap_sgtable(&dcp->piodma->dev, map, DMA_BIDIRECTIONAL, 0);
322+
/* use the piodma iommu domain to unmap from the right IOMMU */
323+
iommu_unmap(dcp->iommu_dom, memdesc->dva, memdesc->size);
324324
}
325325

326326
/*

0 commit comments

Comments
 (0)