Skip to content

Commit dbbde63

Browse files
robclarkRob Clark
authored andcommitted
drm/msm: Add PRR support
Add PRR (Partial Resident Region) is a bypass address which make GPU writes go to /dev/null and reads return zero. This is used to implement vulkan sparse residency. To support PRR/NULL mappings, we allocate a page to reserve a physical address which we know will not be used as part of a GEM object, and configure the SMMU to use this address for PRR/NULL mappings. Signed-off-by: Rob Clark <robdclark@chromium.org> Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com> Tested-by: Antonino Maniscalco <antomani103@gmail.com> Reviewed-by: Antonino Maniscalco <antomani103@gmail.com> Patchwork: https://patchwork.freedesktop.org/patch/661486/
1 parent 2c7ad99 commit dbbde63

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

drivers/gpu/drm/msm/adreno/adreno_gpu.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,13 @@ int adreno_fault_handler(struct msm_gpu *gpu, unsigned long iova, int flags,
357357
return 0;
358358
}
359359

360+
static bool
361+
adreno_smmu_has_prr(struct msm_gpu *gpu)
362+
{
363+
struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(&gpu->pdev->dev);
364+
return adreno_smmu && adreno_smmu->set_prr_addr;
365+
}
366+
360367
int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
361368
uint32_t param, uint64_t *value, uint32_t *len)
362369
{
@@ -440,6 +447,9 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx,
440447
case MSM_PARAM_UCHE_TRAP_BASE:
441448
*value = adreno_gpu->uche_trap_base;
442449
return 0;
450+
case MSM_PARAM_HAS_PRR:
451+
*value = adreno_smmu_has_prr(gpu);
452+
return 0;
443453
default:
444454
return UERR(EINVAL, drm, "%s: invalid param: %u", gpu->name, param);
445455
}

drivers/gpu/drm/msm/msm_iommu.c

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct msm_iommu {
1313
struct msm_mmu base;
1414
struct iommu_domain *domain;
1515
atomic_t pagetables;
16+
struct page *prr_page;
1617
};
1718

1819
#define to_msm_iommu(x) container_of(x, struct msm_iommu, base)
@@ -112,6 +113,36 @@ static int msm_iommu_pagetable_unmap(struct msm_mmu *mmu, u64 iova,
112113
return (size == 0) ? 0 : -EINVAL;
113114
}
114115

116+
static int msm_iommu_pagetable_map_prr(struct msm_mmu *mmu, u64 iova, size_t len, int prot)
117+
{
118+
struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
119+
struct io_pgtable_ops *ops = pagetable->pgtbl_ops;
120+
struct msm_iommu *iommu = to_msm_iommu(pagetable->parent);
121+
phys_addr_t phys = page_to_phys(iommu->prr_page);
122+
u64 addr = iova;
123+
124+
while (len) {
125+
size_t mapped = 0;
126+
size_t size = PAGE_SIZE;
127+
int ret;
128+
129+
ret = ops->map_pages(ops, addr, phys, size, 1, prot, GFP_KERNEL, &mapped);
130+
131+
/* map_pages could fail after mapping some of the pages,
132+
* so update the counters before error handling.
133+
*/
134+
addr += mapped;
135+
len -= mapped;
136+
137+
if (ret) {
138+
msm_iommu_pagetable_unmap(mmu, iova, addr - iova);
139+
return -EINVAL;
140+
}
141+
}
142+
143+
return 0;
144+
}
145+
115146
static int msm_iommu_pagetable_map(struct msm_mmu *mmu, u64 iova,
116147
struct sg_table *sgt, size_t off, size_t len,
117148
int prot)
@@ -122,6 +153,9 @@ static int msm_iommu_pagetable_map(struct msm_mmu *mmu, u64 iova,
122153
u64 addr = iova;
123154
unsigned int i;
124155

156+
if (!sgt)
157+
return msm_iommu_pagetable_map_prr(mmu, iova, len, prot);
158+
125159
for_each_sgtable_sg(sgt, sg, i) {
126160
size_t size = sg->length;
127161
phys_addr_t phys = sg_phys(sg);
@@ -177,9 +211,16 @@ static void msm_iommu_pagetable_destroy(struct msm_mmu *mmu)
177211
* If this is the last attached pagetable for the parent,
178212
* disable TTBR0 in the arm-smmu driver
179213
*/
180-
if (atomic_dec_return(&iommu->pagetables) == 0)
214+
if (atomic_dec_return(&iommu->pagetables) == 0) {
181215
adreno_smmu->set_ttbr0_cfg(adreno_smmu->cookie, NULL);
182216

217+
if (adreno_smmu->set_prr_bit) {
218+
adreno_smmu->set_prr_bit(adreno_smmu->cookie, false);
219+
__free_page(iommu->prr_page);
220+
iommu->prr_page = NULL;
221+
}
222+
}
223+
183224
free_io_pgtable_ops(pagetable->pgtbl_ops);
184225
kfree(pagetable);
185226
}
@@ -336,6 +377,25 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent)
336377
kfree(pagetable);
337378
return ERR_PTR(ret);
338379
}
380+
381+
BUG_ON(iommu->prr_page);
382+
if (adreno_smmu->set_prr_bit) {
383+
/*
384+
* We need a zero'd page for two reasons:
385+
*
386+
* 1) Reserve a known physical address to use when
387+
* mapping NULL / sparsely resident regions
388+
* 2) Read back zero
389+
*
390+
* It appears the hw drops writes to the PRR region
391+
* on the floor, but reads actually return whatever
392+
* is in the PRR page.
393+
*/
394+
iommu->prr_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
395+
adreno_smmu->set_prr_addr(adreno_smmu->cookie,
396+
page_to_phys(iommu->prr_page));
397+
adreno_smmu->set_prr_bit(adreno_smmu->cookie, true);
398+
}
339399
}
340400

341401
/* Needed later for TLB flush */

include/uapi/drm/msm_drm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ struct drm_msm_timespec {
9191
#define MSM_PARAM_UBWC_SWIZZLE 0x12 /* RO */
9292
#define MSM_PARAM_MACROTILE_MODE 0x13 /* RO */
9393
#define MSM_PARAM_UCHE_TRAP_BASE 0x14 /* RO */
94+
/* PRR (Partially Resident Region) is required for sparse residency: */
95+
#define MSM_PARAM_HAS_PRR 0x15 /* RO */
9496

9597
/* For backwards compat. The original support for preemption was based on
9698
* a single ring per priority level so # of priority levels equals the #

0 commit comments

Comments
 (0)