Re: [PATCH] drm/meson: Make use of the helper function devm_platform_ioremap_resourcexxx()

2021-09-13 Thread Neil Armstrong
On 31/08/2021 15:56, Cai Huoqing wrote:
> Use the devm_platform_ioremap_resource_byname() helper instead of
> calling platform_get_resource_byname() and devm_ioremap_resource()
> separately
> 
> Use the devm_platform_ioremap_resource() helper instead of
> calling platform_get_resource() and devm_ioremap_resource()
> separately
> 
> Signed-off-by: Cai Huoqing 
> ---
>  drivers/gpu/drm/meson/meson_drv.c | 3 +--
>  drivers/gpu/drm/meson/meson_dw_hdmi.c | 4 +---
>  2 files changed, 2 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/meson/meson_drv.c 
> b/drivers/gpu/drm/meson/meson_drv.c
> index bc0d60df04ae..7f41a33592c8 100644
> --- a/drivers/gpu/drm/meson/meson_drv.c
> +++ b/drivers/gpu/drm/meson/meson_drv.c
> @@ -206,8 +206,7 @@ static int meson_drv_bind_master(struct device *dev, bool 
> has_components)
>   priv->compat = match->compat;
>   priv->afbcd.ops = match->afbcd_ops;
>  
> - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu");
> - regs = devm_ioremap_resource(dev, res);
> + regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
>   if (IS_ERR(regs)) {
>   ret = PTR_ERR(regs);
>   goto free_drm;
> diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c 
> b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> index 2ed87cfdd735..0afbd1e70bfc 100644
> --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
> +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> @@ -978,7 +978,6 @@ static int meson_dw_hdmi_bind(struct device *dev, struct 
> device *master,
>   struct dw_hdmi_plat_data *dw_plat_data;
>   struct drm_bridge *next_bridge;
>   struct drm_encoder *encoder;
> - struct resource *res;
>   int irq;
>   int ret;
>  
> @@ -1042,8 +1041,7 @@ static int meson_dw_hdmi_bind(struct device *dev, 
> struct device *master,
>   return PTR_ERR(meson_dw_hdmi->hdmitx_phy);
>   }
>  
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res);
> + meson_dw_hdmi->hdmitx = devm_platform_ioremap_resource(pdev, 0);
>   if (IS_ERR(meson_dw_hdmi->hdmitx))
>   return PTR_ERR(meson_dw_hdmi->hdmitx);
>  
> 

Applied to drm-misc-next

Thanks,
Neil


[RFC PATCH v2] drm/ttm: Try to check if new ttm man out of bounds during compile

2021-09-13 Thread xinhui pan
Allow TTM know if vendor set new ttm mananger out of bounds by adding
build_bug_on.

Signed-off-by: xinhui pan 
---
 drivers/gpu/drm/ttm/ttm_range_manager.c |  8 
 include/drm/ttm/ttm_device.h|  3 +++
 include/drm/ttm/ttm_range_manager.h | 18 --
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c 
b/drivers/gpu/drm/ttm/ttm_range_manager.c
index 03395386e8a7..f2d702b66749 100644
--- a/drivers/gpu/drm/ttm/ttm_range_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_range_manager.c
@@ -138,7 +138,7 @@ static const struct ttm_resource_manager_func 
ttm_range_manager_func = {
  * Initialise a generic range manager for the selected memory type.
  * The range manager is installed for this device in the type slot.
  */
-int ttm_range_man_init(struct ttm_device *bdev,
+int ttm_range_man_init_nocheck(struct ttm_device *bdev,
   unsigned type, bool use_tt,
   unsigned long p_size)
 {
@@ -163,7 +163,7 @@ int ttm_range_man_init(struct ttm_device *bdev,
ttm_resource_manager_set_used(man, true);
return 0;
 }
-EXPORT_SYMBOL(ttm_range_man_init);
+EXPORT_SYMBOL(ttm_range_man_init_nocheck);
 
 /**
  * ttm_range_man_fini
@@ -173,7 +173,7 @@ EXPORT_SYMBOL(ttm_range_man_init);
  *
  * Remove the generic range manager from a slot and tear it down.
  */
-int ttm_range_man_fini(struct ttm_device *bdev,
+int ttm_range_man_fini_nocheck(struct ttm_device *bdev,
   unsigned type)
 {
struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
@@ -197,4 +197,4 @@ int ttm_range_man_fini(struct ttm_device *bdev,
kfree(rman);
return 0;
 }
-EXPORT_SYMBOL(ttm_range_man_fini);
+EXPORT_SYMBOL(ttm_range_man_fini_nocheck);
diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h
index 07d722950d5b..6f23724f5a06 100644
--- a/include/drm/ttm/ttm_device.h
+++ b/include/drm/ttm/ttm_device.h
@@ -285,12 +285,15 @@ int ttm_device_swapout(struct ttm_device *bdev, struct 
ttm_operation_ctx *ctx,
 static inline struct ttm_resource_manager *
 ttm_manager_type(struct ttm_device *bdev, int mem_type)
 {
+   BUILD_BUG_ON(__builtin_constant_p(mem_type)
+&& mem_type >= TTM_NUM_MEM_TYPES);
return bdev->man_drv[mem_type];
 }
 
 static inline void ttm_set_driver_manager(struct ttm_device *bdev, int type,
  struct ttm_resource_manager *manager)
 {
+   BUILD_BUG_ON(__builtin_constant_p(type) && type >= TTM_NUM_MEM_TYPES);
bdev->man_drv[type] = manager;
 }
 
diff --git a/include/drm/ttm/ttm_range_manager.h 
b/include/drm/ttm/ttm_range_manager.h
index 22b6fa42ac20..7963b957e9ef 100644
--- a/include/drm/ttm/ttm_range_manager.h
+++ b/include/drm/ttm/ttm_range_manager.h
@@ -4,6 +4,7 @@
 #define _TTM_RANGE_MANAGER_H_
 
 #include 
+#include 
 #include 
 
 /**
@@ -33,10 +34,23 @@ to_ttm_range_mgr_node(struct ttm_resource *res)
return container_of(res, struct ttm_range_mgr_node, base);
 }
 
-int ttm_range_man_init(struct ttm_device *bdev,
+int ttm_range_man_init_nocheck(struct ttm_device *bdev,
   unsigned type, bool use_tt,
   unsigned long p_size);
-int ttm_range_man_fini(struct ttm_device *bdev,
+int ttm_range_man_fini_nocheck(struct ttm_device *bdev,
   unsigned type);
+static __always_inline int ttm_range_man_init(struct ttm_device *bdev,
+  unsigned int type, bool use_tt,
+  unsigned long p_size)
+{
+   BUILD_BUG_ON(__builtin_constant_p(type) && type >= TTM_NUM_MEM_TYPES);
+   return ttm_range_man_init_nocheck(bdev, type, use_tt, p_size);
+}
 
+static __always_inline int ttm_range_man_fini(struct ttm_device *bdev,
+  unsigned int type)
+{
+   BUILD_BUG_ON(__builtin_constant_p(type) && type >= TTM_NUM_MEM_TYPES);
+   return ttm_range_man_fini_nocheck(bdev, type);
+}
 #endif
-- 
2.25.1



Re: [RFC PATCH v2] drm/ttm: Try to check if new ttm man out of bounds during compile

2021-09-13 Thread Christian König

Am 13.09.21 um 10:09 schrieb xinhui pan:

Allow TTM know if vendor set new ttm mananger out of bounds by adding
build_bug_on.

Signed-off-by: xinhui pan 


Yeah, that looks better. Reviewed-by: Christian König 



Going to push that to drm-misc-next.

Thanks,
Christian.


---
  drivers/gpu/drm/ttm/ttm_range_manager.c |  8 
  include/drm/ttm/ttm_device.h|  3 +++
  include/drm/ttm/ttm_range_manager.h | 18 --
  3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c 
b/drivers/gpu/drm/ttm/ttm_range_manager.c
index 03395386e8a7..f2d702b66749 100644
--- a/drivers/gpu/drm/ttm/ttm_range_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_range_manager.c
@@ -138,7 +138,7 @@ static const struct ttm_resource_manager_func 
ttm_range_manager_func = {
   * Initialise a generic range manager for the selected memory type.
   * The range manager is installed for this device in the type slot.
   */
-int ttm_range_man_init(struct ttm_device *bdev,
+int ttm_range_man_init_nocheck(struct ttm_device *bdev,
   unsigned type, bool use_tt,
   unsigned long p_size)
  {
@@ -163,7 +163,7 @@ int ttm_range_man_init(struct ttm_device *bdev,
ttm_resource_manager_set_used(man, true);
return 0;
  }
-EXPORT_SYMBOL(ttm_range_man_init);
+EXPORT_SYMBOL(ttm_range_man_init_nocheck);
  
  /**

   * ttm_range_man_fini
@@ -173,7 +173,7 @@ EXPORT_SYMBOL(ttm_range_man_init);
   *
   * Remove the generic range manager from a slot and tear it down.
   */
-int ttm_range_man_fini(struct ttm_device *bdev,
+int ttm_range_man_fini_nocheck(struct ttm_device *bdev,
   unsigned type)
  {
struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
@@ -197,4 +197,4 @@ int ttm_range_man_fini(struct ttm_device *bdev,
kfree(rman);
return 0;
  }
-EXPORT_SYMBOL(ttm_range_man_fini);
+EXPORT_SYMBOL(ttm_range_man_fini_nocheck);
diff --git a/include/drm/ttm/ttm_device.h b/include/drm/ttm/ttm_device.h
index 07d722950d5b..6f23724f5a06 100644
--- a/include/drm/ttm/ttm_device.h
+++ b/include/drm/ttm/ttm_device.h
@@ -285,12 +285,15 @@ int ttm_device_swapout(struct ttm_device *bdev, struct 
ttm_operation_ctx *ctx,
  static inline struct ttm_resource_manager *
  ttm_manager_type(struct ttm_device *bdev, int mem_type)
  {
+   BUILD_BUG_ON(__builtin_constant_p(mem_type)
+&& mem_type >= TTM_NUM_MEM_TYPES);
return bdev->man_drv[mem_type];
  }
  
  static inline void ttm_set_driver_manager(struct ttm_device *bdev, int type,

  struct ttm_resource_manager *manager)
  {
+   BUILD_BUG_ON(__builtin_constant_p(type) && type >= TTM_NUM_MEM_TYPES);
bdev->man_drv[type] = manager;
  }
  
diff --git a/include/drm/ttm/ttm_range_manager.h b/include/drm/ttm/ttm_range_manager.h

index 22b6fa42ac20..7963b957e9ef 100644
--- a/include/drm/ttm/ttm_range_manager.h
+++ b/include/drm/ttm/ttm_range_manager.h
@@ -4,6 +4,7 @@
  #define _TTM_RANGE_MANAGER_H_
  
  #include 

+#include 
  #include 
  
  /**

@@ -33,10 +34,23 @@ to_ttm_range_mgr_node(struct ttm_resource *res)
return container_of(res, struct ttm_range_mgr_node, base);
  }
  
-int ttm_range_man_init(struct ttm_device *bdev,

+int ttm_range_man_init_nocheck(struct ttm_device *bdev,
   unsigned type, bool use_tt,
   unsigned long p_size);
-int ttm_range_man_fini(struct ttm_device *bdev,
+int ttm_range_man_fini_nocheck(struct ttm_device *bdev,
   unsigned type);
+static __always_inline int ttm_range_man_init(struct ttm_device *bdev,
+  unsigned int type, bool use_tt,
+  unsigned long p_size)
+{
+   BUILD_BUG_ON(__builtin_constant_p(type) && type >= TTM_NUM_MEM_TYPES);
+   return ttm_range_man_init_nocheck(bdev, type, use_tt, p_size);
+}
  
+static __always_inline int ttm_range_man_fini(struct ttm_device *bdev,

+  unsigned int type)
+{
+   BUILD_BUG_ON(__builtin_constant_p(type) && type >= TTM_NUM_MEM_TYPES);
+   return ttm_range_man_fini_nocheck(bdev, type);
+}
  #endif




[Bug 214375] 5.14 Regression: Null pointer dereference in radeon_agp_head_init

2021-09-13 Thread bugzilla-daemon
https://bugzilla.kernel.org/show_bug.cgi?id=214375

Nirmoy (nirmoy.ai...@gmail.com) changed:

   What|Removed |Added

 CC||nirmoy.ai...@gmail.com

--- Comment #1 from Nirmoy (nirmoy.ai...@gmail.com) ---
Created attachment 298765
  --> https://bugzilla.kernel.org/attachment.cgi?id=298765&action=edit
Bug Fix

Please let me know if the above patch fixes your issue. I don't have a card to
test but I think the issue is we are passing an uninitialized drm device
pointer.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are watching the assignee of the bug.

Re: [PATCH 1/2] drm/amdgpu: Clarify that TMZ unsupported message is due to hardware

2021-09-13 Thread Christian König

Am 13.09.21 um 10:34 schrieb Paul Menzel:

The warning

 amdgpu :05:00.0: amdgpu: Trusted Memory Zone (TMZ) feature not 
supported

leaves the reader wondering, if anything can be done about it. As it’s
unsupported in the hardware, and nothing can be done about, mention that
in the log message.

 amdgpu :05:00.0: amdgpu: Trusted Memory Zone (TMZ) feature not 
supported by hardware


I think we should just completely remove the message instead.

Christian.



Signed-off-by: Paul Menzel 
---
  drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index c7797eac83c3..c4c56c57b0c0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -599,7 +599,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
default:
adev->gmc.tmz_enabled = false;
dev_warn(adev->dev,
-"Trusted Memory Zone (TMZ) feature not supported\n");
+"Trusted Memory Zone (TMZ) feature not supported by 
hardware\n");
break;
}
  }




Re: [PATCH v2] kernel/locking: Add context to ww_mutex_trylock.

2021-09-13 Thread Maarten Lankhorst
Op 10-09-2021 om 17:02 schreef Peter Zijlstra:
> On Thu, Sep 09, 2021 at 11:32:18AM +0200, Maarten Lankhorst wrote:
>> diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
>> index d456579d0952..791c28005eef 100644
>> --- a/kernel/locking/mutex.c
>> +++ b/kernel/locking/mutex.c
>> @@ -736,6 +736,44 @@ __ww_mutex_lock(struct mutex *lock, unsigned int state, 
>> unsigned int subclass,
>>  return __mutex_lock_common(lock, state, subclass, NULL, ip, ww_ctx, 
>> true);
>>  }
>>  
>> +/**
>> + * ww_mutex_trylock - tries to acquire the w/w mutex with optional acquire 
>> context
>> + * @lock: mutex to lock
>> + * @ctx: optional w/w acquire context
>> + *
>> + * Trylocks a mutex with the optional acquire context; no deadlock 
>> detection is
>> + * possible. Returns 1 if the mutex has been acquired successfully, 0 
>> otherwise.
>> + *
>> + * Unlike ww_mutex_lock, no deadlock handling is performed. However, if a 
>> @ctx is
>> + * specified, -EALREADY and -EDEADLK handling may happen in calls to 
>> ww_mutex_lock.
>> + *
>> + * A mutex acquired with this function must be released with 
>> ww_mutex_unlock.
>> + */
>> +int __sched
>> +ww_mutex_trylock(struct ww_mutex *ww, struct ww_acquire_ctx *ctx)
>> +{
>> +bool locked;
>> +
>> +if (!ctx)
>> +return mutex_trylock(&ww->base);
>> +
>> +#ifdef CONFIG_DEBUG_MUTEXES
>> +DEBUG_LOCKS_WARN_ON(ww->base.magic != &ww->base);
>> +#endif
>> +
>> +preempt_disable();
>> +locked = __mutex_trylock(&ww->base);
>> +
>> +if (locked) {
>> +ww_mutex_set_context_fastpath(ww, ctx);
>> +mutex_acquire_nest(&ww->base.dep_map, 0, 1, &ctx->dep_map, 
>> _RET_IP_);
>> +}
>> +preempt_enable();
>> +
>> +return locked;
>> +}
>> +EXPORT_SYMBOL(ww_mutex_trylock);
>> +
>>  #ifdef CONFIG_DEBUG_LOCK_ALLOC
>>  void __sched
>>  mutex_lock_nested(struct mutex *lock, unsigned int subclass)
>> diff --git a/kernel/locking/ww_rt_mutex.c b/kernel/locking/ww_rt_mutex.c
>> index 3f1fff7d2780..c4cb863edb4c 100644
>> --- a/kernel/locking/ww_rt_mutex.c
>> +++ b/kernel/locking/ww_rt_mutex.c
>> @@ -50,6 +50,18 @@ __ww_rt_mutex_lock(struct ww_mutex *lock, struct 
>> ww_acquire_ctx *ww_ctx,
>>  return ret;
>>  }
>>  
>> +int __sched
>> +ww_mutex_trylock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
>> +{
>> +int locked = rt_mutex_trylock(&lock->base);
>> +
>> +if (locked && ctx)
>> +ww_mutex_set_context_fastpath(lock, ctx);
>> +
>> +return locked;
>> +}
>> +EXPORT_SYMBOL(ww_mutex_trylock);
>> +
>>  int __sched
>>  ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
>>  {
> That doesn't look right, how's this for you?
>
> ---
> --- a/kernel/locking/mutex.c
> +++ b/kernel/locking/mutex.c
> @@ -94,6 +94,9 @@ static inline unsigned long __owner_flag
>   return owner & MUTEX_FLAGS;
>  }
>  
> +/*
> + * Returns: __mutex_owner(lock) on failure or NULL on success.
> + */
>  static inline struct task_struct *__mutex_trylock_common(struct mutex *lock, 
> bool handoff)
>  {
>   unsigned long owner, curr = (unsigned long)current;
> @@ -736,6 +739,47 @@ __ww_mutex_lock(struct mutex *lock, unsi
>   return __mutex_lock_common(lock, state, subclass, NULL, ip, ww_ctx, 
> true);
>  }
>  
> +/**
> + * ww_mutex_trylock - tries to acquire the w/w mutex with optional acquire 
> context
> + * @ww: mutex to lock
> + * @ww_ctx: optional w/w acquire context
> + *
> + * Trylocks a mutex with the optional acquire context; no deadlock detection 
> is
> + * possible. Returns 1 if the mutex has been acquired successfully, 0 
> otherwise.
> + *
> + * Unlike ww_mutex_lock, no deadlock handling is performed. However, if a 
> @ctx is
> + * specified, -EALREADY handling may happen in calls to ww_mutex_trylock.
> + *
> + * A mutex acquired with this function must be released with ww_mutex_unlock.
> + */
> +int ww_mutex_trylock(struct ww_mutex *ww, struct ww_acquire_ctx *ww_ctx)
> +{
> + if (!ww_ctx)
> + return mutex_trylock(&ww->base);
> +
> + MUTEX_WARN_ON(ww->base.magic != &ww->base);
> +
> + if (unlikely(ww_ctx == READ_ONCE(ww->ctx)))
> + return -EALREADY;

I'm not 100% sure this is a good idea, because it would make the trylock weird.
For i915 I checked manually, because I didn't want to change the function 
signature. This is probably the other extreme.

"if (ww_mutex_trylock())" would look correct, but actually be wrong and lead to 
double unlock without adjustments.
Maybe we could make a ww_mutex_trylock_ctx_err, which would return -EALREADY or 
-EBUSY on failure, and 0 on success?
We could keep ww_mutex_trylock without ctx, probably just #define as 
(!ww_mutex_trylock_ctx_err(lock, NULL))

> + /*
> +  * Reset the wounded flag after a kill. No other process can
> +  * race and wound us here, since they can't have a valid owner
> +  * pointer if we don't have any locks held.
> +  */
> + if (ww_ctx->acquired == 0)
> + ww_ctx->wounded = 0;


[PATCH 2/2] drm/amdgpu: Demote TMZ unsupported log message from warning to info

2021-09-13 Thread Paul Menzel
As the user cannot do anything about the unsupported Trusted Memory Zone
(TMZ) feature, do not warn about it, but make it informational, so
demote the log level from warning to info.

Signed-off-by: Paul Menzel 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index c4c56c57b0c0..bfa0275ff5d4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -598,7 +598,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
break;
default:
adev->gmc.tmz_enabled = false;
-   dev_warn(adev->dev,
+   dev_info(adev->dev,
 "Trusted Memory Zone (TMZ) feature not supported by 
hardware\n");
break;
}
-- 
2.33.0



[PATCH 1/2] drm/amdgpu: Clarify that TMZ unsupported message is due to hardware

2021-09-13 Thread Paul Menzel
The warning

amdgpu :05:00.0: amdgpu: Trusted Memory Zone (TMZ) feature not supported

leaves the reader wondering, if anything can be done about it. As it’s
unsupported in the hardware, and nothing can be done about, mention that
in the log message.

amdgpu :05:00.0: amdgpu: Trusted Memory Zone (TMZ) feature not 
supported by hardware

Signed-off-by: Paul Menzel 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index c7797eac83c3..c4c56c57b0c0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -599,7 +599,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
default:
adev->gmc.tmz_enabled = false;
dev_warn(adev->dev,
-"Trusted Memory Zone (TMZ) feature not supported\n");
+"Trusted Memory Zone (TMZ) feature not supported by 
hardware\n");
break;
}
 }
-- 
2.33.0



Re: [PATCH 1/1] lib, stackdepot: Add helper to print stack entries into buffer.

2021-09-13 Thread Vlastimil Babka
On 9/10/21 16:10, Imran Khan wrote:
> To print stack entries into a buffer, users of stackdepot,
> first get a list of stack entries using stack_depot_fetch
> and then print this list into a buffer using stack_trace_snprint.
> Provide a helper in stackdepot for this purpose.
> Also change above mentioned users to use this helper.
> 
> Signed-off-by: Imran Khan 
> Suggested-by: Vlastimil Babka 

Acked-by: Vlastimil Babka 

A comment below:

> --- a/lib/stackdepot.c
> +++ b/lib/stackdepot.c
> @@ -214,6 +214,29 @@ static inline struct stack_record *find_stack(struct 
> stack_record *bucket,
>   return NULL;
>  }
>  
> +/**
> + * stack_depot_snprint - print stack entries from a depot into a buffer
> + *
> + * @handle:  Stack depot handle which was returned from
> + *   stack_depot_save().
> + * @buf: Pointer to the print buffer
> + *
> + * @size:Size of the print buffer
> + *
> + * @spaces:  Number of leading spaces to print
> + *
> + * Return:   Number of bytes printed.
> + */
> +int stack_depot_snprint(depot_stack_handle_t handle, char *buf, size_t size,
> +int spaces)
> +{
> + unsigned long *entries;
> + unsigned int nr_entries;
> +
> + nr_entries = stack_depot_fetch(handle, &entries);
> + return stack_trace_snprint(buf, size, entries, nr_entries, 0);

stack_trace_snprint() has a WARN_ON(!entries).
So maybe we should not call it if nr_entries is 0 (because e.g. handle was
0) as the warnings are not useful in that case.


Re: [PATCH] drm/fb-helper: disallow if DRM=y and FB=m

2021-09-13 Thread Sam Ravnborg
Hi Adam,

On Sun, Sep 12, 2021 at 11:00:54PM +0200, Adam Borowski wrote:
> A subfeature of a built-in can't depend on a module.

Maybe I am a bit dense this morning, but I do not really see what error
this fixes. Can you elaborate a bit what situations are fixed by this
patch.

Thanks in advance,

Sam

> 
> Signed-off-by: Adam Borowski 
> ---
>  drivers/gpu/drm/Kconfig | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index cea777ae7fb9..75a5a9359d4b 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -103,7 +103,7 @@ config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
>  config DRM_FBDEV_EMULATION
>   bool "Enable legacy fbdev support for your modesetting driver"
>   depends on DRM
> - depends on FB
> + depends on FB >= DRM
>   select DRM_KMS_HELPER
>   select FB_CFB_FILLRECT
>   select FB_CFB_COPYAREA
> -- 
> 2.33.0


Re: [Intel-gfx] [PATCH 08/27] drm/i915: Add logical engine mapping

2021-09-13 Thread Tvrtko Ursulin



On 10/09/2021 20:49, Matthew Brost wrote:

On Fri, Sep 10, 2021 at 12:12:42PM +0100, Tvrtko Ursulin wrote:


On 20/08/2021 23:44, Matthew Brost wrote:

Add logical engine mapping. This is required for split-frame, as
workloads need to be placed on engines in a logically contiguous manner.

v2:
   (Daniel Vetter)
- Add kernel doc for new fields

Signed-off-by: Matthew Brost 
---
   drivers/gpu/drm/i915/gt/intel_engine_cs.c | 60 ---
   drivers/gpu/drm/i915/gt/intel_engine_types.h  |  5 ++
   .../drm/i915/gt/intel_execlists_submission.c  |  1 +
   drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c|  2 +-
   .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 21 +--
   5 files changed, 60 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c 
b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index 0d9105a31d84..4d790f9a65dd 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -290,7 +290,8 @@ static void nop_irq_handler(struct intel_engine_cs *engine, 
u16 iir)
GEM_DEBUG_WARN_ON(iir);
   }
-static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id)
+static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id,
+ u8 logical_instance)
   {
const struct engine_info *info = &intel_engines[id];
struct drm_i915_private *i915 = gt->i915;
@@ -334,6 +335,7 @@ static int intel_engine_setup(struct intel_gt *gt, enum 
intel_engine_id id)
engine->class = info->class;
engine->instance = info->instance;
+   engine->logical_mask = BIT(logical_instance);
__sprint_engine_name(engine);
engine->props.heartbeat_interval_ms =
@@ -572,6 +574,37 @@ static intel_engine_mask_t init_engine_mask(struct 
intel_gt *gt)
return info->engine_mask;
   }
+static void populate_logical_ids(struct intel_gt *gt, u8 *logical_ids,
+u8 class, const u8 *map, u8 num_instances)
+{
+   int i, j;
+   u8 current_logical_id = 0;
+
+   for (j = 0; j < num_instances; ++j) {
+   for (i = 0; i < ARRAY_SIZE(intel_engines); ++i) {
+   if (!HAS_ENGINE(gt, i) ||
+   intel_engines[i].class != class)
+   continue;
+
+   if (intel_engines[i].instance == map[j]) {
+   logical_ids[intel_engines[i].instance] =
+   current_logical_id++;
+   break;
+   }
+   }
+   }
+}
+
+static void setup_logical_ids(struct intel_gt *gt, u8 *logical_ids, u8 class)
+{
+   int i;
+   u8 map[MAX_ENGINE_INSTANCE + 1];
+
+   for (i = 0; i < MAX_ENGINE_INSTANCE + 1; ++i)
+   map[i] = i;


What's the point of the map array since it is 1:1 with instance?



Future products do not have a 1 to 1 mapping and that mapping can change
based on fusing, e.g. XeHP SDV.

Also technically ICL / TGL / ADL physical instance 2 maps to logical
instance 1.


I don't follow the argument. All I can see is that "map[i] = i" always 
in the proposed code, which is then used to check "instance == 
map[instance]". So I'd suggest to remove this array from the code until 
there is a need for it.



+   populate_logical_ids(gt, logical_ids, class, map, ARRAY_SIZE(map));
+}
+
   /**
* intel_engines_init_mmio() - allocate and prepare the Engine Command 
Streamers
* @gt: pointer to struct intel_gt
@@ -583,7 +616,8 @@ int intel_engines_init_mmio(struct intel_gt *gt)
struct drm_i915_private *i915 = gt->i915;
const unsigned int engine_mask = init_engine_mask(gt);
unsigned int mask = 0;
-   unsigned int i;
+   unsigned int i, class;
+   u8 logical_ids[MAX_ENGINE_INSTANCE + 1];
int err;
drm_WARN_ON(&i915->drm, engine_mask == 0);
@@ -593,15 +627,23 @@ int intel_engines_init_mmio(struct intel_gt *gt)
if (i915_inject_probe_failure(i915))
return -ENODEV;
-   for (i = 0; i < ARRAY_SIZE(intel_engines); i++) {
-   if (!HAS_ENGINE(gt, i))
-   continue;
+   for (class = 0; class < MAX_ENGINE_CLASS + 1; ++class) {
+   setup_logical_ids(gt, logical_ids, class);
-   err = intel_engine_setup(gt, i);
-   if (err)
-   goto cleanup;
+   for (i = 0; i < ARRAY_SIZE(intel_engines); ++i) {
+   u8 instance = intel_engines[i].instance;
+
+   if (intel_engines[i].class != class ||
+   !HAS_ENGINE(gt, i))
+   continue;
-   mask |= BIT(i);
+   err = intel_engine_setup(gt, i,
+logical_ids[instance]);
+   if (err)
+   goto cleanu

RE: [PATCH v2 4/6] drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO

2021-09-13 Thread Jani Nikula
On Mon, 13 Sep 2021, "Shankar, Uma"  wrote:
>> -Original Message-
>> From: dri-devel  On Behalf Of Jani 
>> Nikula
>> Sent: Tuesday, August 31, 2021 7:48 PM
>> To: intel-...@lists.freedesktop.org
>> Cc: dri-devel@lists.freedesktop.org; ville.syrj...@linux.intel.com; Nikula, 
>> Jani
>> 
>> Subject: [PATCH v2 4/6] drm/edid: parse the DisplayID v2.0 VESA vendor block 
>> for
>> MSO
>> 
>> The VESA Organization Vendor-Specific Data Block, defined in VESA DisplayID
>> Standard v2.0, specifies the eDP Multi-SST Operation (MSO) stream count and
>> segment pixel overlap.
>> 
>> DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension, describing how
>> DisplayID sections may be embedded in EDID extension blocks. DisplayID v2.0 
>> does
>> not have such a section, perhaps implying that DisplayID v2.0 data should 
>> not be
>> included in EDID extensions, but rather in a "pure" DisplayID structure at 
>> its own DDC
>> address pair A4h/A5h, as described in VESA E-DDC Standard v1.3 chapter 3.
>> 
>> However, in practice, displays out in the field have embedded DisplayID
>> v2.0 data blocks in EDID extensions, including, in particular, some eDP MSO 
>> displays,
>> where a pure DisplayID structure is not available at all.
>> 
>> Parse the MSO data from the DisplayID data block. Do it as part of
>> drm_add_display_info(), extending it to parse also DisplayID data to avoid 
>> requiring
>> extra calls to update the information.
>> 
>> v2: Check for VESA OUI (Ville)
>> 
>> Signed-off-by: Jani Nikula 
>> ---
>>  drivers/gpu/drm/drm_edid.c  | 72 +
>>  include/drm/drm_connector.h | 12 +++  include/drm/drm_displayid.h | 13
>> +++
>>  3 files changed, 97 insertions(+)
>> 
>> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index
>> 92974b1478bc..c45c225267ca 100644
>> --- a/drivers/gpu/drm/drm_edid.c
>> +++ b/drivers/gpu/drm/drm_edid.c
>> @@ -28,6 +28,7 @@
>>   * DEALINGS IN THE SOFTWARE.
>>   */
>> 
>> +#include 
>>  #include 
>>  #include 
>>  #include 
>> @@ -5145,6 +5146,71 @@ void drm_get_monitor_range(struct drm_connector
>> *connector,
>>info->monitor_range.max_vfreq);  }
>> 
>> +static void drm_parse_vesa_mso_data(struct drm_connector *connector,
>> +const struct displayid_block *block) {
>> +struct displayid_vesa_vendor_specific_block *vesa =
>> +(struct displayid_vesa_vendor_specific_block *)block;
>> +struct drm_display_info *info = &connector->display_info;
>> +
>> +if (block->num_bytes < 3) {
>> +drm_dbg_kms(connector->dev, "Unexpected vendor block size
>> %u\n",
>> +block->num_bytes);
>> +return;
>> +}
>> +
>> +if (oui(vesa->oui[0], vesa->oui[1], vesa->oui[2]) != VESA_IEEE_OUI)
>> +return;
>> +
>> +if (sizeof(*vesa) != sizeof(*block) + block->num_bytes) {
>> +drm_dbg_kms(connector->dev, "Unexpected VESA vendor block
>> size\n");
>> +return;
>> +}
>> +
>> +switch (FIELD_GET(DISPLAYID_VESA_MSO_MODE, vesa->mso)) {
>> +default:
>> +drm_dbg_kms(connector->dev, "Reserved MSO mode value\n");
>> +fallthrough;
>> +case 0:
>> +info->mso_stream_count = 0;
>> +break;
>> +case 1:
>> +info->mso_stream_count = 2; /* 2 or 4 links */
>> +break;
>> +case 2:
>> +info->mso_stream_count = 4; /* 4 links */
>> +break;
>> +}
>> +
>> +if (!info->mso_stream_count) {
>> +info->mso_pixel_overlap = 0;
>> +return;
>> +}
>> +
>> +info->mso_pixel_overlap = FIELD_GET(DISPLAYID_VESA_MSO_OVERLAP,
>> vesa->mso);
>> +if (info->mso_pixel_overlap > 8) {
>> +drm_dbg_kms(connector->dev, "Reserved MSO pixel overlap value
>> %u\n",
>> +info->mso_pixel_overlap);
>> +info->mso_pixel_overlap = 8;
>
> Going beyond 8 is not right from a vendor perspective as it goes into 
> reserved region.
> Should we not just set to 0 or how we decide that we fixed overlap at 8. It 
> seems an
> undefined operation and it may vary from sink to sink.

I don't know if there's a right choice here. I don't mind setting it to
0 if you prefer that.

BR,
Jani.


>
> Regards,
> Uma Shankar
>
>> +}
>> +
>> +drm_dbg_kms(connector->dev, "MSO stream count %u, pixel overlap %u\n",
>> +info->mso_stream_count, info->mso_pixel_overlap); }
>> +
>> +static void drm_update_mso(struct drm_connector *connector, const
>> +struct edid *edid) {
>> +const struct displayid_block *block;
>> +struct displayid_iter iter;
>> +
>> +displayid_iter_edid_begin(edid, &iter);
>> +displayid_iter_for_each(block, &iter) {
>> +if (block->tag == DATA_BLOCK_2_VENDOR_SPECIFIC)
>> +drm_parse_vesa_mso_data(connector, block);
>> +}
>> +displayid_iter_end(&iter);
>> +}
>> +
>>  /* A conne

Re: [RFC PATCH] drm/ttm: Add a private member to the struct ttm_resource

2021-09-13 Thread Thomas Hellström



On 9/13/21 8:17 AM, Christian König wrote:

Am 11.09.21 um 08:07 schrieb Thomas Hellström:

On Fri, 2021-09-10 at 19:03 +0200, Christian König wrote:

Am 10.09.21 um 17:30 schrieb Thomas Hellström:

On Fri, 2021-09-10 at 16:40 +0200, Christian König wrote:

Am 10.09.21 um 15:15 schrieb Thomas Hellström:

Both the provider (resource manager) and the consumer (the TTM
driver)
want to subclass struct ttm_resource. Since this is left for
the
resource
manager, we need to provide a private pointer for the TTM
driver.

Provide a struct ttm_resource_private for the driver to
subclass
for
data with the same lifetime as the struct ttm_resource: In the
i915
case
it will, for example, be an sg-table and radix tree into the
LMEM
/VRAM pages that currently are awkwardly attached to the GEM
object.

Provide an ops structure for associated ops (Which is only
destroy() ATM)
It might seem pointless to provide a separate ops structure,
but
Linus
has previously made it clear that that's the norm.

After careful audit one could perhaps also on a per-driver
basis
replace the delete_mem_notify() TTM driver callback with the
above
destroy function.

Well this is a really big NAK to this approach.

If you need to attach some additional information to the resource
then
implement your own resource manager like everybody else does.

Well this was the long discussion we had back then when the
resource
mangagers started to derive from struct resource and I was under
the
impression that we had come to an agreement about the different
use-
cases here, and this was my main concern.

Ok, then we somehow didn't understood each other.


I mean, it's a pretty big layer violation to do that for this use-
case.

Well exactly that's the point. TTM should not have a layer design in
the
first place.

Devices, BOs, resources etc.. are base classes which should implement
a
base functionality which is then extended by the drivers to implement
the driver specific functionality.

That is a component based approach, and not layered at all.


The TTM resource manager doesn't want to know about this data at
all,
it's private to the ttm resource user layer and the resource
manager
works perfectly well without it. (I assume the other drivers that
implement their own resource managers need the data that the
subclassing provides?)

Yes, that's exactly why we have the subclassing.


The fundamental problem here is that there are two layers wanting
to
subclass struct ttm_resource. That means one layer gets to do that,
the
second gets to use a private pointer, (which in turn can provide
yet
another private pointer to a potential third layer). With your
suggestion, the second layer instead is forced to subclass each
subclassed instance it uses from  the first layer provides?

Well completely drop the layer approach/thinking here.

The resource is an object with a base class. The base class
implements
the interface TTM needs to handle the object, e.g.
create/destroy/debug
etc...

Then we need to subclass this object because without any additional
information the object is pretty pointless.

One possibility for this is to use the range manager to implement
something drm_mm based. BTW: We should probably rename that to
something
like ttm_res_drm_mm or similar.

Sure I'm all in on that, but my point is this becomes pretty awkward
because the reusable code already subclasses struct ttm_resource. Let
me give you an example:

Prereqs:
1) We want to be able to re-use resource manager implementations among
drivers.
2) A driver might want to re-use multiple implementations and have
identical data "struct i915_data" attached to both


Well that's the point I don't really understand. Why would a driver 
want to do this?


Let's say you have a struct ttm_object_vram and a struct ttm_object_gtt, 
both subclassing drm_gem_object. Then I'd say a driver would want to 
subclass those to attach identical data, extend functionality and 
provide a single i915_gem_object to the rest of the driver, which 
couldn't care less whether it's vram or gtt? Wouldn't you say having 
separate struct ttm_object_vram and a struct ttm_object_gtt in this case 
would be awkward?. We *want* to allow common handling.


It's the exact same situation here. With struct ttm_resource you let 
*different* implementation flavours subclass it, which makes it awkward 
for the driver to extend the functionality in a common way by 
subclassing, unless the driver only uses a single implementation.


OT:

Having a variable size array as the last member of the range manager 
resource makes embedding that extremely fragile IMO. Perhaps hide that 
variable size functionality in the driver rather than in the common code?


/Thomas





Re: [RFC PATCH] drm/ttm: Add a private member to the struct ttm_resource

2021-09-13 Thread Christian König

Am 13.09.21 um 11:36 schrieb Thomas Hellström:

On 9/13/21 8:17 AM, Christian König wrote:

Am 11.09.21 um 08:07 schrieb Thomas Hellström:

On Fri, 2021-09-10 at 19:03 +0200, Christian König wrote:

Am 10.09.21 um 17:30 schrieb Thomas Hellström:

On Fri, 2021-09-10 at 16:40 +0200, Christian König wrote:

Am 10.09.21 um 15:15 schrieb Thomas Hellström:

Both the provider (resource manager) and the consumer (the TTM
driver)
want to subclass struct ttm_resource. Since this is left for
the
resource
manager, we need to provide a private pointer for the TTM
driver.

Provide a struct ttm_resource_private for the driver to
subclass
for
data with the same lifetime as the struct ttm_resource: In the
i915
case
it will, for example, be an sg-table and radix tree into the
LMEM
/VRAM pages that currently are awkwardly attached to the GEM
object.

Provide an ops structure for associated ops (Which is only
destroy() ATM)
It might seem pointless to provide a separate ops structure,
but
Linus
has previously made it clear that that's the norm.

After careful audit one could perhaps also on a per-driver
basis
replace the delete_mem_notify() TTM driver callback with the
above
destroy function.

Well this is a really big NAK to this approach.

If you need to attach some additional information to the resource
then
implement your own resource manager like everybody else does.

Well this was the long discussion we had back then when the
resource
mangagers started to derive from struct resource and I was under
the
impression that we had come to an agreement about the different
use-
cases here, and this was my main concern.

Ok, then we somehow didn't understood each other.


I mean, it's a pretty big layer violation to do that for this use-
case.

Well exactly that's the point. TTM should not have a layer design in
the
first place.

Devices, BOs, resources etc.. are base classes which should implement
a
base functionality which is then extended by the drivers to implement
the driver specific functionality.

That is a component based approach, and not layered at all.


The TTM resource manager doesn't want to know about this data at
all,
it's private to the ttm resource user layer and the resource
manager
works perfectly well without it. (I assume the other drivers that
implement their own resource managers need the data that the
subclassing provides?)

Yes, that's exactly why we have the subclassing.


The fundamental problem here is that there are two layers wanting
to
subclass struct ttm_resource. That means one layer gets to do that,
the
second gets to use a private pointer, (which in turn can provide
yet
another private pointer to a potential third layer). With your
suggestion, the second layer instead is forced to subclass each
subclassed instance it uses from  the first layer provides?

Well completely drop the layer approach/thinking here.

The resource is an object with a base class. The base class
implements
the interface TTM needs to handle the object, e.g.
create/destroy/debug
etc...

Then we need to subclass this object because without any additional
information the object is pretty pointless.

One possibility for this is to use the range manager to implement
something drm_mm based. BTW: We should probably rename that to
something
like ttm_res_drm_mm or similar.

Sure I'm all in on that, but my point is this becomes pretty awkward
because the reusable code already subclasses struct ttm_resource. Let
me give you an example:

Prereqs:
1) We want to be able to re-use resource manager implementations among
drivers.
2) A driver might want to re-use multiple implementations and have
identical data "struct i915_data" attached to both


Well that's the point I don't really understand. Why would a driver 
want to do this?


Let's say you have a struct ttm_object_vram and a struct 
ttm_object_gtt, both subclassing drm_gem_object. Then I'd say a driver 
would want to subclass those to attach identical data, extend 
functionality and provide a single i915_gem_object to the rest of the 
driver, which couldn't care less whether it's vram or gtt? Wouldn't 
you say having separate struct ttm_object_vram and a struct 
ttm_object_gtt in this case would be awkward?. We *want* to allow 
common handling.


Yeah, but that's a bad idea. This is like diamond inheritance in C++.

When you need the same functionality in different backends you implement 
that as separate object and then add a parent class.




It's the exact same situation here. With struct ttm_resource you let 
*different* implementation flavours subclass it, which makes it 
awkward for the driver to extend the functionality in a common way by 
subclassing, unless the driver only uses a single implementation.


Well the driver should use separate implementations for their different 
domains as much as possible.



OT:

Having a variable size array as the last member of the range manager 
resource makes embedding that extremely fragile IMO. Perhaps hide that 
variable size functi

Re: [Intel-gfx] [PATCH 04/27] drm/i915/guc: Take GT PM ref when deregistering context

2021-09-13 Thread Tvrtko Ursulin



On 20/08/2021 23:44, Matthew Brost wrote:

Taking a PM reference to prevent intel_gt_wait_for_idle from short
circuiting while a deregister context H2G is in flight.

FIXME: Move locking / structure changes into different patch

Signed-off-by: Matthew Brost 
---
  drivers/gpu/drm/i915/gt/intel_context.c   |   2 +
  drivers/gpu/drm/i915/gt/intel_context_types.h |  13 +-
  drivers/gpu/drm/i915/gt/intel_engine_pm.h |   5 +
  drivers/gpu/drm/i915/gt/intel_gt_pm.h |  13 ++
  .../gpu/drm/i915/gt/uc/abi/guc_actions_abi.h  |   1 +
  drivers/gpu/drm/i915/gt/uc/intel_guc.h|  46 ++--
  .../gpu/drm/i915/gt/uc/intel_guc_debugfs.c|  13 +-
  .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 212 +++---
  8 files changed, 199 insertions(+), 106 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_context.c 
b/drivers/gpu/drm/i915/gt/intel_context.c
index adfe49b53b1b..c8595da64ad8 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.c
+++ b/drivers/gpu/drm/i915/gt/intel_context.c
@@ -399,6 +399,8 @@ intel_context_init(struct intel_context *ce, struct 
intel_engine_cs *engine)
ce->guc_id.id = GUC_INVALID_LRC_ID;
INIT_LIST_HEAD(&ce->guc_id.link);
  
+	INIT_LIST_HEAD(&ce->destroyed_link);

+
/*
 * Initialize fence to be complete as this is expected to be complete
 * unless there is a pending schedule disable outstanding.
diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h 
b/drivers/gpu/drm/i915/gt/intel_context_types.h
index 80bbdc7810f6..fd338a30617e 100644
--- a/drivers/gpu/drm/i915/gt/intel_context_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
@@ -190,22 +190,29 @@ struct intel_context {
/**
 * @id: unique handle which is used to communicate information
 * with the GuC about this context, protected by
-* guc->contexts_lock
+* guc->submission_state.lock
 */
u16 id;
/**
 * @ref: the number of references to the guc_id, when
 * transitioning in and out of zero protected by
-* guc->contexts_lock
+* guc->submission_state.lock
 */
atomic_t ref;
/**
 * @link: in guc->guc_id_list when the guc_id has no refs but is
-* still valid, protected by guc->contexts_lock
+* still valid, protected by guc->submission_state.lock
 */
struct list_head link;
} guc_id;
  
+	/**

+* @destroyed_link: link in guc->submission_state.destroyed_contexts, in
+* list when context is pending to be destroyed (deregistered with the
+* GuC), protected by guc->submission_state.lock
+*/
+   struct list_head destroyed_link;
+
  #ifdef CONFIG_DRM_I915_SELFTEST
/**
 * @drop_schedule_enable: Force drop of schedule enable G2H for selftest
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h 
b/drivers/gpu/drm/i915/gt/intel_engine_pm.h
index 70ea46d6cfb0..17a5028ea177 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h
@@ -16,6 +16,11 @@ intel_engine_pm_is_awake(const struct intel_engine_cs 
*engine)
return intel_wakeref_is_active(&engine->wakeref);
  }
  
+static inline void __intel_engine_pm_get(struct intel_engine_cs *engine)

+{
+   __intel_wakeref_get(&engine->wakeref);
+}
+
  static inline void intel_engine_pm_get(struct intel_engine_cs *engine)
  {
intel_wakeref_get(&engine->wakeref);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h 
b/drivers/gpu/drm/i915/gt/intel_gt_pm.h
index d0588d8aaa44..a17bf0d4592b 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h
@@ -41,6 +41,19 @@ static inline void intel_gt_pm_put_async(struct intel_gt *gt)
intel_wakeref_put_async(>->wakeref);
  }
  
+#define with_intel_gt_pm(gt, tmp) \

+   for (tmp = 1, intel_gt_pm_get(gt); tmp; \
+intel_gt_pm_put(gt), tmp = 0)
+#define with_intel_gt_pm_async(gt, tmp) \
+   for (tmp = 1, intel_gt_pm_get(gt); tmp; \
+intel_gt_pm_put_async(gt), tmp = 0)
+#define with_intel_gt_pm_if_awake(gt, tmp) \
+   for (tmp = intel_gt_pm_get_if_awake(gt); tmp; \
+intel_gt_pm_put(gt), tmp = 0)
+#define with_intel_gt_pm_if_awake_async(gt, tmp) \
+   for (tmp = intel_gt_pm_get_if_awake(gt); tmp; \
+intel_gt_pm_put_async(gt), tmp = 0)
+
  static inline int intel_gt_pm_wait_for_idle(struct intel_gt *gt)
  {
return intel_wakeref_wait_for_idle(>->wakeref);
diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h 
b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
index 8ff58aff..ba10bd374cee 100644
--- a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
+++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
@@ -142,6 +142,7 @@ enum intel_guc_

Re: [RFC PATCH] drm/ttm: Add a private member to the struct ttm_resource

2021-09-13 Thread Thomas Hellström



On 9/13/21 11:41 AM, Christian König wrote:

Am 13.09.21 um 11:36 schrieb Thomas Hellström:

On 9/13/21 8:17 AM, Christian König wrote:

Am 11.09.21 um 08:07 schrieb Thomas Hellström:

On Fri, 2021-09-10 at 19:03 +0200, Christian König wrote:

Am 10.09.21 um 17:30 schrieb Thomas Hellström:

On Fri, 2021-09-10 at 16:40 +0200, Christian König wrote:

Am 10.09.21 um 15:15 schrieb Thomas Hellström:

Both the provider (resource manager) and the consumer (the TTM
driver)
want to subclass struct ttm_resource. Since this is left for
the
resource
manager, we need to provide a private pointer for the TTM
driver.

Provide a struct ttm_resource_private for the driver to
subclass
for
data with the same lifetime as the struct ttm_resource: In the
i915
case
it will, for example, be an sg-table and radix tree into the
LMEM
/VRAM pages that currently are awkwardly attached to the GEM
object.

Provide an ops structure for associated ops (Which is only
destroy() ATM)
It might seem pointless to provide a separate ops structure,
but
Linus
has previously made it clear that that's the norm.

After careful audit one could perhaps also on a per-driver
basis
replace the delete_mem_notify() TTM driver callback with the
above
destroy function.

Well this is a really big NAK to this approach.

If you need to attach some additional information to the resource
then
implement your own resource manager like everybody else does.

Well this was the long discussion we had back then when the
resource
mangagers started to derive from struct resource and I was under
the
impression that we had come to an agreement about the different
use-
cases here, and this was my main concern.

Ok, then we somehow didn't understood each other.


I mean, it's a pretty big layer violation to do that for this use-
case.

Well exactly that's the point. TTM should not have a layer design in
the
first place.

Devices, BOs, resources etc.. are base classes which should implement
a
base functionality which is then extended by the drivers to implement
the driver specific functionality.

That is a component based approach, and not layered at all.


The TTM resource manager doesn't want to know about this data at
all,
it's private to the ttm resource user layer and the resource
manager
works perfectly well without it. (I assume the other drivers that
implement their own resource managers need the data that the
subclassing provides?)

Yes, that's exactly why we have the subclassing.


The fundamental problem here is that there are two layers wanting
to
subclass struct ttm_resource. That means one layer gets to do that,
the
second gets to use a private pointer, (which in turn can provide
yet
another private pointer to a potential third layer). With your
suggestion, the second layer instead is forced to subclass each
subclassed instance it uses from  the first layer provides?

Well completely drop the layer approach/thinking here.

The resource is an object with a base class. The base class
implements
the interface TTM needs to handle the object, e.g.
create/destroy/debug
etc...

Then we need to subclass this object because without any additional
information the object is pretty pointless.

One possibility for this is to use the range manager to implement
something drm_mm based. BTW: We should probably rename that to
something
like ttm_res_drm_mm or similar.

Sure I'm all in on that, but my point is this becomes pretty awkward
because the reusable code already subclasses struct ttm_resource. Let
me give you an example:

Prereqs:
1) We want to be able to re-use resource manager implementations among
drivers.
2) A driver might want to re-use multiple implementations and have
identical data "struct i915_data" attached to both


Well that's the point I don't really understand. Why would a driver 
want to do this?


Let's say you have a struct ttm_object_vram and a struct 
ttm_object_gtt, both subclassing drm_gem_object. Then I'd say a 
driver would want to subclass those to attach identical data, extend 
functionality and provide a single i915_gem_object to the rest of the 
driver, which couldn't care less whether it's vram or gtt? Wouldn't 
you say having separate struct ttm_object_vram and a struct 
ttm_object_gtt in this case would be awkward?. We *want* to allow 
common handling.


Yeah, but that's a bad idea. This is like diamond inheritance in C++.

When you need the same functionality in different backends you 
implement that as separate object and then add a parent class.




It's the exact same situation here. With struct ttm_resource you let 
*different* implementation flavours subclass it, which makes it 
awkward for the driver to extend the functionality in a common way by 
subclassing, unless the driver only uses a single implementation.


Well the driver should use separate implementations for their 
different domains as much as possible.


Hmm, Now you lost me a bit. Are you saying that the way we do dynamic 
backends in the struct ttm_buffer_object to facili

Re: [PATCH v4 24/24] drm/exynos: dsi: Adjust probe order

2021-09-13 Thread Andrzej Hajda


W dniu 10.09.2021 o 12:12, Maxime Ripard pisze:
> Without proper care and an agreement between how DSI hosts and devices
> drivers register their MIPI-DSI entities and potential components, we can
> end up in a situation where the drivers can never probe.
>
> Most drivers were taking evasive maneuvers to try to workaround this,
> but not all of them were following the same conventions, resulting in
> various incompatibilities between DSI hosts and devices.
>
> Now that we have a sequence agreed upon and documented, let's convert
> exynos to it.
>
> Signed-off-by: Maxime Ripard 

This patch should be dropped, as it will probably break the driver.

Exynos is already compatible with the pattern 
register-bus-then-get-sink, but it adds/removes panel/bridge 
dynamically, so it creates drm_device without waiting for downstream sink.


Regards

Andrzej


> ---
>   drivers/gpu/drm/exynos/exynos_drm_dsi.c | 19 ---
>   1 file changed, 12 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c 
> b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index e39fac889edc..dfda2b259c44 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1529,6 +1529,7 @@ static const struct drm_encoder_helper_funcs 
> exynos_dsi_encoder_helper_funcs = {
>   
>   MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
>   
> +static const struct component_ops exynos_dsi_component_ops;
>   static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
> struct mipi_dsi_device *device)
>   {
> @@ -1536,6 +1537,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host 
> *host,
>   struct drm_encoder *encoder = &dsi->encoder;
>   struct drm_device *drm = encoder->dev;
>   struct drm_bridge *out_bridge;
> + struct device *dev = host->dev;
>   
>   out_bridge  = of_drm_find_bridge(device->dev.of_node);
>   if (out_bridge) {
> @@ -1585,7 +1587,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host 
> *host,
>   if (drm->mode_config.poll_enabled)
>   drm_kms_helper_hotplug_event(drm);
>   
> - return 0;
> + return component_add(dev, &exynos_dsi_component_ops);
>   }
>   
>   static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
> @@ -1593,6 +1595,9 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host 
> *host,
>   {
>   struct exynos_dsi *dsi = host_to_dsi(host);
>   struct drm_device *drm = dsi->encoder.dev;
> + struct device *dev = host->dev;
> +
> + component_del(dev, &exynos_dsi_component_ops);
>   
>   if (dsi->panel) {
>   mutex_lock(&drm->mode_config.mutex);
> @@ -1716,7 +1721,7 @@ static int exynos_dsi_bind(struct device *dev, struct 
> device *master,
>   of_node_put(in_bridge_node);
>   }
>   
> - return mipi_dsi_host_register(&dsi->dsi_host);
> + return 0;
>   }
>   
>   static void exynos_dsi_unbind(struct device *dev, struct device *master,
> @@ -1726,8 +1731,6 @@ static void exynos_dsi_unbind(struct device *dev, 
> struct device *master,
>   struct drm_encoder *encoder = &dsi->encoder;
>   
>   exynos_dsi_disable(encoder);
> -
> - mipi_dsi_host_unregister(&dsi->dsi_host);
>   }
>   
>   static const struct component_ops exynos_dsi_component_ops = {
> @@ -1821,7 +1824,7 @@ static int exynos_dsi_probe(struct platform_device 
> *pdev)
>   
>   pm_runtime_enable(dev);
>   
> - ret = component_add(dev, &exynos_dsi_component_ops);
> + ret = mipi_dsi_host_register(&dsi->dsi_host);
>   if (ret)
>   goto err_disable_runtime;
>   
> @@ -1835,10 +1838,12 @@ static int exynos_dsi_probe(struct platform_device 
> *pdev)
>   
>   static int exynos_dsi_remove(struct platform_device *pdev)
>   {
> + struct exynos_dsi *dsi = platform_get_drvdata(pdev);
> +
> + mipi_dsi_host_unregister(&dsi->dsi_host);
> +
>   pm_runtime_disable(&pdev->dev);
>   
> - component_del(&pdev->dev, &exynos_dsi_component_ops);
> -
>   return 0;
>   }
>   


Re: [GIT PULL] drm-misc + drm-intel: Add support for out-of-band hotplug notification

2021-09-13 Thread Hans de Goede
Hi,

On 8/26/21 1:43 PM, Vivi, Rodrigo wrote:
> On Thu, 2021-08-26 at 10:23 +0200, Maxime Ripard wrote:
>> On Wed, Aug 25, 2021 at 04:03:43PM +, Vivi, Rodrigo wrote:
>>> On Tue, 2021-08-24 at 18:48 +0200, Hans de Goede wrote:
 Hi,

 On 8/24/21 10:45 AM, Jani Nikula wrote:
> On Fri, 20 Aug 2021, Hans de Goede  wrote:
>> Hello drm-misc and drm-intel maintainers,
>>
>> My "Add support for out-of-band hotplug notification"
>> patchset:
>> https://patchwork.freedesktop.org/series/93763/
>>
>> Is ready for merging now, as discussed on IRC I based this
>> series
>> on top drm-tip and when trying to apply the i915 parts on top
>> of drm-misc this fails due to conflict.
>>
>> So as Jani suggested here is a pull-req for a topic-branch
>> with
>> the
>> entire set, minus the troublesome i915 bits. Once this has
>> been
>> merged
>> into both drm-misc-next and drm-intel-next I can push the 2
>> i915
>> patch do drm-intel-next on top of the merge.
>>
>> Note there are also 2 drivers/usb/typec patches in here these
>> have Greg KH's Reviewed-by for merging through the drm tree,
>> Since this USB code does not change all that much. I also
>> checked
>> and the drm-misc-next-2021-08-12 base of this tree contains
>> the
>> same last commit to the modified file as usb-next.
>>
>> Daniel Vetter mentioned on IRC that it might be better for
>> you to
>> simply
>> pick-up the series directly from patchwork, that is fine too
>> in
>> that
>> case don't forget to add:
>>
>> Reviewed-by: Lyude Paul 
>>
>> To the entire series (given in a reply to the cover-letter)
>>
>> And:
>>
>> Reviewed-by: Greg Kroah-Hartman 
>>
>> To the usb/typec patches (patch 7/8), this was given in reply
>> to a previous posting of the series and I forgot to add this
>> in the resend.
>
> Since this is mostly touching drm core, I think it should be
> merged
> to
> drm-misc-next first, and drm-intel-next after. Please let us
> know.

 I agree this should go to drm-misc-next first.

 (I was planning on pushing this to drm-misc-next myself,
 but then ended up going with the topic branch because of the
 conflict in the i915 bits.)
>>>
>>> Just to be clear and avoid confusion: This pull request does apply
>>> cleanly on drm-misc-next nd drm-intel-next right now.
>>>
>>> I'm just waiting for drm-misc-next maintainers to pull this to drm-
>>> misc-next so I can pull it to drm-intel-next.
>>>
>>> Maxime, is that your round now?
>>> or Thomas?
>>
>> That's me, I just pushed it to drm-misc-next
> 
> Thank you!
> I also pushed to drm-intel-next.

Thanks, I pushed the remaining 2 i915 patches depending on this
to drm-intel-next last week (but I forgot to reply to this email then).

Regards,

Hans



Re: [Intel-gfx] [PATCH 05/27] drm/i915: Add GT PM unpark worker

2021-09-13 Thread Tvrtko Ursulin



On 10/09/2021 21:09, Matthew Brost wrote:

On Fri, Sep 10, 2021 at 09:36:17AM +0100, Tvrtko Ursulin wrote:


On 20/08/2021 23:44, Matthew Brost wrote:

Sometimes it is desirable to queue work up for later if the GT PM isn't
held and run that work on next GT PM unpark.


Sounds maybe plausible, but it depends how much work can happen on unpark
and whether it can have too much of a negative impact on latency for
interactive loads? Or from a reverse angle, why the work wouldn't be done on


All it is does is add an interface to kick a work queue on unpark. i.e.
All the actually work is done async in the work queue so it shouldn't
add any latency.


parking?

Also what kind of mechanism for dealing with too much stuff being put on
this list you have? Can there be pressure which triggers (or would need to


No limits on pressure. See above, I don't think this is a concern.


On unpark it has the potential to send an unbound amount of actions for 
the GuC to process. Which will be competing, in GuC internal processing 
power, with the user action which caused the unpark. That logically does 
feel like can have effect on initial latency. Why you think it cannot?


Why the work wouldn't be done on parking?

With this scheme couldn't we end up with a situation that the worker 
keeps missing the GT unparked state and so keeps piling items on the 
deregistration list? Can you run of some ids like that (which is related 
to my question of how is pressure handled here).


Unpark
Register context
Submit work
Retire
Schedule context deregister
Park

Worker runs
GT parked
Work put on a list

Unpark
Schedule deregistration worker
Register new context
Submit work
Retire
Schedule contect deregister
Park

Worker runs (lets say there was CPU pressure)
GT already parked
 -> deregistration queue now has two contexts on it

... repeat until disaster ...

Unless I have misunderstood the logic.


trigger) these deregistrations to happen at runtime (no park/unpark
transitions)?


Implemented with a list in the GT of all pending work, workqueues in
the list, a callback to add a workqueue to the list, and finally a
wakeref post_get callback that iterates / drains the list + queues the
workqueues.

First user of this is deregistration of GuC contexts.


Does first imply there are more incoming?



Haven't found another user yet but this is generic mechanism so we can
add more in the future if other use cases arrise.


My feeling is it would be best to leave it for later.

  

Signed-off-by: Matthew Brost 
---
   drivers/gpu/drm/i915/Makefile |  1 +
   drivers/gpu/drm/i915/gt/intel_gt.c|  3 ++
   drivers/gpu/drm/i915/gt/intel_gt_pm.c |  8 
   .../gpu/drm/i915/gt/intel_gt_pm_unpark_work.c | 35 
   .../gpu/drm/i915/gt/intel_gt_pm_unpark_work.h | 40 +++
   drivers/gpu/drm/i915/gt/intel_gt_types.h  | 10 +
   drivers/gpu/drm/i915/gt/uc/intel_guc.h|  8 ++--
   .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 15 +--
   drivers/gpu/drm/i915/intel_wakeref.c  |  5 +++
   drivers/gpu/drm/i915/intel_wakeref.h  |  1 +
   10 files changed, 119 insertions(+), 7 deletions(-)
   create mode 100644 drivers/gpu/drm/i915/gt/intel_gt_pm_unpark_work.c
   create mode 100644 drivers/gpu/drm/i915/gt/intel_gt_pm_unpark_work.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 642a5b5a1b81..579bdc069f25 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -103,6 +103,7 @@ gt-y += \
gt/intel_gt_clock_utils.o \
gt/intel_gt_irq.o \
gt/intel_gt_pm.o \
+   gt/intel_gt_pm_unpark_work.o \
gt/intel_gt_pm_irq.o \
gt/intel_gt_requests.o \
gt/intel_gtt.o \
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c 
b/drivers/gpu/drm/i915/gt/intel_gt.c
index 62d40c986642..7e690e74baa2 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -29,6 +29,9 @@ void intel_gt_init_early(struct intel_gt *gt, struct 
drm_i915_private *i915)
spin_lock_init(>->irq_lock);
+   spin_lock_init(>->pm_unpark_work_lock);
+   INIT_LIST_HEAD(>->pm_unpark_work_list);
+
INIT_LIST_HEAD(>->closed_vma);
spin_lock_init(>->closed_lock);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c 
b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
index dea8e2479897..564c11a3748b 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
@@ -90,6 +90,13 @@ static int __gt_unpark(struct intel_wakeref *wf)
return 0;
   }
+static void __gt_unpark_work_queue(struct intel_wakeref *wf)
+{
+   struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref);
+
+   intel_gt_pm_unpark_work_queue(gt);
+}
+
   static int __gt_park(struct intel_wakeref *wf)
   {
struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref);
@@ -118,6 +125,7 @@ static int __gt_park(struct intel_wakeref *wf)
   static const s

Re: [PATCH v11 24/34] media: staging: tegra-vde: Support generic power domain

2021-09-13 Thread Hans Verkuil
On 12/09/2021 22:08, Dmitry Osipenko wrote:
> Currently driver supports legacy power domain API, this patch adds generic
> power domain support. This allows us to utilize a modern GENPD API for
> newer device-trees.
> 
> Tested-by: Peter Geis  # Ouya T30
> Tested-by: Paul Fertser  # PAZ00 T20
> Tested-by: Nicolas Chauvet  # PAZ00 T20 and TK1 T124
> Tested-by: Matt Merhar  # Ouya T30
> Signed-off-by: Dmitry Osipenko 

Acked-by: Hans Verkuil 

Regards,

Hans

> ---
>  drivers/staging/media/tegra-vde/vde.c | 57 +--
>  1 file changed, 46 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-vde/vde.c 
> b/drivers/staging/media/tegra-vde/vde.c
> index ed4c1250b303..bb3079a2c0b5 100644
> --- a/drivers/staging/media/tegra-vde/vde.c
> +++ b/drivers/staging/media/tegra-vde/vde.c
> @@ -20,6 +20,7 @@
>  #include 
>  #include 
>  
> +#include 
>  #include 
>  
>  #include "uapi.h"
> @@ -920,13 +921,17 @@ static __maybe_unused int 
> tegra_vde_runtime_suspend(struct device *dev)
>   struct tegra_vde *vde = dev_get_drvdata(dev);
>   int err;
>  
> - err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC);
> - if (err) {
> - dev_err(dev, "Failed to power down HW: %d\n", err);
> - return err;
> + if (!dev->pm_domain) {
> + err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC);
> + if (err) {
> + dev_err(dev, "Failed to power down HW: %d\n", err);
> + return err;
> + }
>   }
>  
>   clk_disable_unprepare(vde->clk);
> + reset_control_release(vde->rst);
> + reset_control_release(vde->rst_mc);
>  
>   return 0;
>  }
> @@ -936,14 +941,41 @@ static __maybe_unused int 
> tegra_vde_runtime_resume(struct device *dev)
>   struct tegra_vde *vde = dev_get_drvdata(dev);
>   int err;
>  
> - err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC,
> - vde->clk, vde->rst);
> + err = reset_control_acquire(vde->rst_mc);
>   if (err) {
> - dev_err(dev, "Failed to power up HW : %d\n", err);
> + dev_err(dev, "Failed to acquire mc reset: %d\n", err);
>   return err;
>   }
>  
> + err = reset_control_acquire(vde->rst);
> + if (err) {
> + dev_err(dev, "Failed to acquire reset: %d\n", err);
> + goto release_mc_reset;
> + }
> +
> + if (!dev->pm_domain) {
> + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC,
> + vde->clk, vde->rst);
> + if (err) {
> + dev_err(dev, "Failed to power up HW : %d\n", err);
> + goto release_reset;
> + }
> + }
> +
> + err = clk_prepare_enable(vde->clk);
> + if (err) {
> + dev_err(dev, "Failed to enable clock: %d\n", err);
> + goto release_reset;
> + }
> +
>   return 0;
> +
> +release_reset:
> + reset_control_release(vde->rst);
> +release_mc_reset:
> + reset_control_release(vde->rst_mc);
> +
> + return err;
>  }
>  
>  static int tegra_vde_probe(struct platform_device *pdev)
> @@ -1001,14 +1033,14 @@ static int tegra_vde_probe(struct platform_device 
> *pdev)
>   return err;
>   }
>  
> - vde->rst = devm_reset_control_get(dev, NULL);
> + vde->rst = devm_reset_control_get_exclusive_released(dev, NULL);
>   if (IS_ERR(vde->rst)) {
>   err = PTR_ERR(vde->rst);
>   dev_err(dev, "Could not get VDE reset %d\n", err);
>   return err;
>   }
>  
> - vde->rst_mc = devm_reset_control_get_optional(dev, "mc");
> + vde->rst_mc = devm_reset_control_get_optional_exclusive_released(dev, 
> "mc");
>   if (IS_ERR(vde->rst_mc)) {
>   err = PTR_ERR(vde->rst_mc);
>   dev_err(dev, "Could not get MC reset %d\n", err);
> @@ -1066,6 +1098,10 @@ static int tegra_vde_probe(struct platform_device 
> *pdev)
>   pm_runtime_use_autosuspend(dev);
>   pm_runtime_set_autosuspend_delay(dev, 300);
>  
> + err = devm_tegra_core_dev_init_opp_table_common(dev);
> + if (err)
> + goto err_pm_runtime;
> +
>   /*
>* VDE partition may be left ON after bootloader, hence let's
>* power-cycle it in order to put hardware into a predictable lower
> @@ -1133,8 +1169,7 @@ static void tegra_vde_shutdown(struct platform_device 
> *pdev)
>* On some devices bootloader isn't ready to a power-gated VDE on
>* a warm-reboot, machine will hang in that case.
>*/
> - if (pm_runtime_status_suspended(&pdev->dev))
> - tegra_vde_runtime_resume(&pdev->dev);
> + pm_runtime_get_sync(&pdev->dev);
>  }
>  
>  static __maybe_unused int tegra_vde_pm_suspend(struct device *dev)
> 



Re: [PATCH v11 22/34] media: dt: bindings: tegra-vde: Convert to schema

2021-09-13 Thread Hans Verkuil
On 12/09/2021 22:08, Dmitry Osipenko wrote:
> Convert NVIDIA Tegra video decoder binding to schema.
> 
> Reviewed-by: Rob Herring 
> Signed-off-by: Dmitry Osipenko 

Acked-by: Hans Verkuil 

Regards,

Hans

> ---
>  .../bindings/media/nvidia,tegra-vde.txt   |  64 ---
>  .../bindings/media/nvidia,tegra-vde.yaml  | 107 ++
>  2 files changed, 107 insertions(+), 64 deletions(-)
>  delete mode 100644 
> Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt
>  create mode 100644 
> Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml
> 
> diff --git a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt 
> b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt
> deleted file mode 100644
> index 602169b8aa19..
> --- a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt
> +++ /dev/null
> @@ -1,64 +0,0 @@
> -NVIDIA Tegra Video Decoder Engine
> -
> -Required properties:
> -- compatible : Must contain one of the following values:
> -   - "nvidia,tegra20-vde"
> -   - "nvidia,tegra30-vde"
> -   - "nvidia,tegra114-vde"
> -   - "nvidia,tegra124-vde"
> -   - "nvidia,tegra132-vde"
> -- reg : Must contain an entry for each entry in reg-names.
> -- reg-names : Must include the following entries:
> -  - sxe
> -  - bsev
> -  - mbe
> -  - ppe
> -  - mce
> -  - tfe
> -  - ppb
> -  - vdma
> -  - frameid
> -- iram : Must contain phandle to the mmio-sram device node that represents
> - IRAM region used by VDE.
> -- interrupts : Must contain an entry for each entry in interrupt-names.
> -- interrupt-names : Must include the following entries:
> -  - sync-token
> -  - bsev
> -  - sxe
> -- clocks : Must include the following entries:
> -  - vde
> -- resets : Must contain an entry for each entry in reset-names.
> -- reset-names : Should include the following entries:
> -  - vde
> -
> -Optional properties:
> -- resets : Must contain an entry for each entry in reset-names.
> -- reset-names : Must include the following entries:
> -  - mc
> -- iommus: Must contain phandle to the IOMMU device node.
> -
> -Example:
> -
> -video-codec@6001a000 {
> - compatible = "nvidia,tegra20-vde";
> - reg = <0x6001a000 0x1000 /* Syntax Engine */
> -0x6001b000 0x1000 /* Video Bitstream Engine */
> -0x6001c000  0x100 /* Macroblock Engine */
> -0x6001c200  0x100 /* Post-processing Engine */
> -0x6001c400  0x100 /* Motion Compensation Engine */
> -0x6001c600  0x100 /* Transform Engine */
> -0x6001c800  0x100 /* Pixel prediction block */
> -0x6001ca00  0x100 /* Video DMA */
> -0x6001d800  0x300 /* Video frame controls */>;
> - reg-names = "sxe", "bsev", "mbe", "ppe", "mce",
> - "tfe", "ppb", "vdma", "frameid";
> - iram = <&vde_pool>; /* IRAM region */
> - interrupts = , /* Sync token interrupt 
> */
> -  , /* BSE-V interrupt */
> -  ; /* SXE interrupt */
> - interrupt-names = "sync-token", "bsev", "sxe";
> - clocks = <&tegra_car TEGRA20_CLK_VDE>;
> - reset-names = "vde", "mc";
> - resets = <&tegra_car 61>, <&mc TEGRA20_MC_RESET_VDE>;
> - iommus = <&mc TEGRA_SWGROUP_VDE>;
> -};
> diff --git a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml 
> b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml
> new file mode 100644
> index ..3b6c1f031e04
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml
> @@ -0,0 +1,107 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/nvidia,tegra-vde.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: NVIDIA Tegra Video Decoder Engine
> +
> +maintainers:
> +  - Dmitry Osipenko 
> +  - Jon Hunter 
> +  - Thierry Reding 
> +
> +properties:
> +  compatible:
> +oneOf:
> +  - items:
> +  - enum:
> +  - nvidia,tegra132-vde
> +  - nvidia,tegra124-vde
> +  - nvidia,tegra114-vde
> +  - nvidia,tegra30-vde
> +  - enum:
> +  - nvidia,tegra20-vde
> +  - items:
> +  - const: nvidia,tegra20-vde
> +
> +  reg:
> +maxItems: 9
> +
> +  reg-names:
> +items:
> +  - const: sxe
> +  - const: bsev
> +  - const: mbe
> +  - const: ppe
> +  - const: mce
> +  - const: tfe
> +  - const: ppb
> +  - const: vdma
> +  - const: frameid
> +
> +  clocks:
> +maxItems: 1
> +
> +  resets:
> +maxItems: 2
> +
> +  reset-names:
> +items:
> +  - const: vde
> +  - const: mc
> +
> +  interrupts:
> +maxItems: 3
> +
> +  interrupt-names:
> +items:
> +  - const: sync-token
> +  - const: bsev
> +  - const: sxe
> +
> +  iommus:
> +maxItems: 1
> +
> +  iram:
> +$ref: /schemas/types.yaml#/definitions/phandle
> +description:
> +  Phandle of the SRA

Re: [PATCH v11 23/34] media: dt: bindings: tegra-vde: Document OPP and power domain

2021-09-13 Thread Hans Verkuil
On 12/09/2021 22:08, Dmitry Osipenko wrote:
> Document new OPP table and power domain properties of the video decoder
> hardware.
> 
> Reviewed-by: Rob Herring 
> Signed-off-by: Dmitry Osipenko 

Acked-by: Hans Verkuil 

Regards,

Hans

> ---
>  .../devicetree/bindings/media/nvidia,tegra-vde.yaml  | 12 
>  1 file changed, 12 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml 
> b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml
> index 3b6c1f031e04..0b7d4d815707 100644
> --- a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml
> +++ b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml
> @@ -68,6 +68,16 @@ properties:
>  description:
>Phandle of the SRAM MMIO node.
>  
> +  operating-points-v2:
> +description:
> +  Should contain freqs and voltages and opp-supported-hw property,
> +  which is a bitfield indicating SoC speedo or process ID mask.
> +
> +  power-domains:
> +maxItems: 1
> +description:
> +  Phandle to the SoC core power domain.
> +
>  required:
>- compatible
>- reg
> @@ -104,4 +114,6 @@ examples:
>reset-names = "vde", "mc";
>resets = <&rst 61>, <&mem 13>;
>iommus = <&mem 15>;
> +  operating-points-v2 = <&dvfs_opp_table>;
> +  power-domains = <&domain>;
>  };
> 



Re: [Intel-gfx] [PATCH 23/27] drm/i915/guc: Implement no mid batch preemption for multi-lrc

2021-09-13 Thread Tvrtko Ursulin



On 10/09/2021 21:49, Matthew Brost wrote:

On Fri, Sep 10, 2021 at 12:25:43PM +0100, Tvrtko Ursulin wrote:


On 20/08/2021 23:44, Matthew Brost wrote:

For some users of multi-lrc, e.g. split frame, it isn't safe to preempt
mid BB. To safely enable preemption at the BB boundary, a handshake
between to parent and child is needed. This is implemented via custom
emit_bb_start & emit_fini_breadcrumb functions and enabled via by
default if a context is configured by set parallel extension.


FWIW I think it's wrong to hardcode the requirements of a particular
hardware generation fixed media pipeline into the uapi. IMO better solution
was when concept of parallel submission was decoupled from the no preemption
mid batch preambles. Otherwise might as well call the extension
I915_CONTEXT_ENGINES_EXT_MEDIA_SPLIT_FRAME_SUBMIT or something.



I don't disagree but this where we landed per Daniel Vetter's feedback -
default to what our current hardware supports and extend it later to
newer hardware / requirements as needed.


I think this only re-affirms my argument - no point giving the extension 
a generic name if it is so tightly coupled to a specific use case. But I 
wrote FWIW so whatever.


It will be mighty awkward if compute multi-lrc will need to specify a 
flag to allow preemption, when turning off preemption is otherwise not 
something we allow unprivileged clients to do. So it will be kind of 
opt-out from unfriendly/dangerous default behaviour instead of explicit 
requesting it.


Regards,

Tvrtko


RE: [PATCH v2 4/6] drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO

2021-09-13 Thread Shankar, Uma



> -Original Message-
> From: Nikula, Jani 
> Sent: Monday, September 13, 2021 3:00 PM
> To: Shankar, Uma ; intel-...@lists.freedesktop.org
> Cc: dri-devel@lists.freedesktop.org; ville.syrj...@linux.intel.com
> Subject: RE: [PATCH v2 4/6] drm/edid: parse the DisplayID v2.0 VESA vendor 
> block
> for MSO
> 
> On Mon, 13 Sep 2021, "Shankar, Uma"  wrote:
> >> -Original Message-
> >> From: dri-devel  On Behalf
> >> Of Jani Nikula
> >> Sent: Tuesday, August 31, 2021 7:48 PM
> >> To: intel-...@lists.freedesktop.org
> >> Cc: dri-devel@lists.freedesktop.org; ville.syrj...@linux.intel.com;
> >> Nikula, Jani 
> >> Subject: [PATCH v2 4/6] drm/edid: parse the DisplayID v2.0 VESA
> >> vendor block for MSO
> >>
> >> The VESA Organization Vendor-Specific Data Block, defined in VESA
> >> DisplayID Standard v2.0, specifies the eDP Multi-SST Operation (MSO)
> >> stream count and segment pixel overlap.
> >>
> >> DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension,
> >> describing how DisplayID sections may be embedded in EDID extension
> >> blocks. DisplayID v2.0 does not have such a section, perhaps implying
> >> that DisplayID v2.0 data should not be included in EDID extensions,
> >> but rather in a "pure" DisplayID structure at its own DDC address pair 
> >> A4h/A5h, as
> described in VESA E-DDC Standard v1.3 chapter 3.
> >>
> >> However, in practice, displays out in the field have embedded
> >> DisplayID
> >> v2.0 data blocks in EDID extensions, including, in particular, some
> >> eDP MSO displays, where a pure DisplayID structure is not available at all.
> >>
> >> Parse the MSO data from the DisplayID data block. Do it as part of
> >> drm_add_display_info(), extending it to parse also DisplayID data to
> >> avoid requiring extra calls to update the information.
> >>
> >> v2: Check for VESA OUI (Ville)
> >>
> >> Signed-off-by: Jani Nikula 
> >> ---
> >>  drivers/gpu/drm/drm_edid.c  | 72
> >> +
> >>  include/drm/drm_connector.h | 12 +++
> >> include/drm/drm_displayid.h | 13
> >> +++
> >>  3 files changed, 97 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> >> index 92974b1478bc..c45c225267ca 100644
> >> --- a/drivers/gpu/drm/drm_edid.c
> >> +++ b/drivers/gpu/drm/drm_edid.c
> >> @@ -28,6 +28,7 @@
> >>   * DEALINGS IN THE SOFTWARE.
> >>   */
> >>
> >> +#include 
> >>  #include 
> >>  #include 
> >>  #include 
> >> @@ -5145,6 +5146,71 @@ void drm_get_monitor_range(struct
> >> drm_connector *connector,
> >>  info->monitor_range.max_vfreq);  }
> >>
> >> +static void drm_parse_vesa_mso_data(struct drm_connector *connector,
> >> +  const struct displayid_block *block) {
> >> +  struct displayid_vesa_vendor_specific_block *vesa =
> >> +  (struct displayid_vesa_vendor_specific_block *)block;
> >> +  struct drm_display_info *info = &connector->display_info;
> >> +
> >> +  if (block->num_bytes < 3) {
> >> +  drm_dbg_kms(connector->dev, "Unexpected vendor block size
> >> %u\n",
> >> +  block->num_bytes);
> >> +  return;
> >> +  }
> >> +
> >> +  if (oui(vesa->oui[0], vesa->oui[1], vesa->oui[2]) != VESA_IEEE_OUI)
> >> +  return;
> >> +
> >> +  if (sizeof(*vesa) != sizeof(*block) + block->num_bytes) {
> >> +  drm_dbg_kms(connector->dev, "Unexpected VESA vendor block
> >> size\n");
> >> +  return;
> >> +  }
> >> +
> >> +  switch (FIELD_GET(DISPLAYID_VESA_MSO_MODE, vesa->mso)) {
> >> +  default:
> >> +  drm_dbg_kms(connector->dev, "Reserved MSO mode value\n");
> >> +  fallthrough;
> >> +  case 0:
> >> +  info->mso_stream_count = 0;
> >> +  break;
> >> +  case 1:
> >> +  info->mso_stream_count = 2; /* 2 or 4 links */
> >> +  break;
> >> +  case 2:
> >> +  info->mso_stream_count = 4; /* 4 links */
> >> +  break;
> >> +  }
> >> +
> >> +  if (!info->mso_stream_count) {
> >> +  info->mso_pixel_overlap = 0;
> >> +  return;
> >> +  }
> >> +
> >> +  info->mso_pixel_overlap = FIELD_GET(DISPLAYID_VESA_MSO_OVERLAP,
> >> vesa->mso);
> >> +  if (info->mso_pixel_overlap > 8) {
> >> +  drm_dbg_kms(connector->dev, "Reserved MSO pixel overlap value
> >> %u\n",
> >> +  info->mso_pixel_overlap);
> >> +  info->mso_pixel_overlap = 8;
> >
> > Going beyond 8 is not right from a vendor perspective as it goes into 
> > reserved
> region.
> > Should we not just set to 0 or how we decide that we fixed overlap at
> > 8. It seems an undefined operation and it may vary from sink to sink.
> 
> I don't know if there's a right choice here. I don't mind setting it to
> 0 if you prefer that.

I feel it will be wrong on a vendor's behalf if he programs anything above 8. 
But not sure what
should driver do in such case, it's an undefined behavior. If he intentionally 
programs it as say 20,
fixing at 8 will still lead to some artifacts

Re: [RFC PATCH] drm/ttm: Add a private member to the struct ttm_resource

2021-09-13 Thread Thomas Hellström



On 9/13/21 12:16 PM, Thomas Hellström wrote:


On 9/13/21 11:41 AM, Christian König wrote:

Am 13.09.21 um 11:36 schrieb Thomas Hellström:

On 9/13/21 8:17 AM, Christian König wrote:

Am 11.09.21 um 08:07 schrieb Thomas Hellström:

On Fri, 2021-09-10 at 19:03 +0200, Christian König wrote:

Am 10.09.21 um 17:30 schrieb Thomas Hellström:

On Fri, 2021-09-10 at 16:40 +0200, Christian König wrote:

Am 10.09.21 um 15:15 schrieb Thomas Hellström:

Both the provider (resource manager) and the consumer (the TTM
driver)
want to subclass struct ttm_resource. Since this is left for
the
resource
manager, we need to provide a private pointer for the TTM
driver.

Provide a struct ttm_resource_private for the driver to
subclass
for
data with the same lifetime as the struct ttm_resource: In the
i915
case
it will, for example, be an sg-table and radix tree into the
LMEM
/VRAM pages that currently are awkwardly attached to the GEM
object.

Provide an ops structure for associated ops (Which is only
destroy() ATM)
It might seem pointless to provide a separate ops structure,
but
Linus
has previously made it clear that that's the norm.

After careful audit one could perhaps also on a per-driver
basis
replace the delete_mem_notify() TTM driver callback with the
above
destroy function.

Well this is a really big NAK to this approach.

If you need to attach some additional information to the resource
then
implement your own resource manager like everybody else does.

Well this was the long discussion we had back then when the
resource
mangagers started to derive from struct resource and I was under
the
impression that we had come to an agreement about the different
use-
cases here, and this was my main concern.

Ok, then we somehow didn't understood each other.


I mean, it's a pretty big layer violation to do that for this use-
case.

Well exactly that's the point. TTM should not have a layer design in
the
first place.

Devices, BOs, resources etc.. are base classes which should 
implement

a
base functionality which is then extended by the drivers to 
implement

the driver specific functionality.

That is a component based approach, and not layered at all.


The TTM resource manager doesn't want to know about this data at
all,
it's private to the ttm resource user layer and the resource
manager
works perfectly well without it. (I assume the other drivers that
implement their own resource managers need the data that the
subclassing provides?)

Yes, that's exactly why we have the subclassing.


The fundamental problem here is that there are two layers wanting
to
subclass struct ttm_resource. That means one layer gets to do that,
the
second gets to use a private pointer, (which in turn can provide
yet
another private pointer to a potential third layer). With your
suggestion, the second layer instead is forced to subclass each
subclassed instance it uses from  the first layer provides?

Well completely drop the layer approach/thinking here.

The resource is an object with a base class. The base class
implements
the interface TTM needs to handle the object, e.g.
create/destroy/debug
etc...

Then we need to subclass this object because without any additional
information the object is pretty pointless.

One possibility for this is to use the range manager to implement
something drm_mm based. BTW: We should probably rename that to
something
like ttm_res_drm_mm or similar.

Sure I'm all in on that, but my point is this becomes pretty awkward
because the reusable code already subclasses struct ttm_resource. Let
me give you an example:

Prereqs:
1) We want to be able to re-use resource manager implementations 
among

drivers.
2) A driver might want to re-use multiple implementations and have
identical data "struct i915_data" attached to both


Well that's the point I don't really understand. Why would a driver 
want to do this?


Let's say you have a struct ttm_object_vram and a struct 
ttm_object_gtt, both subclassing drm_gem_object. Then I'd say a 
driver would want to subclass those to attach identical data, extend 
functionality and provide a single i915_gem_object to the rest of 
the driver, which couldn't care less whether it's vram or gtt? 
Wouldn't you say having separate struct ttm_object_vram and a struct 
ttm_object_gtt in this case would be awkward?. We *want* to allow 
common handling.


Yeah, but that's a bad idea. This is like diamond inheritance in C++.

When you need the same functionality in different backends you 
implement that as separate object and then add a parent class.




It's the exact same situation here. With struct ttm_resource you let 
*different* implementation flavours subclass it, which makes it 
awkward for the driver to extend the functionality in a common way 
by subclassing, unless the driver only uses a single implementation.


Well the driver should use separate implementations for their 
different domains as much as possible.


Hmm, Now you lost me a bit. Are you saying that the way we do dynami

Deploying new iterator interface for dma-buf

2021-09-13 Thread Christian König
Hi everybody,

we recently found that a good bunch of the RCU accesses to the dma_resv object 
are actually not correctly protected.

Those where fixed by either dropping the RCU approach and taking appropriate 
locks or using a central function to return the current fences as array and 
then work with that snapshot.

This set now tries to prevent adding any new broken code by rolling out two new 
interfaces to access the fences in a dma_resv object:

dma_resv_for_each_fence() - Iterator which should be used while holding the 
reservation lock.
dma_resv_for_each_fence_unlocked() - Iterator based on RCU which can be used 
without holding the reservation lock and automatic restart on concurrent 
modification.

While doing this we also move the decision which fences to use for write and 
read accesses into the dma_resv object which results in a quite nice code 
de-duplication and simplification.

The only two remaining users of the RCU shared fence interface are removing 
shared fences in amdkfd and debugfs code in qxl which will both be addresses in 
the next patch set.

Please review and/or comment,
Christian.




[PATCH 01/26] dma-buf: add dma_resv_for_each_fence_unlocked

2021-09-13 Thread Christian König
Abstract the complexity of iterating over all the fences
in a dma_resv object.

The new loop handles the whole RCU and retry dance and
returns only fences where we can be sure we grabbed the
right one.

Signed-off-by: Christian König 
---
 drivers/dma-buf/dma-resv.c | 63 ++
 include/linux/dma-resv.h   | 36 ++
 2 files changed, 99 insertions(+)

diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index 84fbe60629e3..213a9b7251ca 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -323,6 +323,69 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct 
dma_fence *fence)
 }
 EXPORT_SYMBOL(dma_resv_add_excl_fence);
 
+/**
+ * dma_resv_walk_unlocked - walk over fences in a dma_resv obj
+ * @obj: the dma_resv object
+ * @cursor: cursor to record the current position
+ * @all_fences: true returns also the shared fences
+ * @first: if we should start over
+ *
+ * Return all the fences in the dma_resv object which are not yet signaled.
+ * The returned fence has an extra local reference so will stay alive.
+ * If a concurrent modify is detected the whole iterator is started over again.
+ */
+struct dma_fence *dma_resv_walk_unlocked(struct dma_resv *obj,
+struct dma_resv_cursor *cursor,
+bool all_fences, bool first)
+{
+   struct dma_fence *fence = NULL;
+
+   do {
+   /* Drop the reference from the previous round */
+   dma_fence_put(fence);
+
+   cursor->is_first = first;
+   if (first) {
+   cursor->seq = read_seqcount_begin(&obj->seq);
+   cursor->index = -1;
+   cursor->fences = dma_resv_shared_list(obj);
+   cursor->is_exclusive = true;
+
+   fence = dma_resv_excl_fence(obj);
+   if (fence && test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
+ &fence->flags))
+   fence = NULL;
+   } else {
+   fence = NULL;
+   }
+
+   if (fence) {
+   fence = dma_fence_get_rcu(fence);
+   } else if (all_fences && cursor->fences) {
+   struct dma_resv_list *fences = cursor->fences;
+
+   cursor->is_exclusive = false;
+   while (++cursor->index < fences->shared_count) {
+   fence = rcu_dereference(fences->shared[
+   cursor->index]);
+   if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
+ &fence->flags))
+   break;
+   }
+   if (cursor->index < fences->shared_count)
+   fence = dma_fence_get_rcu(fence);
+   else
+   fence = NULL;
+   }
+
+   /* For the eventually next round */
+   first = true;
+   } while (read_seqcount_retry(&obj->seq, cursor->seq));
+
+   return fence;
+}
+EXPORT_SYMBOL_GPL(dma_resv_walk_unlocked);
+
 /**
  * dma_resv_copy_fences - Copy all fences from src to dst.
  * @dst: the destination reservation object
diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h
index 9100dd3dc21f..f5b91c292ee0 100644
--- a/include/linux/dma-resv.h
+++ b/include/linux/dma-resv.h
@@ -149,6 +149,39 @@ struct dma_resv {
struct dma_resv_list __rcu *fence;
 };
 
+/**
+ * struct dma_resv_cursor - current position into the dma_resv fences
+ * @seq: sequence number to check
+ * @index: index into the shared fences
+ * @shared: the shared fences
+ * @is_first: true if this is the first returned fence
+ * @is_exclusive: if the current fence is the exclusive one
+ */
+struct dma_resv_cursor {
+   unsigned int seq;
+   unsigned int index;
+   struct dma_resv_list *fences;
+   bool is_first;
+   bool is_exclusive;
+};
+
+/**
+ * dma_resv_for_each_fence_unlocked - fence iterator
+ * @obj: a dma_resv object pointer
+ * @cursor: a struct dma_resv_cursor pointer
+ * @all_fences: true if all fences should be returned
+ * @fence: the current fence
+ *
+ * Iterate over the fences in a struct dma_resv object without holding the
+ * dma_resv::lock. The RCU read side lock must be hold when using this, but can
+ * be dropped and re-taken as necessary inside the loop. @all_fences controls
+ * if the shared fences are returned as well.
+ */
+#define dma_resv_for_each_fence_unlocked(obj, cursor, all_fences, fence)\
+   for (fence = dma_resv_walk_unlocked(obj, cursor, all_fences, true); \
+fence; dma_fence_put(fence),   \
+fence = dma_resv_walk_unlocked(obj, curso

[PATCH 03/26] dma-buf: use new iterator in dma_resv_copy_fences

2021-09-13 Thread Christian König
This makes the function much simpler since the complex
retry logic is now handled else where.

Signed-off-by: Christian König 
---
 drivers/dma-buf/dma-resv.c | 81 +++---
 1 file changed, 32 insertions(+), 49 deletions(-)

diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index 8cbccaae169d..9a9c0bba772b 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -433,74 +433,57 @@ EXPORT_SYMBOL_GPL(dma_resv_walk_unlocked);
  */
 int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
 {
-   struct dma_resv_list *src_list, *dst_list;
-   struct dma_fence *old, *new;
-   unsigned int i;
+   struct dma_resv_cursor cursor;
+   struct dma_resv_list *list;
+   struct dma_fence *f, *excl;
 
dma_resv_assert_held(dst);
 
-   rcu_read_lock();
-   src_list = dma_resv_shared_list(src);
+   list = NULL;
+   excl = NULL;
 
-retry:
-   if (src_list) {
-   unsigned int shared_count = src_list->shared_count;
+   rcu_read_lock();
+   dma_resv_for_each_fence_unlocked(dst, &cursor, true, f) {
 
-   rcu_read_unlock();
+   if (cursor.is_first) {
+   dma_resv_list_free(list);
+   dma_fence_put(excl);
 
-   dst_list = dma_resv_list_alloc(shared_count);
-   if (!dst_list)
-   return -ENOMEM;
+   if (cursor.fences) {
+   unsigned int cnt = cursor.fences->shared_count;
 
-   rcu_read_lock();
-   src_list = dma_resv_shared_list(src);
-   if (!src_list || src_list->shared_count > shared_count) {
-   kfree(dst_list);
-   goto retry;
-   }
+   rcu_read_unlock();
+   list = dma_resv_list_alloc(cnt);
+   if (!list)
+   return -ENOMEM;
 
-   dst_list->shared_count = 0;
-   for (i = 0; i < src_list->shared_count; ++i) {
-   struct dma_fence __rcu **dst;
-   struct dma_fence *fence;
+   list->shared_count = 0;
+   rcu_read_lock();
 
-   fence = rcu_dereference(src_list->shared[i]);
-   if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
-&fence->flags))
-   continue;
-
-   if (!dma_fence_get_rcu(fence)) {
-   dma_resv_list_free(dst_list);
-   src_list = dma_resv_shared_list(src);
-   goto retry;
+   } else {
+   list = NULL;
}
+   excl = NULL;
+   }
 
-   if (dma_fence_is_signaled(fence)) {
-   dma_fence_put(fence);
-   continue;
-   }
+   if (cursor.is_exclusive)
+   excl = f;
+   else
+   RCU_INIT_POINTER(list->shared[list->shared_count++], f);
 
-   dst = &dst_list->shared[dst_list->shared_count++];
-   rcu_assign_pointer(*dst, fence);
-   }
-   } else {
-   dst_list = NULL;
+   /* Don't drop the reference */
+   f = NULL;
}
 
-   new = dma_fence_get_rcu_safe(&src->fence_excl);
rcu_read_unlock();
 
-   src_list = dma_resv_shared_list(dst);
-   old = dma_resv_excl_fence(dst);
-
write_seqcount_begin(&dst->seq);
-   /* write_seqcount_begin provides the necessary memory barrier */
-   RCU_INIT_POINTER(dst->fence_excl, new);
-   RCU_INIT_POINTER(dst->fence, dst_list);
+   excl = rcu_replace_pointer(dst->fence_excl, excl, dma_resv_held(dst));
+   list = rcu_replace_pointer(dst->fence, list, dma_resv_held(dst));
write_seqcount_end(&dst->seq);
 
-   dma_resv_list_free(src_list);
-   dma_fence_put(old);
+   dma_resv_list_free(list);
+   dma_fence_put(excl);
 
return 0;
 }
-- 
2.25.1



[PATCH 02/26] dma-buf: add dma_resv_for_each_fence

2021-09-13 Thread Christian König
A simpler version of the iterator to be used when the dma_resv object is
locked.

Signed-off-by: Christian König 
---
 drivers/dma-buf/dma-resv.c | 38 ++
 include/linux/dma-resv.h   | 18 ++
 2 files changed, 56 insertions(+)

diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index 213a9b7251ca..8cbccaae169d 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -323,6 +323,44 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct 
dma_fence *fence)
 }
 EXPORT_SYMBOL(dma_resv_add_excl_fence);
 
+/**
+ * dma_resv_walk - walk over fences in a dma_resv obj
+ * @obj: the dma_resv object
+ * @cursor: cursor to record the current position
+ * @all_fences: true returns also the shared fences
+ * @first: if we should start over
+ *
+ * Return all the fences in the dma_resv object while holding the
+ * dma_resv::lock.
+ */
+struct dma_fence *dma_resv_walk(struct dma_resv *obj,
+   struct dma_resv_cursor *cursor,
+   bool all_fences, bool first)
+{
+   dma_resv_assert_held(obj);
+
+   cursor->is_first = first;
+   if (first) {
+   struct dma_fence *fence;
+
+   cursor->index = -1;
+   cursor->fences = dma_resv_shared_list(obj);
+   cursor->is_exclusive = true;
+
+   fence = dma_resv_excl_fence(obj);
+   if (fence)
+   return fence;
+   }
+
+   if (!all_fences || !cursor->fences ||
+   ++cursor->index >= cursor->fences->shared_count)
+   return NULL;
+
+   return rcu_dereference_protected(cursor->fences->shared[cursor->index],
+dma_resv_held(obj));
+}
+EXPORT_SYMBOL_GPL(dma_resv_walk);
+
 /**
  * dma_resv_walk_unlocked - walk over fences in a dma_resv obj
  * @obj: the dma_resv object
diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h
index f5b91c292ee0..6f9bb7e4c538 100644
--- a/include/linux/dma-resv.h
+++ b/include/linux/dma-resv.h
@@ -165,6 +165,21 @@ struct dma_resv_cursor {
bool is_exclusive;
 };
 
+/**
+ * dma_resv_for_each_fence - fence iterator
+ * @obj: a dma_resv object pointer
+ * @cursor: a struct dma_resv_cursor pointer
+ * @all_fences: true if all fences should be returned
+ * @fence: the current fence
+ *
+ * Iterate over the fences in a struct dma_resv object while holding the
+ * dma_resv::lock. @all_fences controls if the shared fences are returned as
+ * well.
+ */
+#define dma_resv_for_each_fence(obj, cursor, all_fences, fence)
  \
+   for (fence = dma_resv_walk(obj, cursor, all_fences, true); fence; \
+fence = dma_resv_walk(obj, cursor, all_fences, false))
+
 /**
  * dma_resv_for_each_fence_unlocked - fence iterator
  * @obj: a dma_resv object pointer
@@ -399,6 +414,9 @@ void dma_resv_fini(struct dma_resv *obj);
 int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences);
 void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence);
 void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence);
+struct dma_fence *dma_resv_walk(struct dma_resv *obj,
+   struct dma_resv_cursor *cursor,
+   bool first, bool all_fences);
 struct dma_fence *dma_resv_walk_unlocked(struct dma_resv *obj,
 struct dma_resv_cursor *cursor,
 bool first, bool all_fences);
-- 
2.25.1



[PATCH 06/26] dma-buf: use new iterator in dma_resv_test_signaled

2021-09-13 Thread Christian König
This makes the function much simpler since the complex
retry logic is now handled elsewhere.

Signed-off-by: Christian König 
---
 drivers/dma-buf/dma-resv.c | 54 +-
 1 file changed, 7 insertions(+), 47 deletions(-)

diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index 3ce929b770ea..fefc7ec37029 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -593,22 +593,6 @@ long dma_resv_wait_timeout(struct dma_resv *obj, bool 
wait_all, bool intr,
 EXPORT_SYMBOL_GPL(dma_resv_wait_timeout);
 
 
-static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence)
-{
-   struct dma_fence *fence, *lfence = passed_fence;
-   int ret = 1;
-
-   if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) {
-   fence = dma_fence_get_rcu(lfence);
-   if (!fence)
-   return -1;
-
-   ret = !!dma_fence_is_signaled(fence);
-   dma_fence_put(fence);
-   }
-   return ret;
-}
-
 /**
  * dma_resv_test_signaled - Test if a reservation object's fences have been
  * signaled.
@@ -625,43 +609,19 @@ static inline int dma_resv_test_signaled_single(struct 
dma_fence *passed_fence)
  */
 bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all)
 {
+   struct dma_resv_cursor cursor;
struct dma_fence *fence;
-   unsigned int seq;
-   int ret;
 
rcu_read_lock();
-retry:
-   ret = true;
-   seq = read_seqcount_begin(&obj->seq);
-
-   if (test_all) {
-   struct dma_resv_list *fobj = dma_resv_shared_list(obj);
-   unsigned int i, shared_count;
-
-   shared_count = fobj ? fobj->shared_count : 0;
-   for (i = 0; i < shared_count; ++i) {
-   fence = rcu_dereference(fobj->shared[i]);
-   ret = dma_resv_test_signaled_single(fence);
-   if (ret < 0)
-   goto retry;
-   else if (!ret)
-   break;
+   dma_resv_for_each_fence_unlocked(obj, &cursor, test_all, fence) {
+   if (!dma_fence_is_signaled(fence)) {
+   rcu_read_unlock();
+   dma_fence_put(fence);
+   return false;
}
}
-
-   fence = dma_resv_excl_fence(obj);
-   if (ret && fence) {
-   ret = dma_resv_test_signaled_single(fence);
-   if (ret < 0)
-   goto retry;
-
-   }
-
-   if (read_seqcount_retry(&obj->seq, seq))
-   goto retry;
-
rcu_read_unlock();
-   return ret;
+   return true;
 }
 EXPORT_SYMBOL_GPL(dma_resv_test_signaled);
 
-- 
2.25.1



[PATCH 08/26] drm/amdgpu: use the new iterator in amdgpu_sync_resv

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 44 
 1 file changed, 14 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
index 862eb3c1c4c5..031ba20debb9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
@@ -252,41 +252,25 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct 
amdgpu_sync *sync,
 struct dma_resv *resv, enum amdgpu_sync_mode mode,
 void *owner)
 {
-   struct dma_resv_list *flist;
+   struct dma_resv_cursor cursor;
struct dma_fence *f;
-   unsigned i;
-   int r = 0;
+   int r;
 
if (resv == NULL)
return -EINVAL;
 
-   /* always sync to the exclusive fence */
-   f = dma_resv_excl_fence(resv);
-   dma_fence_chain_for_each(f, f) {
-   struct dma_fence_chain *chain = to_dma_fence_chain(f);
-
-   if (amdgpu_sync_test_fence(adev, mode, owner, chain ?
-  chain->fence : f)) {
-   r = amdgpu_sync_fence(sync, f);
-   dma_fence_put(f);
-   if (r)
-   return r;
-   break;
-   }
-   }
-
-   flist = dma_resv_shared_list(resv);
-   if (!flist)
-   return 0;
-
-   for (i = 0; i < flist->shared_count; ++i) {
-   f = rcu_dereference_protected(flist->shared[i],
- dma_resv_held(resv));
-
-   if (amdgpu_sync_test_fence(adev, mode, owner, f)) {
-   r = amdgpu_sync_fence(sync, f);
-   if (r)
-   return r;
+   dma_resv_for_each_fence(resv, &cursor, true, f) {
+   dma_fence_chain_for_each(f, f) {
+   struct dma_fence_chain *chain = to_dma_fence_chain(f);
+
+   if (amdgpu_sync_test_fence(adev, mode, owner, chain ?
+  chain->fence : f)) {
+   r = amdgpu_sync_fence(sync, f);
+   dma_fence_put(f);
+   if (r)
+   return r;
+   break;
+   }
}
}
return 0;
-- 
2.25.1



[PATCH 05/26] dma-buf: use new iterator in dma_resv_wait_timeout

2021-09-13 Thread Christian König
This makes the function much simpler since the complex
retry logic is now handled elsewhere.

Signed-off-by: Christian König 
---
 drivers/dma-buf/dma-resv.c | 64 +-
 1 file changed, 7 insertions(+), 57 deletions(-)

diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index 0a0e3ee62648..3ce929b770ea 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -571,74 +571,24 @@ long dma_resv_wait_timeout(struct dma_resv *obj, bool 
wait_all, bool intr,
   unsigned long timeout)
 {
long ret = timeout ? timeout : 1;
-   unsigned int seq, shared_count;
+   struct dma_resv_cursor cursor;
struct dma_fence *fence;
-   int i;
 
-retry:
-   shared_count = 0;
-   seq = read_seqcount_begin(&obj->seq);
rcu_read_lock();
-   i = -1;
-
-   fence = dma_resv_excl_fence(obj);
-   if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
-   if (!dma_fence_get_rcu(fence))
-   goto unlock_retry;
+   dma_resv_for_each_fence_unlocked(obj, &cursor, wait_all, fence) {
+   rcu_read_unlock();
 
-   if (dma_fence_is_signaled(fence)) {
+   ret = dma_fence_wait_timeout(fence, intr, ret);
+   if (ret <= 0) {
dma_fence_put(fence);
-   fence = NULL;
+   return ret;
}
 
-   } else {
-   fence = NULL;
-   }
-
-   if (wait_all) {
-   struct dma_resv_list *fobj = dma_resv_shared_list(obj);
-
-   if (fobj)
-   shared_count = fobj->shared_count;
-
-   for (i = 0; !fence && i < shared_count; ++i) {
-   struct dma_fence *lfence;
-
-   lfence = rcu_dereference(fobj->shared[i]);
-   if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
-&lfence->flags))
-   continue;
-
-   if (!dma_fence_get_rcu(lfence))
-   goto unlock_retry;
-
-   if (dma_fence_is_signaled(lfence)) {
-   dma_fence_put(lfence);
-   continue;
-   }
-
-   fence = lfence;
-   break;
-   }
+   rcu_read_lock();
}
-
rcu_read_unlock();
-   if (fence) {
-   if (read_seqcount_retry(&obj->seq, seq)) {
-   dma_fence_put(fence);
-   goto retry;
-   }
 
-   ret = dma_fence_wait_timeout(fence, intr, ret);
-   dma_fence_put(fence);
-   if (ret > 0 && wait_all && (i + 1 < shared_count))
-   goto retry;
-   }
return ret;
-
-unlock_retry:
-   rcu_read_unlock();
-   goto retry;
 }
 EXPORT_SYMBOL_GPL(dma_resv_wait_timeout);
 
-- 
2.25.1



[PATCH 04/26] dma-buf: use new iterator in dma_resv_get_fences v2

2021-09-13 Thread Christian König
This makes the function much simpler since the complex
retry logic is now handled elsewhere.

v2: use sizeof(void*) instead

Signed-off-by: Christian König 
---
 drivers/dma-buf/dma-resv.c | 110 +
 1 file changed, 37 insertions(+), 73 deletions(-)

diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index 9a9c0bba772b..0a0e3ee62648 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -493,99 +493,63 @@ EXPORT_SYMBOL(dma_resv_copy_fences);
  * dma_resv_get_fences - Get an object's shared and exclusive
  * fences without update side lock held
  * @obj: the reservation object
- * @pfence_excl: the returned exclusive fence (or NULL)
- * @pshared_count: the number of shared fences returned
- * @pshared: the array of shared fence ptrs returned (array is krealloc'd to
+ * @fence_excl: the returned exclusive fence (or NULL)
+ * @shared_count: the number of shared fences returned
+ * @shared: the array of shared fence ptrs returned (array is krealloc'd to
  * the required size, and must be freed by caller)
  *
  * Retrieve all fences from the reservation object. If the pointer for the
  * exclusive fence is not specified the fence is put into the array of the
  * shared fences as well. Returns either zero or -ENOMEM.
  */
-int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl,
-   unsigned int *pshared_count,
-   struct dma_fence ***pshared)
+int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **fence_excl,
+   unsigned int *shared_count, struct dma_fence ***shared)
 {
-   struct dma_fence **shared = NULL;
-   struct dma_fence *fence_excl;
-   unsigned int shared_count;
-   int ret = 1;
-
-   do {
-   struct dma_resv_list *fobj;
-   unsigned int i, seq;
-   size_t sz = 0;
-
-   shared_count = i = 0;
-
-   rcu_read_lock();
-   seq = read_seqcount_begin(&obj->seq);
-
-   fence_excl = dma_resv_excl_fence(obj);
-   if (fence_excl && !dma_fence_get_rcu(fence_excl))
-   goto unlock;
+   struct dma_resv_cursor cursor;
+   struct dma_fence *fence;
 
-   fobj = dma_resv_shared_list(obj);
-   if (fobj)
-   sz += sizeof(*shared) * fobj->shared_max;
+   *shared_count = 0;
+   *shared = NULL;
 
-   if (!pfence_excl && fence_excl)
-   sz += sizeof(*shared);
+   if (fence_excl)
+   *fence_excl = NULL;
 
-   if (sz) {
-   struct dma_fence **nshared;
+   rcu_read_lock();
+   dma_resv_for_each_fence_unlocked(obj, &cursor, true, fence) {
 
-   nshared = krealloc(shared, sz,
-  GFP_NOWAIT | __GFP_NOWARN);
-   if (!nshared) {
-   rcu_read_unlock();
+   if (cursor.is_first) {
+   unsigned int count;
 
-   dma_fence_put(fence_excl);
-   fence_excl = NULL;
+   while (*shared_count)
+   dma_fence_put((*shared)[--(*shared_count)]);
 
-   nshared = krealloc(shared, sz, GFP_KERNEL);
-   if (nshared) {
-   shared = nshared;
-   continue;
-   }
+   if (fence_excl)
+   dma_fence_put(*fence_excl);
 
-   ret = -ENOMEM;
-   break;
-   }
-   shared = nshared;
-   shared_count = fobj ? fobj->shared_count : 0;
-   for (i = 0; i < shared_count; ++i) {
-   shared[i] = rcu_dereference(fobj->shared[i]);
-   if (!dma_fence_get_rcu(shared[i]))
-   break;
-   }
-   }
+   count = cursor.fences ? cursor.fences->shared_count : 0;
+   count += fence_excl ? 0 : 1;
+   rcu_read_unlock();
 
-   if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
-   while (i--)
-   dma_fence_put(shared[i]);
-   dma_fence_put(fence_excl);
-   goto unlock;
+   /* Eventually re-allocate the array */
+   *shared = krealloc_array(*shared, count,
+sizeof(void*),
+GFP_KERNEL);
+   if (count && !*shared)
+   

[PATCH 13/26] drm/i915: use the new iterator in i915_gem_busy_ioctl

2021-09-13 Thread Christian König
This makes the function much simpler since the complex
retry logic is now handled else where.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/i915/gem/i915_gem_busy.c | 30 +++-
 1 file changed, 9 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_busy.c 
b/drivers/gpu/drm/i915/gem/i915_gem_busy.c
index 6234e17259c1..c6c6d747b33e 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_busy.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_busy.c
@@ -82,8 +82,8 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 {
struct drm_i915_gem_busy *args = data;
struct drm_i915_gem_object *obj;
-   struct dma_resv_list *list;
-   unsigned int seq;
+   struct dma_resv_cursor cursor;
+   struct dma_fence *fence;
int err;
 
err = -ENOENT;
@@ -109,28 +109,16 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 * to report the overall busyness. This is what the wait-ioctl does.
 *
 */
-retry:
-   seq = raw_read_seqcount(&obj->base.resv->seq);
-
-   /* Translate the exclusive fence to the READ *and* WRITE engine */
-   args->busy = busy_check_writer(dma_resv_excl_fence(obj->base.resv));
-
-   /* Translate shared fences to READ set of engines */
-   list = dma_resv_shared_list(obj->base.resv);
-   if (list) {
-   unsigned int shared_count = list->shared_count, i;
-
-   for (i = 0; i < shared_count; ++i) {
-   struct dma_fence *fence =
-   rcu_dereference(list->shared[i]);
-
+   args->busy = false;
+   dma_resv_for_each_fence_unlocked(obj->base.resv, &cursor, true, fence) {
+   if (cursor.is_exclusive)
+   /* Translate the exclusive fence to the READ *and* 
WRITE engine */
+   args->busy = busy_check_writer(fence);
+   else
+   /* Translate shared fences to READ set of engines */
args->busy |= busy_check_reader(fence);
-   }
}
 
-   if (args->busy && read_seqcount_retry(&obj->base.resv->seq, seq))
-   goto retry;
-
err = 0;
 out:
rcu_read_unlock();
-- 
2.25.1



[PATCH 14/26] drm/i915: use the new iterator in i915_sw_fence_await_reservation

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/i915/i915_sw_fence.c | 52 ++--
 1 file changed, 10 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c 
b/drivers/gpu/drm/i915/i915_sw_fence.c
index c589a681da77..09d2c9f96c52 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence.c
+++ b/drivers/gpu/drm/i915/i915_sw_fence.c
@@ -572,56 +572,24 @@ int i915_sw_fence_await_reservation(struct i915_sw_fence 
*fence,
unsigned long timeout,
gfp_t gfp)
 {
-   struct dma_fence *excl;
+   struct dma_resv_cursor cursor;
+   struct dma_fence *f;
int ret = 0, pending;
 
debug_fence_assert(fence);
might_sleep_if(gfpflags_allow_blocking(gfp));
 
-   if (write) {
-   struct dma_fence **shared;
-   unsigned int count, i;
-
-   ret = dma_resv_get_fences(resv, &excl, &count, &shared);
-   if (ret)
-   return ret;
-
-   for (i = 0; i < count; i++) {
-   if (shared[i]->ops == exclude)
-   continue;
-
-   pending = i915_sw_fence_await_dma_fence(fence,
-   shared[i],
-   timeout,
-   gfp);
-   if (pending < 0) {
-   ret = pending;
-   break;
-   }
-
-   ret |= pending;
-   }
-
-   for (i = 0; i < count; i++)
-   dma_fence_put(shared[i]);
-   kfree(shared);
-   } else {
-   excl = dma_resv_get_excl_unlocked(resv);
-   }
-
-   if (ret >= 0 && excl && excl->ops != exclude) {
-   pending = i915_sw_fence_await_dma_fence(fence,
-   excl,
-   timeout,
+   dma_resv_for_each_fence_unlocked(resv, &cursor, write, f) {
+   pending = i915_sw_fence_await_dma_fence(fence, f, timeout,
gfp);
-   if (pending < 0)
+   if (pending < 0) {
ret = pending;
-   else
-   ret |= pending;
-   }
-
-   dma_fence_put(excl);
+   dma_fence_put(f);
+   break;
+   }
 
+   ret |= pending;
+   }
return ret;
 }
 
-- 
2.25.1



[PATCH 07/26] drm/ttm: use the new iterator in ttm_bo_flush_all_fences

2021-09-13 Thread Christian König
This is probably a fix since we didn't even grabed a reference to the
fences.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/ttm/ttm_bo.c | 12 ++--
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 0a3127436f61..5dd0c3dfec3c 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -269,19 +269,11 @@ static int ttm_bo_individualize_resv(struct 
ttm_buffer_object *bo)
 static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo)
 {
struct dma_resv *resv = &bo->base._resv;
-   struct dma_resv_list *fobj;
+   struct dma_resv_cursor cursor;
struct dma_fence *fence;
-   int i;
 
rcu_read_lock();
-   fobj = dma_resv_shared_list(resv);
-   fence = dma_resv_excl_fence(resv);
-   if (fence && !fence->ops->signaled)
-   dma_fence_enable_sw_signaling(fence);
-
-   for (i = 0; fobj && i < fobj->shared_count; ++i) {
-   fence = rcu_dereference(fobj->shared[i]);
-
+   dma_resv_for_each_fence_unlocked(resv, &cursor, true, fence) {
if (!fence->ops->signaled)
dma_fence_enable_sw_signaling(fence);
}
-- 
2.25.1



[PATCH 10/26] drm/msm: use new iterator in msm_gem_describe

2021-09-13 Thread Christian König
Simplifying the code a bit. Also drop the RCU read side lock since the
object is locked anyway.

Untested since I can't get the driver to compile on !ARM.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/msm/msm_gem.c | 19 +--
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 5db07fc287ad..8ee4e8881b03 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -906,7 +906,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct 
seq_file *m,
 {
struct msm_gem_object *msm_obj = to_msm_bo(obj);
struct dma_resv *robj = obj->resv;
-   struct dma_resv_list *fobj;
+   struct dma_resv_cursor cursor;
struct dma_fence *fence;
struct msm_gem_vma *vma;
uint64_t off = drm_vma_node_start(&obj->vma_node);
@@ -981,22 +981,13 @@ void msm_gem_describe(struct drm_gem_object *obj, struct 
seq_file *m,
seq_puts(m, "\n");
}
 
-   rcu_read_lock();
-   fobj = dma_resv_shared_list(robj);
-   if (fobj) {
-   unsigned int i, shared_count = fobj->shared_count;
-
-   for (i = 0; i < shared_count; i++) {
-   fence = rcu_dereference(fobj->shared[i]);
+   dma_resv_for_each_fence(robj, &cursor, true, fence) {
+   if (cursor.is_exclusive)
+   describe_fence(fence, "Exclusive", m);
+   else
describe_fence(fence, "Shared", m);
-   }
}
 
-   fence = dma_resv_excl_fence(robj);
-   if (fence)
-   describe_fence(fence, "Exclusive", m);
-   rcu_read_unlock();
-
msm_gem_unlock(obj);
 }
 
-- 
2.25.1



[PATCH 12/26] drm/scheduler: use new iterator in drm_sched_job_add_implicit_dependencies

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/scheduler/sched_main.c | 26 +++---
 1 file changed, 7 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/scheduler/sched_main.c 
b/drivers/gpu/drm/scheduler/sched_main.c
index 6987d412a946..b64b673ed040 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -699,29 +699,17 @@ int drm_sched_job_add_implicit_dependencies(struct 
drm_sched_job *job,
struct drm_gem_object *obj,
bool write)
 {
+   struct dma_resv_cursor cursor;
+   struct dma_fence *fence;
int ret;
-   struct dma_fence **fences;
-   unsigned int i, fence_count;
-
-   if (!write) {
-   struct dma_fence *fence = dma_resv_get_excl_unlocked(obj->resv);
 
-   return drm_sched_job_add_dependency(job, fence);
-   }
-
-   ret = dma_resv_get_fences(obj->resv, NULL, &fence_count, &fences);
-   if (ret || !fence_count)
-   return ret;
-
-   for (i = 0; i < fence_count; i++) {
-   ret = drm_sched_job_add_dependency(job, fences[i]);
-   if (ret)
+   dma_resv_for_each_fence_unlocked(obj->resv, &cursor, write, fence) {
+   ret = drm_sched_job_add_dependency(job, fence);
+   if (ret) {
+   dma_fence_put(fence);
break;
+   }
}
-
-   for (; i < fence_count; i++)
-   dma_fence_put(fences[i]);
-   kfree(fences);
return ret;
 }
 EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies);
-- 
2.25.1



[PATCH 20/26] drm: use new iterator in drm_gem_fence_array_add_implicit

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/drm_gem.c | 30 --
 1 file changed, 8 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 09c820045859..6e3b8491be68 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1340,31 +1340,17 @@ int drm_gem_fence_array_add_implicit(struct xarray 
*fence_array,
 struct drm_gem_object *obj,
 bool write)
 {
-   int ret;
-   struct dma_fence **fences;
-   unsigned int i, fence_count;
-
-   if (!write) {
-   struct dma_fence *fence =
-   dma_resv_get_excl_unlocked(obj->resv);
-
-   return drm_gem_fence_array_add(fence_array, fence);
-   }
-
-   ret = dma_resv_get_fences(obj->resv, NULL,
-   &fence_count, &fences);
-   if (ret || !fence_count)
-   return ret;
+   struct dma_resv_cursor cursor;
+   struct dma_fence *fence;
+   int ret = 0;
 
-   for (i = 0; i < fence_count; i++) {
-   ret = drm_gem_fence_array_add(fence_array, fences[i]);
-   if (ret)
+   dma_resv_for_each_fence_unlocked(obj->resv, &cursor, write, fence) {
+   ret = drm_gem_fence_array_add(fence_array, fence);
+   if (ret) {
+   dma_fence_put(fence);
break;
+   }
}
-
-   for (; i < fence_count; i++)
-   dma_fence_put(fences[i]);
-   kfree(fences);
return ret;
 }
 EXPORT_SYMBOL(drm_gem_fence_array_add_implicit);
-- 
2.25.1



[PATCH 23/26] drm/nouveau: use the new interator in nv50_wndw_prepare_fb

2021-09-13 Thread Christian König
Makes the handling a bit more complex, but avoids the use of
dma_resv_get_excl_unlocked().

Signed-off-by: Christian König 
---
 drivers/gpu/drm/nouveau/dispnv50/wndw.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c 
b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index 8d048bacd6f0..9a0c42d38a47 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -539,6 +539,8 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct 
drm_plane_state *state)
struct nouveau_bo *nvbo;
struct nv50_head_atom *asyh;
struct nv50_wndw_ctxdma *ctxdma;
+   struct dma_resv_cursor cursor;
+   struct dma_fence *fence;
int ret;
 
NV_ATOMIC(drm, "%s prepare: %p\n", plane->name, fb);
@@ -561,7 +563,12 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct 
drm_plane_state *state)
asyw->image.handle[0] = ctxdma->object.handle;
}
 
-   asyw->state.fence = dma_resv_get_excl_unlocked(nvbo->bo.base.resv);
+   dma_resv_for_each_fence_unlocked(nvbo->bo.base.resv, &cursor, false,
+fence) {
+   /* TODO: We only use the first writer here */
+   asyw->state.fence = fence;
+   break;
+   }
asyw->image.offset[0] = nvbo->offset;
 
if (wndw->func->prepare) {
-- 
2.25.1



[PATCH 09/26] drm/amdgpu: use new iterator in amdgpu_ttm_bo_eviction_valuable

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 14 --
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 489e22190e29..0a927006ba9c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -1332,10 +1332,9 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct 
ttm_buffer_object *bo,
const struct ttm_place *place)
 {
unsigned long num_pages = bo->resource->num_pages;
+   struct dma_resv_cursor resv_cursor;
struct amdgpu_res_cursor cursor;
-   struct dma_resv_list *flist;
struct dma_fence *f;
-   int i;
 
/* Swapout? */
if (bo->resource->mem_type == TTM_PL_SYSTEM)
@@ -1349,14 +1348,9 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct 
ttm_buffer_object *bo,
 * If true, then return false as any KFD process needs all its BOs to
 * be resident to run successfully
 */
-   flist = dma_resv_shared_list(bo->base.resv);
-   if (flist) {
-   for (i = 0; i < flist->shared_count; ++i) {
-   f = rcu_dereference_protected(flist->shared[i],
-   dma_resv_held(bo->base.resv));
-   if (amdkfd_fence_check_mm(f, current->mm))
-   return false;
-   }
+   dma_resv_for_each_fence(bo->base.resv, &resv_cursor, true, f) {
+   if (amdkfd_fence_check_mm(f, current->mm))
+   return false;
}
 
switch (bo->resource->mem_type) {
-- 
2.25.1



[PATCH 22/26] drm/nouveau: use the new iterator in nouveau_fence_sync

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/nouveau/nouveau_fence.c | 48 +++--
 1 file changed, 12 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c 
b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 05d0b3eb3690..dc8d7ca1e239 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -339,14 +339,15 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool 
lazy, bool intr)
 }
 
 int
-nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool 
exclusive, bool intr)
+nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
+  bool exclusive, bool intr)
 {
struct nouveau_fence_chan *fctx = chan->fence;
-   struct dma_fence *fence;
struct dma_resv *resv = nvbo->bo.base.resv;
-   struct dma_resv_list *fobj;
+   struct dma_resv_cursor cursor;
+   struct dma_fence *fence;
struct nouveau_fence *f;
-   int ret = 0, i;
+   int ret;
 
if (!exclusive) {
ret = dma_resv_reserve_shared(resv, 1);
@@ -355,10 +356,7 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct 
nouveau_channel *chan, bool e
return ret;
}
 
-   fobj = dma_resv_shared_list(resv);
-   fence = dma_resv_excl_fence(resv);
-
-   if (fence) {
+   dma_resv_for_each_fence(resv, &cursor, exclusive, fence) {
struct nouveau_channel *prev = NULL;
bool must_wait = true;
 
@@ -366,41 +364,19 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct 
nouveau_channel *chan, bool e
if (f) {
rcu_read_lock();
prev = rcu_dereference(f->channel);
-   if (prev && (prev == chan || fctx->sync(f, prev, chan) 
== 0))
+   if (prev && (prev == chan ||
+fctx->sync(f, prev, chan) == 0))
must_wait = false;
rcu_read_unlock();
}
 
-   if (must_wait)
+   if (must_wait) {
ret = dma_fence_wait(fence, intr);
-
-   return ret;
-   }
-
-   if (!exclusive || !fobj)
-   return ret;
-
-   for (i = 0; i < fobj->shared_count && !ret; ++i) {
-   struct nouveau_channel *prev = NULL;
-   bool must_wait = true;
-
-   fence = rcu_dereference_protected(fobj->shared[i],
-   dma_resv_held(resv));
-
-   f = nouveau_local_fence(fence, chan->drm);
-   if (f) {
-   rcu_read_lock();
-   prev = rcu_dereference(f->channel);
-   if (prev && (prev == chan || fctx->sync(f, prev, chan) 
== 0))
-   must_wait = false;
-   rcu_read_unlock();
+   if (ret)
+   return ret;
}
-
-   if (must_wait)
-   ret = dma_fence_wait(fence, intr);
}
-
-   return ret;
+   return 0;
 }
 
 void
-- 
2.25.1



[PATCH 15/26] drm/i915: use the new iterator in i915_request_await_object

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/i915/i915_request.c | 36 ++---
 1 file changed, 7 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_request.c 
b/drivers/gpu/drm/i915/i915_request.c
index 37aef1308573..b81045ceb619 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -1583,38 +1583,16 @@ i915_request_await_object(struct i915_request *to,
  struct drm_i915_gem_object *obj,
  bool write)
 {
-   struct dma_fence *excl;
+   struct dma_resv_cursor cursor;
+   struct dma_fence *fence;
int ret = 0;
 
-   if (write) {
-   struct dma_fence **shared;
-   unsigned int count, i;
-
-   ret = dma_resv_get_fences(obj->base.resv, &excl, &count,
- &shared);
-   if (ret)
-   return ret;
-
-   for (i = 0; i < count; i++) {
-   ret = i915_request_await_dma_fence(to, shared[i]);
-   if (ret)
-   break;
-
-   dma_fence_put(shared[i]);
+   dma_resv_for_each_fence_unlocked(obj->base.resv, &cursor, write, fence) 
{
+   ret = i915_request_await_dma_fence(to, fence);
+   if (ret) {
+   dma_fence_put(fence);
+   break;
}
-
-   for (; i < count; i++)
-   dma_fence_put(shared[i]);
-   kfree(shared);
-   } else {
-   excl = dma_resv_get_excl_unlocked(obj->base.resv);
-   }
-
-   if (excl) {
-   if (ret == 0)
-   ret = i915_request_await_dma_fence(to, excl);
-
-   dma_fence_put(excl);
}
 
return ret;
-- 
2.25.1



[PATCH 17/26] drm/i915: use new iterator in i915_gem_object_wait_priority

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/i915/gem/i915_gem_wait.c | 29 
 1 file changed, 5 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c 
b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
index 13174541f6c8..e2173a55e527 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
@@ -120,31 +120,12 @@ i915_gem_object_wait_priority(struct drm_i915_gem_object 
*obj,
  unsigned int flags,
  const struct i915_sched_attr *attr)
 {
-   struct dma_fence *excl;
-
-   if (flags & I915_WAIT_ALL) {
-   struct dma_fence **shared;
-   unsigned int count, i;
-   int ret;
-
-   ret = dma_resv_get_fences(obj->base.resv, &excl, &count,
- &shared);
-   if (ret)
-   return ret;
-
-   for (i = 0; i < count; i++) {
-   i915_gem_fence_wait_priority(shared[i], attr);
-   dma_fence_put(shared[i]);
-   }
-
-   kfree(shared);
-   } else {
-   excl = dma_resv_get_excl_unlocked(obj->base.resv);
-   }
+   struct dma_resv_cursor cursor;
+   struct dma_fence *fence;
 
-   if (excl) {
-   i915_gem_fence_wait_priority(excl, attr);
-   dma_fence_put(excl);
+   dma_resv_for_each_fence_unlocked(obj->base.resv, &cursor,
+flags & I915_WAIT_ALL, fence) {
+   i915_gem_fence_wait_priority(fence, attr);
}
return 0;
 }
-- 
2.25.1



[PATCH 18/26] drm/i915: use new iterator in i915_gem_object_last_write_engine

2021-09-13 Thread Christian König
This is maybe even a fix since the RCU usage here looks incorrect.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/i915/gem/i915_gem_object.h | 15 +++
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h 
b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index e9eecebf5c9d..3343922af4d6 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -500,16 +500,15 @@ static inline struct intel_engine_cs *
 i915_gem_object_last_write_engine(struct drm_i915_gem_object *obj)
 {
struct intel_engine_cs *engine = NULL;
+   struct dma_resv_cursor cursor;
struct dma_fence *fence;
 
-   rcu_read_lock();
-   fence = dma_resv_get_excl_unlocked(obj->base.resv);
-   rcu_read_unlock();
-
-   if (fence && dma_fence_is_i915(fence) && !dma_fence_is_signaled(fence))
-   engine = to_request(fence)->engine;
-   dma_fence_put(fence);
-
+   dma_resv_for_each_fence_unlocked(obj->base.resv, &cursor, false,
+fence) {
+   if (fence && dma_fence_is_i915(fence) &&
+   !dma_fence_is_signaled(fence))
+   engine = to_request(fence)->engine;
+   }
return engine;
 }
 
-- 
2.25.1



[PATCH 16/26] drm/i915: use new iterator in i915_gem_object_wait_reservation

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/i915/gem/i915_gem_wait.c | 49 +---
 1 file changed, 9 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c 
b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
index 1e97520c62b2..13174541f6c8 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
@@ -37,55 +37,24 @@ i915_gem_object_wait_reservation(struct dma_resv *resv,
 unsigned int flags,
 long timeout)
 {
-   struct dma_fence *excl;
-   bool prune_fences = false;
+   struct dma_resv_cursor cursor;
+   struct dma_fence *fence;
 
-   if (flags & I915_WAIT_ALL) {
-   struct dma_fence **shared;
-   unsigned int count, i;
-   int ret;
+   dma_resv_for_each_fence_unlocked(resv, &cursor, flags & I915_WAIT_ALL,
+fence) {
 
-   ret = dma_resv_get_fences(resv, &excl, &count, &shared);
-   if (ret)
-   return ret;
-
-   for (i = 0; i < count; i++) {
-   timeout = i915_gem_object_wait_fence(shared[i],
-flags, timeout);
-   if (timeout < 0)
-   break;
-
-   dma_fence_put(shared[i]);
+   timeout = i915_gem_object_wait_fence(fence, flags, timeout);
+   if (timeout < 0) {
+   dma_fence_put(fence);
+   break;
}
-
-   for (; i < count; i++)
-   dma_fence_put(shared[i]);
-   kfree(shared);
-
-   /*
-* If both shared fences and an exclusive fence exist,
-* then by construction the shared fences must be later
-* than the exclusive fence. If we successfully wait for
-* all the shared fences, we know that the exclusive fence
-* must all be signaled. If all the shared fences are
-* signaled, we can prune the array and recover the
-* floating references on the fences/requests.
-*/
-   prune_fences = count && timeout >= 0;
-   } else {
-   excl = dma_resv_get_excl_unlocked(resv);
}
 
-   if (excl && timeout >= 0)
-   timeout = i915_gem_object_wait_fence(excl, flags, timeout);
-
-   dma_fence_put(excl);
-
/*
 * Opportunistically prune the fences iff we know they have *all* been
 * signaled.
 */
-   if (prune_fences)
+   if (timeout > 0)
dma_resv_prune(resv);
 
return timeout;
-- 
2.25.1



[PATCH 21/26] drm: use new iterator in drm_gem_plane_helper_prepare_fb

2021-09-13 Thread Christian König
Makes the handling a bit more complex, but avoids the use of
dma_resv_get_excl_unlocked().

Signed-off-by: Christian König 
---
 drivers/gpu/drm/drm_gem_atomic_helper.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c 
b/drivers/gpu/drm/drm_gem_atomic_helper.c
index e570398abd78..9f51fef82644 100644
--- a/drivers/gpu/drm/drm_gem_atomic_helper.c
+++ b/drivers/gpu/drm/drm_gem_atomic_helper.c
@@ -143,6 +143,7 @@
  */
 int drm_gem_plane_helper_prepare_fb(struct drm_plane *plane, struct 
drm_plane_state *state)
 {
+   struct dma_resv_cursor cursor;
struct drm_gem_object *obj;
struct dma_fence *fence;
 
@@ -150,9 +151,13 @@ int drm_gem_plane_helper_prepare_fb(struct drm_plane 
*plane, struct drm_plane_st
return 0;
 
obj = drm_gem_fb_get_obj(state->fb, 0);
-   fence = dma_resv_get_excl_unlocked(obj->resv);
-   drm_atomic_set_fence_for_plane(state, fence);
+   dma_resv_for_each_fence_unlocked(obj->resv, &cursor, false, fence) {
+   /* TODO: We only use the first write fence here */
+   drm_atomic_set_fence_for_plane(state, fence);
+   return 0;
+   }
 
+   drm_atomic_set_fence_for_plane(state, NULL);
return 0;
 }
 EXPORT_SYMBOL_GPL(drm_gem_plane_helper_prepare_fb);
-- 
2.25.1



[PATCH 11/26] drm/radeon: use new iterator in radeon_sync_resv

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/radeon/radeon_sync.c | 22 +++---
 1 file changed, 3 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_sync.c 
b/drivers/gpu/drm/radeon/radeon_sync.c
index 9257b60144c4..14a4d8135bad 100644
--- a/drivers/gpu/drm/radeon/radeon_sync.c
+++ b/drivers/gpu/drm/radeon/radeon_sync.c
@@ -91,33 +91,17 @@ int radeon_sync_resv(struct radeon_device *rdev,
 struct dma_resv *resv,
 bool shared)
 {
-   struct dma_resv_list *flist;
-   struct dma_fence *f;
+   struct dma_resv_cursor cursor;
struct radeon_fence *fence;
-   unsigned i;
+   struct dma_fence *f;
int r = 0;
 
-   /* always sync to the exclusive fence */
-   f = dma_resv_excl_fence(resv);
-   fence = f ? to_radeon_fence(f) : NULL;
-   if (fence && fence->rdev == rdev)
-   radeon_sync_fence(sync, fence);
-   else if (f)
-   r = dma_fence_wait(f, true);
-
-   flist = dma_resv_shared_list(resv);
-   if (shared || !flist || r)
-   return r;
-
-   for (i = 0; i < flist->shared_count; ++i) {
-   f = rcu_dereference_protected(flist->shared[i],
- dma_resv_held(resv));
+   dma_resv_for_each_fence(resv, &cursor, shared, f) {
fence = to_radeon_fence(f);
if (fence && fence->rdev == rdev)
radeon_sync_fence(sync, fence);
else
r = dma_fence_wait(f, true);
-
if (r)
break;
}
-- 
2.25.1



[PATCH 19/26] drm/i915: use new cursor in intel_prepare_plane_fb

2021-09-13 Thread Christian König
Simplifying the code a bit.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/i915/display/intel_display.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c 
b/drivers/gpu/drm/i915/display/intel_display.c
index eec6c9e9cda7..11c38e0f7fe0 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -11133,6 +11133,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane,
i915_gem_object_flush_frontbuffer(obj, ORIGIN_DIRTYFB);
 
if (!new_plane_state->uapi.fence) { /* implicit fencing */
+   struct dma_resv_cursor cursor;
struct dma_fence *fence;
 
ret = i915_sw_fence_await_reservation(&state->commit_ready,
@@ -11143,11 +11144,10 @@ intel_prepare_plane_fb(struct drm_plane *_plane,
if (ret < 0)
goto unpin_fb;
 
-   fence = dma_resv_get_excl_unlocked(obj->base.resv);
-   if (fence) {
+   dma_resv_for_each_fence_unlocked(obj->base.resv, &cursor, false,
+fence) {
add_rps_boost_after_vblank(new_plane_state->hw.crtc,
   fence);
-   dma_fence_put(fence);
}
} else {
add_rps_boost_after_vblank(new_plane_state->hw.crtc,
-- 
2.25.1



[PATCH 25/26] drm/etnaviv: replace dma_resv_get_excl_unlocked

2021-09-13 Thread Christian König
We certainly hold the reservation lock here, no need for the RCU dance.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 4dd7d9d541c0..7e17bc2b5df1 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -195,7 +195,7 @@ static int submit_fence_sync(struct etnaviv_gem_submit 
*submit)
if (ret)
return ret;
} else {
-   bo->excl = dma_resv_get_excl_unlocked(robj);
+   bo->excl = dma_fence_get(dma_resv_excl_fence(robj));
}
 
}
-- 
2.25.1



[PATCH 26/26] dma-buf: nuke dma_resv_get_excl_unlocked

2021-09-13 Thread Christian König
Heureka, that's finally not used any more.

Signed-off-by: Christian König 
---
 include/linux/dma-resv.h | 26 --
 1 file changed, 26 deletions(-)

diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h
index 6f9bb7e4c538..90c15cbe7d92 100644
--- a/include/linux/dma-resv.h
+++ b/include/linux/dma-resv.h
@@ -370,32 +370,6 @@ dma_resv_excl_fence(struct dma_resv *obj)
return rcu_dereference_check(obj->fence_excl, dma_resv_held(obj));
 }
 
-/**
- * dma_resv_get_excl_unlocked - get the reservation object's
- * exclusive fence, without lock held.
- * @obj: the reservation object
- *
- * If there is an exclusive fence, this atomically increments it's
- * reference count and returns it.
- *
- * RETURNS
- * The exclusive fence or NULL if none
- */
-static inline struct dma_fence *
-dma_resv_get_excl_unlocked(struct dma_resv *obj)
-{
-   struct dma_fence *fence;
-
-   if (!rcu_access_pointer(obj->fence_excl))
-   return NULL;
-
-   rcu_read_lock();
-   fence = dma_fence_get_rcu_safe(&obj->fence_excl);
-   rcu_read_unlock();
-
-   return fence;
-}
-
 /**
  * dma_resv_shared_list - get the reservation object's shared fence list
  * @obj: the reservation object
-- 
2.25.1



[PATCH 24/26] drm/etnaviv: use new iterator in etnaviv_gem_describe

2021-09-13 Thread Christian König
Instead of hand rolling the logic.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 27 +--
 1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index b8fa6ed3dd73..6808dbef5c79 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -437,19 +437,17 @@ int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct 
drm_gem_object *obj,
 static void etnaviv_gem_describe_fence(struct dma_fence *fence,
const char *type, struct seq_file *m)
 {
-   if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
-   seq_printf(m, "\t%9s: %s %s seq %llu\n",
-  type,
-  fence->ops->get_driver_name(fence),
-  fence->ops->get_timeline_name(fence),
-  fence->seqno);
+   seq_printf(m, "\t%9s: %s %s seq %llu\n", type,
+  fence->ops->get_driver_name(fence),
+  fence->ops->get_timeline_name(fence),
+  fence->seqno);
 }
 
 static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file 
*m)
 {
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
struct dma_resv *robj = obj->resv;
-   struct dma_resv_list *fobj;
+   struct dma_resv_cursor cursor;
struct dma_fence *fence;
unsigned long off = drm_vma_node_start(&obj->vma_node);
 
@@ -459,19 +457,12 @@ static void etnaviv_gem_describe(struct drm_gem_object 
*obj, struct seq_file *m)
off, etnaviv_obj->vaddr, obj->size);
 
rcu_read_lock();
-   fobj = dma_resv_shared_list(robj);
-   if (fobj) {
-   unsigned int i, shared_count = fobj->shared_count;
-
-   for (i = 0; i < shared_count; i++) {
-   fence = rcu_dereference(fobj->shared[i]);
+   dma_resv_for_each_fence_unlocked(robj, &cursor, true, fence) {
+   if (cursor.is_exclusive)
+   etnaviv_gem_describe_fence(fence, "Exclusive", m);
+   else
etnaviv_gem_describe_fence(fence, "Shared", m);
-   }
}
-
-   fence = dma_resv_excl_fence(robj);
-   if (fence)
-   etnaviv_gem_describe_fence(fence, "Exclusive", m);
rcu_read_unlock();
 }
 
-- 
2.25.1



[PATCH] drm/rockchip: add DRM_BRIDGE_ATTACH_NO_CONNECTOR flag to drm_bridge_attach

2021-09-13 Thread Alex Bee
Commit a25b988ff83f ("drm/bridge: Extend bridge API to disable connector 
creation")
added DRM_BRIDGE_ATTACH_NO_CONNECTOR bridge flag and all bridges handle
this flag in some way since then.
Newly added bridge drivers must no longer contain the connector creation and
will fail probing if this flag isn't set.

In order to be able to connect to those newly added bridges as well,
make use of drm_bridge_connector API and have the connector initialized
by the display controller.

Signed-off-by: Alex Bee 
---
 drivers/gpu/drm/rockchip/rockchip_lvds.c | 29 
 drivers/gpu/drm/rockchip/rockchip_rgb.c  | 26 -
 2 files changed, 45 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c 
b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 551653940e39..e3953c72fbdb 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -19,6 +19,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -612,9 +613,9 @@ static int rockchip_lvds_bind(struct device *dev, struct 
device *master,
}
 
drm_encoder_helper_add(encoder, lvds->soc_data->helper_funcs);
+   connector = &lvds->connector;
 
if (lvds->panel) {
-   connector = &lvds->connector;
connector->dpms = DRM_MODE_DPMS_OFF;
ret = drm_connector_init(drm_dev, connector,
 &rockchip_lvds_connector_funcs,
@@ -627,17 +628,27 @@ static int rockchip_lvds_bind(struct device *dev, struct 
device *master,
 
drm_connector_helper_add(connector,
 &rockchip_lvds_connector_helper_funcs);
-
-   ret = drm_connector_attach_encoder(connector, encoder);
-   if (ret < 0) {
-   DRM_DEV_ERROR(drm_dev->dev,
- "failed to attach encoder: %d\n", ret);
-   goto err_free_connector;
-   }
} else {
-   ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0);
+   ret = drm_bridge_attach(encoder, lvds->bridge, NULL,
+   DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
goto err_free_encoder;
+
+   connector = drm_bridge_connector_init(lvds->drm_dev, encoder);
+   if (IS_ERR(connector)) {
+   DRM_DEV_ERROR(drm_dev->dev,
+ "failed to initialize bridge connector: 
%pe\n",
+ connector);
+   ret = PTR_ERR(connector);
+   goto err_free_encoder;
+   }
+   }
+
+   ret = drm_connector_attach_encoder(connector, encoder);
+   if (ret < 0) {
+   DRM_DEV_ERROR(drm_dev->dev,
+ "failed to attach encoder: %d\n", ret);
+   goto err_free_connector;
}
 
pm_runtime_enable(dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c 
b/drivers/gpu/drm/rockchip/rockchip_rgb.c
index d691d9bef8e7..09be9678f2bd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -10,6 +10,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -27,6 +28,7 @@ struct rockchip_rgb {
struct drm_device *drm_dev;
struct drm_bridge *bridge;
struct drm_encoder encoder;
+   struct drm_connector connector;
int output_mode;
 };
 
@@ -80,6 +82,7 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
int ret = 0, child_count = 0;
struct drm_panel *panel;
struct drm_bridge *bridge;
+   struct drm_connector *connector;
 
rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL);
if (!rgb)
@@ -142,12 +145,32 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
 
rgb->bridge = bridge;
 
-   ret = drm_bridge_attach(encoder, rgb->bridge, NULL, 0);
+   ret = drm_bridge_attach(encoder, rgb->bridge, NULL,
+   DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
goto err_free_encoder;
 
+   connector = &rgb->connector;
+   connector = drm_bridge_connector_init(rgb->drm_dev, encoder);
+   if (IS_ERR(connector)) {
+   DRM_DEV_ERROR(drm_dev->dev,
+ "failed to initialize bridge connector: %pe\n",
+ connector);
+   ret = PTR_ERR(connector);
+   goto err_free_encoder;
+   }
+
+   ret = drm_connector_attach_encoder(connector, encoder);
+   if (ret < 0) {
+   DRM_DEV_ERROR(drm_dev->dev,
+ "failed to attach encoder: %d\n", ret);
+   goto err_free_connector;
+   }
+
return rgb;
 
+err_free_connector:
+   drm_connector_cleanup(connector);
 err_fr

Re: [PATCH v2 2/2] drm/msm/dpu: Fix timeout issues on command mode panels

2021-09-13 Thread Marijn Suijten
On 2021-09-11 18:39:19, AngeloGioacchino Del Regno wrote:
> In function dpu_encoder_phys_cmd_wait_for_commit_done we are always
> checking if the relative CTL is started by waiting for an interrupt
> to fire: it is fine to do that, but then sometimes we call this
> function while the CTL is up and has never been put down, but that
> interrupt gets raised only when the CTL gets a state change from
> 0 to 1 (disabled to enabled), so we're going to wait for something
> that will never happen on its own.
> 
> Solving this while avoiding to restart the CTL is actually possible
> and can be done by just checking if it is already up and running
> when the wait_for_commit_done function is called: in this case, so,
> if the CTL was already running, we can say that the commit is done
> if the command transmission is complete (in other terms, if the
> interface has been flushed).
> 
> Signed-off-by: AngeloGioacchino Del Regno 
> 

This has unfortunately not solved any ctl_start timeout issues for me/us
on other platforms yet, but for the code:

Reviewed-by: Marijn Suijten 

> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
> index aa01698d6b25..aa5d3b3cef15 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
> @@ -682,6 +682,9 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done(
>   if (!dpu_encoder_phys_cmd_is_master(phys_enc))
>   return 0;
>  
> + if (phys_enc->hw_ctl->ops.is_started(phys_enc->hw_ctl))
> + return dpu_encoder_phys_cmd_wait_for_tx_complete(phys_enc);
> +
>   return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc);
>  }
>  
> -- 
> 2.32.0
> 


[v5 3/5] drm/panel: support for BOE and INX video mode panel

2021-09-13 Thread yangcong
Support for these two panels fits in nicely with the existing
panel-boe-tv101wum-nl6 driver as suggested by Sam [1]. The main things
we needed to handle were:
a) These panels need slightly longer delays in two places. Since these
new delays aren't much longer, let's just unconditionally increase
them for the driver.
b) One of these two panels doesn't support DSI HS mode so this patch
adds a flag for a panel to disable that.

[1] https://lore.kernel.org/r/yspasee6wd8dd...@ravnborg.org/

Signed-off-by: yangcong 
Reviewed-by: Douglas Anderson 
---
 .../gpu/drm/panel/panel-boe-tv101wum-nl6.c| 915 +-
 1 file changed, 912 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c 
b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
index 9a644433629e..2acbb5c623d8 100644
--- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
+++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
@@ -36,6 +36,7 @@ struct panel_desc {
const struct panel_init_cmd *init_cmds;
unsigned int lanes;
bool discharge_on_disable;
+   bool unsupport_dsi_hs_mode;
 };
 
 struct boe_panel {
@@ -75,6 +76,852 @@ struct panel_init_cmd {
.len = sizeof((char[]){__VA_ARGS__}), \
.data = (char[]){__VA_ARGS__} }
 
+static const struct panel_init_cmd boe_tv110c9m_init_cmd[] = {
+
+   _INIT_DCS_CMD(0xFF, 0x20),
+   _INIT_DCS_CMD(0xFB, 0x01),
+   _INIT_DCS_CMD(0x05, 0xD9),
+   _INIT_DCS_CMD(0x07, 0x78),
+   _INIT_DCS_CMD(0x08, 0x5A),
+   _INIT_DCS_CMD(0x0D, 0x63),
+   _INIT_DCS_CMD(0x95, 0xEB),
+   _INIT_DCS_CMD(0x96, 0xEB),
+   _INIT_DCS_CMD(0x30, 0x11),
+   _INIT_DCS_CMD(0x6D, 0x66),
+   _INIT_DCS_CMD(0x75, 0xA2),
+   _INIT_DCS_CMD(0x77, 0x3B),
+
+   _INIT_DCS_CMD(0xB0, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4D, 0x00, 0x6D, 
0x00, 0x89, 0x00, 0xA1, 0x00, 0xB6, 0x00, 0xC9),
+   _INIT_DCS_CMD(0xB1, 0x00, 0xDA, 0x01, 0x13, 0x01, 0x3C, 0x01, 0x7E, 
0x01, 0xAB, 0x01, 0xF7, 0x02, 0x2F, 0x02, 0x31),
+   _INIT_DCS_CMD(0xB2, 0x02, 0x67, 0x02, 0xA6, 0x02, 0xD1, 0x03, 0x08, 
0x03, 0x2E, 0x03, 0x5B, 0x03, 0x6B, 0x03, 0x7B),
+   _INIT_DCS_CMD(0xB3, 0x03, 0x8E, 0x03, 0xA2, 0x03, 0xB7, 0x03, 0xE7, 
0x03, 0xFD, 0x03, 0xFF),
+
+   _INIT_DCS_CMD(0xB4, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4D, 0x00, 0x6D, 
0x00, 0x89, 0x00, 0xA1, 0x00, 0xB6, 0x00, 0xC9),
+   _INIT_DCS_CMD(0xB5, 0x00, 0xDA, 0x01, 0x13, 0x01, 0x3C, 0x01, 0x7E, 
0x01, 0xAB, 0x01, 0xF7, 0x02, 0x2F, 0x02, 0x31),
+   _INIT_DCS_CMD(0xB6, 0x02, 0x67, 0x02, 0xA6, 0x02, 0xD1, 0x03, 0x08, 
0x03, 0x2E, 0x03, 0x5B, 0x03, 0x6B, 0x03, 0x7B),
+   _INIT_DCS_CMD(0xB7, 0x03, 0x8E, 0x03, 0xA2, 0x03, 0xB7, 0x03, 0xE7, 
0x03, 0xFD, 0x03, 0xFF),
+   _INIT_DCS_CMD(0xB8, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4D, 0x00, 0x6D, 
0x00, 0x89, 0x00, 0xA1, 0x00, 0xB6, 0x00, 0xC9),
+   _INIT_DCS_CMD(0xB9, 0x00, 0xDA, 0x01, 0x13, 0x01, 0x3C, 0x01, 0x7E, 
0x01, 0xAB, 0x01, 0xF7, 0x02, 0x2F, 0x02, 0x31),
+   _INIT_DCS_CMD(0xBA, 0x02, 0x67, 0x02, 0xA6, 0x02, 0xD1, 0x03, 0x08, 
0x03, 0x2E, 0x03, 0x5B, 0x03, 0x6B, 0x03, 0x7B),
+   _INIT_DCS_CMD(0xBB, 0x03, 0x8E, 0x03, 0xA2, 0x03, 0xB7, 0x03, 0xE7, 
0x03, 0xFD, 0x03, 0xFF),
+
+   _INIT_DCS_CMD(0xFF, 0x21),
+   _INIT_DCS_CMD(0xFB, 0x01),
+
+   _INIT_DCS_CMD(0xB0, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 
0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1),
+   _INIT_DCS_CMD(0xB1, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 
0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29),
+   _INIT_DCS_CMD(0xB2, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 
0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73),
+   _INIT_DCS_CMD(0xB3, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 
0x03, 0xF5, 0x03, 0xF7),
+
+   _INIT_DCS_CMD(0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 
0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1),
+   _INIT_DCS_CMD(0xB5, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 
0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29),
+   _INIT_DCS_CMD(0xB6, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 
0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73),
+   _INIT_DCS_CMD(0xB7, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 
0x03, 0xF5, 0x03, 0xF7),
+
+   _INIT_DCS_CMD(0xB8, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 
0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1),
+   _INIT_DCS_CMD(0xB9, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 
0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29),
+   _INIT_DCS_CMD(0xBA, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 
0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73),
+   _INIT_DCS_CMD(0xBB, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 
0x03, 0xF5, 0x03, 0xF7),
+
+   _INIT_DCS_CMD(0xFF, 0x24),
+   _INIT_DCS_CMD(0xFB, 0x01),
+
+   _INIT_DCS_CMD(0x00, 0x00),
+   _INIT_DCS_CMD(0x01, 0x00),
+
+   _INIT_DCS_CMD(0x02, 0x1C),
+   _INIT_DCS_CMD(0x03, 0x1C),
+
+   _INIT_DCS_CMD(0x04, 0x1D),
+   _INIT_DCS_CMD(

Re: [RFC][PATCH] drm/amdgpu/powerplay/smu10: Add custom profile

2021-09-13 Thread Alex Deucher
On Wed, Sep 8, 2021 at 3:23 AM Daniel Gomez  wrote:
>
> On Tue, 7 Sept 2021 at 19:23, Alex Deucher  wrote:
> >
> > On Tue, Sep 7, 2021 at 4:53 AM Daniel Gomez  wrote:
> > >
> > > Add custom power profile mode support on smu10.
> > > Update workload bit list.
> > > ---
> > >
> > > Hi,
> > >
> > > I'm trying to add custom profile for the Raven Ridge but not sure if
> > > I'd need a different parameter than PPSMC_MSG_SetCustomPolicy to
> > > configure the custom values. The code seemed to support CUSTOM for
> > > workload types but it didn't show up in the menu or accept any user
> > > input parameter. So far, I've added that part but a bit confusing to
> > > me what is the policy I need for setting these parameters or if it's
> > > maybe not possible at all.
> > >
> > > After applying the changes I'd configure the CUSTOM mode as follows:
> > >
> > > echo manual > 
> > > /sys/class/drm/card0/device/hwmon/hwmon1/device/power_dpm_force_performance_level
> > > echo "6 70 90 0 0" > 
> > > /sys/class/drm/card0/device/hwmon/hwmon1/device/pp_power_profile_mode
> > >
> > > Then, using Darren Powell script for testing modes I get the following
> > > output:
> > >
> > > 05:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. 
> > > [AMD/ATI] Raven Ridge [Radeon Vega Series / Radeon Vega Mobile Series] 
> > > [1002:15dd] (rev 83)
> > > === pp_dpm_sclk ===
> > > 0: 200Mhz
> > > 1: 400Mhz *
> > > 2: 1100Mhz
> > > === pp_dpm_mclk ===
> > > 0: 400Mhz
> > > 1: 933Mhz *
> > > 2: 1067Mhz
> > > 3: 1200Mhz
> > > === pp_power_profile_mode ===
> > > NUMMODE_NAME BUSY_SET_POINT FPS USE_RLC_BUSY MIN_ACTIVE_LEVEL
> > >   0 BOOTUP_DEFAULT : 70  60  0  0
> > >   1 3D_FULL_SCREEN : 70  60  1  3
> > >   2   POWER_SAVING : 90  60  0  0
> > >   3  VIDEO : 70  60  0  0
> > >   4 VR : 70  90  0  0
> > >   5COMPUTE : 30  60  0  6
> > >   6 CUSTOM*: 70  90  0  0
> > >
> > > As you can also see in my changes, I've also updated the workload bit
> > > table but I'm not completely sure about that change. With the tests
> > > I've done, using bit 5 for the WORKLOAD_PPLIB_CUSTOM_BIT makes the
> > > gpu sclk locked around ~36%. So, maybe I'm missing a clock limit
> > > configuraton table somewhere. Would you give me some hints to
> > > proceed with this?
> >
> > I don't think APUs support customizing the workloads the same way
> > dGPUs do.  I think they just support predefined profiles.
> >
> > Alex
>
>
> Thanks Alex for the quick response. Would it make sense then to remove
> the custom workload code (PP_SMC_POWER_PROFILE_CUSTOM) from the smu10?
> That workload was added in this commit:
> f6f75ebdc06c04d3cfcd100f1b10256a9cdca407 [1] and not use at all in the
> code as it's limited to PP_SMC_POWER_PROFILE_COMPUTE index. The
> smu10.h also includes the custom workload bit definition and that was
> a bit confusing for me to understand if it was half-supported or not
> possible to use at all as I understood from your comment.
>
> Perhaps could also be mentioned (if that's kind of standard) in the
> documentation[2] so, the custom pp_power_profile_mode is only
> supported in dGPUs.
>
> I can send the patches if it makes sense.

I guess I was thinking of another asic.  @Huang Rui, @changzhu, @Quan,
Evan can any of you comment on what is required for custom profiles on
APUs?

Alex


>
> [1]: 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c?id=f6f75ebdc06c04d3cfcd100f1b10256a9cdca407
> [2]: 
> https://www.kernel.org/doc/html/latest/gpu/amdgpu.html#pp-power-profile-mode
>
> Daniel
>
> >
> >
> > >
> > > Thanks in advance,
> > > Daniel
> > >
> > >
> > >  drivers/gpu/drm/amd/pm/inc/smu10.h| 14 +++--
> > >  .../drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c  | 57 +--
> > >  .../drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h  |  1 +
> > >  3 files changed, 61 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/amd/pm/inc/smu10.h 
> > > b/drivers/gpu/drm/amd/pm/inc/smu10.h
> > > index 9e837a5014c5..b96520528240 100644
> > > --- a/drivers/gpu/drm/amd/pm/inc/smu10.h
> > > +++ b/drivers/gpu/drm/amd/pm/inc/smu10.h
> > > @@ -136,12 +136,14 @@
> > >  #define FEATURE_CORE_CSTATES_MASK (1 << FEATURE_CORE_CSTATES_BIT)
> > >
> > >  /* Workload bits */
> > > -#define WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT 0
> > > -#define WORKLOAD_PPLIB_VIDEO_BIT  2
> > > -#define WORKLOAD_PPLIB_VR_BIT 3
> > > -#define WORKLOAD_PPLIB_COMPUTE_BIT4
> > > -#define WORKLOAD_PPLIB_CUSTOM_BIT 5
> > > -#define WORKLOAD_PPLIB_COUNT  6
> > > +#define WORKLOAD_DEFAULT_BIT  0
> > > +#define WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT 1
> > > +#define WORKLOAD_P

Re: [PATCH 1/1] drm/amdkfd: Add sysfs bitfields and enums to uAPI

2021-09-13 Thread Alex Deucher
On Fri, Sep 10, 2021 at 3:54 PM Felix Kuehling  wrote:
>
> These bits are de-facto part of the uAPI, so declare them in a uAPI header.
>

Please include a link to the userspace that uses this in the commit message.

Alex

> Signed-off-by: Felix Kuehling 
> ---
>  MAINTAINERS   |   1 +
>  drivers/gpu/drm/amd/amdkfd/kfd_topology.h |  46 +
>  include/uapi/linux/kfd_sysfs.h| 108 ++
>  3 files changed, 110 insertions(+), 45 deletions(-)
>  create mode 100644 include/uapi/linux/kfd_sysfs.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 84cd16694640..7554ec928ee2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -930,6 +930,7 @@ F:  drivers/gpu/drm/amd/include/kgd_kfd_interface.h
>  F: drivers/gpu/drm/amd/include/v9_structs.h
>  F: drivers/gpu/drm/amd/include/vi_structs.h
>  F: include/uapi/linux/kfd_ioctl.h
> +F: include/uapi/linux/kfd_sysfs.h
>
>  AMD SPI DRIVER
>  M: Sanjay R Mehta 
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h 
> b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
> index a8db017c9b8e..f0cc59d2fd5d 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
> @@ -25,38 +25,11 @@
>
>  #include 
>  #include 
> +#include 
>  #include "kfd_crat.h"
>
>  #define KFD_TOPOLOGY_PUBLIC_NAME_SIZE 32
>
> -#define HSA_CAP_HOT_PLUGGABLE  0x0001
> -#define HSA_CAP_ATS_PRESENT0x0002
> -#define HSA_CAP_SHARED_WITH_GRAPHICS   0x0004
> -#define HSA_CAP_QUEUE_SIZE_POW20x0008
> -#define HSA_CAP_QUEUE_SIZE_32BIT   0x0010
> -#define HSA_CAP_QUEUE_IDLE_EVENT   0x0020
> -#define HSA_CAP_VA_LIMIT   0x0040
> -#define HSA_CAP_WATCH_POINTS_SUPPORTED 0x0080
> -#define HSA_CAP_WATCH_POINTS_TOTALBITS_MASK0x0f00
> -#define HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT   8
> -#define HSA_CAP_DOORBELL_TYPE_TOTALBITS_MASK   0x3000
> -#define HSA_CAP_DOORBELL_TYPE_TOTALBITS_SHIFT  12
> -
> -#define HSA_CAP_DOORBELL_TYPE_PRE_1_0  0x0
> -#define HSA_CAP_DOORBELL_TYPE_1_0  0x1
> -#define HSA_CAP_DOORBELL_TYPE_2_0  0x2
> -#define HSA_CAP_AQL_QUEUE_DOUBLE_MAP   0x4000
> -
> -#define HSA_CAP_RESERVED_WAS_SRAM_EDCSUPPORTED 0x0008 /* Old buggy user 
> mode depends on this being 0 */
> -#define HSA_CAP_MEM_EDCSUPPORTED   0x0010
> -#define HSA_CAP_RASEVENTNOTIFY 0x0020
> -#define HSA_CAP_ASIC_REVISION_MASK 0x03c0
> -#define HSA_CAP_ASIC_REVISION_SHIFT22
> -#define HSA_CAP_SRAM_EDCSUPPORTED  0x0400
> -#define HSA_CAP_SVMAPI_SUPPORTED   0x0800
> -#define HSA_CAP_FLAGS_COHERENTHOSTACCESS   0x1000
> -#define HSA_CAP_RESERVED   0xe00f8000
> -
>  struct kfd_node_properties {
> uint64_t hive_id;
> uint32_t cpu_cores_count;
> @@ -93,17 +66,6 @@ struct kfd_node_properties {
> char name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE];
>  };
>
> -#define HSA_MEM_HEAP_TYPE_SYSTEM   0
> -#define HSA_MEM_HEAP_TYPE_FB_PUBLIC1
> -#define HSA_MEM_HEAP_TYPE_FB_PRIVATE   2
> -#define HSA_MEM_HEAP_TYPE_GPU_GDS  3
> -#define HSA_MEM_HEAP_TYPE_GPU_LDS  4
> -#define HSA_MEM_HEAP_TYPE_GPU_SCRATCH  5
> -
> -#define HSA_MEM_FLAGS_HOT_PLUGGABLE0x0001
> -#define HSA_MEM_FLAGS_NON_VOLATILE 0x0002
> -#define HSA_MEM_FLAGS_RESERVED 0xfffc
> -
>  struct kfd_mem_properties {
> struct list_headlist;
> uint32_theap_type;
> @@ -116,12 +78,6 @@ struct kfd_mem_properties {
> struct attributeattr;
>  };
>
> -#define HSA_CACHE_TYPE_DATA0x0001
> -#define HSA_CACHE_TYPE_INSTRUCTION 0x0002
> -#define HSA_CACHE_TYPE_CPU 0x0004
> -#define HSA_CACHE_TYPE_HSACU   0x0008
> -#define HSA_CACHE_TYPE_RESERVED0xfff0
> -
>  struct kfd_cache_properties {
> struct list_headlist;
> uint32_tprocessor_id_low;
> diff --git a/include/uapi/linux/kfd_sysfs.h b/include/uapi/linux/kfd_sysfs.h
> new file mode 100644
> index ..e1fb78b4bf09
> --- /dev/null
> +++ b/include/uapi/linux/kfd_sysfs.h
> @@ -0,0 +1,108 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR MIT WITH Linux-syscall-note */
> +/*
> + * Copyright 2021 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the followin

[Bug 214375] 5.14 Regression: Null pointer dereference in radeon_agp_head_init

2021-09-13 Thread bugzilla-daemon
https://bugzilla.kernel.org/show_bug.cgi?id=214375

--- Comment #2 from Calvin Walton (calvin.wal...@kepstin.ca) ---
Thank you for the quick patch! I've tested it on top of 5.14.2, and the kms
driver initialization and fb console are now working correctly.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are watching the assignee of the bug.

[Bug 211425] [drm:atom_op_jump] *ERROR* atombios stuck in loop for more than 20secs aborting

2021-09-13 Thread bugzilla-daemon
https://bugzilla.kernel.org/show_bug.cgi?id=211425

Andreas (icedragon...@web.de) changed:

   What|Removed |Added

 Kernel Version|5.13.13 |5.14.3
   Severity|high|normal

--- Comment #20 from Andreas (icedragon...@web.de) ---
With 5.14.x the issue in general still persists, but I was not able again to
observe the hard crash without recovering (good) -- the screen keeps black for
only 2x20 sec with the typical error messages (e.g. above in comment 16) and
recovers. So I changed back the importance state in the header back to normal.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are watching the assignee of the bug.

[PATCH v2 01/12] ext4/xfs: add page refcount helper

2021-09-13 Thread Alex Sierra
From: Ralph Campbell 

There are several places where ZONE_DEVICE struct pages assume a reference
count == 1 means the page is idle and free. Instead of open coding this,
add a helper function to hide this detail.

Signed-off-by: Ralph Campbell 
Signed-off-by: Alex Sierra 
Reviewed-by: Christoph Hellwig 
Acked-by: Theodore Ts'o 
Acked-by: Darrick J. Wong 
---
v3:
[AS]: rename dax_layout_is_idle_page func to dax_page_unused

v4:
[AS]: This ref count functionality was missing on fuse/dax.c.
---
 fs/dax.c|  4 ++--
 fs/ext4/inode.c |  5 +
 fs/fuse/dax.c   |  4 +---
 fs/xfs/xfs_file.c   |  4 +---
 include/linux/dax.h | 10 ++
 5 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/fs/dax.c b/fs/dax.c
index 62352cbcf0f4..c387d09e3e5a 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -369,7 +369,7 @@ static void dax_disassociate_entry(void *entry, struct 
address_space *mapping,
for_each_mapped_pfn(entry, pfn) {
struct page *page = pfn_to_page(pfn);
 
-   WARN_ON_ONCE(trunc && page_ref_count(page) > 1);
+   WARN_ON_ONCE(trunc && !dax_page_unused(page));
WARN_ON_ONCE(page->mapping && page->mapping != mapping);
page->mapping = NULL;
page->index = 0;
@@ -383,7 +383,7 @@ static struct page *dax_busy_page(void *entry)
for_each_mapped_pfn(entry, pfn) {
struct page *page = pfn_to_page(pfn);
 
-   if (page_ref_count(page) > 1)
+   if (!dax_page_unused(page))
return page;
}
return NULL;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index fe6045a46599..05ffe6875cb1 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3971,10 +3971,7 @@ int ext4_break_layouts(struct inode *inode)
if (!page)
return 0;
 
-   error = ___wait_var_event(&page->_refcount,
-   atomic_read(&page->_refcount) == 1,
-   TASK_INTERRUPTIBLE, 0, 0,
-   ext4_wait_dax_page(ei));
+   error = dax_wait_page(ei, page, ext4_wait_dax_page);
} while (error == 0);
 
return error;
diff --git a/fs/fuse/dax.c b/fs/fuse/dax.c
index ff99ab2a3c43..2b1f190ba78a 100644
--- a/fs/fuse/dax.c
+++ b/fs/fuse/dax.c
@@ -677,9 +677,7 @@ static int __fuse_dax_break_layouts(struct inode *inode, 
bool *retry,
return 0;
 
*retry = true;
-   return ___wait_var_event(&page->_refcount,
-   atomic_read(&page->_refcount) == 1, TASK_INTERRUPTIBLE,
-   0, 0, fuse_wait_dax_page(inode));
+   return dax_wait_page(inode, page, fuse_wait_dax_page);
 }
 
 /* dmap_end == 0 leads to unmapping of whole file */
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 396ef36dcd0a..182057281086 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -840,9 +840,7 @@ xfs_break_dax_layouts(
return 0;
 
*retry = true;
-   return ___wait_var_event(&page->_refcount,
-   atomic_read(&page->_refcount) == 1, TASK_INTERRUPTIBLE,
-   0, 0, xfs_wait_dax_page(inode));
+   return dax_wait_page(inode, page, xfs_wait_dax_page);
 }
 
 int
diff --git a/include/linux/dax.h b/include/linux/dax.h
index b52f084aa643..8b5da1d60dbc 100644
--- a/include/linux/dax.h
+++ b/include/linux/dax.h
@@ -243,6 +243,16 @@ static inline bool dax_mapping(struct address_space 
*mapping)
return mapping->host && IS_DAX(mapping->host);
 }
 
+static inline bool dax_page_unused(struct page *page)
+{
+   return page_ref_count(page) == 1;
+}
+
+#define dax_wait_page(_inode, _page, _wait_cb) \
+   ___wait_var_event(&(_page)->_refcount,  \
+   dax_page_unused(_page), \
+   TASK_INTERRUPTIBLE, 0, 0, _wait_cb(_inode))
+
 #ifdef CONFIG_DEV_DAX_HMEM_DEVICES
 void hmem_register_device(int target_nid, struct resource *r);
 #else
-- 
2.32.0



[PATCH v2 00/12] MEMORY_DEVICE_PUBLIC for CPU-accessible coherent device memory

2021-09-13 Thread Alex Sierra
v1:
AMD is building a system architecture for the Frontier supercomputer
with a coherent interconnect between CPUs and GPUs. This hardware
architecture allows the CPUs to coherently access GPU device memory.
We have hardware in our labs and we are working with our partner HPE on
the BIOS, firmware and software for delivery to the DOE.

The system BIOS advertises the GPU device memory (aka VRAM) as SPM
(special purpose memory) in the UEFI system address map. The amdgpu
driver registers the memory with devmap as MEMORY_DEVICE_PUBLIC using
devm_memremap_pages.

This patch series adds MEMORY_DEVICE_PUBLIC, which is similar to
MEMORY_DEVICE_GENERIC in that it can be mapped for CPU access, but adds
support for migrating this memory similar to MEMORY_DEVICE_PRIVATE. We
also included and updated two patches from Ralph Campbell (Nvidia),
which change ZONE_DEVICE reference counting as requested in previous
reviews of this patch series (see 
https://patchwork.freedesktop.org/series/90706/).
Finally, we extended hmm_test to cover migration of MEMORY_DEVICE_PUBLIC.

This work is based on HMM and our SVM memory manager, which has landed
in Linux 5.14 recently.

v2:
Major changes on this version:
Fold patches: 'mm: call pgmap->ops->page_free for DEVICE_PUBLIC' and
'mm: add public type support to migrate_vma helpers' into 'mm: add
zone device public type memory support'

Condition added at migrate_vma_collect_pmd, for migrations from
device public pages. Making sure pages are from device zone and with
the proper MIGRATE_VMA_SELECT_DEVICE_PUBLIC flag.
Patch: 'mm: add device public vma selection for memory migration'

Fix logic in 'drm/amdkfd: add SPM support for SVM' to detect error in
both DEVICE_PRIVATE and DEVICE_PUBLIC.

Minor changes: 
Swap patch order 03 and 04.

Addings
Add VM_BUG_ON_PAGE(page_ref_count(page), page) to patch 'drm/amdkfd:
ref count init for device pages', to make sure page hasn't been used

Alex Sierra (10):
  mm: add zone device public type memory support
  mm: add device public vma selection for memory migration
  drm/amdkfd: ref count init for device pages
  drm/amdkfd: add SPM support for SVM
  drm/amdkfd: public type as sys mem on migration to ram
  lib: test_hmm add ioctl to get zone device type
  lib: test_hmm add module param for zone device type
  lib: add support for device public type in test_hmm
  tools: update hmm-test to support device public type
  tools: update test_hmm script to support SP config

Ralph Campbell (2):
  ext4/xfs: add page refcount helper
  mm: remove extra ZONE_DEVICE struct page refcount

 arch/powerpc/kvm/book3s_hv_uvmem.c   |   2 +-
 drivers/gpu/drm/amd/amdkfd/kfd_migrate.c |  40 ++--
 drivers/gpu/drm/nouveau/nouveau_dmem.c   |   2 +-
 fs/dax.c |   8 +-
 fs/ext4/inode.c  |   5 +-
 fs/fuse/dax.c|   4 +-
 fs/xfs/xfs_file.c|   4 +-
 include/linux/dax.h  |  10 +
 include/linux/memremap.h |  15 +-
 include/linux/migrate.h  |   1 +
 include/linux/mm.h   |  19 +-
 lib/test_hmm.c   | 247 +++
 lib/test_hmm_uapi.h  |  16 ++
 mm/internal.h|   8 +
 mm/memcontrol.c  |   6 +-
 mm/memory-failure.c  |   6 +-
 mm/memremap.c|  71 ++-
 mm/migrate.c |  33 +--
 mm/page_alloc.c  |   3 +
 mm/swap.c|  45 +
 tools/testing/selftests/vm/hmm-tests.c   | 142 +++--
 tools/testing/selftests/vm/test_hmm.sh   |  20 +-
 22 files changed, 451 insertions(+), 256 deletions(-)

-- 
2.32.0



[PATCH v2 03/12] mm: add zone device public type memory support

2021-09-13 Thread Alex Sierra
Device memory that is cache coherent from device and CPU point of view.
This is use on platform that have an advance system bus (like CAPI or
CCIX). Any page of a process can be migrated to such memory. However,
no one should be allow to pin such memory so that it can always be
evicted.

Signed-off-by: Alex Sierra 
---
 include/linux/memremap.h |  8 
 include/linux/mm.h   |  8 
 mm/memcontrol.c  |  6 +++---
 mm/memory-failure.c  |  6 +-
 mm/memremap.c|  2 ++
 mm/migrate.c | 19 ---
 6 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/include/linux/memremap.h b/include/linux/memremap.h
index 77ff5fd0685f..431e1b0bc949 100644
--- a/include/linux/memremap.h
+++ b/include/linux/memremap.h
@@ -39,6 +39,13 @@ struct vmem_altmap {
  * A more complete discussion of unaddressable memory may be found in
  * include/linux/hmm.h and Documentation/vm/hmm.rst.
  *
+ * MEMORY_DEVICE_PUBLIC:
+ * Device memory that is cache coherent from device and CPU point of view. This
+ * is use on platform that have an advance system bus (like CAPI or CCIX). A
+ * driver can hotplug the device memory using ZONE_DEVICE and with that memory
+ * type. Any page of a process can be migrated to such memory. However no one
+ * should be allow to pin such memory so that it can always be evicted.
+ *
  * MEMORY_DEVICE_FS_DAX:
  * Host memory that has similar access semantics as System RAM i.e. DMA
  * coherent and supports page pinning. In support of coordinating page
@@ -59,6 +66,7 @@ struct vmem_altmap {
 enum memory_type {
/* 0 is reserved to catch uninitialized type fields */
MEMORY_DEVICE_PRIVATE = 1,
+   MEMORY_DEVICE_PUBLIC,
MEMORY_DEVICE_FS_DAX,
MEMORY_DEVICE_GENERIC,
MEMORY_DEVICE_PCI_P2PDMA,
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e24c904deeec..70a932e8a2ee 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1187,6 +1187,14 @@ static inline bool is_device_private_page(const struct 
page *page)
page->pgmap->type == MEMORY_DEVICE_PRIVATE;
 }
 
+static inline bool is_device_page(const struct page *page)
+{
+   return IS_ENABLED(CONFIG_DEV_PAGEMAP_OPS) &&
+   is_zone_device_page(page) &&
+   (page->pgmap->type == MEMORY_DEVICE_PRIVATE ||
+   page->pgmap->type == MEMORY_DEVICE_PUBLIC);
+}
+
 static inline bool is_pci_p2pdma_page(const struct page *page)
 {
return IS_ENABLED(CONFIG_DEV_PAGEMAP_OPS) &&
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 64ada9e650a5..1599ef1a3b03 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -5530,8 +5530,8 @@ static int mem_cgroup_move_account(struct page *page,
  *   2(MC_TARGET_SWAP): if the swap entry corresponding to this pte is a
  * target for charge migration. if @target is not NULL, the entry is stored
  * in target->ent.
- *   3(MC_TARGET_DEVICE): like MC_TARGET_PAGE  but page is 
MEMORY_DEVICE_PRIVATE
- * (so ZONE_DEVICE page and thus not on the lru).
+ *   3(MC_TARGET_DEVICE): like MC_TARGET_PAGE  but page is MEMORY_DEVICE_PUBLIC
+ * or MEMORY_DEVICE_PRIVATE (so ZONE_DEVICE page and thus not on the lru).
  * For now we such page is charge like a regular page would be as for all
  * intent and purposes it is just special memory taking the place of a
  * regular page.
@@ -5565,7 +5565,7 @@ static enum mc_target_type get_mctgt_type(struct 
vm_area_struct *vma,
 */
if (page_memcg(page) == mc.from) {
ret = MC_TARGET_PAGE;
-   if (is_device_private_page(page))
+   if (is_device_page(page))
ret = MC_TARGET_DEVICE;
if (target)
target->page = page;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 6f5f78885ab4..16cadbabfc99 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1373,12 +1373,16 @@ static int memory_failure_dev_pagemap(unsigned long 
pfn, int flags,
goto unlock;
}
 
-   if (pgmap->type == MEMORY_DEVICE_PRIVATE) {
+   switch (pgmap->type) {
+   case MEMORY_DEVICE_PRIVATE:
+   case MEMORY_DEVICE_PUBLIC:
/*
 * TODO: Handle HMM pages which may need coordination
 * with device-side memory.
 */
goto unlock;
+   default:
+   break;
}
 
/*
diff --git a/mm/memremap.c b/mm/memremap.c
index ab949a571e78..685be704b28e 100644
--- a/mm/memremap.c
+++ b/mm/memremap.c
@@ -294,6 +294,7 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid)
 
switch (pgmap->type) {
case MEMORY_DEVICE_PRIVATE:
+   case MEMORY_DEVICE_PUBLIC:
if (!IS_ENABLED(CONFIG_DEVICE_PRIVATE)) {
WARN(1, "Device private memory not supported\n");
r

[PATCH v2 04/12] mm: add device public vma selection for memory migration

2021-09-13 Thread Alex Sierra
This case is used to migrate pages from device memory, back to system
memory. Device public type memory is cache coherent from device and CPU
point of view.

Signed-off-by: Alex Sierra 
---
v2:
condition added when migrations from device public pages.
---
 include/linux/migrate.h | 1 +
 mm/migrate.c| 9 +++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 4bb4e519e3f5..2fe22596e02c 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -156,6 +156,7 @@ static inline unsigned long migrate_pfn(unsigned long pfn)
 enum migrate_vma_direction {
MIGRATE_VMA_SELECT_SYSTEM = 1 << 0,
MIGRATE_VMA_SELECT_DEVICE_PRIVATE = 1 << 1,
+   MIGRATE_VMA_SELECT_DEVICE_PUBLIC = 1 << 2,
 };
 
 struct migrate_vma {
diff --git a/mm/migrate.c b/mm/migrate.c
index 7392648966d2..036baf24b58b 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -2406,8 +2406,6 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
if (is_write_device_private_entry(entry))
mpfn |= MIGRATE_PFN_WRITE;
} else {
-   if (!(migrate->flags & MIGRATE_VMA_SELECT_SYSTEM))
-   goto next;
pfn = pte_pfn(pte);
if (is_zero_pfn(pfn)) {
mpfn = MIGRATE_PFN_MIGRATE;
@@ -2415,6 +2413,13 @@ static int migrate_vma_collect_pmd(pmd_t *pmdp,
goto next;
}
page = vm_normal_page(migrate->vma, addr, pte);
+   if (!is_zone_device_page(page) &&
+   !(migrate->flags & MIGRATE_VMA_SELECT_SYSTEM))
+   goto next;
+   if (is_zone_device_page(page) &&
+   (!(migrate->flags & 
MIGRATE_VMA_SELECT_DEVICE_PUBLIC) ||
+page->pgmap->owner != migrate->pgmap_owner))
+   goto next;
mpfn = migrate_pfn(pfn) | MIGRATE_PFN_MIGRATE;
mpfn |= pte_write(pte) ? MIGRATE_PFN_WRITE : 0;
}
-- 
2.32.0



[PATCH v2 06/12] drm/amdkfd: add SPM support for SVM

2021-09-13 Thread Alex Sierra
When CPU is connected throug XGMI, it has coherent
access to VRAM resource. In this case that resource
is taken from a table in the device gmc aperture base.
This resource is used along with the device type, which could
be DEVICE_PRIVATE or DEVICE_PUBLIC to create the device
page map region.

Signed-off-by: Alex Sierra 
Reviewed-by: Felix Kuehling 
---
v7:
Remove lookup_resource call, so export symbol for this function
is not longer required. Patch dropped "kernel: resource:
lookup_resource as exported symbol"
---
 drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 32 +++-
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c 
b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index ffad39ffa8c6..d0e04f79a06e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -866,7 +866,7 @@ int svm_migrate_init(struct amdgpu_device *adev)
 {
struct kfd_dev *kfddev = adev->kfd.dev;
struct dev_pagemap *pgmap;
-   struct resource *res;
+   struct resource *res = NULL;
unsigned long size;
void *r;
 
@@ -881,22 +881,29 @@ int svm_migrate_init(struct amdgpu_device *adev)
 * should remove reserved size
 */
size = ALIGN(adev->gmc.real_vram_size, 2ULL << 20);
-   res = devm_request_free_mem_region(adev->dev, &iomem_resource, size);
-   if (IS_ERR(res))
-   return -ENOMEM;
+   if (adev->gmc.xgmi.connected_to_cpu) {
+   pgmap->range.start = adev->gmc.aper_base;
+   pgmap->range.end = adev->gmc.aper_base + adev->gmc.aper_size - 
1;
+   pgmap->type = MEMORY_DEVICE_PUBLIC;
+   } else {
+   res = devm_request_free_mem_region(adev->dev, &iomem_resource, 
size);
+   if (IS_ERR(res))
+   return -ENOMEM;
+   pgmap->range.start = res->start;
+   pgmap->range.end = res->end;
+   pgmap->type = MEMORY_DEVICE_PRIVATE;
+   }
 
-   pgmap->type = MEMORY_DEVICE_PRIVATE;
pgmap->nr_range = 1;
-   pgmap->range.start = res->start;
-   pgmap->range.end = res->end;
pgmap->ops = &svm_migrate_pgmap_ops;
pgmap->owner = SVM_ADEV_PGMAP_OWNER(adev);
-   pgmap->flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE;
+   pgmap->flags = 0;
r = devm_memremap_pages(adev->dev, pgmap);
if (IS_ERR(r)) {
pr_err("failed to register HMM device memory\n");
-   devm_release_mem_region(adev->dev, res->start,
-   res->end - res->start + 1);
+   if (pgmap->type == MEMORY_DEVICE_PRIVATE)
+   devm_release_mem_region(adev->dev, res->start,
+   res->end - res->start + 1);
return PTR_ERR(r);
}
 
@@ -915,6 +922,7 @@ void svm_migrate_fini(struct amdgpu_device *adev)
struct dev_pagemap *pgmap = &adev->kfd.dev->pgmap;
 
devm_memunmap_pages(adev->dev, pgmap);
-   devm_release_mem_region(adev->dev, pgmap->range.start,
-   pgmap->range.end - pgmap->range.start + 1);
+   if (pgmap->type == MEMORY_DEVICE_PRIVATE)
+   devm_release_mem_region(adev->dev, pgmap->range.start,
+   pgmap->range.end - pgmap->range.start + 
1);
 }
-- 
2.32.0



[PATCH v2 05/12] drm/amdkfd: ref count init for device pages

2021-09-13 Thread Alex Sierra
Ref counter from device pages is init to zero during memmap init zone.
The first time a new device page is allocated to migrate data into it,
its ref counter needs to be initialized to one.

Signed-off-by: Alex Sierra 
---
 drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c 
b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index dab290a4d19d..ffad39ffa8c6 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -220,7 +220,8 @@ svm_migrate_get_vram_page(struct svm_range *prange, 
unsigned long pfn)
page = pfn_to_page(pfn);
svm_range_bo_ref(prange->svm_bo);
page->zone_device_data = prange->svm_bo;
-   get_page(page);
+   VM_BUG_ON_PAGE(page_ref_count(page), page);
+   init_page_count(page);
lock_page(page);
 }
 
-- 
2.32.0



[PATCH v2 07/12] drm/amdkfd: public type as sys mem on migration to ram

2021-09-13 Thread Alex Sierra
Public device type memory on VRAM to RAM migration, has similar access
as System RAM from the CPU. This flag sets the source from the sender.
Which in Public type case, should be set as
MIGRATE_VMA_SELECT_DEVICE_PUBLIC.

Signed-off-by: Alex Sierra 
Reviewed-by: Felix Kuehling 
---
 drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c 
b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index d0e04f79a06e..b5b9ae4e2e27 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -617,9 +617,12 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct 
svm_range *prange,
migrate.vma = vma;
migrate.start = start;
migrate.end = end;
-   migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE;
migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev);
 
+   if (adev->gmc.xgmi.connected_to_cpu)
+   migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PUBLIC;
+   else
+   migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE;
size = 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t);
size *= npages;
buf = kvmalloc(size, GFP_KERNEL | __GFP_ZERO);
-- 
2.32.0



[PATCH v2 02/12] mm: remove extra ZONE_DEVICE struct page refcount

2021-09-13 Thread Alex Sierra
From: Ralph Campbell 

ZONE_DEVICE struct pages have an extra reference count that complicates the
code for put_page() and several places in the kernel that need to check the
reference count to see that a page is not being used (gup, compaction,
migration, etc.). Clean up the code so the reference count doesn't need to
be treated specially for ZONE_DEVICE.

Signed-off-by: Ralph Campbell 
Signed-off-by: Alex Sierra 
Reviewed-by: Christoph Hellwig 
---
v2:
AS: merged this patch in linux 5.11 version

v5:
AS: add condition at try_grab_page to check for the zone device type, while
page ref counter is checked less/equal to zero. In case of device zone, pages
ref counter are initialized to zero.

v7:
AS: fix condition at try_grab_page added at v5, is invalid. It supposed
to fix xfstests/generic/413 test, however, there's a known issue on
this test where DAX mapped area DIO to non-DAX expect to fail.
https://patchwork.kernel.org/project/fstests/patch/1489463960-3579-1-git-send-email-xz...@redhat.com
This condition was removed after rebase over patch series
https://lore.kernel.org/r/20210813044133.1536842-4-jhubb...@nvidia.com
---
 arch/powerpc/kvm/book3s_hv_uvmem.c |  2 +-
 drivers/gpu/drm/nouveau/nouveau_dmem.c |  2 +-
 fs/dax.c   |  4 +-
 include/linux/dax.h|  2 +-
 include/linux/memremap.h   |  7 +--
 include/linux/mm.h | 11 
 lib/test_hmm.c |  2 +-
 mm/internal.h  |  8 +++
 mm/memremap.c  | 69 +++---
 mm/migrate.c   |  5 --
 mm/page_alloc.c|  3 ++
 mm/swap.c  | 45 ++---
 12 files changed, 45 insertions(+), 115 deletions(-)

diff --git a/arch/powerpc/kvm/book3s_hv_uvmem.c 
b/arch/powerpc/kvm/book3s_hv_uvmem.c
index 84e5a2dc8be5..acee67710620 100644
--- a/arch/powerpc/kvm/book3s_hv_uvmem.c
+++ b/arch/powerpc/kvm/book3s_hv_uvmem.c
@@ -711,7 +711,7 @@ static struct page *kvmppc_uvmem_get_page(unsigned long 
gpa, struct kvm *kvm)
 
dpage = pfn_to_page(uvmem_pfn);
dpage->zone_device_data = pvt;
-   get_page(dpage);
+   init_page_count(dpage);
lock_page(dpage);
return dpage;
 out_clear:
diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c 
b/drivers/gpu/drm/nouveau/nouveau_dmem.c
index 92987daa5e17..8bc7120e1216 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dmem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c
@@ -324,7 +324,7 @@ nouveau_dmem_page_alloc_locked(struct nouveau_drm *drm)
return NULL;
}
 
-   get_page(page);
+   init_page_count(page);
lock_page(page);
return page;
 }
diff --git a/fs/dax.c b/fs/dax.c
index c387d09e3e5a..1166630b7190 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -571,14 +571,14 @@ static void *grab_mapping_entry(struct xa_state *xas,
 
 /**
  * dax_layout_busy_page_range - find first pinned page in @mapping
- * @mapping: address space to scan for a page with ref count > 1
+ * @mapping: address space to scan for a page with ref count > 0
  * @start: Starting offset. Page containing 'start' is included.
  * @end: End offset. Page containing 'end' is included. If 'end' is LLONG_MAX,
  *   pages from 'start' till the end of file are included.
  *
  * DAX requires ZONE_DEVICE mapped pages. These pages are never
  * 'onlined' to the page allocator so they are considered idle when
- * page->count == 1. A filesystem uses this interface to determine if
+ * page->count == 0. A filesystem uses this interface to determine if
  * any page in the mapping is busy, i.e. for DMA, or other
  * get_user_pages() usages.
  *
diff --git a/include/linux/dax.h b/include/linux/dax.h
index 8b5da1d60dbc..05fc982ce153 100644
--- a/include/linux/dax.h
+++ b/include/linux/dax.h
@@ -245,7 +245,7 @@ static inline bool dax_mapping(struct address_space 
*mapping)
 
 static inline bool dax_page_unused(struct page *page)
 {
-   return page_ref_count(page) == 1;
+   return page_ref_count(page) == 0;
 }
 
 #define dax_wait_page(_inode, _page, _wait_cb) \
diff --git a/include/linux/memremap.h b/include/linux/memremap.h
index 45a79da89c5f..77ff5fd0685f 100644
--- a/include/linux/memremap.h
+++ b/include/linux/memremap.h
@@ -66,9 +66,10 @@ enum memory_type {
 
 struct dev_pagemap_ops {
/*
-* Called once the page refcount reaches 1.  (ZONE_DEVICE pages never
-* reach 0 refcount unless there is a refcount bug. This allows the
-* device driver to implement its own memory management.)
+* Called once the page refcount reaches 0. The reference count
+* should be reset to one with init_page_count(page) before reusing
+* the page. This allows the device driver to implement its own
+* memory management.
 */
void (*page_free)(struct page *page);
 
diff --git a/include/linux/mm.

[PATCH v2 11/12] tools: update hmm-test to support device public type

2021-09-13 Thread Alex Sierra
Test cases such as migrate_fault and migrate_multiple,
were modified to explicit migrate from device to sys memory
without the need of page faults, when using device public
type.

Snapshot test case updated to read memory device type
first and based on that, get the proper returned results
migrate_ping_pong test case added to test explicit migration
from device to sys memory for both private and public
zone types.

Helpers to migrate from device to sys memory and vicerversa
were also added.

Signed-off-by: Alex Sierra 
---
 tools/testing/selftests/vm/hmm-tests.c | 142 +
 1 file changed, 124 insertions(+), 18 deletions(-)

diff --git a/tools/testing/selftests/vm/hmm-tests.c 
b/tools/testing/selftests/vm/hmm-tests.c
index 5d1ac691b9f4..477c6283dd1b 100644
--- a/tools/testing/selftests/vm/hmm-tests.c
+++ b/tools/testing/selftests/vm/hmm-tests.c
@@ -44,6 +44,8 @@ struct hmm_buffer {
int fd;
uint64_tcpages;
uint64_tfaults;
+   int zone_device_type;
+   boolalloc_to_devmem;
 };
 
 #define TWOMEG (1 << 21)
@@ -133,6 +135,7 @@ static int hmm_dmirror_cmd(int fd,
cmd.addr = (__u64)buffer->ptr;
cmd.ptr = (__u64)buffer->mirror;
cmd.npages = npages;
+   cmd.alloc_to_devmem = buffer->alloc_to_devmem;
 
for (;;) {
ret = ioctl(fd, request, &cmd);
@@ -144,6 +147,7 @@ static int hmm_dmirror_cmd(int fd,
}
buffer->cpages = cmd.cpages;
buffer->faults = cmd.faults;
+   buffer->zone_device_type = cmd.zone_device_type;
 
return 0;
 }
@@ -211,6 +215,34 @@ static void hmm_nanosleep(unsigned int n)
nanosleep(&t, NULL);
 }
 
+static int hmm_migrate_sys_to_dev(int fd,
+  struct hmm_buffer *buffer,
+  unsigned long npages)
+{
+   buffer->alloc_to_devmem = true;
+   return hmm_dmirror_cmd(fd, HMM_DMIRROR_MIGRATE, buffer, npages);
+}
+
+static int hmm_migrate_dev_to_sys(int fd,
+  struct hmm_buffer *buffer,
+  unsigned long npages)
+{
+   buffer->alloc_to_devmem = false;
+   return hmm_dmirror_cmd(fd, HMM_DMIRROR_MIGRATE, buffer, npages);
+}
+
+static int hmm_is_private_device(int fd, bool *res)
+{
+   struct hmm_buffer buffer;
+   int ret;
+
+   buffer.ptr = 0;
+   ret = hmm_dmirror_cmd(fd, HMM_DMIRROR_GET_MEM_DEV_TYPE, &buffer, 1);
+   *res = (buffer.zone_device_type == HMM_DMIRROR_MEMORY_DEVICE_PRIVATE);
+
+   return ret;
+}
+
 /*
  * Simple NULL test of device open/close.
  */
@@ -875,7 +907,7 @@ TEST_F(hmm, migrate)
ptr[i] = i;
 
/* Migrate memory to device. */
-   ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_MIGRATE, buffer, npages);
+   ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
ASSERT_EQ(ret, 0);
ASSERT_EQ(buffer->cpages, npages);
 
@@ -923,7 +955,7 @@ TEST_F(hmm, migrate_fault)
ptr[i] = i;
 
/* Migrate memory to device. */
-   ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_MIGRATE, buffer, npages);
+   ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
ASSERT_EQ(ret, 0);
ASSERT_EQ(buffer->cpages, npages);
 
@@ -936,7 +968,7 @@ TEST_F(hmm, migrate_fault)
ASSERT_EQ(ptr[i], i);
 
/* Migrate memory to the device again. */
-   ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_MIGRATE, buffer, npages);
+   ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
ASSERT_EQ(ret, 0);
ASSERT_EQ(buffer->cpages, npages);
 
@@ -976,7 +1008,7 @@ TEST_F(hmm, migrate_shared)
ASSERT_NE(buffer->ptr, MAP_FAILED);
 
/* Migrate memory to device. */
-   ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_MIGRATE, buffer, npages);
+   ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
ASSERT_EQ(ret, -ENOENT);
 
hmm_buffer_free(buffer);
@@ -1015,7 +1047,7 @@ TEST_F(hmm2, migrate_mixed)
p = buffer->ptr;
 
/* Migrating a protected area should be an error. */
-   ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, npages);
+   ret = hmm_migrate_sys_to_dev(self->fd1, buffer, npages);
ASSERT_EQ(ret, -EINVAL);
 
/* Punch a hole after the first page address. */
@@ -1023,7 +1055,7 @@ TEST_F(hmm2, migrate_mixed)
ASSERT_EQ(ret, 0);
 
/* We expect an error if the vma doesn't cover the range. */
-   ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, 3);
+   ret = hmm_migrate_sys_to_dev(self->fd1, buffer, 3);
ASSERT_EQ(ret, -EINVAL);
 
/* Page 2 will be a read-only zero page. */
@@ -1055,13 +1087,13 @@ TEST_F(hmm2, migrate_mixed)
 
/* Now try to migrate pages 2-5 to device 1. */
buffer->ptr = p + 2 * self->page_size;
-   ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, 4);
+  

[PATCH v2 08/12] lib: test_hmm add ioctl to get zone device type

2021-09-13 Thread Alex Sierra
new ioctl cmd added to query zone device type. This will be
used once the test_hmm adds zone device public type.

Signed-off-by: Alex Sierra 
---
 lib/test_hmm.c  | 15 ++-
 lib/test_hmm_uapi.h |  7 +++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index 6998f10350ea..3cd91ca31dd7 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -82,6 +82,7 @@ struct dmirror_chunk {
 struct dmirror_device {
struct cdev cdevice;
struct hmm_devmem   *devmem;
+   unsigned intzone_device_type;
 
unsigned intdevmem_capacity;
unsigned intdevmem_count;
@@ -468,6 +469,7 @@ static bool dmirror_allocate_chunk(struct dmirror_device 
*mdevice,
if (IS_ERR(res))
goto err_devmem;
 
+   mdevice->zone_device_type = HMM_DMIRROR_MEMORY_DEVICE_PRIVATE;
devmem->pagemap.type = MEMORY_DEVICE_PRIVATE;
devmem->pagemap.range.start = res->start;
devmem->pagemap.range.end = res->end;
@@ -912,6 +914,15 @@ static int dmirror_snapshot(struct dmirror *dmirror,
return ret;
 }
 
+static int dmirror_get_device_type(struct dmirror *dmirror,
+   struct hmm_dmirror_cmd *cmd)
+{
+   mutex_lock(&dmirror->mutex);
+   cmd->zone_device_type = dmirror->mdevice->zone_device_type;
+   mutex_unlock(&dmirror->mutex);
+
+   return 0;
+}
 static long dmirror_fops_unlocked_ioctl(struct file *filp,
unsigned int command,
unsigned long arg)
@@ -952,7 +963,9 @@ static long dmirror_fops_unlocked_ioctl(struct file *filp,
case HMM_DMIRROR_SNAPSHOT:
ret = dmirror_snapshot(dmirror, &cmd);
break;
-
+   case HMM_DMIRROR_GET_MEM_DEV_TYPE:
+   ret = dmirror_get_device_type(dmirror, &cmd);
+   break;
default:
return -EINVAL;
}
diff --git a/lib/test_hmm_uapi.h b/lib/test_hmm_uapi.h
index 670b4ef2a5b6..ee88701793d5 100644
--- a/lib/test_hmm_uapi.h
+++ b/lib/test_hmm_uapi.h
@@ -26,6 +26,7 @@ struct hmm_dmirror_cmd {
__u64   npages;
__u64   cpages;
__u64   faults;
+   __u64   zone_device_type;
 };
 
 /* Expose the address space of the calling process through hmm device file */
@@ -33,6 +34,7 @@ struct hmm_dmirror_cmd {
 #define HMM_DMIRROR_WRITE  _IOWR('H', 0x01, struct hmm_dmirror_cmd)
 #define HMM_DMIRROR_MIGRATE_IOWR('H', 0x02, struct hmm_dmirror_cmd)
 #define HMM_DMIRROR_SNAPSHOT   _IOWR('H', 0x03, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_GET_MEM_DEV_TYPE   _IOWR('H', 0x04, struct hmm_dmirror_cmd)
 
 /*
  * Values returned in hmm_dmirror_cmd.ptr for HMM_DMIRROR_SNAPSHOT.
@@ -60,4 +62,9 @@ enum {
HMM_DMIRROR_PROT_DEV_PRIVATE_REMOTE = 0x30,
 };
 
+enum {
+   /* 0 is reserved to catch uninitialized type fields */
+   HMM_DMIRROR_MEMORY_DEVICE_PRIVATE = 1,
+};
+
 #endif /* _LIB_TEST_HMM_UAPI_H */
-- 
2.32.0



[PATCH v2 09/12] lib: test_hmm add module param for zone device type

2021-09-13 Thread Alex Sierra
In order to configure device public in test_hmm, two module parameters
should be passed, which correspond to the SP start address of each
device (2) spm_addr_dev0 & spm_addr_dev1. If no parameters are passed,
private device type is configured.

Signed-off-by: Alex Sierra 
---
v5:
Remove devmem->pagemap.type = MEMORY_DEVICE_PRIVATE at
dmirror_allocate_chunk that was forcing to configure pagemap.type
to MEMORY_DEVICE_PRIVATE

v6:
Check for null pointers for resource and memremap references
at dmirror_allocate_chunk

v7:
Due to patch dropped from these patch series "kernel: resource:
lookup_resource as exported symbol", lookup_resource was not longer a
callable function. This was used in public device configuration, to
get start and end addresses, to create pgmap->range struct. This
information is now taken directly from the spm_addr_devX parameters and
the fixed size DEVMEM_CHUNK_SIZE.
---
 lib/test_hmm.c  | 66 +++--
 lib/test_hmm_uapi.h |  1 +
 2 files changed, 47 insertions(+), 20 deletions(-)

diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index 3cd91ca31dd7..ef27e355738a 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -33,6 +33,16 @@
 #define DEVMEM_CHUNK_SIZE  (256 * 1024 * 1024U)
 #define DEVMEM_CHUNKS_RESERVE  16
 
+static unsigned long spm_addr_dev0;
+module_param(spm_addr_dev0, long, 0644);
+MODULE_PARM_DESC(spm_addr_dev0,
+   "Specify start address for SPM (special purpose memory) used 
for device 0. By setting this Generic device type will be used. Make sure 
spm_addr_dev1 is set too");
+
+static unsigned long spm_addr_dev1;
+module_param(spm_addr_dev1, long, 0644);
+MODULE_PARM_DESC(spm_addr_dev1,
+   "Specify start address for SPM (special purpose memory) used 
for device 1. By setting this Generic device type will be used. Make sure 
spm_addr_dev0 is set too");
+
 static const struct dev_pagemap_ops dmirror_devmem_ops;
 static const struct mmu_interval_notifier_ops dmirror_min_ops;
 static dev_t dmirror_dev;
@@ -450,11 +460,11 @@ static int dmirror_write(struct dmirror *dmirror, struct 
hmm_dmirror_cmd *cmd)
return ret;
 }
 
-static bool dmirror_allocate_chunk(struct dmirror_device *mdevice,
+static int dmirror_allocate_chunk(struct dmirror_device *mdevice,
   struct page **ppage)
 {
struct dmirror_chunk *devmem;
-   struct resource *res;
+   struct resource *res = NULL;
unsigned long pfn;
unsigned long pfn_first;
unsigned long pfn_last;
@@ -462,17 +472,29 @@ static bool dmirror_allocate_chunk(struct dmirror_device 
*mdevice,
 
devmem = kzalloc(sizeof(*devmem), GFP_KERNEL);
if (!devmem)
-   return false;
+   return -ENOMEM;
 
-   res = request_free_mem_region(&iomem_resource, DEVMEM_CHUNK_SIZE,
- "hmm_dmirror");
-   if (IS_ERR(res))
-   goto err_devmem;
+   if (!spm_addr_dev0 && !spm_addr_dev1) {
+   res = request_free_mem_region(&iomem_resource, 
DEVMEM_CHUNK_SIZE,
+ "hmm_dmirror");
+   if (IS_ERR_OR_NULL(res))
+   goto err_devmem;
+   devmem->pagemap.range.start = res->start;
+   devmem->pagemap.range.end = res->end;
+   devmem->pagemap.type = MEMORY_DEVICE_PRIVATE;
+   mdevice->zone_device_type = HMM_DMIRROR_MEMORY_DEVICE_PRIVATE;
+   } else if (spm_addr_dev0 && spm_addr_dev1) {
+   devmem->pagemap.range.start = MINOR(mdevice->cdevice.dev) ?
+   spm_addr_dev0 :
+   spm_addr_dev1;
+   devmem->pagemap.range.end = devmem->pagemap.range.start +
+   DEVMEM_CHUNK_SIZE - 1;
+   devmem->pagemap.type = MEMORY_DEVICE_PUBLIC;
+   mdevice->zone_device_type = HMM_DMIRROR_MEMORY_DEVICE_PUBLIC;
+   } else {
+   pr_err("Both spm_addr_dev parameters should be set\n");
+   }
 
-   mdevice->zone_device_type = HMM_DMIRROR_MEMORY_DEVICE_PRIVATE;
-   devmem->pagemap.type = MEMORY_DEVICE_PRIVATE;
-   devmem->pagemap.range.start = res->start;
-   devmem->pagemap.range.end = res->end;
devmem->pagemap.nr_range = 1;
devmem->pagemap.ops = &dmirror_devmem_ops;
devmem->pagemap.owner = mdevice;
@@ -493,10 +515,14 @@ static bool dmirror_allocate_chunk(struct dmirror_device 
*mdevice,
mdevice->devmem_capacity = new_capacity;
mdevice->devmem_chunks = new_chunks;
}
-
ptr = memremap_pages(&devmem->pagemap, numa_node_id());
-   if (IS_ERR(ptr))
+   if (IS_ERR_OR_NULL(ptr)) {
+   if (ptr)
+   ret = PTR_ERR(ptr);
+   else
+   ret = -EFAULT;
goto e

[PATCH v2 12/12] tools: update test_hmm script to support SP config

2021-09-13 Thread Alex Sierra
Add two more parameters to set spm_addr_dev0 & spm_addr_dev1
addresses. These two parameters configure the start SP
addresses for each device in test_hmm driver.
Consequently, this configures zone device type as public.

Signed-off-by: Alex Sierra 
---
 tools/testing/selftests/vm/test_hmm.sh | 20 +---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/vm/test_hmm.sh 
b/tools/testing/selftests/vm/test_hmm.sh
index 0647b525a625..3eeabe94399f 100755
--- a/tools/testing/selftests/vm/test_hmm.sh
+++ b/tools/testing/selftests/vm/test_hmm.sh
@@ -40,7 +40,18 @@ check_test_requirements()
 
 load_driver()
 {
-   modprobe $DRIVER > /dev/null 2>&1
+   if [ $# -eq 0 ]; then
+   modprobe $DRIVER > /dev/null 2>&1
+   else
+   if [ $# -eq 2 ]; then
+   modprobe $DRIVER spm_addr_dev0=$1 spm_addr_dev1=$2
+   > /dev/null 2>&1
+   else
+   echo "Missing module parameters. Make sure pass"\
+   "spm_addr_dev0 and spm_addr_dev1"
+   usage
+   fi
+   fi
if [ $? == 0 ]; then
major=$(awk "\$2==\"HMM_DMIRROR\" {print \$1}" /proc/devices)
mknod /dev/hmm_dmirror0 c $major 0
@@ -58,7 +69,7 @@ run_smoke()
 {
echo "Running smoke test. Note, this test provides basic coverage."
 
-   load_driver
+   load_driver $1 $2
$(dirname "${BASH_SOURCE[0]}")/hmm-tests
unload_driver
 }
@@ -75,6 +86,9 @@ usage()
echo "# Smoke testing"
echo "./${TEST_NAME}.sh smoke"
echo
+   echo "# Smoke testing with SPM enabled"
+   echo "./${TEST_NAME}.sh smoke  "
+   echo
exit 0
 }
 
@@ -84,7 +98,7 @@ function run_test()
usage
else
if [ "$1" = "smoke" ]; then
-   run_smoke
+   run_smoke $2 $3
else
usage
fi
-- 
2.32.0



[PATCH v2 10/12] lib: add support for device public type in test_hmm

2021-09-13 Thread Alex Sierra
Device Public type uses device memory that is coherently accesible by
the CPU. This could be shown as SP (special purpose) memory range
at the BIOS-e820 memory enumeration. If no SP memory is supported in
system, this could be faked by setting CONFIG_EFI_FAKE_MEMMAP.

Currently, test_hmm only supports two different SP ranges of at least
256MB size. This could be specified in the kernel parameter variable
efi_fake_mem. Ex. Two SP ranges of 1GB starting at 0x1 &
0x14000 physical address. Ex.
efi_fake_mem=1G@0x1:0x4,1G@0x14000:0x4

Signed-off-by: Alex Sierra 
---
 lib/test_hmm.c  | 166 +++-
 lib/test_hmm_uapi.h |  10 ++-
 2 files changed, 113 insertions(+), 63 deletions(-)

diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index ef27e355738a..e346a48e2509 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -469,6 +469,7 @@ static int dmirror_allocate_chunk(struct dmirror_device 
*mdevice,
unsigned long pfn_first;
unsigned long pfn_last;
void *ptr;
+   int ret = -ENOMEM;
 
devmem = kzalloc(sizeof(*devmem), GFP_KERNEL);
if (!devmem)
@@ -551,7 +552,7 @@ static int dmirror_allocate_chunk(struct dmirror_device 
*mdevice,
}
spin_unlock(&mdevice->lock);
 
-   return true;
+   return 0;
 
 err_release:
mutex_unlock(&mdevice->devmem_lock);
@@ -560,7 +561,7 @@ static int dmirror_allocate_chunk(struct dmirror_device 
*mdevice,
 err_devmem:
kfree(devmem);
 
-   return false;
+   return ret;
 }
 
 static struct page *dmirror_devmem_alloc_page(struct dmirror_device *mdevice)
@@ -569,8 +570,10 @@ static struct page *dmirror_devmem_alloc_page(struct 
dmirror_device *mdevice)
struct page *rpage;
 
/*
-* This is a fake device so we alloc real system memory to store
-* our device memory.
+* For ZONE_DEVICE private type, this is a fake device so we alloc real
+* system memory to store our device memory.
+* For ZONE_DEVICE public type we use the actual dpage to store the data
+* and ignore rpage.
 */
rpage = alloc_page(GFP_HIGHUSER);
if (!rpage)
@@ -603,7 +606,7 @@ static void dmirror_migrate_alloc_and_copy(struct 
migrate_vma *args,
   struct dmirror *dmirror)
 {
struct dmirror_device *mdevice = dmirror->mdevice;
-   const unsigned long *src = args->src;
+   unsigned long *src = args->src;
unsigned long *dst = args->dst;
unsigned long addr;
 
@@ -621,12 +624,18 @@ static void dmirror_migrate_alloc_and_copy(struct 
migrate_vma *args,
 * unallocated pte_none() or read-only zero page.
 */
spage = migrate_pfn_to_page(*src);
-
+   if (spage && is_zone_device_page(spage)) {
+   pr_debug("page already in device spage pfn: 0x%lx\n",
+ page_to_pfn(spage));
+   *src &= ~MIGRATE_PFN_MIGRATE;
+   continue;
+   }
dpage = dmirror_devmem_alloc_page(mdevice);
if (!dpage)
continue;
 
-   rpage = dpage->zone_device_data;
+   rpage = is_device_private_page(dpage) ? dpage->zone_device_data 
:
+   dpage;
if (spage)
copy_highpage(rpage, spage);
else
@@ -638,8 +647,10 @@ static void dmirror_migrate_alloc_and_copy(struct 
migrate_vma *args,
 * the simulated device memory and that page holds the pointer
 * to the mirror.
 */
+   rpage = dpage->zone_device_data;
rpage->zone_device_data = dmirror;
-
+   pr_debug("migrating from sys to dev pfn src: 0x%lx pfn dst: 
0x%lx\n",
+page_to_pfn(spage), page_to_pfn(dpage));
*dst = migrate_pfn(page_to_pfn(dpage)) |
MIGRATE_PFN_LOCKED;
if ((*src & MIGRATE_PFN_WRITE) ||
@@ -673,10 +684,13 @@ static int dmirror_migrate_finalize_and_map(struct 
migrate_vma *args,
continue;
 
/*
-* Store the page that holds the data so the page table
-* doesn't have to deal with ZONE_DEVICE private pages.
+* For ZONE_DEVICE private pages we store the page that
+* holds the data so the page table doesn't have to deal it.
+* For ZONE_DEVICE public pages we store the actual page, since
+* the CPU has coherent access to the page.
 */
-   entry = dpage->zone_device_data;
+   entry = is_device_private_page(dpage) ? dpage->zone_device_data 
:
+   dpage;
if (*dst & MIGRATE_PF

Re: [PATCH v2 0/6] drm/displayid: VESA vendor block and drm/i915 MSO use of it

2021-09-13 Thread Jani Nikula
On Tue, 31 Aug 2021, Jani Nikula  wrote:
> v2 of https://patchwork.freedesktop.org/series/94161/ with the VESA OUI
> check and an OUI helper patch added.

Maarten, Maxime, Thomas - may I have an ack for merging this via
drm-intel? I think at this time we can get the merge to drm-next and
backmerge to drm-misc fairly quickly, and a topic branch would be
overkill.

Alternative, I think it's also fine to merge all of this via drm-misc if
you prefer.

BR,
Jani.


>
> Jani Nikula (6):
>   drm/displayid: re-align data block macros
>   drm/displayid: add DisplayID v2.0 data blocks and primary use cases
>   drm/edid: abstract OUI conversion to 24-bit int
>   drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO
>   drm/i915/edp: postpone MSO init until after EDID read
>   drm/i915/edp: use MSO pixel overlap from DisplayID data
>
>  drivers/gpu/drm/drm_edid.c  |  89 ++---
>  drivers/gpu/drm/i915/display/intel_dp.c |  14 ++--
>  include/drm/drm_connector.h |  12 +++
>  include/drm/drm_displayid.h | 101 +---
>  4 files changed, 172 insertions(+), 44 deletions(-)

-- 
Jani Nikula, Intel Open Source Graphics Center


[PATCH] drm/msm: Fix devfreq NULL pointer dereference on a3xx

2021-09-13 Thread Stephan Gerhold
There is no devfreq on a3xx at the moment since gpu_busy is not
implemented. This means that msm_devfreq_init() will return early
and the entire devfreq setup is skipped.

However, msm_devfreq_active() and msm_devfreq_idle() are still called
unconditionally later, causing a NULL pointer dereference:

  Unable to handle kernel NULL pointer dereference at virtual address 
0010
  Internal error: Oops: 9604 [#1] PREEMPT SMP
  CPU: 0 PID: 133 Comm: ring0 Not tainted 5.15.0-rc1 #4
  Hardware name: Longcheer L8150 (DT)
  pc : mutex_lock_io+0x2bc/0x2f0
  lr : msm_devfreq_active+0x3c/0xe0 [msm]
  Call trace:
   mutex_lock_io+0x2bc/0x2f0
   msm_gpu_submit+0x164/0x180 [msm]
   msm_job_run+0x54/0xe0 [msm]
   drm_sched_main+0x2b0/0x4a0 [gpu_sched]
   kthread+0x154/0x160
   ret_from_fork+0x10/0x20

Fix this by adding a check in msm_devfreq_active/idle() which ensures
that devfreq was actually initialized earlier.

Fixes: 9bc95570175a ("drm/msm: Devfreq tuning")
Reported-by: Nikita Travkin 
Tested-by: Nikita Travkin 
Signed-off-by: Stephan Gerhold 
---
 drivers/gpu/drm/msm/msm_gpu_devfreq.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c 
b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
index 0a1ee20296a2..84e98c07c900 100644
--- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c
+++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
@@ -151,6 +151,9 @@ void msm_devfreq_active(struct msm_gpu *gpu)
unsigned int idle_time;
unsigned long target_freq = df->idle_freq;
 
+   if (!df->devfreq)
+   return;
+
/*
 * Hold devfreq lock to synchronize with get_dev_status()/
 * target() callbacks
@@ -186,6 +189,9 @@ void msm_devfreq_idle(struct msm_gpu *gpu)
struct msm_gpu_devfreq *df = &gpu->devfreq;
unsigned long idle_freq, target_freq = 0;
 
+   if (!df->devfreq)
+   return;
+
/*
 * Hold devfreq lock to synchronize with get_dev_status()/
 * target() callbacks
-- 
2.33.0



Re: [PATCH 2/2] drm/amdgpu: Demote TMZ unsupported log message from warning to info

2021-09-13 Thread Alex Deucher
Applied.  Thanks.

Alex

On Mon, Sep 13, 2021 at 4:46 AM Paul Menzel  wrote:
>
> As the user cannot do anything about the unsupported Trusted Memory Zone
> (TMZ) feature, do not warn about it, but make it informational, so
> demote the log level from warning to info.
>
> Signed-off-by: Paul Menzel 
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> index c4c56c57b0c0..bfa0275ff5d4 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
> @@ -598,7 +598,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
> break;
> default:
> adev->gmc.tmz_enabled = false;
> -   dev_warn(adev->dev,
> +   dev_info(adev->dev,
>  "Trusted Memory Zone (TMZ) feature not supported by 
> hardware\n");
> break;
> }
> --
> 2.33.0
>


Re: [Intel-gfx] [PATCH 08/27] drm/i915: Add logical engine mapping

2021-09-13 Thread Matthew Brost
On Mon, Sep 13, 2021 at 10:24:43AM +0100, Tvrtko Ursulin wrote:
> 
> On 10/09/2021 20:49, Matthew Brost wrote:
> > On Fri, Sep 10, 2021 at 12:12:42PM +0100, Tvrtko Ursulin wrote:
> > > 
> > > On 20/08/2021 23:44, Matthew Brost wrote:
> > > > Add logical engine mapping. This is required for split-frame, as
> > > > workloads need to be placed on engines in a logically contiguous manner.
> > > > 
> > > > v2:
> > > >(Daniel Vetter)
> > > > - Add kernel doc for new fields
> > > > 
> > > > Signed-off-by: Matthew Brost 
> > > > ---
> > > >drivers/gpu/drm/i915/gt/intel_engine_cs.c | 60 
> > > > ---
> > > >drivers/gpu/drm/i915/gt/intel_engine_types.h  |  5 ++
> > > >.../drm/i915/gt/intel_execlists_submission.c  |  1 +
> > > >drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c|  2 +-
> > > >.../gpu/drm/i915/gt/uc/intel_guc_submission.c | 21 +--
> > > >5 files changed, 60 insertions(+), 29 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c 
> > > > b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
> > > > index 0d9105a31d84..4d790f9a65dd 100644
> > > > --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
> > > > +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
> > > > @@ -290,7 +290,8 @@ static void nop_irq_handler(struct intel_engine_cs 
> > > > *engine, u16 iir)
> > > > GEM_DEBUG_WARN_ON(iir);
> > > >}
> > > > -static int intel_engine_setup(struct intel_gt *gt, enum 
> > > > intel_engine_id id)
> > > > +static int intel_engine_setup(struct intel_gt *gt, enum 
> > > > intel_engine_id id,
> > > > + u8 logical_instance)
> > > >{
> > > > const struct engine_info *info = &intel_engines[id];
> > > > struct drm_i915_private *i915 = gt->i915;
> > > > @@ -334,6 +335,7 @@ static int intel_engine_setup(struct intel_gt *gt, 
> > > > enum intel_engine_id id)
> > > > engine->class = info->class;
> > > > engine->instance = info->instance;
> > > > +   engine->logical_mask = BIT(logical_instance);
> > > > __sprint_engine_name(engine);
> > > > engine->props.heartbeat_interval_ms =
> > > > @@ -572,6 +574,37 @@ static intel_engine_mask_t init_engine_mask(struct 
> > > > intel_gt *gt)
> > > > return info->engine_mask;
> > > >}
> > > > +static void populate_logical_ids(struct intel_gt *gt, u8 *logical_ids,
> > > > +u8 class, const u8 *map, u8 
> > > > num_instances)
> > > > +{
> > > > +   int i, j;
> > > > +   u8 current_logical_id = 0;
> > > > +
> > > > +   for (j = 0; j < num_instances; ++j) {
> > > > +   for (i = 0; i < ARRAY_SIZE(intel_engines); ++i) {
> > > > +   if (!HAS_ENGINE(gt, i) ||
> > > > +   intel_engines[i].class != class)
> > > > +   continue;
> > > > +
> > > > +   if (intel_engines[i].instance == map[j]) {
> > > > +   logical_ids[intel_engines[i].instance] =
> > > > +   current_logical_id++;
> > > > +   break;
> > > > +   }
> > > > +   }
> > > > +   }
> > > > +}
> > > > +
> > > > +static void setup_logical_ids(struct intel_gt *gt, u8 *logical_ids, u8 
> > > > class)
> > > > +{
> > > > +   int i;
> > > > +   u8 map[MAX_ENGINE_INSTANCE + 1];
> > > > +
> > > > +   for (i = 0; i < MAX_ENGINE_INSTANCE + 1; ++i)
> > > > +   map[i] = i;
> > > 
> > > What's the point of the map array since it is 1:1 with instance?
> > > 
> > 
> > Future products do not have a 1 to 1 mapping and that mapping can change
> > based on fusing, e.g. XeHP SDV.
> > 
> > Also technically ICL / TGL / ADL physical instance 2 maps to logical
> > instance 1.
> 
> I don't follow the argument. All I can see is that "map[i] = i" always in
> the proposed code, which is then used to check "instance == map[instance]".
> So I'd suggest to remove this array from the code until there is a need for
> it.
> 

Ok, this logic is slightly confusing and makes more sense once we have
non-standard mappings. Yes, map is setup in a 1 to 1 mapping by default
with the value in map[i] being a physical instance. Populate_logical_ids
searches the map finding all physical instances present in the map
assigning each found instance a new logical id increasing by 1 each
time.

e.g. If the map is setup 0-N and only physical instance 0 / 2 are
present they will get logical mapping 0 / 1 respectfully.

This algorithm works for non-standard mappings too /w fused parts. e.g.
on XeHP SDV the map is: { 0, 2, 4, 6, 1, 3, 5, 7 } and if any of the
physical instances can't be found due to fusing the logical mapping is
still correct per the bspec.

This array is absolutely needed for multi-lrc submission to work, even
on ICL / TGL / ADL as the GuC only supports logically contiguous engine
instances.

> > > > +   populate

Re: [Intel-gfx] [PATCH 07/27] drm/i915/guc: Don't call switch_to_kernel_context with GuC submission

2021-09-13 Thread Matthew Brost
On Thu, Sep 09, 2021 at 03:51:27PM -0700, John Harrison wrote:
> On 8/20/2021 15:44, Matthew Brost wrote:
> > Calling switch_to_kernel_context isn't needed if the engine PM reference
> > is taken while all contexts are pinned. By not calling
> > switch_to_kernel_context we save on issuing a request to the engine.
> I thought the intention of the switch_to_kernel was to ensure that the GPU
> is not touching any user context and is basically idle. That is not a valid
> assumption with an external scheduler such as GuC. So why is the description
> above only mentioning PM references? What is the connection between the PM
> ref and the switch_to_kernel?
> 
> Also, the comment in the code does not mention anything about PM references,
> it just says 'not necessary with GuC' but no explanation at all.
> 

Yea, this need to be explained better. How about this?

Calling switch_to_kernel_context isn't needed if the engine PM reference
is take while all user contexts have scheduling enabled. Once scheduling
is disabled on all user contexts the GuC is guaranteed to not touch any
user context state which is effectively the same pointing to a kernel
context.

Matt

> 
> > v2:
> >   (Daniel Vetter)
> >- Add FIXME comment about pushing switch_to_kernel_context to backend
> > 
> > Signed-off-by: Matthew Brost 
> > Reviewed-by: Daniel Vetter 
> > ---
> >   drivers/gpu/drm/i915/gt/intel_engine_pm.c | 9 +
> >   1 file changed, 9 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c 
> > b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
> > index 1f07ac4e0672..11fee66daf60 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
> > @@ -162,6 +162,15 @@ static bool switch_to_kernel_context(struct 
> > intel_engine_cs *engine)
> > unsigned long flags;
> > bool result = true;
> > +   /*
> > +* No need to switch_to_kernel_context if GuC submission
> > +*
> > +* FIXME: This execlists specific backend behavior in generic code, this
> "This execlists" -> "This is execlist"
> 
> "this should be" -> "it should be"
> 
> John.
> 
> > +* should be pushed to the backend.
> > +*/
> > +   if (intel_engine_uses_guc(engine))
> > +   return true;
> > +
> > /* GPU is pointing to the void, as good as in the kernel context. */
> > if (intel_gt_is_wedged(engine->gt))
> > return true;
> 


Re: [Intel-gfx] [PATCH 07/27] drm/i915/guc: Don't call switch_to_kernel_context with GuC submission

2021-09-13 Thread Matthew Brost
On Thu, Sep 09, 2021 at 03:51:27PM -0700, John Harrison wrote:
> On 8/20/2021 15:44, Matthew Brost wrote:
> > Calling switch_to_kernel_context isn't needed if the engine PM reference
> > is taken while all contexts are pinned. By not calling
> > switch_to_kernel_context we save on issuing a request to the engine.
> I thought the intention of the switch_to_kernel was to ensure that the GPU
> is not touching any user context and is basically idle. That is not a valid
> assumption with an external scheduler such as GuC. So why is the description
> above only mentioning PM references? What is the connection between the PM
> ref and the switch_to_kernel?
> 
> Also, the comment in the code does not mention anything about PM references,
> it just says 'not necessary with GuC' but no explanation at all.
> 
> 
> > v2:
> >   (Daniel Vetter)
> >- Add FIXME comment about pushing switch_to_kernel_context to backend
> > 
> > Signed-off-by: Matthew Brost 
> > Reviewed-by: Daniel Vetter 
> > ---
> >   drivers/gpu/drm/i915/gt/intel_engine_pm.c | 9 +
> >   1 file changed, 9 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c 
> > b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
> > index 1f07ac4e0672..11fee66daf60 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
> > @@ -162,6 +162,15 @@ static bool switch_to_kernel_context(struct 
> > intel_engine_cs *engine)
> > unsigned long flags;
> > bool result = true;
> > +   /*
> > +* No need to switch_to_kernel_context if GuC submission
> > +*
> > +* FIXME: This execlists specific backend behavior in generic code, this
> "This execlists" -> "This is execlist"
> 
> "this should be" -> "it should be"
> 

Missed this. Will fix in next rev.

Matt

> John.
> 
> > +* should be pushed to the backend.
> > +*/
> > +   if (intel_engine_uses_guc(engine))
> > +   return true;
> > +
> > /* GPU is pointing to the void, as good as in the kernel context. */
> > if (intel_gt_is_wedged(engine->gt))
> > return true;
> 


Re: [Intel-gfx] [PATCH 04/27] drm/i915/guc: Take GT PM ref when deregistering context

2021-09-13 Thread Matthew Brost
On Mon, Sep 13, 2021 at 10:55:59AM +0100, Tvrtko Ursulin wrote:
> 
> On 20/08/2021 23:44, Matthew Brost wrote:
> > Taking a PM reference to prevent intel_gt_wait_for_idle from short
> > circuiting while a deregister context H2G is in flight.
> > 
> > FIXME: Move locking / structure changes into different patch
> > 
> > Signed-off-by: Matthew Brost 
> > ---
> >   drivers/gpu/drm/i915/gt/intel_context.c   |   2 +
> >   drivers/gpu/drm/i915/gt/intel_context_types.h |  13 +-
> >   drivers/gpu/drm/i915/gt/intel_engine_pm.h |   5 +
> >   drivers/gpu/drm/i915/gt/intel_gt_pm.h |  13 ++
> >   .../gpu/drm/i915/gt/uc/abi/guc_actions_abi.h  |   1 +
> >   drivers/gpu/drm/i915/gt/uc/intel_guc.h|  46 ++--
> >   .../gpu/drm/i915/gt/uc/intel_guc_debugfs.c|  13 +-
> >   .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 212 +++---
> >   8 files changed, 199 insertions(+), 106 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/intel_context.c 
> > b/drivers/gpu/drm/i915/gt/intel_context.c
> > index adfe49b53b1b..c8595da64ad8 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_context.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_context.c
> > @@ -399,6 +399,8 @@ intel_context_init(struct intel_context *ce, struct 
> > intel_engine_cs *engine)
> > ce->guc_id.id = GUC_INVALID_LRC_ID;
> > INIT_LIST_HEAD(&ce->guc_id.link);
> > +   INIT_LIST_HEAD(&ce->destroyed_link);
> > +
> > /*
> >  * Initialize fence to be complete as this is expected to be complete
> >  * unless there is a pending schedule disable outstanding.
> > diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h 
> > b/drivers/gpu/drm/i915/gt/intel_context_types.h
> > index 80bbdc7810f6..fd338a30617e 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_context_types.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
> > @@ -190,22 +190,29 @@ struct intel_context {
> > /**
> >  * @id: unique handle which is used to communicate information
> >  * with the GuC about this context, protected by
> > -* guc->contexts_lock
> > +* guc->submission_state.lock
> >  */
> > u16 id;
> > /**
> >  * @ref: the number of references to the guc_id, when
> >  * transitioning in and out of zero protected by
> > -* guc->contexts_lock
> > +* guc->submission_state.lock
> >  */
> > atomic_t ref;
> > /**
> >  * @link: in guc->guc_id_list when the guc_id has no refs but is
> > -* still valid, protected by guc->contexts_lock
> > +* still valid, protected by guc->submission_state.lock
> >  */
> > struct list_head link;
> > } guc_id;
> > +   /**
> > +* @destroyed_link: link in guc->submission_state.destroyed_contexts, in
> > +* list when context is pending to be destroyed (deregistered with the
> > +* GuC), protected by guc->submission_state.lock
> > +*/
> > +   struct list_head destroyed_link;
> > +
> >   #ifdef CONFIG_DRM_I915_SELFTEST
> > /**
> >  * @drop_schedule_enable: Force drop of schedule enable G2H for selftest
> > diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h 
> > b/drivers/gpu/drm/i915/gt/intel_engine_pm.h
> > index 70ea46d6cfb0..17a5028ea177 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h
> > @@ -16,6 +16,11 @@ intel_engine_pm_is_awake(const struct intel_engine_cs 
> > *engine)
> > return intel_wakeref_is_active(&engine->wakeref);
> >   }
> > +static inline void __intel_engine_pm_get(struct intel_engine_cs *engine)
> > +{
> > +   __intel_wakeref_get(&engine->wakeref);
> > +}
> > +
> >   static inline void intel_engine_pm_get(struct intel_engine_cs *engine)
> >   {
> > intel_wakeref_get(&engine->wakeref);
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h 
> > b/drivers/gpu/drm/i915/gt/intel_gt_pm.h
> > index d0588d8aaa44..a17bf0d4592b 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h
> > @@ -41,6 +41,19 @@ static inline void intel_gt_pm_put_async(struct intel_gt 
> > *gt)
> > intel_wakeref_put_async(>->wakeref);
> >   }
> > +#define with_intel_gt_pm(gt, tmp) \
> > +   for (tmp = 1, intel_gt_pm_get(gt); tmp; \
> > +intel_gt_pm_put(gt), tmp = 0)
> > +#define with_intel_gt_pm_async(gt, tmp) \
> > +   for (tmp = 1, intel_gt_pm_get(gt); tmp; \
> > +intel_gt_pm_put_async(gt), tmp = 0)
> > +#define with_intel_gt_pm_if_awake(gt, tmp) \
> > +   for (tmp = intel_gt_pm_get_if_awake(gt); tmp; \
> > +intel_gt_pm_put(gt), tmp = 0)
> > +#define with_intel_gt_pm_if_awake_async(gt, tmp) \
> > +   for (tmp = intel_gt_pm_get_if_awake(gt); tmp; \
> > +intel_gt_pm_put_async(gt), tmp = 0)
> > +
> >   static inline int intel_gt_pm_wait_for_idle(struct intel_gt *gt)
> >   {
> > return intel_wakeref_wait_for_idle(>-

[PATCH] drm/sun4i: dw-hdmi: Fix HDMI PHY clock setup

2021-09-13 Thread Jernej Skrabec
Recent rework, which made HDMI PHY driver a platform device, inadvertely
reversed clock setup order. HW is very touchy about it. Proper way is to
handle controllers resets and clocks first and HDMI PHYs second.

Currently, without this fix, first mode set completely fails (nothing on
HDMI monitor) on H3 era PHYs. On H6, it still somehow work.

Move HDMI PHY reset & clocks handling to sun8i_hdmi_phy_init() which
will assure that code is executed after controllers reset & clocks are
handled. Additionally, add sun8i_hdmi_phy_deinit() which will deinit
them at controllers driver unload.

Tested on A64, H3, H6 and R40.

Fixes: 9bf3797796f5 ("drm/sun4i: dw-hdmi: Make HDMI PHY into a platform device")
Signed-off-by: Jernej Skrabec 
---
 drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c  |  7 +-
 drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h  |  4 +-
 drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 97 ++
 3 files changed, 61 insertions(+), 47 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c 
b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
index f75fb157f2ff..5fa5407ac583 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
@@ -216,11 +216,13 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct 
device *master,
goto err_disable_clk_tmds;
}
 
+   ret = sun8i_hdmi_phy_init(hdmi->phy);
+   if (ret)
+   return ret;
+
drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs);
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
-   sun8i_hdmi_phy_init(hdmi->phy);
-
plat_data->mode_valid = hdmi->quirks->mode_valid;
plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe;
sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data);
@@ -262,6 +264,7 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct 
device *master,
struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev);
 
dw_hdmi_unbind(hdmi->hdmi);
+   sun8i_hdmi_phy_deinit(hdmi->phy);
clk_disable_unprepare(hdmi->clk_tmds);
reset_control_assert(hdmi->rst_ctrl);
gpiod_set_value(hdmi->ddc_en, 0);
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h 
b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index 74f6ed0e2570..bffe1b9cd3dc 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -169,6 +169,7 @@ struct sun8i_hdmi_phy {
struct clk  *clk_phy;
struct clk  *clk_pll0;
struct clk  *clk_pll1;
+   struct device   *dev;
unsigned intrcal;
struct regmap   *regs;
struct reset_control*rst_phy;
@@ -205,7 +206,8 @@ encoder_to_sun8i_dw_hdmi(struct drm_encoder *encoder)
 
 int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node);
 
-void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
+int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
+void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy);
 void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
struct dw_hdmi_plat_data *plat_data);
 
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c 
b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index c9239708d398..78b152973957 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -506,9 +506,60 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy 
*phy)
phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2;
 }
 
-void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
+int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
 {
+   int ret;
+
+   ret = reset_control_deassert(phy->rst_phy);
+   if (ret) {
+   dev_err(phy->dev, "Cannot deassert phy reset control: %d\n", 
ret);
+   return ret;
+   }
+
+   ret = clk_prepare_enable(phy->clk_bus);
+   if (ret) {
+   dev_err(phy->dev, "Cannot enable bus clock: %d\n", ret);
+   goto err_deassert_rst_phy;
+   }
+
+   ret = clk_prepare_enable(phy->clk_mod);
+   if (ret) {
+   dev_err(phy->dev, "Cannot enable mod clock: %d\n", ret);
+   goto err_disable_clk_bus;
+   }
+
+   if (phy->variant->has_phy_clk) {
+   ret = sun8i_phy_clk_create(phy, phy->dev,
+  phy->variant->has_second_pll);
+   if (ret) {
+   dev_err(phy->dev, "Couldn't create the PHY clock\n");
+   goto err_disable_clk_mod;
+   }
+
+   clk_prepare_enable(phy->clk_phy);
+   }
+
phy->variant->phy_init(phy);
+
+   return 0;
+
+err_disable_clk_mod:
+   clk_disable_unprepare(phy->clk_mod);
+err_disable_clk_bus:
+   clk_disable_unprepare(phy->clk_bus);
+err_deassert_rst_phy:
+   reset_control_assert(phy->rst_phy);
+
+   r

Re: [Intel-gfx] [PATCH 05/27] drm/i915: Add GT PM unpark worker

2021-09-13 Thread Matthew Brost
On Mon, Sep 13, 2021 at 11:33:46AM +0100, Tvrtko Ursulin wrote:
> 
> On 10/09/2021 21:09, Matthew Brost wrote:
> > On Fri, Sep 10, 2021 at 09:36:17AM +0100, Tvrtko Ursulin wrote:
> > > 
> > > On 20/08/2021 23:44, Matthew Brost wrote:
> > > > Sometimes it is desirable to queue work up for later if the GT PM isn't
> > > > held and run that work on next GT PM unpark.
> > > 
> > > Sounds maybe plausible, but it depends how much work can happen on unpark
> > > and whether it can have too much of a negative impact on latency for
> > > interactive loads? Or from a reverse angle, why the work wouldn't be done 
> > > on
> > 
> > All it is does is add an interface to kick a work queue on unpark. i.e.
> > All the actually work is done async in the work queue so it shouldn't
> > add any latency.
> > 
> > > parking?
> > > 
> > > Also what kind of mechanism for dealing with too much stuff being put on
> > > this list you have? Can there be pressure which triggers (or would need to
> > 
> > No limits on pressure. See above, I don't think this is a concern.
> 
> On unpark it has the potential to send an unbound amount of actions for the
> GuC to process. Which will be competing, in GuC internal processing power,
> with the user action which caused the unpark. That logically does feel like
> can have effect on initial latency. Why you think it cannot?
> 

Ah, I see what you mean. Yes, bunch of deregisters could be sent before
a submission adding latency. Maybe I just drop this whole idea / patch
for now. Not going to respond to individual comments because this will
be dropped.

Matt

> Why the work wouldn't be done on parking?
> 
> With this scheme couldn't we end up with a situation that the worker keeps
> missing the GT unparked state and so keeps piling items on the
> deregistration list? Can you run of some ids like that (which is related to
> my question of how is pressure handled here).
> 
> Unpark
> Register context
> Submit work
> Retire
> Schedule context deregister
> Park
> 
> Worker runs
> GT parked
> Work put on a list
> 
> Unpark
> Schedule deregistration worker
> Register new context
> Submit work
> Retire
> Schedule contect deregister
> Park
> 
> Worker runs (lets say there was CPU pressure)
> GT already parked
>  -> deregistration queue now has two contexts on it
> 
> ... repeat until disaster ...
> 
> Unless I have misunderstood the logic.
> 
> > > trigger) these deregistrations to happen at runtime (no park/unpark
> > > transitions)?
> > > 
> > > > Implemented with a list in the GT of all pending work, workqueues in
> > > > the list, a callback to add a workqueue to the list, and finally a
> > > > wakeref post_get callback that iterates / drains the list + queues the
> > > > workqueues.
> > > > 
> > > > First user of this is deregistration of GuC contexts.
> > > 
> > > Does first imply there are more incoming?
> > > 
> > 
> > Haven't found another user yet but this is generic mechanism so we can
> > add more in the future if other use cases arrise.
> 
> My feeling is it would be best to leave it for later.
> 
> > > > Signed-off-by: Matthew Brost 
> > > > ---
> > > >drivers/gpu/drm/i915/Makefile |  1 +
> > > >drivers/gpu/drm/i915/gt/intel_gt.c|  3 ++
> > > >drivers/gpu/drm/i915/gt/intel_gt_pm.c |  8 
> > > >.../gpu/drm/i915/gt/intel_gt_pm_unpark_work.c | 35 
> > > >.../gpu/drm/i915/gt/intel_gt_pm_unpark_work.h | 40 
> > > > +++
> > > >drivers/gpu/drm/i915/gt/intel_gt_types.h  | 10 +
> > > >drivers/gpu/drm/i915/gt/uc/intel_guc.h|  8 ++--
> > > >.../gpu/drm/i915/gt/uc/intel_guc_submission.c | 15 +--
> > > >drivers/gpu/drm/i915/intel_wakeref.c  |  5 +++
> > > >drivers/gpu/drm/i915/intel_wakeref.h  |  1 +
> > > >10 files changed, 119 insertions(+), 7 deletions(-)
> > > >create mode 100644 drivers/gpu/drm/i915/gt/intel_gt_pm_unpark_work.c
> > > >create mode 100644 drivers/gpu/drm/i915/gt/intel_gt_pm_unpark_work.h
> > > > 
> > > > diff --git a/drivers/gpu/drm/i915/Makefile 
> > > > b/drivers/gpu/drm/i915/Makefile
> > > > index 642a5b5a1b81..579bdc069f25 100644
> > > > --- a/drivers/gpu/drm/i915/Makefile
> > > > +++ b/drivers/gpu/drm/i915/Makefile
> > > > @@ -103,6 +103,7 @@ gt-y += \
> > > > gt/intel_gt_clock_utils.o \
> > > > gt/intel_gt_irq.o \
> > > > gt/intel_gt_pm.o \
> > > > +   gt/intel_gt_pm_unpark_work.o \
> > > > gt/intel_gt_pm_irq.o \
> > > > gt/intel_gt_requests.o \
> > > > gt/intel_gtt.o \
> > > > diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c 
> > > > b/drivers/gpu/drm/i915/gt/intel_gt.c
> > > > index 62d40c986642..7e690e74baa2 100644
> > > > --- a/drivers/gpu/drm/i915/gt/intel_gt.c
> > > > +++ b/drivers/gpu/drm/i915/gt/intel_gt.c
> > > > @@ -29,6 +29,9 @@ void intel_gt_init_early(struct intel_gt *gt, struct 
> > > > drm_i915_private *i915)
> > > > spin_lock_init(>->irq_lock);
> > 

Re: [virtio-dev] [PATCH v1 09/12] drm/virtio: implement context init: allocate an array of fence contexts

2021-09-13 Thread Gurchetan Singh
On Fri, Sep 10, 2021 at 12:33 PM Chia-I Wu  wrote:

> On Wed, Sep 8, 2021 at 6:37 PM Gurchetan Singh
>  wrote:
> >
> > We don't want fences from different 3D contexts (virgl, gfxstream,
> > venus) to be on the same timeline.  With explicit context creation,
> > we can specify the number of ring each context wants.
> >
> > Execbuffer can specify which ring to use.
> >
> > Signed-off-by: Gurchetan Singh 
> > Acked-by: Lingfeng Yang 
> > ---
> >  drivers/gpu/drm/virtio/virtgpu_drv.h   |  3 +++
> >  drivers/gpu/drm/virtio/virtgpu_ioctl.c | 34 --
> >  2 files changed, 35 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h
> b/drivers/gpu/drm/virtio/virtgpu_drv.h
> > index a5142d60c2fa..cca9ab505deb 100644
> > --- a/drivers/gpu/drm/virtio/virtgpu_drv.h
> > +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
> > @@ -56,6 +56,7 @@
> >  #define STATE_ERR 2
> >
> >  #define MAX_CAPSET_ID 63
> > +#define MAX_RINGS 64
> >
> >  struct virtio_gpu_object_params {
> > unsigned long size;
> > @@ -263,6 +264,8 @@ struct virtio_gpu_fpriv {
> > uint32_t ctx_id;
> > uint32_t context_init;
> > bool context_created;
> > +   uint32_t num_rings;
> > +   uint64_t base_fence_ctx;
> > struct mutex context_lock;
> >  };
> >
> > diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
> b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
> > index f51f3393a194..262f79210283 100644
> > --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
> > +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
> > @@ -99,6 +99,11 @@ static int virtio_gpu_execbuffer_ioctl(struct
> drm_device *dev, void *data,
> > int in_fence_fd = exbuf->fence_fd;
> > int out_fence_fd = -1;
> > void *buf;
> > +   uint64_t fence_ctx;
> > +   uint32_t ring_idx;
> > +
> > +   fence_ctx = vgdev->fence_drv.context;
> > +   ring_idx = 0;
> >
> > if (vgdev->has_virgl_3d == false)
> > return -ENOSYS;
> > @@ -106,6 +111,17 @@ static int virtio_gpu_execbuffer_ioctl(struct
> drm_device *dev, void *data,
> > if ((exbuf->flags & ~VIRTGPU_EXECBUF_FLAGS))
> > return -EINVAL;
> >
> > +   if ((exbuf->flags & VIRTGPU_EXECBUF_RING_IDX)) {
> > +   if (exbuf->ring_idx >= vfpriv->num_rings)
> > +   return -EINVAL;
> > +
> > +   if (!vfpriv->base_fence_ctx)
> > +   return -EINVAL;
> > +
> > +   fence_ctx = vfpriv->base_fence_ctx;
> > +   ring_idx = exbuf->ring_idx;
> > +   }
> > +
> > exbuf->fence_fd = -1;
> >
> > virtio_gpu_create_context(dev, file);
> > @@ -173,7 +189,7 @@ static int virtio_gpu_execbuffer_ioctl(struct
> drm_device *dev, void *data,
> > goto out_memdup;
> > }
> >
> > -   out_fence = virtio_gpu_fence_alloc(vgdev,
> vgdev->fence_drv.context, 0);
> > +   out_fence = virtio_gpu_fence_alloc(vgdev, fence_ctx, ring_idx);
> > if(!out_fence) {
> > ret = -ENOMEM;
> > goto out_unresv;
> > @@ -691,7 +707,7 @@ static int virtio_gpu_context_init_ioctl(struct
> drm_device *dev,
> > return -EINVAL;
> >
> > /* Number of unique parameters supported at this time. */
> > -   if (num_params > 1)
> > +   if (num_params > 2)
> > return -EINVAL;
> >
> > ctx_set_params =
> memdup_user(u64_to_user_ptr(args->ctx_set_params),
> > @@ -731,6 +747,20 @@ static int virtio_gpu_context_init_ioctl(struct
> drm_device *dev,
> >
> > vfpriv->context_init |= value;
> > break;
> > +   case VIRTGPU_CONTEXT_PARAM_NUM_RINGS:
> > +   if (vfpriv->base_fence_ctx) {
> > +   ret = -EINVAL;
> > +   goto out_unlock;
> > +   }
> > +
> > +   if (value > MAX_RINGS) {
> > +   ret = -EINVAL;
> > +   goto out_unlock;
> > +   }
> > +
> > +   vfpriv->base_fence_ctx =
> dma_fence_context_alloc(value);
> With multiple fence contexts, we should do something about implicit
> fencing.
>
> The classic example is Mesa and X server.  When both use virgl and the
> global fence context, no dma_fence_wait is fine.  But when Mesa uses
> venus and the ring fence context, dma_fence_wait should be inserted.
>

 If I read your comment correctly, the use case is:

context A (venus)

sharing a render target with

context B (Xserver backed virgl)

?

Which function do you envisage dma_fence_wait(...) to be inserted?  Doesn't
implicit synchronization mean there's no fence to share between contexts
(only buffer objects)?

It may be possible to wait on the reservation object associated with a
buffer object from a different context (userspace can also do
DRM_IOCTL_VIRTGPU_WAIT), but not sure i

Re: [PATCH 0/3] drm/i915: Enable -Wsometimes-uninitialized

2021-09-13 Thread Nathan Chancellor
On Tue, Aug 24, 2021 at 03:54:24PM -0700, Nathan Chancellor wrote:
> Commit 46e2068081e9 ("drm/i915: Disable some extra clang warnings")
> disabled -Wsometimes-uninitialized as noisy but there have been a few
> fixes to clang that make the false positive rate fairly low so it should
> be enabled to help catch obvious mistakes. The first two patches fix
> revent instances of this warning then enables it for i915 like the rest
> of the tree.
> 
> Cheers,
> Nathan
> 
> Nathan Chancellor (3):
>   drm/i915/selftests: Do not use import_obj uninitialized
>   drm/i915/selftests: Always initialize err in
> igt_dmabuf_import_same_driver_lmem()
>   drm/i915: Enable -Wsometimes-uninitialized
> 
>  drivers/gpu/drm/i915/Makefile| 1 -
>  drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c | 7 ---
>  2 files changed, 4 insertions(+), 4 deletions(-)
> 
> 
> base-commit: fb43ebc83e069625cfeeb2490efc3ffa0013bfa4
> -- 
> 2.33.0
> 
> 

Ping, could this be picked up for an -rc as these are very clearly bugs?

Cheers,
Nathan


[PATCH 00/14] drm/hdcp: Pull HDCP auth/exchange/check into

2021-09-13 Thread Sean Paul
From: Sean Paul 

Hello,
This patchset pulls the HDCP protocol auth/exchange/check logic out from
i915 into a HDCP helper library which drivers can use to implement the
proper protocol and UAPI interactions for achieving HDCP.

Originally this was all stuffed into i915 since it was the only driver
supporting HDCP. Over the last while I've been working on HDCP support
in the msm driver and have identified the parts which can/should be
shared between drivers and the parts which are hw-specific.

We can generalize all of the sink interactions in the helper as well as
state handling and link checks. This tends to be the trickiest part of
adding HDCP support, since the property state and locking is a bit of a
nightmare. The driver need only implement the more mechanical display
controller register accesses.

The first third of the pachset is establishing the helpers, the next
third is converting the i915 driver to use the helpers, and the last
third is the msm driver implementation.

I've left out HDCP 2.x support, since we still only have i915 as the
reference implementation and I'm not super comfortable speculating on
which parts are platform independent.

Please take a look,

Sean

Sean Paul (14):
  drm/hdcp: Add drm_hdcp_atomic_check()
  drm/hdcp: Avoid changing crtc state in hdcp atomic check
  drm/hdcp: Update property value on content type and user changes
  drm/hdcp: Expand HDCP helper library for enable/disable/check
  drm/i915/hdcp: Consolidate HDCP setup/state cache
  drm/i915/hdcp: Retain hdcp_capable return codes
  drm/i915/hdcp: Use HDCP helpers for i915
  drm/msm/dpu_kms: Re-order dpu includes
  drm/msm/dpu: Remove useless checks in dpu_encoder
  drm/msm/dpu: Remove encoder->enable() hack
  drm/msm/dp: Re-order dp_audio_put in deinit_sub_modules
  dt-bindings: msm/dp: Add bindings for HDCP registers
  drm/msm: Add hdcp register ranges to sc7180 device tree
  drm/msm: Implement HDCP 1.x using the new drm HDCP helpers

 .../bindings/display/msm/dp-controller.yaml   |   11 +-
 drivers/gpu/drm/drm_hdcp.c| 1198 -
 drivers/gpu/drm/i915/display/intel_atomic.c   |7 +-
 drivers/gpu/drm/i915/display/intel_ddi.c  |   29 +-
 .../drm/i915/display/intel_display_debugfs.c  |   11 +-
 .../drm/i915/display/intel_display_types.h|   58 +-
 drivers/gpu/drm/i915/display/intel_dp_hdcp.c  |  341 ++---
 drivers/gpu/drm/i915/display/intel_dp_mst.c   |   17 +-
 drivers/gpu/drm/i915/display/intel_hdcp.c | 1011 +++---
 drivers/gpu/drm/i915/display/intel_hdcp.h |   35 +-
 drivers/gpu/drm/i915/display/intel_hdmi.c |  256 ++--
 drivers/gpu/drm/msm/Makefile  |1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   |   17 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c   |   30 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h   |2 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h |4 -
 drivers/gpu/drm/msm/dp/dp_debug.c |   49 +-
 drivers/gpu/drm/msm/dp/dp_debug.h |6 +-
 drivers/gpu/drm/msm/dp/dp_display.c   |   47 +-
 drivers/gpu/drm/msm/dp/dp_display.h   |5 +
 drivers/gpu/drm/msm/dp/dp_drm.c   |   68 +-
 drivers/gpu/drm/msm/dp/dp_drm.h   |5 +
 drivers/gpu/drm/msm/dp/dp_hdcp.c  |  433 ++
 drivers/gpu/drm/msm/dp/dp_hdcp.h  |   27 +
 drivers/gpu/drm/msm/dp/dp_parser.c|   30 +-
 drivers/gpu/drm/msm/dp/dp_parser.h|4 +
 drivers/gpu/drm/msm/dp/dp_reg.h   |   44 +-
 drivers/gpu/drm/msm/msm_atomic.c  |   15 +
 include/drm/drm_hdcp.h|  194 +++
 29 files changed, 2570 insertions(+), 1385 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.h

-- 
Sean Paul, Software Engineer, Google / Chromium OS



[PATCH 01/14] drm/hdcp: Add drm_hdcp_atomic_check()

2021-09-13 Thread Sean Paul
From: Sean Paul 

This patch moves the hdcp atomic check from i915 to drm_hdcp so other
drivers can use it. No functional changes, just cleaned up some of the
code when moving it over.

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/drm_hdcp.c  | 71 -
 drivers/gpu/drm/i915/display/intel_atomic.c |  4 +-
 drivers/gpu/drm/i915/display/intel_hdcp.c   | 47 --
 drivers/gpu/drm/i915/display/intel_hdcp.h   |  3 -
 include/drm/drm_hdcp.h  |  3 +
 5 files changed, 75 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/drm_hdcp.c b/drivers/gpu/drm/drm_hdcp.c
index ca9b8f697202..522326b03e66 100644
--- a/drivers/gpu/drm/drm_hdcp.c
+++ b/drivers/gpu/drm/drm_hdcp.c
@@ -13,13 +13,14 @@
 #include 
 #include 
 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
-#include 
 
 #include "drm_internal.h"
 
@@ -421,3 +422,71 @@ void drm_hdcp_update_content_protection(struct 
drm_connector *connector,
 dev->mode_config.content_protection_property);
 }
 EXPORT_SYMBOL(drm_hdcp_update_content_protection);
+
+/**
+ * drm_hdcp_atomic_check - Helper for drivers to call during 
connector->atomic_check
+ *
+ * @state: pointer to the atomic state being checked
+ * @connector: drm_connector on which content protection state needs an update
+ *
+ * This function can be used by display drivers to perform an atomic check on 
the
+ * hdcp state elements. If hdcp state has changed, this function will set
+ * mode_changed on the crtc driving the connector so it can update its hardware
+ * to match the hdcp state.
+ */
+void drm_hdcp_atomic_check(struct drm_connector *connector,
+  struct drm_atomic_state *state)
+{
+   struct drm_connector_state *new_conn_state, *old_conn_state;
+   struct drm_crtc_state *new_crtc_state;
+   u64 old_hdcp, new_hdcp;
+
+   old_conn_state = drm_atomic_get_old_connector_state(state, connector);
+   old_hdcp = old_conn_state->content_protection;
+
+   new_conn_state = drm_atomic_get_new_connector_state(state, connector);
+   new_hdcp = new_conn_state->content_protection;
+
+   if (!new_conn_state->crtc) {
+   /*
+* If the connector is being disabled with CP enabled, mark it
+* desired so it's re-enabled when the connector is brought back
+*/
+   if (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
+   new_conn_state->content_protection =
+   DRM_MODE_CONTENT_PROTECTION_DESIRED;
+   return;
+   }
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(state,
+  new_conn_state->crtc);
+   /*
+   * Fix the HDCP uapi content protection state in case of modeset.
+   * FIXME: As per HDCP content protection property uapi doc, an uevent()
+   * need to be sent if there is transition from ENABLED->DESIRED.
+   */
+   if (drm_atomic_crtc_needs_modeset(new_crtc_state) &&
+   (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
+new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
+   new_conn_state->content_protection =
+   DRM_MODE_CONTENT_PROTECTION_DESIRED;
+
+   /*
+* Nothing to do if content type is unchanged and one of:
+*  - state didn't change
+*  - HDCP was activated since the last commit
+*  - attempting to set to desired while already enabled
+*/
+   if (old_hdcp == new_hdcp ||
+   (old_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
+new_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED) ||
+   (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
+new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED)) {
+   if (old_conn_state->hdcp_content_type ==
+   new_conn_state->hdcp_content_type)
+   return;
+   }
+
+   new_crtc_state->mode_changed = true;
+}
+EXPORT_SYMBOL(drm_hdcp_atomic_check);
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c 
b/drivers/gpu/drm/i915/display/intel_atomic.c
index b4e7ac51aa31..1e306e8427ec 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -32,13 +32,13 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "intel_atomic.h"
 #include "intel_cdclk.h"
 #include "intel_display_types.h"
 #include "intel_global_state.h"
-#include "intel_hdcp.h"
 #include "intel_psr.h"
 #include "skl_universal_plane.h"
 
@@ -122,7 +122,7 @@ int intel_digital_connector_atomic_check(struct 
drm_connector *conn,
to_intel_digital_connector_state(old_state);
struct drm_crtc_state *crtc_state;
 
-   intel_hdcp_atomic_check(conn, old_state, new_state);
+   drm_hdcp_atomic_check(conn, state);
 
if (!new_s

[PATCH 02/14] drm/hdcp: Avoid changing crtc state in hdcp atomic check

2021-09-13 Thread Sean Paul
From: Sean Paul 

Instead of forcing a modeset in the hdcp atomic check, simply return
true if the content protection value is changing and let the driver
decide whether a modeset is required or not.

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/drm_hdcp.c  | 33 +++--
 drivers/gpu/drm/i915/display/intel_atomic.c |  5 ++--
 include/drm/drm_hdcp.h  |  2 +-
 3 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/drm_hdcp.c b/drivers/gpu/drm/drm_hdcp.c
index 522326b03e66..dd8fa91c51d6 100644
--- a/drivers/gpu/drm/drm_hdcp.c
+++ b/drivers/gpu/drm/drm_hdcp.c
@@ -430,11 +430,14 @@ EXPORT_SYMBOL(drm_hdcp_update_content_protection);
  * @connector: drm_connector on which content protection state needs an update
  *
  * This function can be used by display drivers to perform an atomic check on 
the
- * hdcp state elements. If hdcp state has changed, this function will set
- * mode_changed on the crtc driving the connector so it can update its hardware
- * to match the hdcp state.
+ * hdcp state elements. If hdcp state has changed in a manner which requires 
the
+ * driver to enable or disable content protection, this function will return
+ * true.
+ *
+ * Returns:
+ * true if the driver must enable/disable hdcp, false otherwise
  */
-void drm_hdcp_atomic_check(struct drm_connector *connector,
+bool drm_hdcp_atomic_check(struct drm_connector *connector,
   struct drm_atomic_state *state)
 {
struct drm_connector_state *new_conn_state, *old_conn_state;
@@ -452,10 +455,12 @@ void drm_hdcp_atomic_check(struct drm_connector 
*connector,
 * If the connector is being disabled with CP enabled, mark it
 * desired so it's re-enabled when the connector is brought back
 */
-   if (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
+   if (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
new_conn_state->content_protection =
DRM_MODE_CONTENT_PROTECTION_DESIRED;
-   return;
+   return true;
+   }
+   return false;
}
 
new_crtc_state = drm_atomic_get_new_crtc_state(state,
@@ -467,9 +472,19 @@ void drm_hdcp_atomic_check(struct drm_connector *connector,
*/
if (drm_atomic_crtc_needs_modeset(new_crtc_state) &&
(old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
-new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
+new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)) {
new_conn_state->content_protection =
DRM_MODE_CONTENT_PROTECTION_DESIRED;
+   return true;
+   }
+
+   /*
+* Coming back from disable or changing CRTC with DESIRED state requires
+* that the driver try CP enable.
+*/
+   if (new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
+   new_conn_state->crtc != old_conn_state->crtc)
+   return true;
 
/*
 * Nothing to do if content type is unchanged and one of:
@@ -484,9 +499,9 @@ void drm_hdcp_atomic_check(struct drm_connector *connector,
 new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED)) {
if (old_conn_state->hdcp_content_type ==
new_conn_state->hdcp_content_type)
-   return;
+   return false;
}
 
-   new_crtc_state->mode_changed = true;
+   return true;
 }
 EXPORT_SYMBOL(drm_hdcp_atomic_check);
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c 
b/drivers/gpu/drm/i915/display/intel_atomic.c
index 1e306e8427ec..c7b5470c40aa 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -122,8 +122,6 @@ int intel_digital_connector_atomic_check(struct 
drm_connector *conn,
to_intel_digital_connector_state(old_state);
struct drm_crtc_state *crtc_state;
 
-   drm_hdcp_atomic_check(conn, state);
-
if (!new_state->crtc)
return 0;
 
@@ -139,7 +137,8 @@ int intel_digital_connector_atomic_check(struct 
drm_connector *conn,
new_conn_state->base.picture_aspect_ratio != 
old_conn_state->base.picture_aspect_ratio ||
new_conn_state->base.content_type != 
old_conn_state->base.content_type ||
new_conn_state->base.scaling_mode != 
old_conn_state->base.scaling_mode ||
-   !drm_connector_atomic_hdr_metadata_equal(old_state, new_state))
+   !drm_connector_atomic_hdr_metadata_equal(old_state, new_state) ||
+   drm_hdcp_atomic_check(conn, state))
crtc_state->mode_changed = true;
 
return 0;
diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h
index d49977a042e1..e6e3d16bc7d3 100644
--- a/include/drm/drm_hdcp.h
+++ b/include/drm/drm_hdcp.h
@@ -301,7 +301,7 @@ int drm_

[PATCH 03/14] drm/hdcp: Update property value on content type and user changes

2021-09-13 Thread Sean Paul
From: Sean Paul 

This patch updates the connector's property value in 2 cases which were
previously missed:

1- Content type changes. The value should revert back to DESIRED from
   ENABLED in case the driver must re-authenticate the link due to the
   new content type.

2- Userspace sets value to DESIRED while ENABLED. In this case, the
   value should be reset immediately to ENABLED since the link is
   actively being encrypted.

To accommodate these changes, I've split up the conditionals to make
things a bit more clear (as much as one can with this mess of state).

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/drm_hdcp.c | 26 +-
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_hdcp.c b/drivers/gpu/drm/drm_hdcp.c
index dd8fa91c51d6..742313ce8f6f 100644
--- a/drivers/gpu/drm/drm_hdcp.c
+++ b/drivers/gpu/drm/drm_hdcp.c
@@ -487,21 +487,29 @@ bool drm_hdcp_atomic_check(struct drm_connector 
*connector,
return true;
 
/*
-* Nothing to do if content type is unchanged and one of:
-*  - state didn't change
+* Content type changes require an HDCP disable/enable cycle.
+*/
+   if (new_conn_state->hdcp_content_type != 
old_conn_state->hdcp_content_type) {
+   new_conn_state->content_protection =
+   DRM_MODE_CONTENT_PROTECTION_DESIRED;
+   return true;
+   }
+
+   /*
+* Ignore meaningless state changes:
 *  - HDCP was activated since the last commit
-*  - attempting to set to desired while already enabled
+*  - Attempting to set to desired while already enabled
 */
-   if (old_hdcp == new_hdcp ||
-   (old_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
+   if ((old_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
 new_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED) ||
(old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
 new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED)) {
-   if (old_conn_state->hdcp_content_type ==
-   new_conn_state->hdcp_content_type)
-   return false;
+   new_conn_state->content_protection =
+   DRM_MODE_CONTENT_PROTECTION_ENABLED;
+return false;
}
 
-   return true;
+   /* Finally, if state changes, we need action */
+   return old_hdcp != new_hdcp;
 }
 EXPORT_SYMBOL(drm_hdcp_atomic_check);
-- 
Sean Paul, Software Engineer, Google / Chromium OS



[PATCH 04/14] drm/hdcp: Expand HDCP helper library for enable/disable/check

2021-09-13 Thread Sean Paul
From: Sean Paul 

This patch expands upon the HDCP helper library to manage HDCP
enable, disable, and check.

Previous to this patch, the majority of the state management and sink
interaction is tucked inside the Intel driver with the understanding
that once a new platform supported HDCP we could make good decisions
about what should be centralized. With the addition of HDCP support
for Qualcomm, it's time to migrate the protocol-specific bits of HDCP
authentication, key exchange, and link checks to the HDCP helper.

In terms of functionality, this migration is 1:1 with the Intel driver,
however things are laid out a bit differently than with intel_hdcp.c,
which is why this is a separate patch from the i915 transition to the
helper. On i915, the "shim" vtable is used to account for HDMI vs. DP
vs. DP-MST differences whereas the helper library uses a LUT to
account for the register offsets and a remote read function to route
the messages. On i915, storing the sink information in the source is
done inline whereas now we use the new drm_hdcp_helper_funcs vtable
to store and fetch information to/from source hw. Finally, instead of
calling enable/disable directly from the driver, we'll leave that
decision to the helper and by calling drm_hdcp_helper_atomic_commit()
from the driver. All told, this will centralize the protocol and state
handling in the helper, ensuring we collect all of our bugs^Wlogic
in one place.

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/drm_hdcp.c | 1104 
 include/drm/drm_hdcp.h |  191 +++
 2 files changed, 1295 insertions(+)

diff --git a/drivers/gpu/drm/drm_hdcp.c b/drivers/gpu/drm/drm_hdcp.c
index 742313ce8f6f..c22390c127a2 100644
--- a/drivers/gpu/drm/drm_hdcp.c
+++ b/drivers/gpu/drm/drm_hdcp.c
@@ -6,15 +6,20 @@
  * Ramalingam C 
  */
 
+#include 
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -513,3 +518,1102 @@ bool drm_hdcp_atomic_check(struct drm_connector 
*connector,
return old_hdcp != new_hdcp;
 }
 EXPORT_SYMBOL(drm_hdcp_atomic_check);
+
+struct drm_hdcp_helper_data {
+   struct mutex mutex;
+   struct mutex *driver_mutex;
+
+   struct drm_connector *connector;
+   const struct drm_hdcp_helper_funcs *funcs;
+
+   u64 value;
+   unsigned int enabled_type;
+
+   struct delayed_work check_work;
+   struct work_struct prop_work;
+
+   struct drm_dp_aux *aux;
+   const struct drm_hdcp_hdcp1_receiver_reg_lut *hdcp1_lut;
+};
+
+struct drm_hdcp_hdcp1_receiver_reg_lut {
+   unsigned int bksv;
+   unsigned int ri;
+   unsigned int aksv;
+   unsigned int an;
+   unsigned int ainfo;
+   unsigned int v[5];
+   unsigned int bcaps;
+   unsigned int bcaps_mask_repeater_present;
+   unsigned int bstatus;
+};
+
+static const struct drm_hdcp_hdcp1_receiver_reg_lut drm_hdcp_hdcp1_ddc_lut = {
+   .bksv = DRM_HDCP_DDC_BKSV,
+   .ri = DRM_HDCP_DDC_RI_PRIME,
+   .aksv = DRM_HDCP_DDC_AKSV,
+   .an = DRM_HDCP_DDC_AN,
+   .ainfo = DRM_HDCP_DDC_AINFO,
+   .v = { DRM_HDCP_DDC_V_PRIME(0), DRM_HDCP_DDC_V_PRIME(1),
+  DRM_HDCP_DDC_V_PRIME(2), DRM_HDCP_DDC_V_PRIME(3),
+  DRM_HDCP_DDC_V_PRIME(4) },
+   .bcaps = DRM_HDCP_DDC_BCAPS,
+   .bcaps_mask_repeater_present = DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT,
+   .bstatus = DRM_HDCP_DDC_BSTATUS,
+};
+
+static const struct drm_hdcp_hdcp1_receiver_reg_lut drm_hdcp_hdcp1_dpcd_lut = {
+   .bksv = DP_AUX_HDCP_BKSV,
+   .ri = DP_AUX_HDCP_RI_PRIME,
+   .aksv = DP_AUX_HDCP_AKSV,
+   .an = DP_AUX_HDCP_AN,
+   .ainfo = DP_AUX_HDCP_AINFO,
+   .v = { DP_AUX_HDCP_V_PRIME(0), DP_AUX_HDCP_V_PRIME(1),
+  DP_AUX_HDCP_V_PRIME(2), DP_AUX_HDCP_V_PRIME(3),
+  DP_AUX_HDCP_V_PRIME(4) },
+   .bcaps = DP_AUX_HDCP_BCAPS,
+   .bcaps_mask_repeater_present = DP_BCAPS_REPEATER_PRESENT,
+
+   /*
+* For some reason the HDMI and DP HDCP specs call this register
+* definition by different names. In the HDMI spec, it's called BSTATUS,
+* but in DP it's called BINFO.
+*/
+   .bstatus = DP_AUX_HDCP_BINFO,
+};
+
+static int drm_hdcp_remote_ddc_read(struct i2c_adapter *i2c,
+   unsigned int offset, u8 *value, size_t len)
+{
+   int ret;
+   u8 start = offset & 0xff;
+   struct i2c_msg msgs[] = {
+   {
+   .addr = DRM_HDCP_DDC_ADDR,
+   .flags = 0,
+   .len = 1,
+   .buf = &start,
+   },
+   {
+   .addr = DRM_HDCP_DDC_ADDR,
+   .flags = I2C_M_RD,
+   .len = len,
+   .buf = value
+   }
+   };
+   ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs));
+   

[PATCH 05/14] drm/i915/hdcp: Consolidate HDCP setup/state cache

2021-09-13 Thread Sean Paul
From: Sean Paul 

Stick all of the setup for HDCP into a dedicated function. No functional
change, but this will facilitate moving HDCP logic into helpers.

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/i915/display/intel_hdcp.c | 52 +++
 1 file changed, 35 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c 
b/drivers/gpu/drm/i915/display/intel_hdcp.c
index feebafead046..af166baf8c71 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -2167,6 +2167,37 @@ static enum mei_fw_tc intel_get_mei_fw_tc(enum 
transcoder cpu_transcoder)
}
 }
 
+static int
+_intel_hdcp_setup(struct intel_connector *connector,
+ const struct intel_crtc_state *pipe_config, u8 content_type)
+{
+   struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+   struct intel_digital_port *dig_port = 
intel_attached_dig_port(connector);
+   struct intel_hdcp *hdcp = &connector->hdcp;
+   int ret = 0;
+
+   if (!connector->encoder) {
+   drm_err(&dev_priv->drm, "[%s:%d] encoder is not initialized\n",
+   connector->base.name, connector->base.base.id);
+   return -ENODEV;
+   }
+
+   hdcp->content_type = content_type;
+
+   if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
+   hdcp->cpu_transcoder = pipe_config->mst_master_transcoder;
+   hdcp->stream_transcoder = pipe_config->cpu_transcoder;
+   } else {
+   hdcp->cpu_transcoder = pipe_config->cpu_transcoder;
+   hdcp->stream_transcoder = INVALID_TRANSCODER;
+   }
+
+   if (DISPLAY_VER(dev_priv) >= 12)
+   dig_port->hdcp_port_data.fw_tc = 
intel_get_mei_fw_tc(hdcp->cpu_transcoder);
+
+   return ret;
+}
+
 static int initialize_hdcp_port_data(struct intel_connector *connector,
 struct intel_digital_port *dig_port,
 const struct intel_hdcp_shim *shim)
@@ -2306,28 +2337,14 @@ int intel_hdcp_enable(struct intel_connector *connector,
if (!hdcp->shim)
return -ENOENT;
 
-   if (!connector->encoder) {
-   drm_err(&dev_priv->drm, "[%s:%d] encoder is not initialized\n",
-   connector->base.name, connector->base.base.id);
-   return -ENODEV;
-   }
-
mutex_lock(&hdcp->mutex);
mutex_lock(&dig_port->hdcp_mutex);
drm_WARN_ON(&dev_priv->drm,
hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
-   hdcp->content_type = content_type;
-
-   if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
-   hdcp->cpu_transcoder = pipe_config->mst_master_transcoder;
-   hdcp->stream_transcoder = pipe_config->cpu_transcoder;
-   } else {
-   hdcp->cpu_transcoder = pipe_config->cpu_transcoder;
-   hdcp->stream_transcoder = INVALID_TRANSCODER;
-   }
 
-   if (DISPLAY_VER(dev_priv) >= 12)
-   dig_port->hdcp_port_data.fw_tc = 
intel_get_mei_fw_tc(hdcp->cpu_transcoder);
+   ret = _intel_hdcp_setup(connector, pipe_config, content_type);
+   if (ret)
+   goto out;
 
/*
 * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
@@ -2355,6 +2372,7 @@ int intel_hdcp_enable(struct intel_connector *connector,
true);
}
 
+out:
mutex_unlock(&dig_port->hdcp_mutex);
mutex_unlock(&hdcp->mutex);
return ret;
-- 
Sean Paul, Software Engineer, Google / Chromium OS



[PATCH 06/14] drm/i915/hdcp: Retain hdcp_capable return codes

2021-09-13 Thread Sean Paul
From: Sean Paul 

The shim functions return error codes, but they are discarded in
intel_hdcp.c. This patch plumbs the return codes through so they are
properly handled.

Signed-off-by: Sean Paul 
---
 .../drm/i915/display/intel_display_debugfs.c  |  9 +++-
 drivers/gpu/drm/i915/display/intel_hdcp.c | 51 ++-
 drivers/gpu/drm/i915/display/intel_hdcp.h |  4 +-
 3 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c 
b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 68f4ba8c46e7..5ffd31e9908f 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -644,6 +644,7 @@ static void intel_panel_info(struct seq_file *m, struct 
intel_panel *panel)
 static void intel_hdcp_info(struct seq_file *m,
struct intel_connector *intel_connector)
 {
+   int ret;
bool hdcp_cap, hdcp2_cap;
 
if (!intel_connector->hdcp.shim) {
@@ -651,8 +652,12 @@ static void intel_hdcp_info(struct seq_file *m,
goto out;
}
 
-   hdcp_cap = intel_hdcp_capable(intel_connector);
-   hdcp2_cap = intel_hdcp2_capable(intel_connector);
+   ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
+   if (ret)
+   hdcp_cap = false;
+   ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
+   if (ret)
+   hdcp2_cap = false;
 
if (hdcp_cap)
seq_puts(m, "HDCP1.4 ");
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c 
b/drivers/gpu/drm/i915/display/intel_hdcp.c
index af166baf8c71..59275919e7b9 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -153,50 +153,49 @@ int intel_hdcp_read_valid_bksv(struct intel_digital_port 
*dig_port,
 }
 
 /* Is HDCP1.4 capable on Platform and Sink */
-bool intel_hdcp_capable(struct intel_connector *connector)
+int intel_hdcp_capable(struct intel_connector *connector, bool *capable)
 {
struct intel_digital_port *dig_port = 
intel_attached_dig_port(connector);
const struct intel_hdcp_shim *shim = connector->hdcp.shim;
-   bool capable = false;
u8 bksv[5];
 
+   *capable = false;
+
if (!shim)
-   return capable;
+   return 0;
 
-   if (shim->hdcp_capable) {
-   shim->hdcp_capable(dig_port, &capable);
-   } else {
-   if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
-   capable = true;
-   }
+   if (shim->hdcp_capable)
+   return shim->hdcp_capable(dig_port, capable);
+
+   if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
+   *capable = true;
 
-   return capable;
+   return 0;
 }
 
 /* Is HDCP2.2 capable on Platform and Sink */
-bool intel_hdcp2_capable(struct intel_connector *connector)
+int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
 {
struct intel_digital_port *dig_port = 
intel_attached_dig_port(connector);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_hdcp *hdcp = &connector->hdcp;
-   bool capable = false;
+
+   *capable = false;
 
/* I915 support for HDCP2.2 */
if (!hdcp->hdcp2_supported)
-   return false;
+   return 0;
 
/* MEI interface is solid */
mutex_lock(&dev_priv->hdcp_comp_mutex);
if (!dev_priv->hdcp_comp_added ||  !dev_priv->hdcp_master) {
mutex_unlock(&dev_priv->hdcp_comp_mutex);
-   return false;
+   return 0;
}
mutex_unlock(&dev_priv->hdcp_comp_mutex);
 
/* Sink's capability for HDCP2.2 */
-   hdcp->shim->hdcp_2_2_capable(dig_port, &capable);
-
-   return capable;
+   return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
 }
 
 static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
@@ -2332,6 +2331,7 @@ int intel_hdcp_enable(struct intel_connector *connector,
struct intel_digital_port *dig_port = 
intel_attached_dig_port(connector);
struct intel_hdcp *hdcp = &connector->hdcp;
unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
+   bool capable;
int ret = -EINVAL;
 
if (!hdcp->shim)
@@ -2350,21 +2350,27 @@ int intel_hdcp_enable(struct intel_connector *connector,
 * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
 */
-   if (intel_hdcp2_capable(connector)) {
+   ret = intel_hdcp2_capable(connector, &capable);
+   if (capable) {
ret = _intel_hdcp2_enable(connector);
-   if (!ret)
+   if (!ret) {
check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
+   goto out;
+   }
}
 
/*

[PATCH 07/14] drm/i915/hdcp: Use HDCP helpers for i915

2021-09-13 Thread Sean Paul
From: Sean Paul 

Now that all of the HDCP 1.x logic has been migrated to the central HDCP
helpers, use it in the i915 driver.

The majority of the driver code for HDCP 1.x will live in intel_hdcp.c,
however there are a few helper hooks which are connector-specific and
need to be partially or fully implemented in the intel_dp_hdcp.c or
intel_hdmi.c.

We'll leave most of the HDCP 2.x code alone since we don't have another
implementation of HDCP 2.x to use as reference for what should and
should not live in the drm helpers. The helper will call the overly
general enable/disable/is_capable HDCP 2.x callbacks and leave the
interesting stuff for the driver. Once we have another HDCP 2.x
implementation, we should do a similar migration.

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/i915/display/intel_ddi.c  |  29 +-
 .../drm/i915/display/intel_display_debugfs.c  |   6 +-
 .../drm/i915/display/intel_display_types.h|  58 +-
 drivers/gpu/drm/i915/display/intel_dp_hdcp.c  | 341 +++
 drivers/gpu/drm/i915/display/intel_dp_mst.c   |  17 +-
 drivers/gpu/drm/i915/display/intel_hdcp.c | 935 +++---
 drivers/gpu/drm/i915/display/intel_hdcp.h |  30 +-
 drivers/gpu/drm/i915/display/intel_hdmi.c | 256 ++---
 8 files changed, 413 insertions(+), 1259 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c 
b/drivers/gpu/drm/i915/display/intel_ddi.c
index 23ef291f7b30..8bdf41593174 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -26,6 +26,7 @@
  */
 
 #include 
+#include 
 
 #include "i915_drv.h"
 #include "intel_audio.h"
@@ -3131,6 +3132,9 @@ static void intel_enable_ddi(struct intel_atomic_state 
*state,
 const struct intel_crtc_state *crtc_state,
 const struct drm_connector_state *conn_state)
 {
+   struct intel_connector *connector = 
to_intel_connector(conn_state->connector);
+   struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
 
if (!crtc_state->bigjoiner_slave)
@@ -3147,12 +3151,10 @@ static void intel_enable_ddi(struct intel_atomic_state 
*state,
else
intel_enable_ddi_dp(state, encoder, crtc_state, conn_state);
 
-   /* Enable hdcp if it's desired */
-   if (conn_state->content_protection ==
-   DRM_MODE_CONTENT_PROTECTION_DESIRED)
-   intel_hdcp_enable(to_intel_connector(conn_state->connector),
- crtc_state,
- (u8)conn_state->hdcp_content_type);
+   if (connector->hdcp_helper_data)
+   drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+   &state->base,
+   &dig_port->hdcp_mutex);
 }
 
 static void intel_disable_ddi_dp(struct intel_atomic_state *state,
@@ -3212,7 +3214,13 @@ static void intel_disable_ddi(struct intel_atomic_state 
*state,
  const struct intel_crtc_state *old_crtc_state,
  const struct drm_connector_state *old_conn_state)
 {
-   intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
+   struct intel_connector *connector = 
to_intel_connector(old_conn_state->connector);
+   struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
+   if (connector->hdcp_helper_data)
+   drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+   &state->base,
+   &dig_port->hdcp_mutex);
 
if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
intel_disable_ddi_hdmi(state, encoder, old_crtc_state,
@@ -3243,13 +3251,18 @@ void intel_ddi_update_pipe(struct intel_atomic_state 
*state,
   const struct intel_crtc_state *crtc_state,
   const struct drm_connector_state *conn_state)
 {
+   struct intel_connector *connector = 
to_intel_connector(conn_state->connector);
+   struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
 
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
!intel_encoder_is_mst(encoder))
intel_ddi_update_pipe_dp(state, encoder, crtc_state,
 conn_state);
 
-   intel_hdcp_update_pipe(state, encoder, crtc_state, conn_state);
+   if (connector->hdcp_helper_data)
+   drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+ &state->base,
+ &dig_port->hdcp_mutex);
 }
 
 static void
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c 
b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 5ffd31e9908f..74c1f5b48797 100644
--- a/drivers/gpu/drm/i915/display/intel_display_de

[PATCH 08/14] drm/msm/dpu_kms: Re-order dpu includes

2021-09-13 Thread Sean Paul
From: Sean Paul 

Make includes alphabetical in dpu_kms.c

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index ae48f41821cf..fb0d9f781c66 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -21,14 +21,14 @@
 #include "msm_gem.h"
 #include "disp/msm_disp_snapshot.h"
 
-#include "dpu_kms.h"
 #include "dpu_core_irq.h"
+#include "dpu_crtc.h"
+#include "dpu_encoder.h"
 #include "dpu_formats.h"
 #include "dpu_hw_vbif.h"
-#include "dpu_vbif.h"
-#include "dpu_encoder.h"
+#include "dpu_kms.h"
 #include "dpu_plane.h"
-#include "dpu_crtc.h"
+#include "dpu_vbif.h"
 
 #define CREATE_TRACE_POINTS
 #include "dpu_trace.h"
-- 
Sean Paul, Software Engineer, Google / Chromium OS



[PATCH 09/14] drm/msm/dpu: Remove useless checks in dpu_encoder

2021-09-13 Thread Sean Paul
From: Sean Paul 

A couple more useless checks to remove in dpu_encoder.

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 12 
 1 file changed, 12 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 0e9d3fa1544b..984f8a59cb73 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1153,10 +1153,6 @@ static void dpu_encoder_virt_enable(struct drm_encoder 
*drm_enc)
struct msm_drm_private *priv;
struct drm_display_mode *cur_mode = NULL;
 
-   if (!drm_enc) {
-   DPU_ERROR("invalid encoder\n");
-   return;
-   }
dpu_enc = to_dpu_encoder_virt(drm_enc);
 
mutex_lock(&dpu_enc->enc_lock);
@@ -1203,14 +1199,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder 
*drm_enc)
struct msm_drm_private *priv;
int i = 0;
 
-   if (!drm_enc) {
-   DPU_ERROR("invalid encoder\n");
-   return;
-   } else if (!drm_enc->dev) {
-   DPU_ERROR("invalid dev\n");
-   return;
-   }
-
dpu_enc = to_dpu_encoder_virt(drm_enc);
DPU_DEBUG_ENC(dpu_enc, "\n");
 
-- 
Sean Paul, Software Engineer, Google / Chromium OS



[PATCH 10/14] drm/msm/dpu: Remove encoder->enable() hack

2021-09-13 Thread Sean Paul
From: Sean Paul 

encoder->commit() was being misused because there were some global
resources which needed to be tweaked in encoder->enable() which were not
accessible in dpu_encoder.c. That is no longer true and the redirect
serves no purpose any longer. So remove the indirection.

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |  5 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 22 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h |  2 --
 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h   |  4 
 4 files changed, 1 insertion(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 984f8a59cb73..ddc542a0d41f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2122,11 +2122,8 @@ static void dpu_encoder_frame_done_timeout(struct 
timer_list *t)
 static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.mode_set = dpu_encoder_virt_mode_set,
.disable = dpu_encoder_virt_disable,
-   .enable = dpu_kms_encoder_enable,
+   .enable = dpu_encoder_virt_enable,
.atomic_check = dpu_encoder_virt_atomic_check,
-
-   /* This is called by dpu_kms_encoder_enable */
-   .commit = dpu_encoder_virt_enable,
 };
 
 static const struct drm_encoder_funcs dpu_encoder_funcs = {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index fb0d9f781c66..4a0b55d145ad 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -381,28 +381,6 @@ static void dpu_kms_flush_commit(struct msm_kms *kms, 
unsigned crtc_mask)
}
 }
 
-/*
- * Override the encoder enable since we need to setup the inline rotator and do
- * some crtc magic before enabling any bridge that might be present.
- */
-void dpu_kms_encoder_enable(struct drm_encoder *encoder)
-{
-   const struct drm_encoder_helper_funcs *funcs = encoder->helper_private;
-   struct drm_device *dev = encoder->dev;
-   struct drm_crtc *crtc;
-
-   /* Forward this enable call to the commit hook */
-   if (funcs && funcs->commit)
-   funcs->commit(encoder);
-
-   drm_for_each_crtc(crtc, dev) {
-   if (!(crtc->state->encoder_mask & drm_encoder_mask(encoder)))
-   continue;
-
-   trace_dpu_kms_enc_enable(DRMID(crtc));
-   }
-}
-
 static void dpu_kms_complete_commit(struct msm_kms *kms, unsigned crtc_mask)
 {
struct dpu_kms *dpu_kms = to_dpu_kms(kms);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
index 323a6bce9e64..f1ebb60dacab 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
@@ -248,8 +248,6 @@ void *dpu_debugfs_get_root(struct dpu_kms *dpu_kms);
 int dpu_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 void dpu_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 
-void dpu_kms_encoder_enable(struct drm_encoder *encoder);
-
 /**
  * dpu_kms_get_clk_rate() - get the clock rate
  * @dpu_kms:  pointer to dpu_kms structure
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
index 37bba57675a8..54d74341e690 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
@@ -266,10 +266,6 @@ DEFINE_EVENT(dpu_drm_obj_template, 
dpu_crtc_complete_commit,
TP_PROTO(uint32_t drm_id),
TP_ARGS(drm_id)
 );
-DEFINE_EVENT(dpu_drm_obj_template, dpu_kms_enc_enable,
-   TP_PROTO(uint32_t drm_id),
-   TP_ARGS(drm_id)
-);
 DEFINE_EVENT(dpu_drm_obj_template, dpu_kms_commit,
TP_PROTO(uint32_t drm_id),
TP_ARGS(drm_id)
-- 
Sean Paul, Software Engineer, Google / Chromium OS



[PATCH 11/14] drm/msm/dp: Re-order dp_audio_put in deinit_sub_modules

2021-09-13 Thread Sean Paul
From: Sean Paul 

Audio is initialized last, it should be de-initialized first to match
the order in dp_init_sub_modules().

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index fbe4c2cd52a3..19946024e235 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -714,9 +714,9 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, 
u32 data)
 static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
 {
dp_debug_put(dp->debug);
+   dp_audio_put(dp->audio);
dp_panel_put(dp->panel);
dp_aux_put(dp->aux);
-   dp_audio_put(dp->audio);
 }
 
 static int dp_init_sub_modules(struct dp_display_private *dp)
-- 
Sean Paul, Software Engineer, Google / Chromium OS



[PATCH 12/14] dt-bindings: msm/dp: Add bindings for HDCP registers

2021-09-13 Thread Sean Paul
From: Sean Paul 

This patch adds the bindings for the MSM DisplayPort HDCP registers
which are required to write the HDCP key into the display controller as
well as the registers to enable HDCP authentication/key
exchange/encryption.

Signed-off-by: Sean Paul 
---
 .../bindings/display/msm/dp-controller.yaml   | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml 
b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
index 64d8d9e5e47a..984301442653 100644
--- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
+++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
@@ -21,6 +21,11 @@ properties:
   reg:
 maxItems: 1
 
+  reg-names:
+const: dp_controller
+const: hdcp_key
+const: hdcp_tz
+
   interrupts:
 maxItems: 1
 
@@ -99,8 +104,10 @@ examples:
 #include 
 
 displayport-controller@ae9 {
-compatible = "qcom,sc7180-dp";
-reg = <0xae9 0x1400>;
+reg = <0 0x0ae9 0 0x1400>,
+  <0 0x0aed1000 0 0x174>,
+  <0 0x0aee1000 0 0x2c>;
+reg-names = "dp_controller", "hdcp_key", "hdcp_tz";
 interrupt-parent = <&mdss>;
 interrupts = <12>;
 clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
-- 
Sean Paul, Software Engineer, Google / Chromium OS



[PATCH 13/14] drm/msm: Add hdcp register ranges to sc7180 device tree

2021-09-13 Thread Sean Paul
From: Sean Paul 

This patch adds the register ranges required for HDCP to the sc7180
device tree. These registers will be used to inject HDCP key as well as
toggle HDCP on and off.

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/msm/dp/dp_parser.c | 30 +++---
 drivers/gpu/drm/msm/dp/dp_parser.h |  4 
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c 
b/drivers/gpu/drm/msm/dp/dp_parser.c
index 0519dd3ac3c3..4bbe2485ce3c 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -20,11 +20,19 @@ static const struct dp_regulator_cfg sdm845_dp_reg_cfg = {
 };
 
 static int msm_dss_ioremap(struct platform_device *pdev,
-   struct dss_io_data *io_data)
+   struct dss_io_data *io_data, const char *name,
+   int fallback_idx)
 {
struct resource *res = NULL;
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+
+   /* Support dts which do not have named resources */
+   if (!res) {
+   if (fallback_idx >= 0)
+   res = platform_get_resource(pdev, IORESOURCE_MEM,
+   fallback_idx);
+   }
if (!res) {
DRM_ERROR("%pS->%s: msm_dss_get_res failed\n",
__builtin_return_address(0), __func__);
@@ -55,6 +63,8 @@ static void dp_parser_unmap_io_resources(struct dp_parser 
*parser)
 {
struct dp_io *io = &parser->io;
 
+   msm_dss_iounmap(&io->hdcp_tz);
+   msm_dss_iounmap(&io->hdcp_key);
msm_dss_iounmap(&io->dp_controller);
 }
 
@@ -64,12 +74,26 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
struct platform_device *pdev = parser->pdev;
struct dp_io *io = &parser->io;
 
-   rc = msm_dss_ioremap(pdev, &io->dp_controller);
+   rc = msm_dss_ioremap(pdev, &io->dp_controller, "dp_controller", 0);
if (rc) {
DRM_ERROR("unable to remap dp io resources, rc=%d\n", rc);
goto err;
}
 
+   rc = msm_dss_ioremap(pdev, &io->hdcp_key, "hdcp_key", -1);
+   if (rc) {
+   DRM_INFO("unable to remap dp hdcp resources, rc=%d\n", rc);
+   io->hdcp_key.base = NULL;
+   io->hdcp_key.len = 0;
+   }
+
+   rc = msm_dss_ioremap(pdev, &io->hdcp_tz, "hdcp_tz", -1);
+   if (rc) {
+   DRM_INFO("unable to remap dp hdcp resources, rc=%d\n", rc);
+   io->hdcp_tz.base = NULL;
+   io->hdcp_tz.len = 0;
+   }
+
io->phy = devm_phy_get(&pdev->dev, "dp");
if (IS_ERR(io->phy)) {
rc = PTR_ERR(io->phy);
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h 
b/drivers/gpu/drm/msm/dp/dp_parser.h
index 34b49628bbaf..09d876620175 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -62,10 +62,14 @@ struct dp_display_data {
  * struct dp_ctrl_resource - controller's IO related data
  *
  * @dp_controller: Display Port controller mapped memory address
+ * @hdcp_key: mapped memory for HDCP key ingestion
+ * @hdcp_tz: mapped memory for HDCP TZ interaction
  * @phy_io: phy's mapped memory address
  */
 struct dp_io {
struct dss_io_data dp_controller;
+   struct dss_io_data hdcp_key;
+   struct dss_io_data hdcp_tz;
struct phy *phy;
union phy_configure_opts phy_opts;
 };
-- 
Sean Paul, Software Engineer, Google / Chromium OS



[PATCH 14/14] drm/msm: Implement HDCP 1.x using the new drm HDCP helpers

2021-09-13 Thread Sean Paul
From: Sean Paul 

This patch adds HDCP 1.x support to msm DP connectors using the new HDCP
helpers.

Signed-off-by: Sean Paul 
---
 drivers/gpu/drm/msm/Makefile|   1 +
 drivers/gpu/drm/msm/dp/dp_debug.c   |  49 +++-
 drivers/gpu/drm/msm/dp/dp_debug.h   |   6 +-
 drivers/gpu/drm/msm/dp/dp_display.c |  45 ++-
 drivers/gpu/drm/msm/dp/dp_display.h |   5 +
 drivers/gpu/drm/msm/dp/dp_drm.c |  68 -
 drivers/gpu/drm/msm/dp/dp_drm.h |   5 +
 drivers/gpu/drm/msm/dp/dp_hdcp.c| 433 
 drivers/gpu/drm/msm/dp/dp_hdcp.h|  27 ++
 drivers/gpu/drm/msm/dp/dp_reg.h |  44 ++-
 drivers/gpu/drm/msm/msm_atomic.c|  15 +
 11 files changed, 685 insertions(+), 13 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 904535eda0c4..98731fd262d6 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -109,6 +109,7 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_ctrl.o \
dp/dp_display.o \
dp/dp_drm.o \
+   dp/dp_hdcp.o \
dp/dp_hpd.o \
dp/dp_link.o \
dp/dp_panel.o \
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c 
b/drivers/gpu/drm/msm/dp/dp_debug.c
index 2f6247e80e9d..de16fca8782a 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "dp_parser.h"
 #include "dp_catalog.h"
@@ -15,6 +16,7 @@
 #include "dp_ctrl.h"
 #include "dp_debug.h"
 #include "dp_display.h"
+#include "dp_hdcp.h"
 
 #define DEBUG_NAME "msm_dp"
 
@@ -24,6 +26,7 @@ struct dp_debug_private {
struct dp_usbpd *usbpd;
struct dp_link *link;
struct dp_panel *panel;
+   struct dp_hdcp *hdcp;
struct drm_connector **connector;
struct device *dev;
struct drm_device *drm_dev;
@@ -349,6 +352,38 @@ static int dp_test_active_open(struct inode *inode,
inode->i_private);
 }
 
+static ssize_t dp_hdcp_key_write(struct file *file, const char __user *ubuf,
+size_t len, loff_t *offp)
+{
+   char *input_buffer;
+   int ret = 0;
+   struct dp_debug_private *debug = file->private_data;
+   struct drm_device *dev;
+
+   dev = debug->drm_dev;
+
+   if (len != (DRM_HDCP_KSV_LEN + DP_HDCP_NUM_KEYS * DP_HDCP_KEY_LEN))
+   return -EINVAL;
+
+   if (!debug->hdcp)
+   return -ENOENT;
+
+   input_buffer = memdup_user_nul(ubuf, len);
+   if (IS_ERR(input_buffer))
+   return PTR_ERR(input_buffer);
+
+   ret = dp_hdcp_ingest_key(debug->hdcp, input_buffer, len);
+
+   kfree(input_buffer);
+   if (ret < 0) {
+   DRM_ERROR("Could not ingest HDCP key, ret=%d\n", ret);
+   return ret;
+   }
+
+   *offp += len;
+   return len;
+}
+
 static const struct file_operations dp_debug_fops = {
.open = simple_open,
.read = dp_debug_read_info,
@@ -363,6 +398,12 @@ static const struct file_operations test_active_fops = {
.write = dp_test_active_write
 };
 
+static const struct file_operations dp_hdcp_key_fops = {
+   .owner = THIS_MODULE,
+   .open = simple_open,
+   .write = dp_hdcp_key_write,
+};
+
 static int dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor)
 {
int rc = 0;
@@ -384,6 +425,10 @@ static int dp_debug_init(struct dp_debug *dp_debug, struct 
drm_minor *minor)
minor->debugfs_root,
debug, &dp_test_type_fops);
 
+   debugfs_create_file("msm_dp_hdcp_key", 0222,
+   minor->debugfs_root,
+   debug, &dp_hdcp_key_fops);
+
debug->root = minor->debugfs_root;
 
return rc;
@@ -391,7 +436,8 @@ static int dp_debug_init(struct dp_debug *dp_debug, struct 
drm_minor *minor)
 
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
struct dp_usbpd *usbpd, struct dp_link *link,
-   struct drm_connector **connector, struct drm_minor *minor)
+   struct dp_hdcp *hdcp, struct drm_connector **connector,
+   struct drm_minor *minor)
 {
int rc = 0;
struct dp_debug_private *debug;
@@ -413,6 +459,7 @@ struct dp_debug *dp_debug_get(struct device *dev, struct 
dp_panel *panel,
debug->usbpd = usbpd;
debug->link = link;
debug->panel = panel;
+   debug->hdcp = hdcp;
debug->dev = dev;
debug->drm_dev = minor->dev;
debug->connector = connector;
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h 
b/drivers/gpu/drm/msm/dp/dp_debug.h
index 7eaedfbb149c..c4481339c0c5 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.h
+++ b/drivers/gpu/drm/msm/dp/dp_debug.h
@@ -6,6 +6,7 @@
 #ifndef _DP_DEBUG_H_
 #define _DP_DEBUG_H_
 
+#include "dp_hdcp.h"
 #include "d

Re: [PATCH 00/14] drm/hdcp: Pull HDCP auth/exchange/check into

2021-09-13 Thread Alex Deucher
On Mon, Sep 13, 2021 at 1:57 PM Sean Paul  wrote:
>
> From: Sean Paul 
>
> Hello,
> This patchset pulls the HDCP protocol auth/exchange/check logic out from
> i915 into a HDCP helper library which drivers can use to implement the
> proper protocol and UAPI interactions for achieving HDCP.
>
> Originally this was all stuffed into i915 since it was the only driver
> supporting HDCP. Over the last while I've been working on HDCP support
> in the msm driver and have identified the parts which can/should be
> shared between drivers and the parts which are hw-specific.
>
> We can generalize all of the sink interactions in the helper as well as
> state handling and link checks. This tends to be the trickiest part of
> adding HDCP support, since the property state and locking is a bit of a
> nightmare. The driver need only implement the more mechanical display
> controller register accesses.
>
> The first third of the pachset is establishing the helpers, the next
> third is converting the i915 driver to use the helpers, and the last
> third is the msm driver implementation.
>
> I've left out HDCP 2.x support, since we still only have i915 as the
> reference implementation and I'm not super comfortable speculating on
> which parts are platform independent.

FWIW, amdgpu has support for both HDCP 1.x and 2.x

Alex

>
> Please take a look,
>
> Sean
>
> Sean Paul (14):
>   drm/hdcp: Add drm_hdcp_atomic_check()
>   drm/hdcp: Avoid changing crtc state in hdcp atomic check
>   drm/hdcp: Update property value on content type and user changes
>   drm/hdcp: Expand HDCP helper library for enable/disable/check
>   drm/i915/hdcp: Consolidate HDCP setup/state cache
>   drm/i915/hdcp: Retain hdcp_capable return codes
>   drm/i915/hdcp: Use HDCP helpers for i915
>   drm/msm/dpu_kms: Re-order dpu includes
>   drm/msm/dpu: Remove useless checks in dpu_encoder
>   drm/msm/dpu: Remove encoder->enable() hack
>   drm/msm/dp: Re-order dp_audio_put in deinit_sub_modules
>   dt-bindings: msm/dp: Add bindings for HDCP registers
>   drm/msm: Add hdcp register ranges to sc7180 device tree
>   drm/msm: Implement HDCP 1.x using the new drm HDCP helpers
>
>  .../bindings/display/msm/dp-controller.yaml   |   11 +-
>  drivers/gpu/drm/drm_hdcp.c| 1198 -
>  drivers/gpu/drm/i915/display/intel_atomic.c   |7 +-
>  drivers/gpu/drm/i915/display/intel_ddi.c  |   29 +-
>  .../drm/i915/display/intel_display_debugfs.c  |   11 +-
>  .../drm/i915/display/intel_display_types.h|   58 +-
>  drivers/gpu/drm/i915/display/intel_dp_hdcp.c  |  341 ++---
>  drivers/gpu/drm/i915/display/intel_dp_mst.c   |   17 +-
>  drivers/gpu/drm/i915/display/intel_hdcp.c | 1011 +++---
>  drivers/gpu/drm/i915/display/intel_hdcp.h |   35 +-
>  drivers/gpu/drm/i915/display/intel_hdmi.c |  256 ++--
>  drivers/gpu/drm/msm/Makefile  |1 +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   |   17 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c   |   30 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h   |2 -
>  drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h |4 -
>  drivers/gpu/drm/msm/dp/dp_debug.c |   49 +-
>  drivers/gpu/drm/msm/dp/dp_debug.h |6 +-
>  drivers/gpu/drm/msm/dp/dp_display.c   |   47 +-
>  drivers/gpu/drm/msm/dp/dp_display.h   |5 +
>  drivers/gpu/drm/msm/dp/dp_drm.c   |   68 +-
>  drivers/gpu/drm/msm/dp/dp_drm.h   |5 +
>  drivers/gpu/drm/msm/dp/dp_hdcp.c  |  433 ++
>  drivers/gpu/drm/msm/dp/dp_hdcp.h  |   27 +
>  drivers/gpu/drm/msm/dp/dp_parser.c|   30 +-
>  drivers/gpu/drm/msm/dp/dp_parser.h|4 +
>  drivers/gpu/drm/msm/dp/dp_reg.h   |   44 +-
>  drivers/gpu/drm/msm/msm_atomic.c  |   15 +
>  include/drm/drm_hdcp.h|  194 +++
>  29 files changed, 2570 insertions(+), 1385 deletions(-)
>  create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.c
>  create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.h
>
> --
> Sean Paul, Software Engineer, Google / Chromium OS
>


[PATCH 2/8] drm/ttm: add TTM_PAGE_FLAG_SHMEM

2021-09-13 Thread Matthew Auld
Add new flag to indicate special shmem based tt, which can directly
handle swapping itself, and should be visible to some shrinker.

As part of this we should skip the ttm_pages_allocated accounting, since
such tt objects should already be reachable, and potentially reclaimable
by some shrinker, if under memory pressure, and so shouldn't directly
count towards the swap "watermark" level.

We also need to stop touching the page->mapping and page->index for such
objects, like in ttm_tt_add_mapping, since shmem already uses these.
Some drivers seems to depend on the tt mapping/index behaviour for their
own purposes, so directly using shmem tt likely won't be usable there
as-is.

Signed-off-by: Matthew Auld 
Cc: Thomas Hellström 
Cc: Christian König 
---
 drivers/gpu/drm/ttm/ttm_bo_vm.c |  4 ++--
 drivers/gpu/drm/ttm/ttm_tt.c| 10 +-
 include/drm/ttm/ttm_tt.h|  1 +
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index f56be5bc0861..e2131c73dcb6 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -346,8 +346,8 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
} else if (unlikely(!page)) {
break;
}
-   page->index = drm_vma_node_start(&bo->base.vma_node) +
-   page_offset;
+   if (!(bo->ttm->page_flags & TTM_PAGE_FLAG_SHMEM))
+   page->index = 
drm_vma_node_start(&bo->base.vma_node) + page_offset;
pfn = page_to_pfn(page);
}
 
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index dae52433beeb..cc4815c1f505 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -293,7 +293,7 @@ static void ttm_tt_add_mapping(struct ttm_device *bdev, 
struct ttm_tt *ttm)
 {
pgoff_t i;
 
-   if (ttm->page_flags & TTM_PAGE_FLAG_SG)
+   if (ttm->page_flags & (TTM_PAGE_FLAG_SG | TTM_PAGE_FLAG_SHMEM))
return;
 
for (i = 0; i < ttm->num_pages; ++i)
@@ -311,7 +311,7 @@ int ttm_tt_populate(struct ttm_device *bdev,
if (ttm_tt_is_populated(ttm))
return 0;
 
-   if (!(ttm->page_flags & TTM_PAGE_FLAG_SG)) {
+   if (!(ttm->page_flags & (TTM_PAGE_FLAG_SG | TTM_PAGE_FLAG_SHMEM))) {
atomic_long_add(ttm->num_pages, &ttm_pages_allocated);
if (bdev->pool.use_dma32)
atomic_long_add(ttm->num_pages,
@@ -349,7 +349,7 @@ int ttm_tt_populate(struct ttm_device *bdev,
return 0;
 
 error:
-   if (!(ttm->page_flags & TTM_PAGE_FLAG_SG)) {
+   if (!(ttm->page_flags & (TTM_PAGE_FLAG_SG | TTM_PAGE_FLAG_SHMEM))) {
atomic_long_sub(ttm->num_pages, &ttm_pages_allocated);
if (bdev->pool.use_dma32)
atomic_long_sub(ttm->num_pages,
@@ -364,7 +364,7 @@ static void ttm_tt_clear_mapping(struct ttm_tt *ttm)
pgoff_t i;
struct page **page = ttm->pages;
 
-   if (ttm->page_flags & TTM_PAGE_FLAG_SG)
+   if (ttm->page_flags & (TTM_PAGE_FLAG_SG | TTM_PAGE_FLAG_SHMEM))
return;
 
for (i = 0; i < ttm->num_pages; ++i) {
@@ -384,7 +384,7 @@ void ttm_tt_unpopulate(struct ttm_device *bdev, struct 
ttm_tt *ttm)
else
ttm_pool_free(&bdev->pool, ttm);
 
-   if (!(ttm->page_flags & TTM_PAGE_FLAG_SG)) {
+   if (!(ttm->page_flags & (TTM_PAGE_FLAG_SG | TTM_PAGE_FLAG_SHMEM))) {
atomic_long_sub(ttm->num_pages, &ttm_pages_allocated);
if (bdev->pool.use_dma32)
atomic_long_sub(ttm->num_pages,
diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h
index 89b15d673b22..20d550185065 100644
--- a/include/drm/ttm/ttm_tt.h
+++ b/include/drm/ttm/ttm_tt.h
@@ -42,6 +42,7 @@ struct ttm_operation_ctx;
 #define TTM_PAGE_FLAG_ZERO_ALLOC  (1 << 6)
 #define TTM_PAGE_FLAG_SG  (1 << 8)
 #define TTM_PAGE_FLAG_NO_RETRY   (1 << 9)
+#define TTM_PAGE_FLAG_SHMEM  (1 << 10)
 
 #define TTM_PAGE_FLAG_PRIV_POPULATED  (1 << 31)
 
-- 
2.26.3



  1   2   >