Am Freitag, dem 08.05.2026 um 18:05 +0000 schrieb Ziyi Guo:
> The IOMMU mapping for a userptr BO was installed with a hard-coded
> ETNAVIV_PROT_READ | ETNAVIV_PROT_WRITE, ignoring the read-only
> attribute set when the BO was created without ETNA_USERPTR_WRITE.
> Build the prot mask from etnaviv_obj->userptr.ro so MMUv2 clears
> MMUv2_PTE_WRITEABLE for read-only userptr BOs.
>
> MMUv1 PTEs carry no R/W bits and its fast path skips the MMU, so
> read-only cannot be enforced there; refuse such a mapping with
> -ENODEV.
I don't think it's a good idea to completely reject those mappings on
MMUv1. We can always force a BO to be mapped through the
translation/protection region of the MMUv1 by adding the
ETNA_BO_FORCE_MMU flag, which is what you might want to do when
constructing a ro userptr BO.
Regards,
Lucas
>
> Fixes: a8c21a5451d8 ("drm/etnaviv: add initial etnaviv DRM driver")
> Signed-off-by: Ziyi Guo <[email protected]>
> ---
> drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
> b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
> index e3572461b599..28f26d60ac05 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
> @@ -269,10 +269,18 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu_context
> *context,
> {
> struct sg_table *sgt = etnaviv_obj->sgt;
> struct drm_mm_node *node;
> + int prot = ETNAVIV_PROT_READ;
> int ret;
>
> lockdep_assert_held(&etnaviv_obj->lock);
>
> + if (!etnaviv_obj->userptr.ptr || !etnaviv_obj->userptr.ro)
> + prot |= ETNAVIV_PROT_WRITE;
> +
> + if (etnaviv_obj->userptr.ptr && etnaviv_obj->userptr.ro &&
> + context->global->version == ETNAVIV_IOMMU_V1)
> + return -ENODEV;
> +
> mutex_lock(&context->lock);
>
> /* v1 MMU can optimize single entry (contiguous) scatterlists */
> @@ -301,7 +309,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu_context
> *context,
>
> mapping->iova = node->start;
> ret = etnaviv_iommu_map(context, node->start, etnaviv_obj->size, sgt,
> - ETNAVIV_PROT_READ | ETNAVIV_PROT_WRITE);
> + prot);
>
> if (ret < 0) {
> drm_mm_remove_node(node);