[Intel-gfx] [RFC 1/1] drm/i915/dgfx: Avoid parent bridge rpm on mmap mappings

Rodrigo Vivi rodrigo.vivi at intel.com
Tue Aug 9 15:05:46 UTC 2022


On Mon, Aug 08, 2022 at 04:05:55PM +0530, Anshuman Gupta wrote:
> As per PCIe Spec Section 5.3,
> When a Type 1 Function associated with a Switch/Root
> Port (a “virtual bridge”) is in a non-D0 power state,
> it will emulate the behavior of a conventional PCI bridge
> in its handling of Memory, I/O, and Configuration
> Requests and Completions. All Memory and I/O requests
> flowing Downstream are terminated as Unsupported Requests.
> 
> Due to above limitations when Intel DGFX Cards graphics
> PCI func's upstream bridge(referred as VSP) enters to D3,
> all mmap memory mapping associated with lmem objects
> reads 0xff, therefore avoiding VSP runtime suspend
> accordingly.
> 
> This will make sure that user can read valid data from lmem,
> while DGFX Card graphics PCI func is in D3 state.
> 
> Signed-off-by: Anshuman Gupta <anshuman.gupta at intel.com>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_mman.c | 11 ++++++++
>  drivers/gpu/drm/i915/gem/i915_gem_ttm.c  |  8 ++++++
>  drivers/gpu/drm/i915/intel_runtime_pm.c  | 35 ++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_runtime_pm.h  |  2 ++
>  4 files changed, 56 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c
> index 0c5c43852e24..968bed5b56d3 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c
> @@ -845,6 +845,10 @@ static void vm_open(struct vm_area_struct *vma)
>  	struct drm_i915_gem_object *obj = mmo->obj;
>  
>  	GEM_BUG_ON(!obj);
> +
> +	if (i915_gem_object_is_lmem(obj))
> +		intel_runtime_pm_get_vsp(to_i915(obj->base.dev));
> +
>  	i915_gem_object_get(obj);
>  }
>  
> @@ -854,6 +858,10 @@ static void vm_close(struct vm_area_struct *vma)
>  	struct drm_i915_gem_object *obj = mmo->obj;
>  
>  	GEM_BUG_ON(!obj);
> +
> +	if (i915_gem_object_is_lmem(obj))
> +		intel_runtime_pm_put_vsp(to_i915(obj->base.dev));
> +
>  	i915_gem_object_put(obj);
>  }
>  
> @@ -972,6 +980,9 @@ int i915_gem_mmap(struct file *filp, struct vm_area_struct *vma)
>  		return PTR_ERR(anon);
>  	}
>  
> +	if (i915_gem_object_is_lmem(obj))
> +		intel_runtime_pm_get_vsp(to_i915(obj->base.dev));
> +
>  	vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
>  
>  	/*
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> index 5a5cf332d8a5..bcacd95fdbc1 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> @@ -1101,6 +1101,10 @@ static void ttm_vm_open(struct vm_area_struct *vma)
>  		i915_ttm_to_gem(vma->vm_private_data);
>  
>  	GEM_BUG_ON(!obj);
> +
> +	if (i915_gem_object_is_lmem(obj))
> +		intel_runtime_pm_get_vsp(to_i915(obj->base.dev));
> +
>  	i915_gem_object_get(obj);
>  }
>  
> @@ -1110,6 +1114,10 @@ static void ttm_vm_close(struct vm_area_struct *vma)
>  		i915_ttm_to_gem(vma->vm_private_data);
>  
>  	GEM_BUG_ON(!obj);
> +
> +	if (i915_gem_object_is_lmem(obj))
> +		intel_runtime_pm_put_vsp(to_i915(obj->base.dev));
> +
>  	i915_gem_object_put(obj);
>  }

we need to ensure the runtime pm get / put at dma buf attach & detach as well, no?

>  
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> index 6ed5786bcd29..a5557918674f 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -646,3 +646,38 @@ void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm)
>  
>  	init_intel_runtime_pm_wakeref(rpm);
>  }
> +
> +void intel_runtime_pm_get_vsp(struct drm_i915_private *i915)
> +{
> +	struct pci_dev *pdev = to_pci_dev(i915->drm.dev), *vsp;
> +
> +	if (!IS_DGFX(i915))
> +		return;
> +
> +	vsp = pci_upstream_bridge(pdev);
> +	if (!vsp) {
> +		drm_err(&i915->drm, "Failed to get the PCI upstream bridge\n");
> +		return;
> +	}
> +
> +	pci_dbg(vsp, "get runtime usage count\n");

we should always prefer the drm_dbg in our subsystem

> +	pm_runtime_get_sync(&vsp->dev);

why? I believe that grabbing our own ref would be enough to block the
upstream chain. I don't understand why this is such an special case
that we don't see any other driver in the linux tree having to do such
a thing. what am I missing?

> +}
> +
> +void intel_runtime_pm_put_vsp(struct drm_i915_private *i915)
> +{
> +	struct pci_dev *pdev = to_pci_dev(i915->drm.dev), *vsp;
> +
> +	if (!IS_DGFX(i915))
> +		return;
> +
> +	vsp = pci_upstream_bridge(pdev);
> +	if (!vsp) {
> +		drm_err(&i915->drm, "Failed to get the PCI upstream bridge\n");
> +		return;
> +	}
> +
> +	pci_dbg(vsp, "put runtime usage count\n");
> +	pm_runtime_mark_last_busy(&vsp->dev);
> +	pm_runtime_put(&vsp->dev);
> +}
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h
> index d9160e3ff4af..b86843bf4f5d 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.h
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h
> @@ -173,6 +173,8 @@ void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm);
>  void intel_runtime_pm_enable(struct intel_runtime_pm *rpm);
>  void intel_runtime_pm_disable(struct intel_runtime_pm *rpm);
>  void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm);
> +void intel_runtime_pm_get_vsp(struct drm_i915_private *i915);
> +void intel_runtime_pm_put_vsp(struct drm_i915_private *i915);
>  
>  intel_wakeref_t intel_runtime_pm_get(struct intel_runtime_pm *rpm);
>  intel_wakeref_t intel_runtime_pm_get_if_in_use(struct intel_runtime_pm *rpm);
> -- 
> 2.26.2
> 


More information about the dri-devel mailing list