[PATCH v3 6/8] drm/v3d: Support Big/Super Pages when writing out PTEs

Tvrtko Ursulin tvrtko.ursulin at igalia.com
Mon Apr 22 09:57:10 UTC 2024


On 21/04/2024 22:44, Maíra Canal wrote:
> The V3D MMU also supports 64KB and 1MB pages, called big and super pages,
> respectively. In order to set a 64KB page or 1MB page in the MMU, we need
> to make sure that page table entries for all 4KB pages within a big/super
> page must be correctly configured.
> 
> In order to create a big/super page, we need a contiguous memory region.
> That's why we use a separate mountpoint with THP enabled. In order to
> place the page table entries in the MMU, we iterate over the 16 4KB pages
> (for big pages) or 256 4KB pages (for super pages) and insert the PTE.
> 
> Signed-off-by: Maíra Canal <mcanal at igalia.com>
> ---
>   drivers/gpu/drm/v3d/v3d_drv.h |  1 +
>   drivers/gpu/drm/v3d/v3d_mmu.c | 52 ++++++++++++++++++++++++++---------
>   2 files changed, 40 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
> index 17236ee23490..79d8a1a059aa 100644
> --- a/drivers/gpu/drm/v3d/v3d_drv.h
> +++ b/drivers/gpu/drm/v3d/v3d_drv.h
> @@ -18,6 +18,7 @@ struct platform_device;
>   struct reset_control;
>   
>   #define V3D_MMU_PAGE_SHIFT 12
> +#define V3D_PAGE_FACTOR (PAGE_SIZE >> V3D_MMU_PAGE_SHIFT)
>   
>   #define V3D_MAX_QUEUES (V3D_CPU + 1)
>   
> diff --git a/drivers/gpu/drm/v3d/v3d_mmu.c b/drivers/gpu/drm/v3d/v3d_mmu.c
> index 14f3af40d6f6..2e0b31e373b2 100644
> --- a/drivers/gpu/drm/v3d/v3d_mmu.c
> +++ b/drivers/gpu/drm/v3d/v3d_mmu.c
> @@ -25,9 +25,16 @@
>    * superpage bit set.
>    */
>   #define V3D_PTE_SUPERPAGE BIT(31)
> +#define V3D_PTE_BIGPAGE BIT(30)
>   #define V3D_PTE_WRITEABLE BIT(29)
>   #define V3D_PTE_VALID BIT(28)
>   
> +static bool v3d_mmu_is_aligned(u32 page, u32 page_address, size_t alignment)
> +{
> +	return IS_ALIGNED(page, alignment >> V3D_MMU_PAGE_SHIFT) &&
> +		IS_ALIGNED(page_address, alignment >> V3D_MMU_PAGE_SHIFT);
> +}
> +
>   static int v3d_mmu_flush_all(struct v3d_dev *v3d)
>   {
>   	int ret;
> @@ -87,19 +94,38 @@ void v3d_mmu_insert_ptes(struct v3d_bo *bo)
>   	struct drm_gem_shmem_object *shmem_obj = &bo->base;
>   	struct v3d_dev *v3d = to_v3d_dev(shmem_obj->base.dev);
>   	u32 page = bo->node.start;
> -	u32 page_prot = V3D_PTE_WRITEABLE | V3D_PTE_VALID;
> -	struct sg_dma_page_iter dma_iter;
> -
> -	for_each_sgtable_dma_page(shmem_obj->sgt, &dma_iter, 0) {
> -		dma_addr_t dma_addr = sg_page_iter_dma_address(&dma_iter);
> -		u32 page_address = dma_addr >> V3D_MMU_PAGE_SHIFT;
> -		u32 pte = page_prot | page_address;
> -		u32 i;
> -
> -		BUG_ON(page_address + (PAGE_SIZE >> V3D_MMU_PAGE_SHIFT) >=
> -		       BIT(24));
> -		for (i = 0; i < PAGE_SIZE >> V3D_MMU_PAGE_SHIFT; i++)
> -			v3d->pt[page++] = pte + i;
> +	struct scatterlist *sgl;
> +	unsigned int count;
> +
> +	for_each_sgtable_dma_sg(shmem_obj->sgt, sgl, count) {
> +		dma_addr_t dma_addr = sg_dma_address(sgl);
> +		u32 pfn = dma_addr >> V3D_MMU_PAGE_SHIFT;
> +		unsigned int len = sg_dma_len(sgl);
> +
> +		while (len > 0) {
> +			u32 page_prot = V3D_PTE_WRITEABLE | V3D_PTE_VALID;
> +			u32 page_address = page_prot | pfn;
> +			unsigned int i, page_size;
> +
> +			BUG_ON(pfn + V3D_PAGE_FACTOR >= BIT(24));
> +
> +			if (len >= SZ_1M && v3d_mmu_is_aligned(page, page_address, SZ_1M)) {
> +				page_size = SZ_1M;
> +				page_address |= V3D_PTE_SUPERPAGE;
> +			} else if (len >= SZ_64K && v3d_mmu_is_aligned(page, page_address, SZ_64K)) {
> +				page_size = SZ_64K;
> +				page_address |= V3D_PTE_BIGPAGE;
> +			} else {
> +				page_size = SZ_4K;
> +			}
> +
> +			for (i = 0; i < page_size >> V3D_MMU_PAGE_SHIFT; i++) {
> +				v3d->pt[page++] = page_address + i;
> +				pfn++;
> +			}
> +
> +			len -= page_size;
> +		}
>   	}
>   
>   	WARN_ON_ONCE(page - bo->node.start !=

It looks correct to me.

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>

Regards,

Tvrtko


More information about the dri-devel mailing list