Re: [PATCH v10 14/16] drm/mediatek: aal: Rewrite kerneldoc for struct mtk_disp_aal

2023-10-03 Thread 胡俊光


RE: [PATCH v4 2/3] drm/i915/guc: Close deregister-context race against CT-loss

2023-10-03 Thread Gupta, Anshuman



> -Original Message-
> From: Teres Alexis, Alan Previn 
> Sent: Wednesday, September 27, 2023 12:35 AM
> To: intel-...@lists.freedesktop.org
> Cc: Teres Alexis, Alan Previn ; dri-
> de...@lists.freedesktop.org; Vivi, Rodrigo ; Ceraolo
> Spurio, Daniele ; Harrison, John C
> ; Anshuman Gupta Alan Previn
> ; Gupta,
> Anshuman ; Jana, Mousumi
> 
> Subject: [PATCH v4 2/3] drm/i915/guc: Close deregister-context race against 
> CT-
> loss
> 
> If we are at the end of suspend or very early in resume its possible an async 
> fence
> signal (via rcu_call) is triggered to free_engines which could lead us to the
> execution of the context destruction worker (after a prior worker flush).
> 
> Thus, when suspending, insert an rcu_barrier at the start of wait_for_suspend 
> so
> that all such cases have completed and context destruction list isn't missing
> anything.
> 
> In destroyed_worker_func, close the race against CT-loss by checking that CT 
> is
> enabled before calling into deregister_destroyed_contexts.
> 
> Based on testing, guc_lrc_desc_unpin may still race and fail as we traverse 
> the
> GuC's context-destroy list because the CT could be disabled right before 
> calling
> GuC's CT send function.
> 
> We've witnessed this race condition once every ~6000-8000 suspend-resume
> cycles while ensuring workloads that render something onscreen is continuously
> started just before we suspend (and the workload is small enough to complete
> and trigger the queued engine/context free-up either very late in suspend or 
> very
> early in resume).
> 
> In such a case, we need to unroll the entire process because guc-lrc-unpin 
> takes a
> gt wakeref which only gets released in the G2H IRQ reply that never comes
> through in this corner case. Without the unroll, the taken wakeref is leaked 
> and
> will cascade into a kernel hang later at the tail end of suspend in this 
> function:
> 
>intel_wakeref_wait_for_idle(>->wakeref)
>(called by) - intel_gt_pm_wait_for_idle
>(called by) - wait_for_suspend
> 
> Thus, do an unroll in guc_lrc_desc_unpin and deregister_destroyed_- contexts 
> if
> guc_lrc_desc_unpin fails due to CT send falure.
> When unrolling, keep the context in the GuC's destroy-list so it can get 
> picked up
> on the next destroy worker invocation (if suspend aborted) or get fully 
> purged as
> part of a GuC sanitization (end of suspend) or a reset flow.
> 
> Signed-off-by: Alan Previn 
> Signed-off-by: Anshuman Gupta 
> Tested-by: Mousumi Jana 
> ---
>  drivers/gpu/drm/i915/gt/intel_gt_pm.c |  7 ++
>  .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 81 ---
>  2 files changed, 77 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c
> b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
> index 5a942af0a14e..59b5658a17fb 100644
> --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c
> +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
> @@ -289,6 +289,13 @@ int intel_gt_resume(struct intel_gt *gt)
> 
>  static void wait_for_suspend(struct intel_gt *gt)  {
> + /*
> +  * On rare occasions, we've observed the fence completion trigger
> +  * free_engines asynchronously via rcu_call. Ensure those are done.
> +  * This path is only called on suspend, so it's an acceptable cost.
> +  */
> + rcu_barrier();
Let's add the barrier after the end of prepare suspend and at start of late 
suspend.
To make sure we don't have any async destroy from any user request or any 
internal  kmd request during i915 suspend?
Br,
Anshuman Gupta.
> +
>   if (!intel_gt_pm_is_awake(gt))
>   return;
> 
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> index fdd7179f502a..465baf7660d7 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> @@ -235,6 +235,13 @@ set_context_destroyed(struct intel_context *ce)
>   ce->guc_state.sched_state |= SCHED_STATE_DESTROYED;  }
> 
> +static inline void
> +clr_context_destroyed(struct intel_context *ce) {
> + lockdep_assert_held(&ce->guc_state.lock);
> + ce->guc_state.sched_state &= ~SCHED_STATE_DESTROYED; }
> +
>  static inline bool context_pending_disable(struct intel_context *ce)  {
>   return ce->guc_state.sched_state & SCHED_STATE_PENDING_DISABLE;
> @@ -612,6 +619,8 @@ static int guc_submission_send_busy_loop(struct
> intel_guc *guc,
>u32 g2h_len_dw,
>bool loop)
>  {
> + int ret;
> +
>   /*
>* We always loop when a send requires a reply (i.e. g2h_len_dw > 0),
>* so we don't handle the case where we don't get a reply because we
> @@ -622,7 +631,11 @@ static int guc_submission_send_busy_loop(struct
> intel_guc *guc,
>   if (g2h_len_dw)
>   atomic_inc(&guc->outstanding_submission_g2h);
> 
> - return intel_guc_send_busy_loop(guc, action, len, 

Re: [PATCH v10 15/16] drm/mediatek: gamma: Add kerneldoc for struct mtk_disp_gamma

2023-10-03 Thread 胡俊光


Re: [PATCH v10 16/16] drm/mediatek: aal: Compress of_device_id entries and add sentinel

2023-10-03 Thread 胡俊光


Re: [PATCH] dma-buf: Deny copy-on-writes mmaps

2023-10-03 Thread kernel test robot
Hi Andi,

kernel test robot noticed the following build errors:

[auto build test ERROR on drm-misc/drm-misc-next]
[also build test ERROR on linus/master v6.6-rc4 next-20231003]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:
https://github.com/intel-lab-lkp/linux/commits/Andi-Shyti/dma-buf-Deny-copy-on-writes-mmaps/20231004-070556
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:
https://lore.kernel.org/r/20231003230332.513051-1-andi.shyti%40linux.intel.com
patch subject: [PATCH] dma-buf: Deny copy-on-writes mmaps
config: sh-allyesconfig 
(https://download.01.org/0day-ci/archive/20231004/202310041156.bi2vshvb-...@intel.com/config)
compiler: sh4-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): 
(https://download.01.org/0day-ci/archive/20231004/202310041156.bi2vshvb-...@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot 
| Closes: 
https://lore.kernel.org/oe-kbuild-all/202310041156.bi2vshvb-...@intel.com/

All errors (new ones prefixed by >>):

   drivers/dma-buf/dma-buf.c: In function 'dma_buf_get_unmapped_area':
>> drivers/dma-buf/dma-buf.c:142:27: error: 'struct mm_struct' has no member 
>> named 'get_unmapped_area'
 142 | return current->mm->get_unmapped_area(file, addr, len, 
pgoff, flags);
 |   ^~
   drivers/dma-buf/dma-buf.c:143:1: error: control reaches end of non-void 
function [-Werror=return-type]
 143 | }
 | ^
   cc1: some warnings being treated as errors


vim +142 drivers/dma-buf/dma-buf.c

   131  
   132  static unsigned long
   133  dma_buf_get_unmapped_area(struct file *file,
   134unsigned long addr,
   135unsigned long len,
   136unsigned long pgoff,
   137unsigned long flags)
   138  {
   139  if ((flags & MAP_TYPE) == MAP_PRIVATE)
   140  return -EINVAL;
   141  
 > 142  return current->mm->get_unmapped_area(file, addr, len, pgoff, 
 > flags);
   143  }
   144  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


bulk_move in ttm_resource manager

2023-10-03 Thread Zeng, Oak
Hi Christian,

As a follow up to this thread: 
https://www.spinics.net/lists/dri-devel/msg410740.html, I started the work of 
moving the lru out of ttm_resource_manager and make it a common library for 
both ttm and svm. While look into the details of the bulk_move in ttm resource 
manager, I found a potential problem:

For simplicity, let's say we only have one memory type and one priority, so ttm 
resource manager only maintains one global lru list. Let's say this list has 10 
nodes, node1 to node10.

But the lru_bulk_move is per vm. Let's say vm1 has a bulk_move covering node 
range [node4, node7] and vm2 has a bulk_move covering node range [node6, 
node9]. Notice those two range has an overlap. Since two vm can simultaneously 
add nodes to lru, I think this scenario can happen.

Now if we perform a bulk move for vm1, moving [node4, node7] to the tail of the 
lru list. The lru after this bulk move will be: node1, node2, node3,node8, 
node9, node10, node4, node5, node6, node7. Now notice that for vm2's bulk_move, 
the first pointer  (pointing to node6) is actually after the last pointer 
(pointing to node9), which doesn't make sense.

Is this a real problem? As I understand it, with this issue, we only mess up 
the lru list order, but there won't be any functional problem. If it is a real 
problem, should we make the bulk_move global instead of per vm based?

Thanks,
Oak



[Patch v2] Add uAPI to query microcontroller fw version

2023-10-03 Thread Vivaik Balasubrawmanian
Due to a bug in GuC firmware, Mesa can't enable by default the usage of 
async compute engines feature in DG2 and newer. A new GuC firmware fixed the 
issue but 
until now there was no way for Mesa to know if KMD was running with the fixed 
GuC version or not,
so this uAPI is required.

More context on the issue:
Vulkan allows applications to create types of queues: graphics, compute and 
copy.
Today Intel Vulkan driver uses Render engine to implement all those 3 queues 
types.

There is a set of operations that a queue type is required to implement, 
DG2 compute engine have almost all the operations required by compute queue but 
still lacks some.
So the solution is to send those operations not supported by compute engine to 
render engine 
and do some synchronization around it. But doing so causes the GuC scheduler to 
get stuck 
around the synchronization, until KMD resets the engine and ban the application 
context.
This issue was root caused to a GuC firmware issue and was fixed in newer 
version.

So Mesa can't enable the "async compute" without knowing for sure that KMD is 
running 
with a GuC version that has the scheduler fix. Same will happen when Mesa start 
to use 
copy engine.

This uAPI  may be expanded in future to query other firmware versions too.

More information:
https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23661
Mesa usage: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25233

v2:
- incorporated feedback from Tvrtko Ursulin:
  - updated patch description to clarify the use case that identified
this issue.
  - updated query_uc_fw_version() to use copy_query_item() helper.
  - updated the implemented GuC version query to return Submission
version.

Cc: John Harrison 
Cc: Daniele Ceraolo Spurio 
Cc: José Roberto de Souza 

Signed-off-by: Vivaik Balasubrawmanian 
---
 drivers/gpu/drm/i915/i915_query.c | 42 +++
 include/uapi/drm/i915_drm.h   | 32 +++
 2 files changed, 74 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_query.c 
b/drivers/gpu/drm/i915/i915_query.c
index 00871ef99792..3e3563ab62b7 100644
--- a/drivers/gpu/drm/i915/i915_query.c
+++ b/drivers/gpu/drm/i915/i915_query.c
@@ -551,6 +551,47 @@ static int query_hwconfig_blob(struct drm_i915_private 
*i915,
return hwconfig->size;
 }
 
+static int
+query_uc_fw_version(struct drm_i915_private *i915, struct drm_i915_query_item 
*query)
+{
+   struct drm_i915_query_uc_fw_version __user *query_ptr = 
u64_to_user_ptr(query->data_ptr);
+   size_t size = sizeof(struct drm_i915_query_uc_fw_version);
+   struct drm_i915_query_uc_fw_version resp;
+   int ret;
+
+   ret = copy_query_item(&resp, size, size, query);
+   if (ret == size) {
+   query->length = size;
+   return 0;
+   } else if (ret != 0)
+   return ret;
+
+   if (resp.pad || resp.pad2 || resp.reserved) {
+   drm_dbg(&i915->drm,
+   "Invalid input fw version query structure parameters 
received");
+   return -EINVAL;
+   }
+
+   switch (resp.uc_type) {
+   case I915_QUERY_UC_TYPE_GUC_SUBMISSION: {
+   struct intel_guc *guc = &i915->gt0.uc.guc;
+
+   resp.major_ver = guc->submission_version.major;
+   resp.minor_ver = guc->submission_version.minor;
+   resp.patch_ver = guc->submission_version.patch;
+   resp.branch_ver = 0;
+   break;
+   }
+   default:
+   return -EINVAL;
+   }
+
+   if (copy_to_user(query_ptr, &resp, size))
+   return -EFAULT;
+
+   return 0;
+}
+
 static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv,
struct drm_i915_query_item *query_item) 
= {
query_topology_info,
@@ -559,6 +600,7 @@ static int (* const i915_query_funcs[])(struct 
drm_i915_private *dev_priv,
query_memregion_info,
query_hwconfig_blob,
query_geometry_subslices,
+   query_uc_fw_version,
 };
 
 int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 7000e5910a1d..6f9d52263c77 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -3013,6 +3013,7 @@ struct drm_i915_query_item {
 *  - %DRM_I915_QUERY_MEMORY_REGIONS (see struct 
drm_i915_query_memory_regions)
 *  - %DRM_I915_QUERY_HWCONFIG_BLOB (see `GuC HWCONFIG blob uAPI`)
 *  - %DRM_I915_QUERY_GEOMETRY_SUBSLICES (see struct 
drm_i915_query_topology_info)
+*  - %DRM_I915_QUERY_UC_FW_VERSION (see struct 
drm_i915_query_uc_fw_version)
 */
__u64 query_id;
 #define DRM_I915_QUERY_TOPOLOGY_INFO   1
@@ -3021,6 +3022,7 @@ struct drm_i915_query_item {
 #define DRM_I915_QUERY_MEMORY_REGIONS  4
 #define DRM_I915_QUERY_HWCONFIG_BLOB   5
 #define 

[PATCH] drm/msm/dpu: drop MSM_ENC_VBLANK support

2023-10-03 Thread Dmitry Baryshkov
There are no in-kernel users of MSM_ENC_VBLANK wait type. Drop it
together with the corresponding wait_for_vblank callback.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   |  3 --
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  1 -
 .../drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c  | 28 ---
 .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c  |  9 +++---
 drivers/gpu/drm/msm/msm_drv.h |  2 --
 5 files changed, 4 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index d34e684a4178..83045aa8ba01 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2429,9 +2429,6 @@ int dpu_encoder_wait_for_event(struct drm_encoder 
*drm_enc,
case MSM_ENC_TX_COMPLETE:
fn_wait = phys->ops.wait_for_tx_complete;
break;
-   case MSM_ENC_VBLANK:
-   fn_wait = phys->ops.wait_for_vblank;
-   break;
default:
DPU_ERROR_ENC(dpu_enc, "unknown wait event %d\n",
event);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index d48558ede488..c6cccab3bb6d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -106,7 +106,6 @@ struct dpu_encoder_phys_ops {
int (*control_vblank_irq)(struct dpu_encoder_phys *enc, bool enable);
int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc);
int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc);
-   int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc);
void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc);
void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc);
void (*trigger_start)(struct dpu_encoder_phys *phys_enc);
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 df88358e7037..285246837b73 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
@@ -690,33 +690,6 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done(
return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc);
 }
 
-static int dpu_encoder_phys_cmd_wait_for_vblank(
-   struct dpu_encoder_phys *phys_enc)
-{
-   int rc = 0;
-   struct dpu_encoder_phys_cmd *cmd_enc;
-   struct dpu_encoder_wait_info wait_info;
-
-   cmd_enc = to_dpu_encoder_phys_cmd(phys_enc);
-
-   /* only required for master controller */
-   if (!dpu_encoder_phys_cmd_is_master(phys_enc))
-   return rc;
-
-   wait_info.wq = &cmd_enc->pending_vblank_wq;
-   wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt;
-   wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
-
-   atomic_inc(&cmd_enc->pending_vblank_cnt);
-
-   rc = dpu_encoder_helper_wait_for_irq(phys_enc,
-   phys_enc->irq[INTR_IDX_RDPTR],
-   dpu_encoder_phys_cmd_te_rd_ptr_irq,
-   &wait_info);
-
-   return rc;
-}
-
 static void dpu_encoder_phys_cmd_handle_post_kickoff(
struct dpu_encoder_phys *phys_enc)
 {
@@ -745,7 +718,6 @@ static void dpu_encoder_phys_cmd_init_ops(
ops->wait_for_commit_done = dpu_encoder_phys_cmd_wait_for_commit_done;
ops->prepare_for_kickoff = dpu_encoder_phys_cmd_prepare_for_kickoff;
ops->wait_for_tx_complete = dpu_encoder_phys_cmd_wait_for_tx_complete;
-   ops->wait_for_vblank = dpu_encoder_phys_cmd_wait_for_vblank;
ops->trigger_start = dpu_encoder_phys_cmd_trigger_start;
ops->needs_single_flush = dpu_encoder_phys_cmd_needs_single_flush;
ops->irq_control = dpu_encoder_phys_cmd_irq_control;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index c2189e58de6a..94521f6d7f70 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -444,7 +444,7 @@ static void dpu_encoder_phys_vid_destroy(struct 
dpu_encoder_phys *phys_enc)
kfree(phys_enc);
 }
 
-static int dpu_encoder_phys_vid_wait_for_vblank(
+static int dpu_encoder_phys_vid_wait_for_tx_complete(
struct dpu_encoder_phys *phys_enc)
 {
struct dpu_encoder_wait_info wait_info;
@@ -558,7 +558,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
 * scanout buffer) don't latch properly..
 */
if (dpu_encoder_phys_vid_is_master(phys_enc)) {
-   ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc);
+   ret = dpu_encoder_phys_vid_wait_for_tx_complete(phys_enc

Re: [PATCH 01/10] drm/mediatek: Add interface to allocate MediaTek GEM buffer.

2023-10-03 Thread 林睿祥


[PATCH v11 5/9] drm/mediatek: Add connector dynamic selection capability

2023-10-03 Thread Jason-JH . Lin
Add dynamic select available connector flow in mtk_drm_crtc_create()
and mtk_drm_crtc_atomic_enable().

In mtk_drm_crtc_create(), if there is a connector routes array in drm
driver data, all components definded in the connector routes array will
be checked and their encoder_index will be set.

In mtk_drm_crtc_atomic_enable(), crtc will check its encoder_index to
identify which componet in the connector routes array should append.

Signed-off-by: Jason-JH.Lin 
Signed-off-by: Nancy Lin 
Signed-off-by: Nathan Lu 
Tested-by: Fei Shao 
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 72 -
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h |  5 +-
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 30 -
 drivers/gpu/drm/mediatek/mtk_drm_drv.c  | 13 +++-
 drivers/gpu/drm/mediatek/mtk_drm_drv.h  |  7 ++
 5 files changed, 120 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index b6fa4ad2f94d..742218691080 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -63,6 +63,8 @@ struct mtk_drm_crtc {
struct mtk_mutex*mutex;
unsigned intddp_comp_nr;
struct mtk_ddp_comp **ddp_comp;
+   unsigned intnum_conn_routes;
+   const struct mtk_drm_route  *conn_routes;
 
/* lock for display hardware access */
struct mutexhw_lock;
@@ -647,6 +649,43 @@ static void mtk_drm_crtc_disable_vblank(struct drm_crtc 
*crtc)
mtk_ddp_comp_disable_vblank(comp);
 }
 
+static void mtk_drm_crtc_update_output(struct drm_crtc *crtc,
+  struct drm_atomic_state *state)
+{
+   int crtc_index = drm_crtc_index(crtc);
+   int i;
+   struct device *dev;
+   struct drm_crtc_state *crtc_state = state->crtcs[crtc_index].new_state;
+   struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+   struct mtk_drm_private *priv;
+   unsigned int encoder_mask = crtc_state->encoder_mask;
+
+   if (!crtc_state->connectors_changed)
+   return;
+
+   if (!mtk_crtc->num_conn_routes)
+   return;
+
+   priv = ((struct mtk_drm_private 
*)crtc->dev->dev_private)->all_drm_private[crtc_index];
+   dev = priv->dev;
+
+   dev_dbg(dev, "connector change:%d, encoder mask:0x%x for crtc:%d\n",
+   crtc_state->connectors_changed, encoder_mask, crtc_index);
+
+   for (i = 0; i < mtk_crtc->num_conn_routes; i++) {
+   unsigned int comp_id = mtk_crtc->conn_routes[i].route_ddp;
+   struct mtk_ddp_comp *comp = &priv->ddp_comp[comp_id];
+
+   if (comp->encoder_index >= 0 &&
+   (encoder_mask & BIT(comp->encoder_index))) {
+   mtk_crtc->ddp_comp[mtk_crtc->ddp_comp_nr - 1] = comp;
+   dev_dbg(dev, "Add comp_id: %d at path index %d\n",
+   comp->id, mtk_crtc->ddp_comp_nr - 1);
+   break;
+   }
+   }
+}
+
 int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
 struct mtk_plane_state *state)
 {
@@ -685,6 +724,8 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc 
*crtc,
return;
}
 
+   mtk_drm_crtc_update_output(crtc, state);
+
ret = mtk_crtc_ddp_hw_init(mtk_crtc);
if (ret) {
pm_runtime_put(comp->dev);
@@ -884,7 +925,8 @@ struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc 
*crtc)
 
 int mtk_drm_crtc_create(struct drm_device *drm_dev,
const unsigned int *path, unsigned int path_len,
-   int priv_data_index)
+   int priv_data_index, const struct mtk_drm_route 
*conn_routes,
+   unsigned int num_conn_routes)
 {
struct mtk_drm_private *priv = drm_dev->dev_private;
struct device *dev = drm_dev->dev;
@@ -935,7 +977,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
 
mtk_crtc->mmsys_dev = priv->mmsys_dev;
mtk_crtc->ddp_comp_nr = path_len;
-   mtk_crtc->ddp_comp = devm_kmalloc_array(dev, mtk_crtc->ddp_comp_nr,
+   mtk_crtc->ddp_comp = devm_kmalloc_array(dev,
+   mtk_crtc->ddp_comp_nr + 
(conn_routes ? 1 : 0),
sizeof(*mtk_crtc->ddp_comp),
GFP_KERNEL);
if (!mtk_crtc->ddp_comp)
@@ -1038,5 +1081,30 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
init_waitqueue_head(&mtk_crtc->cb_blocking_queue);
}
 #endif
+
+   if (conn_routes) {
+   for (i = 0; i < num_conn_routes; i++) {
+   unsigned int comp_id = conn_routes[i].route_ddp;
+   struct device_node *node = priv->com

[PATCH v11 4/9] drm/mediatek: Add encoder_index interface for mtk_ddp_comp_funcs

2023-10-03 Thread Jason-JH . Lin
To support dynamic connector selection function, each ddp_comp need to
get their encoder_index to identify which connector should be selected.

Add encoder_index interface for mtk_ddp_comp_funcs to get the encoder
identifier by drm_encoder_index().
Then drm driver will call mtk_ddp_comp_encoder_index_set() to store the
encoder_index to each ddp_comp in connector routes.

Signed-off-by: Jason-JH.Lin 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h 
b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
index febcaeef16a1..0797b3ac75d8 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
@@ -80,12 +80,14 @@ struct mtk_ddp_comp_funcs {
void (*disconnect)(struct device *dev, struct device *mmsys_dev, 
unsigned int next);
void (*add)(struct device *dev, struct mtk_mutex *mutex);
void (*remove)(struct device *dev, struct mtk_mutex *mutex);
+   unsigned int (*encoder_index)(struct device *dev);
 };
 
 struct mtk_ddp_comp {
struct device *dev;
int irq;
unsigned int id;
+   int encoder_index;
const struct mtk_ddp_comp_funcs *funcs;
 };
 
@@ -275,6 +277,12 @@ static inline bool mtk_ddp_comp_disconnect(struct 
mtk_ddp_comp *comp, struct dev
return false;
 }
 
+static inline void mtk_ddp_comp_encoder_index_set(struct mtk_ddp_comp *comp)
+{
+   if (comp->funcs && comp->funcs->encoder_index)
+   comp->encoder_index = 
(int)comp->funcs->encoder_index(comp->dev);
+}
+
 int mtk_ddp_comp_get_id(struct device_node *node,
enum mtk_ddp_comp_type comp_type);
 unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm,
-- 
2.18.0



[PATCH v11 0/9] Add connector dynamic selection capability

2023-10-03 Thread Jason-JH . Lin
To support DSI and eDP as main display connector without modifying
mtk-drm driver, we add connector dynamic selection capability.

Change in v11:
1. move some global variable to a scope.
2. move mtk_drm_crtc_update_output() after pm_runtime_resume_and_get().
3. move return 0 when error occurred into mtk_drm_find_comp_in_ddp_conn_path().

Change in v10:
1. rebase to Linux 6.6-rc3.
2. separate the common part of adding encoder_index interface for ddp_comp
   to a single patch.
3. separate the DP_INTF0 support dynamic selection to a single patch.
4. add the array size while allocating ddp_comp array in mtk_crtc.
5. add some comment for marking encoder_index to -1.

Change in v9:
1. change subject title and [PATCH v11 5/7] title.
2. separate [PATCH v11 4/7]
   and [PATCH v11 5/7].
3. fix typo and some grammar problems in commit message.

Change in v8:
1. add mtk_drm_crtc_path enum to replace array index of all_drm_priv.
2. separate add encoder_index function to another patch.
3. separate add dpi and dsi encoder_index function implementation to
   another patch.
4. separate add dsi conn_routes support to another patch.
5. set encoder_index to -1 if comp->dev doesn't not exist and add
   (encoder_index >= 0) checking before assigning conn_routes.
6. move conn_routes statement to the end of mtk_drm_crtc_create.

Change in v7:
1. separate 2 fixes patch from v6.
2. remove unnecessary null checking and variable.
3. move ddp_comp checking to crtc create.

Change in v6:
1. remove max_ddp_comp_nr.

Change in v5:
1. Change conn_routes array to single component enum id.

Change in v4:
1. Change variable naming from conn_route_num to num_conn_routes.
2. Change he encoder_index function return valuew from int to unsigned int.

Change in v3:
1. Change max_num comparison statement to max().

Change in v2:
1. rebase on linux-next: next-20230426
2. Fix alphabetical order and max_num condition check problem.

Change in v1:
1. based on mediatek-drm maintainer's tree / mediatek-drm-next branch:
https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux.git/log/?h=mediatek-drm-next

Jason-JH.Lin (9):
  drm/mediatek: Add mmsys_dev_num to mt8188 vdosys0 driver data
  drm/mediatek: Add crtc path enum for all_drm_priv array
  drm/mediatek: Fix using wrong drm private data to bind mediatek-drm
  drm/mediatek: Add encoder_index interface for mtk_ddp_comp_funcs
  drm/mediatek: Add connector dynamic selection capability
  drm/mediatek: dpi: Support dynamic connector selection
  drm/mediatek: Support dynamic selection of DP_INTF0 on MT8188 VDOSYS0
  drm/mediatek: dsi: Support dynamic connector selection
  drm/mediatek: Support dynamic selection of DSI0 on MT8188 VDOSYS0

 drivers/gpu/drm/mediatek/mtk_disp_drv.h |  2 +
 drivers/gpu/drm/mediatek/mtk_dpi.c  |  9 +++
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 72 -
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h |  5 +-
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 32 -
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |  8 +++
 drivers/gpu/drm/mediatek/mtk_drm_drv.c  | 45 ++---
 drivers/gpu/drm/mediatek/mtk_drm_drv.h  | 15 -
 drivers/gpu/drm/mediatek/mtk_dsi.c  |  9 +++
 9 files changed, 182 insertions(+), 15 deletions(-)

-- 
2.18.0



[PATCH v11 6/9] drm/mediatek: dpi: Support dynamic connector selection

2023-10-03 Thread Jason-JH . Lin
Add implementation of mtk_dpi_encoder_index to mtk_ddp_comp_func
to make mtk_dpi support dynamic connector selection.

Signed-off-by: Jason-JH.Lin 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_disp_drv.h | 1 +
 drivers/gpu/drm/mediatek/mtk_dpi.c  | 9 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 1 +
 3 files changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h 
b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 2254038519e1..5f07037670e9 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -44,6 +44,7 @@ void mtk_dither_set_common(void __iomem *regs, struct 
cmdq_client_reg *cmdq_reg,
 
 void mtk_dpi_start(struct device *dev);
 void mtk_dpi_stop(struct device *dev);
+unsigned int mtk_dpi_encoder_index(struct device *dev);
 
 void mtk_dsi_ddp_start(struct device *dev);
 void mtk_dsi_ddp_stop(struct device *dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c 
b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 2f931e4e2b60..4e3d9f7b4d8c 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -781,6 +781,15 @@ void mtk_dpi_stop(struct device *dev)
mtk_dpi_power_off(dpi);
 }
 
+unsigned int mtk_dpi_encoder_index(struct device *dev)
+{
+   struct mtk_dpi *dpi = dev_get_drvdata(dev);
+   unsigned int encoder_index = drm_encoder_index(&dpi->encoder);
+
+   dev_dbg(dev, "encoder index:%d\n", encoder_index);
+   return encoder_index;
+}
+
 static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
 {
struct mtk_dpi *dpi = dev_get_drvdata(dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c 
b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 02f0ada3754b..601755925520 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -304,6 +304,7 @@ static const struct mtk_ddp_comp_funcs ddp_dither = {
 static const struct mtk_ddp_comp_funcs ddp_dpi = {
.start = mtk_dpi_start,
.stop = mtk_dpi_stop,
+   .encoder_index = mtk_dpi_encoder_index,
 };
 
 static const struct mtk_ddp_comp_funcs ddp_dsc = {
-- 
2.18.0



[PATCH v11 9/9] drm/mediatek: Support dynamic selection of DSI0 on MT8188 VDOSYS0

2023-10-03 Thread Jason-JH . Lin
Add DDP_COMPONENT_DSI0 as a main display output selection on
MT8188 VDOSYS0.

Signed-off-by: Nathan Lu 
Signed-off-by: Jason-JH.Lin 
Reviewed-by: Matthias Brugger 
Reviewed-by: Fei Shao 
Reviewed-by: AngeloGioacchino Del Regno 

Tested-by: Fei Shao 
---
 drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c 
b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 70c9501250a0..5226be88d088 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -190,6 +190,7 @@ static const unsigned int mt8188_mtk_ddp_main[] = {
 
 static const struct mtk_drm_route mt8188_mtk_ddp_main_routes[] = {
{0, DDP_COMPONENT_DP_INTF0},
+   {0, DDP_COMPONENT_DSI0},
 };
 
 static const unsigned int mt8192_mtk_ddp_main[] = {
-- 
2.18.0



[PATCH v11 3/9] drm/mediatek: Fix using wrong drm private data to bind mediatek-drm

2023-10-03 Thread Jason-JH . Lin
According to mtk_drm_kms_init(), the all_drm_private array in each
drm private data stores all drm private data in display path order.

In mtk_drm_get_all_drm_priv(), each element in all_drm_priv should have one
display path private data, such as:
all_drm_priv[CRTC_MAIN] should only have main_path data
all_drm_priv[CRTC_EXT] should only have ext_path data
all_drm_priv[CRTC_THIRD] should only have third_path data

So we need to add the length checking for each display path before
assigning their drm private data into all_drm_priv array.

Then the all_drm_private array in each drm private data needs to be
assigned in their display path order.

Fixes: 1ef7ed48356c ("drm/mediatek: Modify mediatek-drm for mt8195 multi mmsys 
support")
Signed-off-by: Jason-JH.Lin 
Reviewed-by: AngeloGioacchino Del Regno 

Reviewed-by: CK Hu 
Tested-by: Fei Shao 
---
 drivers/gpu/drm/mediatek/mtk_drm_drv.c | 17 ++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c 
b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index efe36eace8f0..bf4a04c1156b 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -352,6 +352,7 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
 {
struct mtk_drm_private *drm_priv = dev_get_drvdata(dev);
struct mtk_drm_private *all_drm_priv[MAX_CRTC];
+   struct mtk_drm_private *temp_drm_priv;
struct device_node *phandle = dev->parent->of_node;
const struct of_device_id *of_id;
struct device_node *node;
@@ -371,11 +372,21 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
continue;
 
drm_dev = device_find_child(&pdev->dev, NULL, mtk_drm_match);
-   if (!drm_dev || !dev_get_drvdata(drm_dev))
+   if (!drm_dev)
continue;
 
-   all_drm_priv[cnt] = dev_get_drvdata(drm_dev);
-   if (all_drm_priv[cnt] && all_drm_priv[cnt]->mtk_drm_bound)
+   temp_drm_priv = dev_get_drvdata(drm_dev);
+   if (!temp_drm_priv)
+   continue;
+
+   if (temp_drm_priv->data->main_len)
+   all_drm_priv[CRTC_MAIN] = temp_drm_priv;
+   else if (temp_drm_priv->data->ext_len)
+   all_drm_priv[CRTC_EXT] = temp_drm_priv;
+   else if (temp_drm_priv->data->third_len)
+   all_drm_priv[CRTC_THIRD] = temp_drm_priv;
+
+   if (temp_drm_priv->mtk_drm_bound)
cnt++;
 
if (cnt == MAX_CRTC)
-- 
2.18.0



[PATCH v11 7/9] drm/mediatek: Support dynamic selection of DP_INTF0 on MT8188 VDOSYS0

2023-10-03 Thread Jason-JH . Lin
Move DDP_COMPONENT_DP_INTF0 from mt8188_mtk_ddp_main array to a
connector routes array called mt8188_mtk_ddp_main_routes to support
dynamic selection capability for mt8188.

Signed-off-by: Jason-JH.Lin 
Reviewed-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_drm_drv.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c 
b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 5d2e191b4106..70c9501250a0 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -186,7 +186,10 @@ static const unsigned int mt8188_mtk_ddp_main[] = {
DDP_COMPONENT_GAMMA,
DDP_COMPONENT_POSTMASK0,
DDP_COMPONENT_DITHER0,
-   DDP_COMPONENT_DP_INTF0,
+};
+
+static const struct mtk_drm_route mt8188_mtk_ddp_main_routes[] = {
+   {0, DDP_COMPONENT_DP_INTF0},
 };
 
 static const unsigned int mt8192_mtk_ddp_main[] = {
@@ -288,6 +291,8 @@ static const struct mtk_mmsys_driver_data 
mt8186_mmsys_driver_data = {
 static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = {
.main_path = mt8188_mtk_ddp_main,
.main_len = ARRAY_SIZE(mt8188_mtk_ddp_main),
+   .conn_routes = mt8188_mtk_ddp_main_routes,
+   .num_conn_routes = ARRAY_SIZE(mt8188_mtk_ddp_main_routes),
.mmsys_dev_num = 1,
 };
 
-- 
2.18.0



[PATCH v11 8/9] drm/mediatek: dsi: Support dynamic connector selection

2023-10-03 Thread Jason-JH . Lin
Add implementation of mtk_dsi_encoder_index to mtk_ddp_comp_func
to make mtk_dsi support dynamic connector selection.

Signed-off-by: Jason-JH.Lin 
Reviewed-by: CK Hu 
Reviewed-by: Fei Shao 
Reviewed-by: AngeloGioacchino Del Regno 

Tested-by: Fei Shao 
---
 drivers/gpu/drm/mediatek/mtk_disp_drv.h | 1 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 1 +
 drivers/gpu/drm/mediatek/mtk_dsi.c  | 9 +
 3 files changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h 
b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 5f07037670e9..fdaa21b6a9da 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -48,6 +48,7 @@ unsigned int mtk_dpi_encoder_index(struct device *dev);
 
 void mtk_dsi_ddp_start(struct device *dev);
 void mtk_dsi_ddp_stop(struct device *dev);
+unsigned int mtk_dsi_encoder_index(struct device *dev);
 
 int mtk_gamma_clk_enable(struct device *dev);
 void mtk_gamma_clk_disable(struct device *dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c 
b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
index 601755925520..f3345af12cb8 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
@@ -318,6 +318,7 @@ static const struct mtk_ddp_comp_funcs ddp_dsc = {
 static const struct mtk_ddp_comp_funcs ddp_dsi = {
.start = mtk_dsi_ddp_start,
.stop = mtk_dsi_ddp_stop,
+   .encoder_index = mtk_dsi_encoder_index,
 };
 
 static const struct mtk_ddp_comp_funcs ddp_gamma = {
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c 
b/drivers/gpu/drm/mediatek/mtk_dsi.c
index d8bfc2cce54d..124647a4d985 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -865,6 +865,15 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, 
struct mtk_dsi *dsi)
return ret;
 }
 
+unsigned int mtk_dsi_encoder_index(struct device *dev)
+{
+   struct mtk_dsi *dsi = dev_get_drvdata(dev);
+   unsigned int encoder_index = drm_encoder_index(&dsi->encoder);
+
+   dev_dbg(dev, "encoder index:%d\n", encoder_index);
+   return encoder_index;
+}
+
 static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
 {
int ret;
-- 
2.18.0



[PATCH v11 2/9] drm/mediatek: Add crtc path enum for all_drm_priv array

2023-10-03 Thread Jason-JH . Lin
Add mtk_drm_crtc_path enum for each display path.

Instead of using array index of all_drm_priv in mtk_drm_kms_init(),
mtk_drm_crtc_path enum can make code more readable.

Signed-off-by: Jason-JH.Lin 
Reviewed-by: Fei Shao 
Reviewed-by: CK Hu 
Reviewed-by: AngeloGioacchino Del Regno 

Tested-by: Fei Shao 
---
 drivers/gpu/drm/mediatek/mtk_drm_drv.c | 6 +++---
 drivers/gpu/drm/mediatek/mtk_drm_drv.h | 8 +++-
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c 
b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 2d6a979afe8f..efe36eace8f0 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -469,21 +469,21 @@ static int mtk_drm_kms_init(struct drm_device *drm)
for (j = 0; j < private->data->mmsys_dev_num; j++) {
priv_n = private->all_drm_private[j];
 
-   if (i == 0 && priv_n->data->main_len) {
+   if (i == CRTC_MAIN && priv_n->data->main_len) {
ret = mtk_drm_crtc_create(drm, 
priv_n->data->main_path,
  
priv_n->data->main_len, j);
if (ret)
goto err_component_unbind;
 
continue;
-   } else if (i == 1 && priv_n->data->ext_len) {
+   } else if (i == CRTC_EXT && priv_n->data->ext_len) {
ret = mtk_drm_crtc_create(drm, 
priv_n->data->ext_path,
  
priv_n->data->ext_len, j);
if (ret)
goto err_component_unbind;
 
continue;
-   } else if (i == 2 && priv_n->data->third_len) {
+   } else if (i == CRTC_THIRD && priv_n->data->third_len) {
ret = mtk_drm_crtc_create(drm, 
priv_n->data->third_path,
  
priv_n->data->third_len, j);
if (ret)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h 
b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index eb2fd45941f0..f4de8bb27685 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -9,11 +9,17 @@
 #include 
 #include "mtk_drm_ddp_comp.h"
 
-#define MAX_CRTC   3
 #define MAX_CONNECTOR  2
 #define DDP_COMPONENT_DRM_OVL_ADAPTOR (DDP_COMPONENT_ID_MAX + 1)
 #define DDP_COMPONENT_DRM_ID_MAX (DDP_COMPONENT_DRM_OVL_ADAPTOR + 1)
 
+enum mtk_drm_crtc_path {
+   CRTC_MAIN,
+   CRTC_EXT,
+   CRTC_THIRD,
+   MAX_CRTC,
+};
+
 struct device;
 struct device_node;
 struct drm_crtc;
-- 
2.18.0



[PATCH v11 1/9] drm/mediatek: Add mmsys_dev_num to mt8188 vdosys0 driver data

2023-10-03 Thread Jason-JH . Lin
Add missing mmsys_dev_num to mt8188 vdosys0 driver data.

Fixes: 54b48080278a ("drm/mediatek: Add mediatek-drm of vdosys0 support for 
mt8188")
Signed-off-by: Jason-JH.Lin 
Reviewed-by: CK Hu 
Reviewed-by: AngeloGioacchino Del Regno 

Reviewed-by: Fei Shao 
Tested-by: Fei Shao 
---
 drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c 
b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 93552d76b6e7..2d6a979afe8f 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -288,6 +288,7 @@ static const struct mtk_mmsys_driver_data 
mt8186_mmsys_driver_data = {
 static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = {
.main_path = mt8188_mtk_ddp_main,
.main_len = ARRAY_SIZE(mt8188_mtk_ddp_main),
+   .mmsys_dev_num = 1,
 };
 
 static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
-- 
2.18.0



Re: [PATCH v4 1/4] drm/format-helper: Export line conversion helper for drm_panic

2023-10-03 Thread nerdopolis
On Tuesday, October 3, 2023 10:22:44 AM EDT Jocelyn Falempe wrote:
> drm_panic will need the low-level drm_fb__line functions.
> Also add drm_fb_r1_to_xrgb to render the fonts.
> 
> Signed-off-by: Jocelyn Falempe 
> ---
>  drivers/gpu/drm/drm_format_helper.c | 88 ++---
>  include/drm/drm_format_helper.h |  9 +++
>  2 files changed, 89 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_format_helper.c 
> b/drivers/gpu/drm/drm_format_helper.c
> index f93a4efcee90..c238e5d84f1f 100644
> --- a/drivers/gpu/drm/drm_format_helper.c
> +++ b/drivers/gpu/drm/drm_format_helper.c
> @@ -270,7 +270,30 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned 
> int *dst_pitch,
>  
>   drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, swab_line);
>  }
> -EXPORT_SYMBOL(drm_fb_swab);
I had to add this line back to get it to build, but once I did, it worked. 
> +
> +/**
> + * drm_fb_r1_to_32bit_line - Convert one line from monochrome to any 32bit 
> pixel format
> + * @dbuf: Pointer to the destination line (in any 32bit format)
> + * @sbuf: Pointer to the source line (in monochrome)
> + * @pixels: Number of pixels to convert.
> + * @fg_color: Foreground color, applied when R1 is 1
> + * @bg_color: Background color, applied when R1 is 0
> + *
> + * Convert monochrome to any format with 32bit pixel.
> + * There is a limitation, as sbuf is a pointer, it can only points to a 
> multiple
> + * of 8 pixels in the source buffer.
> + */
> +void drm_fb_r1_to_32bit_line(void *dbuf, const void *sbuf, unsigned int 
> pixels,
> + u32 fg_color, u32 bg_color)
> +{
> + unsigned int x;
> + const u8 *sbuf8 = sbuf;
> + u32 *dubf32 = dbuf;
> +
> + for (x = 0; x < pixels; x++)
> + dubf32[x] = (sbuf8[x / 8] & (0x80 >> (x % 8))) ? fg_color : 
> bg_color;
> +}
> +EXPORT_SYMBOL(drm_fb_r1_to_32bit_line);
>  
>  static void drm_fb_xrgb_to_rgb332_line(void *dbuf, const void *sbuf, 
> unsigned int pixels)
>  {
> @@ -320,7 +343,13 @@ void drm_fb_xrgb_to_rgb332(struct iosys_map *dst, 
> const unsigned int *dst_pi
>  }
>  EXPORT_SYMBOL(drm_fb_xrgb_to_rgb332);
>  
> -static void drm_fb_xrgb_to_rgb565_line(void *dbuf, const void *sbuf, 
> unsigned int pixels)
> +/**
> + * drm_fb_xrgb_to_rgb565_line - Convert one line from XRGB to RGB565
> + * @dbuf: Pointer to the destination line (in RGB565)
> + * @sbuf: Pointer to the source line (in XRGB)
> + * @pixels: Number of pixels to convert.
> + */
> +void drm_fb_xrgb_to_rgb565_line(void *dbuf, const void *sbuf, unsigned 
> int pixels)
>  {
>   __le16 *dbuf16 = dbuf;
>   const __le32 *sbuf32 = sbuf;
> @@ -336,6 +365,7 @@ static void drm_fb_xrgb_to_rgb565_line(void *dbuf, 
> const void *sbuf, unsigne
>   dbuf16[x] = cpu_to_le16(val16);
>   }
>  }
> +EXPORT_SYMBOL(drm_fb_xrgb_to_rgb565_line);
>  
>  /* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */
>  static void drm_fb_xrgb_to_rgb565_swab_line(void *dbuf, const void *sbuf,
> @@ -396,7 +426,13 @@ void drm_fb_xrgb_to_rgb565(struct iosys_map *dst, 
> const unsigned int *dst_pi
>  }
>  EXPORT_SYMBOL(drm_fb_xrgb_to_rgb565);
>  
> -static void drm_fb_xrgb_to_xrgb1555_line(void *dbuf, const void *sbuf, 
> unsigned int pixels)
> +/**
> + * drm_fb_xrgb_to_rgb565_line - Convert one line from XRGB to 
> XRGB1555
> + * @dbuf: Pointer to the destination line (in XRGB1555)
> + * @sbuf: Pointer to the source line (in XRGB)
> + * @pixels: Number of pixels to convert.
> + */
> +void drm_fb_xrgb_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned 
> int pixels)
>  {
>   __le16 *dbuf16 = dbuf;
>   const __le32 *sbuf32 = sbuf;
> @@ -412,6 +448,7 @@ static void drm_fb_xrgb_to_xrgb1555_line(void *dbuf, 
> const void *sbuf, unsig
>   dbuf16[x] = cpu_to_le16(val16);
>   }
>  }
> +EXPORT_SYMBOL(drm_fb_xrgb_to_xrgb1555_line);
>  
>  /**
>   * drm_fb_xrgb_to_xrgb1555 - Convert XRGB to XRGB1555 clip buffer
> @@ -447,7 +484,13 @@ void drm_fb_xrgb_to_xrgb1555(struct iosys_map *dst, 
> const unsigned int *dst_
>  }
>  EXPORT_SYMBOL(drm_fb_xrgb_to_xrgb1555);
>  
> -static void drm_fb_xrgb_to_argb1555_line(void *dbuf, const void *sbuf, 
> unsigned int pixels)
> +/**
> + * drm_fb_xrgb_to_rgb565_line - Convert one line from XRGB to 
> ARGB1555
> + * @dbuf: Pointer to the destination line (in ARGB1555)
> + * @sbuf: Pointer to the source line (in XRGB)
> + * @pixels: Number of pixels to convert.
> + */
> +void drm_fb_xrgb_to_argb1555_line(void *dbuf, const void *sbuf, unsigned 
> int pixels)
>  {
>   __le16 *dbuf16 = dbuf;
>   const __le32 *sbuf32 = sbuf;
> @@ -464,6 +507,7 @@ static void drm_fb_xrgb_to_argb1555_line(void *dbuf, 
> const void *sbuf, unsig
>   dbuf16[x] = cpu_to_le16(val16);
>   }
>  }
> +EXPORT_SYMBOL(drm_fb_xrgb_to_argb1555_line);
>  
>  /**
>   * drm

[PATCH] drm/amdgpu: Annotate struct amdgpu_bo_list with __counted_by

2023-10-03 Thread Kees Cook
Prepare for the coming implementation by GCC and Clang of the __counted_by
attribute. Flexible array members annotated with __counted_by can have
their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for
array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family
functions).

As found with Coccinelle[1], add __counted_by for struct amdgpu_bo_list.
Additionally, since the element count member must be set before accessing
the annotated flexible array member, move its initialization earlier.

Cc: Alex Deucher 
Cc: "Christian König" 
Cc: "Pan, Xinhui" 
Cc: David Airlie 
Cc: Daniel Vetter 
Cc: "Gustavo A. R. Silva" 
Cc: Luben Tuikov 
Cc: Christophe JAILLET 
Cc: Felix Kuehling 
Cc: amd-...@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org
Cc: linux-harden...@vger.kernel.org
Link: 
https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci
 [1]
Signed-off-by: Kees Cook 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
index 6f5b641b631e..781e5c5ce04d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -84,6 +84,7 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct 
drm_file *filp,
 
kref_init(&list->refcount);
 
+   list->num_entries = num_entries;
array = list->entries;
 
for (i = 0; i < num_entries; ++i) {
@@ -129,7 +130,6 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, 
struct drm_file *filp,
}
 
list->first_userptr = first_userptr;
-   list->num_entries = num_entries;
sort(array, last_entry, sizeof(struct amdgpu_bo_list_entry),
 amdgpu_bo_list_entry_cmp, NULL);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
index 6a703be45d04..555cd6d877c3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
@@ -56,7 +56,7 @@ struct amdgpu_bo_list {
 */
struct mutex bo_list_mutex;
 
-   struct amdgpu_bo_list_entry entries[];
+   struct amdgpu_bo_list_entry entries[] __counted_by(num_entries);
 };
 
 int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id,
-- 
2.34.1



[PATCH] dma-buf: Deny copy-on-writes mmaps

2023-10-03 Thread Andi Shyti
From: Chris Wilson 

Enforce that an mmap of a dmabuf is always using MAP_SHARED so that all
access (both read and writes) using the device memory and not a local
copy-on-write page in system memory.

Signed-off-by: Chris Wilson 
Signed-off-by: Andi Shyti 
---
 drivers/dma-buf/dma-buf.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 21916bba77d5..1ec297241842 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -128,6 +129,19 @@ static struct file_system_type dma_buf_fs_type = {
.kill_sb = kill_anon_super,
 };
 
+static unsigned long
+dma_buf_get_unmapped_area(struct file *file,
+ unsigned long addr,
+ unsigned long len,
+ unsigned long pgoff,
+ unsigned long flags)
+{
+   if ((flags & MAP_TYPE) == MAP_PRIVATE)
+   return -EINVAL;
+
+   return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
+}
+
 static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
 {
struct dma_buf *dmabuf;
@@ -508,6 +522,7 @@ static void dma_buf_show_fdinfo(struct seq_file *m, struct 
file *file)
 
 static const struct file_operations dma_buf_fops = {
.release= dma_buf_file_release,
+   .get_unmapped_area = dma_buf_get_unmapped_area,
.mmap   = dma_buf_mmap_internal,
.llseek = dma_buf_llseek,
.poll   = dma_buf_poll,
-- 
2.40.1



Re: [PATCH v4 7/8] drm/msm/dp: add pm_runtime_force_suspend()/resume()

2023-10-03 Thread Kuogee Hsieh



On 10/3/2023 3:36 PM, Dmitry Baryshkov wrote:

On Wed, 4 Oct 2023 at 01:12, Kuogee Hsieh  wrote:


On 10/3/2023 10:53 AM, Dmitry Baryshkov wrote:

On Tue, 3 Oct 2023 at 19:44, Kuogee Hsieh  wrote:

On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote:

On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  wrote:

After incorporated pm_runtime framework into eDP/DP driver, the

incorporating



original dp_pm_suspend() to handle power off both DP phy and
controller during suspend and dp_pm_resume() to handle power on
both DP phy and controller during resume are not necessary since
those function are replaced by dp_pm_runtime_suspend() and
dp_pm_runtime_resume() through pm runtime framework.
Therefore add pm framework provides functions,
pm_runtime_force_suspend()/resume() to complete incorporating pm
runtime framework into DP driver.

Changes in v4:
-- drop both dp_pm_prepare() and dp_pm_compete() from this change
-- delete ST_SUSPENDED state
-- rewording commit text to add more details regrading the purpose
  of this change

Changes in v3:
-- replace dp_pm_suspend() with pm_runtime_force_suspend()
-- replace dp_pm_resume() with pm_runtime_force_resume()

Signed-off-by: Kuogee Hsieh 
---
drivers/gpu/drm/msm/dp/dp_display.c | 113 
++--
1 file changed, 5 insertions(+), 108 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 9158a2c..711d262 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -49,7 +49,6 @@ enum {
   ST_CONNECTED,
   ST_DISCONNECT_PENDING,
   ST_DISPLAY_OFF,
-   ST_SUSPENDED,
};

enum {
@@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private 
*dp, u32 data)
   drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
   dp->dp_display.connector_type, state);

-   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
+   if (state == ST_DISPLAY_OFF) {
   mutex_unlock(&dp->event_mutex);
   return 0;
   }
@@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, 
u32 data)
   drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
   dp->dp_display.connector_type, state);

-   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
+   if (state == ST_DISPLAY_OFF) {
   mutex_unlock(&dp->event_mutex);
   return 0;
   }
@@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev)
   return 0;
}

-static int dp_pm_resume(struct device *dev)
-{
-   struct platform_device *pdev = to_platform_device(dev);
-   struct msm_dp *dp_display = platform_get_drvdata(pdev);
-   struct dp_display_private *dp;
-   int sink_count = 0;
-
-   dp = container_of(dp_display, struct dp_display_private, dp_display);
-
-   mutex_lock(&dp->event_mutex);
-
-   drm_dbg_dp(dp->drm_dev,
-   "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n",
-   dp->dp_display.connector_type, dp->core_initialized,
-   dp->phy_initialized, dp_display->power_on);
-
-   /* start from disconnected state */
-   dp->hpd_state = ST_DISCONNECTED;
-
-   /* turn on dp ctrl/phy */
-   dp_display_host_init(dp);
-
-   if (dp_display->is_edp)
-   dp_catalog_ctrl_hpd_enable(dp->catalog);
-
-   if (dp_catalog_link_is_connected(dp->catalog)) {
-   /*
-* set sink to normal operation mode -- D0
-* before dpcd read
-*/
-   dp_display_host_phy_init(dp);
-   dp_link_psm_config(dp->link, &dp->panel->link_info, false);
-   sink_count = drm_dp_read_sink_count(dp->aux);
-   if (sink_count < 0)
-   sink_count = 0;
-
-   dp_display_host_phy_exit(dp);
-   }
-
-   dp->link->sink_count = sink_count;
-   /*
-* can not declared display is connected unless
-* HDMI cable is plugged in and sink_count of
-* dongle become 1
-* also only signal audio when disconnected
-*/
-   if (dp->link->sink_count) {
-   dp->dp_display.link_ready = true;
-   } else {
-   dp->dp_display.link_ready = false;
-   dp_display_handle_plugged_change(dp_display, false);
-   }
-
-   drm_dbg_dp(dp->drm_dev,
-   "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d 
power=%d\n",
-   dp->dp_display.connector_type, dp->link->sink_count,
-   dp->dp_display.link_ready, dp->core_initialized,
-   dp->phy_initialized, dp_display->power_on);
-
-   mutex_unlock(&dp->event_mutex);
-
-   return 0;
-}
-
-static int dp_pm_suspend(struct device *dev)
-{
-   struct platform_device *pdev = to_platform_device(dev);
-   st

Re: [PATCH v4 7/8] drm/msm/dp: add pm_runtime_force_suspend()/resume()

2023-10-03 Thread Dmitry Baryshkov
On Wed, 4 Oct 2023 at 01:12, Kuogee Hsieh  wrote:
>
>
> On 10/3/2023 10:53 AM, Dmitry Baryshkov wrote:
> > On Tue, 3 Oct 2023 at 19:44, Kuogee Hsieh  wrote:
> >>
> >> On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote:
> >>> On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  
> >>> wrote:
>  After incorporated pm_runtime framework into eDP/DP driver, the
> >>> incorporating
> >>>
> >>>
>  original dp_pm_suspend() to handle power off both DP phy and
>  controller during suspend and dp_pm_resume() to handle power on
>  both DP phy and controller during resume are not necessary since
>  those function are replaced by dp_pm_runtime_suspend() and
>  dp_pm_runtime_resume() through pm runtime framework.
>  Therefore add pm framework provides functions,
>  pm_runtime_force_suspend()/resume() to complete incorporating pm
>  runtime framework into DP driver.
> 
>  Changes in v4:
>  -- drop both dp_pm_prepare() and dp_pm_compete() from this change
>  -- delete ST_SUSPENDED state
>  -- rewording commit text to add more details regrading the purpose
>   of this change
> 
>  Changes in v3:
>  -- replace dp_pm_suspend() with pm_runtime_force_suspend()
>  -- replace dp_pm_resume() with pm_runtime_force_resume()
> 
>  Signed-off-by: Kuogee Hsieh 
>  ---
> drivers/gpu/drm/msm/dp/dp_display.c | 113 
>  ++--
> 1 file changed, 5 insertions(+), 108 deletions(-)
> 
>  diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
>  b/drivers/gpu/drm/msm/dp/dp_display.c
>  index 9158a2c..711d262 100644
>  --- a/drivers/gpu/drm/msm/dp/dp_display.c
>  +++ b/drivers/gpu/drm/msm/dp/dp_display.c
>  @@ -49,7 +49,6 @@ enum {
>    ST_CONNECTED,
>    ST_DISCONNECT_PENDING,
>    ST_DISPLAY_OFF,
>  -   ST_SUSPENDED,
> };
> 
> enum {
>  @@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct 
>  dp_display_private *dp, u32 data)
>    drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
>    dp->dp_display.connector_type, state);
> 
>  -   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
>  +   if (state == ST_DISPLAY_OFF) {
>    mutex_unlock(&dp->event_mutex);
>    return 0;
>    }
>  @@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct 
>  dp_display_private *dp, u32 data)
>    drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
>    dp->dp_display.connector_type, state);
> 
>  -   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
>  +   if (state == ST_DISPLAY_OFF) {
>    mutex_unlock(&dp->event_mutex);
>    return 0;
>    }
>  @@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device 
>  *dev)
>    return 0;
> }
> 
>  -static int dp_pm_resume(struct device *dev)
>  -{
>  -   struct platform_device *pdev = to_platform_device(dev);
>  -   struct msm_dp *dp_display = platform_get_drvdata(pdev);
>  -   struct dp_display_private *dp;
>  -   int sink_count = 0;
>  -
>  -   dp = container_of(dp_display, struct dp_display_private, 
>  dp_display);
>  -
>  -   mutex_lock(&dp->event_mutex);
>  -
>  -   drm_dbg_dp(dp->drm_dev,
>  -   "Before, type=%d core_inited=%d phy_inited=%d 
>  power_on=%d\n",
>  -   dp->dp_display.connector_type, dp->core_initialized,
>  -   dp->phy_initialized, dp_display->power_on);
>  -
>  -   /* start from disconnected state */
>  -   dp->hpd_state = ST_DISCONNECTED;
>  -
>  -   /* turn on dp ctrl/phy */
>  -   dp_display_host_init(dp);
>  -
>  -   if (dp_display->is_edp)
>  -   dp_catalog_ctrl_hpd_enable(dp->catalog);
>  -
>  -   if (dp_catalog_link_is_connected(dp->catalog)) {
>  -   /*
>  -* set sink to normal operation mode -- D0
>  -* before dpcd read
>  -*/
>  -   dp_display_host_phy_init(dp);
>  -   dp_link_psm_config(dp->link, &dp->panel->link_info, 
>  false);
>  -   sink_count = drm_dp_read_sink_count(dp->aux);
>  -   if (sink_count < 0)
>  -   sink_count = 0;
>  -
>  -   dp_display_host_phy_exit(dp);
>  -   }
>  -
>  -   dp->link->sink_count = sink_count;
>  -   /*
>  -* can not declared display is connected unless
>  -* HDMI cable is plugged in and sink_count of
>  -* dongle become 1
>  -* also only signal audio when disconnected

Re: [PATCH v4 7/8] drm/msm/dp: add pm_runtime_force_suspend()/resume()

2023-10-03 Thread Kuogee Hsieh



On 10/3/2023 10:53 AM, Dmitry Baryshkov wrote:

On Tue, 3 Oct 2023 at 19:44, Kuogee Hsieh  wrote:


On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote:

On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  wrote:

After incorporated pm_runtime framework into eDP/DP driver, the

incorporating



original dp_pm_suspend() to handle power off both DP phy and
controller during suspend and dp_pm_resume() to handle power on
both DP phy and controller during resume are not necessary since
those function are replaced by dp_pm_runtime_suspend() and
dp_pm_runtime_resume() through pm runtime framework.
Therefore add pm framework provides functions,
pm_runtime_force_suspend()/resume() to complete incorporating pm
runtime framework into DP driver.

Changes in v4:
-- drop both dp_pm_prepare() and dp_pm_compete() from this change
-- delete ST_SUSPENDED state
-- rewording commit text to add more details regrading the purpose
 of this change

Changes in v3:
-- replace dp_pm_suspend() with pm_runtime_force_suspend()
-- replace dp_pm_resume() with pm_runtime_force_resume()

Signed-off-by: Kuogee Hsieh 
---
   drivers/gpu/drm/msm/dp/dp_display.c | 113 
++--
   1 file changed, 5 insertions(+), 108 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 9158a2c..711d262 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -49,7 +49,6 @@ enum {
  ST_CONNECTED,
  ST_DISCONNECT_PENDING,
  ST_DISPLAY_OFF,
-   ST_SUSPENDED,
   };

   enum {
@@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private 
*dp, u32 data)
  drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
  dp->dp_display.connector_type, state);

-   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
+   if (state == ST_DISPLAY_OFF) {
  mutex_unlock(&dp->event_mutex);
  return 0;
  }
@@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, 
u32 data)
  drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
  dp->dp_display.connector_type, state);

-   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
+   if (state == ST_DISPLAY_OFF) {
  mutex_unlock(&dp->event_mutex);
  return 0;
  }
@@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev)
  return 0;
   }

-static int dp_pm_resume(struct device *dev)
-{
-   struct platform_device *pdev = to_platform_device(dev);
-   struct msm_dp *dp_display = platform_get_drvdata(pdev);
-   struct dp_display_private *dp;
-   int sink_count = 0;
-
-   dp = container_of(dp_display, struct dp_display_private, dp_display);
-
-   mutex_lock(&dp->event_mutex);
-
-   drm_dbg_dp(dp->drm_dev,
-   "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n",
-   dp->dp_display.connector_type, dp->core_initialized,
-   dp->phy_initialized, dp_display->power_on);
-
-   /* start from disconnected state */
-   dp->hpd_state = ST_DISCONNECTED;
-
-   /* turn on dp ctrl/phy */
-   dp_display_host_init(dp);
-
-   if (dp_display->is_edp)
-   dp_catalog_ctrl_hpd_enable(dp->catalog);
-
-   if (dp_catalog_link_is_connected(dp->catalog)) {
-   /*
-* set sink to normal operation mode -- D0
-* before dpcd read
-*/
-   dp_display_host_phy_init(dp);
-   dp_link_psm_config(dp->link, &dp->panel->link_info, false);
-   sink_count = drm_dp_read_sink_count(dp->aux);
-   if (sink_count < 0)
-   sink_count = 0;
-
-   dp_display_host_phy_exit(dp);
-   }
-
-   dp->link->sink_count = sink_count;
-   /*
-* can not declared display is connected unless
-* HDMI cable is plugged in and sink_count of
-* dongle become 1
-* also only signal audio when disconnected
-*/
-   if (dp->link->sink_count) {
-   dp->dp_display.link_ready = true;
-   } else {
-   dp->dp_display.link_ready = false;
-   dp_display_handle_plugged_change(dp_display, false);
-   }
-
-   drm_dbg_dp(dp->drm_dev,
-   "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d 
power=%d\n",
-   dp->dp_display.connector_type, dp->link->sink_count,
-   dp->dp_display.link_ready, dp->core_initialized,
-   dp->phy_initialized, dp_display->power_on);
-
-   mutex_unlock(&dp->event_mutex);
-
-   return 0;
-}
-
-static int dp_pm_suspend(struct device *dev)
-{
-   struct platform_device *pdev = to_platform_device(dev);
-   struct msm_dp *dp_display = platform_get_drvdata(pdev);
-   struct dp_display_private *dp;
-
-   dp = container_

Re: [PATCH v4 8/8] drm/msm/dp: move of_dp_aux_populate_bus() to eDP probe()

2023-10-03 Thread Dmitry Baryshkov
On Tue, 3 Oct 2023 at 23:18, Kuogee Hsieh  wrote:
>
>
> On 10/3/2023 10:56 AM, Dmitry Baryshkov wrote:
> > On 03/10/2023 20:25, Kuogee Hsieh wrote:
> >>
> >> On 9/27/2023 2:57 PM, Dmitry Baryshkov wrote:
> >>> On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh
> >>>  wrote:
>  Currently eDP population is done at msm_dp_modeset_init() which happen
>  at binding time. Move eDP population to be done at display probe time
>  so that probe deferral cases can be handled effectively.
>  wait_for_hpd_asserted callback is added during drm_dp_aux_init()
>  to ensure eDP's HPD is up before proceeding eDP population.
> 
>  Changes in v4:
>  -- delete duplicate initialize code to dp_aux before
>  drm_dp_aux_register()
>  -- delete of_get_child_by_name(dev->of_node, "aux-bus") and inline
>  the function
>  -- not initialize rc = 0
> 
>  Changes in v3:
>  -- add done_probing callback into devm_of_dp_aux_populate_bus()
> 
>  Signed-off-by: Kuogee Hsieh 
>  ---
>    drivers/gpu/drm/msm/dp/dp_aux.c | 34 ++
>    drivers/gpu/drm/msm/dp/dp_display.c | 69
>  ++---
>    2 files changed, 60 insertions(+), 43 deletions(-)
> 
>  diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c
>  b/drivers/gpu/drm/msm/dp/dp_aux.c
>  index 22eb774..425b5c5 100644
>  --- a/drivers/gpu/drm/msm/dp/dp_aux.c
>  +++ b/drivers/gpu/drm/msm/dp/dp_aux.c
>  @@ -480,7 +480,6 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux)
> 
>    int dp_aux_register(struct drm_dp_aux *dp_aux)
>    {
>  -   struct dp_aux_private *aux;
>   int ret;
> 
>   if (!dp_aux) {
>  @@ -488,12 +487,7 @@ int dp_aux_register(struct drm_dp_aux *dp_aux)
>   return -EINVAL;
>   }
> 
>  -   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
>  -
>  -   aux->dp_aux.name = "dpu_dp_aux";
>  -   aux->dp_aux.dev = aux->dev;
>  -   aux->dp_aux.transfer = dp_aux_transfer;
>  -   ret = drm_dp_aux_register(&aux->dp_aux);
>  +   ret = drm_dp_aux_register(dp_aux);
>   if (ret) {
>   DRM_ERROR("%s: failed to register drm aux: %d\n",
>  __func__,
>   ret);
>  @@ -508,6 +502,21 @@ void dp_aux_unregister(struct drm_dp_aux *dp_aux)
>   drm_dp_aux_unregister(dp_aux);
>    }
> 
>  +static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux,
>  +unsigned long wait_us)
>  +{
>  +   int ret;
>  +   struct dp_aux_private *aux;
>  +
>  +   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
>  +
>  +   pm_runtime_get_sync(aux->dev);
>  +   ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog);
>  +   pm_runtime_put_sync(aux->dev);
> >>> Ok, so here you have used put_sync instead of autosuspend. Can we have
> >>> some uniformity? (I'd prefer to see put_sync or just put everywhere)
> >>
> >>
> >> my point is,
> >>
> >> since display is user interface,
> >>
> >> if there has any inputs before timer expire then there is no reason
> >> to execute  pm_runtime_suspend().
> >>
> >> otherwise pm_runtime_suspend() should be executed.
> >>
> >> Therefore I used autosuspend  at aux_transfer() an
> >> ddp_bridge_atomic_post_disable().
> >>
> >> here is not related to user interface so that i use put_sysn() directly.
> >>
> >> is my point make sense?
> >>
> >>   or should I drop all autosuspend and replace them with put_sync()?
> >
> > This was my question from the beginning: what was the reason for using
> > autosuspend? Did it bring any sensible improvement in the disable &
> > reenable path?
>
> ok, i got your point.
>
> 1) I will use put_sync() at dp_bridge_atomic_dsiable() and
> dp_bridge_hpd_disable() instead of put_autosuspend().
>
> 2) keep pm_runtime_put_autosuspend() at dp_aux_transfer().

Why? The panel driver should take care about keeping DP on between transfers.

>
> Is this good?
>
> >
> >>
> >>
> >>>
>  +
>  +   return ret;
>  +}
>  +
>    struct drm_dp_aux *dp_aux_get(struct device *dev, struct
>  dp_catalog *catalog,
> bool is_edp)
>    {
>  @@ -531,6 +540,17 @@ struct drm_dp_aux *dp_aux_get(struct device
>  *dev, struct dp_catalog *catalog,
>   aux->catalog = catalog;
>   aux->retry_cnt = 0;
> 
>  +   /*
>  +* Use the drm_dp_aux_init() to use the aux adapter
>  +* before registering aux with the DRM device so that
>  +* msm edp panel can be detected by generic_dep_panel_probe().
> >>> eDP, AUX, generic_edp_panel_probe().
> >>>
>  +*/
>  +   aux->dp_aux.name = "dpu_dp_aux";
>  +   aux->dp_aux.dev = dev;
>  +   aux->dp_aux.trans

Re: [PATCH 1/3] drm/i915/guc: Support new and improved engine busyness

2023-10-03 Thread Umesh Nerlige Ramappa

On Fri, Sep 22, 2023 at 03:25:08PM -0700, john.c.harri...@intel.com wrote:

From: John Harrison 

The GuC has been extended to support a much more friendly engine
busyness interface. So partition the old interface into a 'busy_v1'
space and add 'busy_v2' support alongside. And if v2 is available, use
that in preference to v1. Note that v2 provides extra features over
and above v1 which will be exposed via PMU in subsequent patches.


Since we are thinking of using the existing busyness counter to expose 
the v2 values, we can drop the last sentence from above.




Signed-off-by: John Harrison 
---
drivers/gpu/drm/i915/gt/intel_engine_types.h  |   4 +-
.../gpu/drm/i915/gt/uc/abi/guc_actions_abi.h  |   4 +-
drivers/gpu/drm/i915/gt/uc/intel_guc.h|  82 ++--
drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c|  55 ++-
drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h|   9 +-
drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h   |  23 +-
.../gpu/drm/i915/gt/uc/intel_guc_submission.c | 381 ++
7 files changed, 427 insertions(+), 131 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h 
b/drivers/gpu/drm/i915/gt/intel_engine_types.h
index a7e6775980043..40fd8f984d64b 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
@@ -323,7 +323,7 @@ struct intel_engine_execlists_stats {
ktime_t start;
};

-struct intel_engine_guc_stats {
+struct intel_engine_guc_stats_v1 {
/**
 * @running: Active state of the engine when busyness was last sampled.
 */
@@ -603,7 +603,7 @@ struct intel_engine_cs {
struct {
union {
struct intel_engine_execlists_stats execlists;
-   struct intel_engine_guc_stats guc;
+   struct intel_engine_guc_stats_v1 guc_v1;
};


Overall, I would suggest having the renames as a separate patch. Would 
make the review easier.




/**
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 f359bef046e0b..c190a99a36c38 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
@@ -137,7 +137,9 @@ enum intel_guc_action {
INTEL_GUC_ACTION_DEREGISTER_CONTEXT_DONE = 0x4600,
INTEL_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC = 0x4601,
INTEL_GUC_ACTION_CLIENT_SOFT_RESET = 0x5507,
-   INTEL_GUC_ACTION_SET_ENG_UTIL_BUFF = 0x550A,
+   INTEL_GUC_ACTION_SET_ENG_UTIL_BUFF_V1 = 0x550A,
+   INTEL_GUC_ACTION_SET_DEVICE_ENGINE_UTILIZATION_V2 = 0x550C,
+   INTEL_GUC_ACTION_SET_FUNCTION_ENGINE_UTILIZATION_V2 = 0x550D,
INTEL_GUC_ACTION_STATE_CAPTURE_NOTIFICATION = 0x8002,
INTEL_GUC_ACTION_NOTIFY_FLUSH_LOG_BUFFER_TO_FILE = 0x8003,
INTEL_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED = 0x8004,
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h 
b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
index 6c392bad29c19..e6502ab5f049f 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
@@ -226,45 +226,61 @@ struct intel_guc {
struct mutex send_mutex;

/**
-* @timestamp: GT timestamp object that stores a copy of the timestamp
-* and adjusts it for overflow using a worker.
+* @busy: Data used by the different versions of engine busyness 
implementations.
 */
-   struct {
-   /**
-* @lock: Lock protecting the below fields and the engine stats.
-*/
-   spinlock_t lock;
-
-   /**
-* @gt_stamp: 64 bit extended value of the GT timestamp.
-*/
-   u64 gt_stamp;
-
-   /**
-* @ping_delay: Period for polling the GT timestamp for
-* overflow.
-*/
-   unsigned long ping_delay;
-
-   /**
-* @work: Periodic work to adjust GT timestamp, engine and
-* context usage for overflows.
-*/
-   struct delayed_work work;
-
+   union {
/**
-* @shift: Right shift value for the gpm timestamp
+* @v1: Data used by v1 engine busyness implementation. Mostly 
a copy
+* of the GT timestamp extended to 64 bits and the worker for 
maintaining it.
 */
-   u32 shift;
+   struct {
+   /**
+* @lock: Lock protecting the below fields and the 
engine stats.
+*/
+   spinlock_t lock;
+
+   /**
+* @gt_stamp: 64 bit extended value of the GT timestamp.
+*/
+   u64 gt_stamp;
+
+   /**
+* @ping_delay: Period for polling the GT timestam

Re: [PATCH V4 2/2] drm/panel: nv3051d: Add Support for Anbernic 351V

2023-10-03 Thread Jessica Zhang




On 10/3/2023 9:33 AM, Chris Morgan wrote:

From: Chris Morgan 

Add support for the Anbernic 351V. Just like the 353 series the
underlying vendor is unknown/unmarked (at least not visible in a
non-destructive manner). The panel had slightly different init
sequences and timings in the BSP kernel, but works fine with the
same ones used in the existing driver. The panel will not work without
the inclusion of the MIPI_DSI_CLOCK_NON_CONTINUOUS flag, and this flag
prevents the 353 series from working correctly, so a new compatible
string is added.

Tested colors and timings using modetest and all seem to work identical
to the 353 otherwise.


Hi Chris,

LGTM, thanks!

Reviewed-by: Jessica Zhang 

BR,

Jessica Zhang



Signed-off-by: Chris Morgan 
---
  drivers/gpu/drm/panel/panel-newvision-nv3051d.c | 7 +++
  1 file changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c 
b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c
index ad98dd9322b4..79de6c886292 100644
--- a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c
+++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c
@@ -388,6 +388,13 @@ static int panel_nv3051d_probe(struct mipi_dsi_device *dsi)
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
  MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
  
+	/*

+* The panel in the RG351V is identical to the 353P, except it
+* requires MIPI_DSI_CLOCK_NON_CONTINUOUS to operate correctly.
+*/
+   if (of_device_is_compatible(dev->of_node, "anbernic,rg351v-panel"))
+   dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
drm_panel_init(&ctx->panel, &dsi->dev, &panel_nv3051d_funcs,
   DRM_MODE_CONNECTOR_DSI);
  
--

2.34.1



Re: [PATCH v4 8/8] drm/msm/dp: move of_dp_aux_populate_bus() to eDP probe()

2023-10-03 Thread Kuogee Hsieh



On 10/3/2023 10:56 AM, Dmitry Baryshkov wrote:

On 03/10/2023 20:25, Kuogee Hsieh wrote:


On 9/27/2023 2:57 PM, Dmitry Baryshkov wrote:
On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh 
 wrote:

Currently eDP population is done at msm_dp_modeset_init() which happen
at binding time. Move eDP population to be done at display probe time
so that probe deferral cases can be handled effectively.
wait_for_hpd_asserted callback is added during drm_dp_aux_init()
to ensure eDP's HPD is up before proceeding eDP population.

Changes in v4:
-- delete duplicate initialize code to dp_aux before 
drm_dp_aux_register()
-- delete of_get_child_by_name(dev->of_node, "aux-bus") and inline 
the function

-- not initialize rc = 0

Changes in v3:
-- add done_probing callback into devm_of_dp_aux_populate_bus()

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/dp/dp_aux.c | 34 ++
  drivers/gpu/drm/msm/dp/dp_display.c | 69 
++---

  2 files changed, 60 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c 
b/drivers/gpu/drm/msm/dp/dp_aux.c

index 22eb774..425b5c5 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -480,7 +480,6 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux)

  int dp_aux_register(struct drm_dp_aux *dp_aux)
  {
-   struct dp_aux_private *aux;
 int ret;

 if (!dp_aux) {
@@ -488,12 +487,7 @@ int dp_aux_register(struct drm_dp_aux *dp_aux)
 return -EINVAL;
 }

-   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
-   aux->dp_aux.name = "dpu_dp_aux";
-   aux->dp_aux.dev = aux->dev;
-   aux->dp_aux.transfer = dp_aux_transfer;
-   ret = drm_dp_aux_register(&aux->dp_aux);
+   ret = drm_dp_aux_register(dp_aux);
 if (ret) {
 DRM_ERROR("%s: failed to register drm aux: %d\n", 
__func__,

 ret);
@@ -508,6 +502,21 @@ void dp_aux_unregister(struct drm_dp_aux *dp_aux)
 drm_dp_aux_unregister(dp_aux);
  }

+static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux,
+    unsigned long wait_us)
+{
+   int ret;
+   struct dp_aux_private *aux;
+
+   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+   pm_runtime_get_sync(aux->dev);
+   ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog);
+   pm_runtime_put_sync(aux->dev);

Ok, so here you have used put_sync instead of autosuspend. Can we have
some uniformity? (I'd prefer to see put_sync or just put everywhere)



my point is,

since display is user interface,

if there has any inputs before timer expire then there is no reason 
to execute  pm_runtime_suspend().


otherwise pm_runtime_suspend() should be executed.

Therefore I used autosuspend  at aux_transfer() an 
ddp_bridge_atomic_post_disable().


here is not related to user interface so that i use put_sysn() directly.

is my point make sense?

  or should I drop all autosuspend and replace them with put_sync()?


This was my question from the beginning: what was the reason for using 
autosuspend? Did it bring any sensible improvement in the disable & 
reenable path?


ok, i got your point.

1) I will use put_sync() at dp_bridge_atomic_dsiable() and 
dp_bridge_hpd_disable() instead of put_autosuspend().


2) keep pm_runtime_put_autosuspend() at dp_aux_transfer().

Is this good?









+
+   return ret;
+}
+
  struct drm_dp_aux *dp_aux_get(struct device *dev, struct 
dp_catalog *catalog,

   bool is_edp)
  {
@@ -531,6 +540,17 @@ struct drm_dp_aux *dp_aux_get(struct device 
*dev, struct dp_catalog *catalog,

 aux->catalog = catalog;
 aux->retry_cnt = 0;

+   /*
+    * Use the drm_dp_aux_init() to use the aux adapter
+    * before registering aux with the DRM device so that
+    * msm edp panel can be detected by generic_dep_panel_probe().

eDP, AUX, generic_edp_panel_probe().


+    */
+   aux->dp_aux.name = "dpu_dp_aux";
+   aux->dp_aux.dev = dev;
+   aux->dp_aux.transfer = dp_aux_transfer;
+   aux->dp_aux.wait_hpd_asserted = dp_wait_hpd_asserted;
+   drm_dp_aux_init(&aux->dp_aux);
+
 return &aux->dp_aux;
  }

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c

index 711d262..9a2b403 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1203,6 +1203,28 @@ static const struct msm_dp_desc 
*dp_display_get_desc(struct platform_device *pde

 return NULL;
  }

+static int dp_auxbus_done_probe(struct drm_dp_aux *aux)
+{
+   int rc;
+
+   rc = component_add(aux->dev, &dp_display_comp_ops);
+   if (rc)
+   DRM_ERROR("eDP component add failed, rc=%d\n", rc);

drop.


+
+   return rc;
+}
+
+static inline int dp_display_auxbus_population(struct 
dp_display_private *dp)

It's not `population`. It is just `populate

Re: [PATCH 0/5] drm/amd/display: Remove migrate-disable and move memory allocation.

2023-10-03 Thread Harry Wentland
On 2023-10-02 06:58, Sebastian Andrzej Siewior wrote:
> On 2023-09-22 07:33:26 [+0200], Christian König wrote:
>> Am 21.09.23 um 16:15 schrieb Sebastian Andrzej Siewior:
>>> Hi,
>>>
>>> I stumbled uppon the amdgpu driver via a bugzilla report. The actual fix
>>> is #4 + #5 and the rest was made while looking at the code.
>>
>> Oh, yes please :)
>>
>> Rodrigo and I have been trying to sort those things out previously, but
>> that's Sisyphean work.
>>
>> In general the DC team needs to judge, but of hand it looks good to me.
> 
> Any way to get this merged? There was no reply from the DC team… No
> reply from the person breaking it either. The bugzilla reporter stated
> that it solves his trouble. He didn't report anything new ;)
> 

Apologies for the slow progress. We're feeding it through our CI and
will let you know the verdict soon.

Do you happen to have the bugzilla link that this is fixing? It would
be helpful to include that as a link in the patches as well, to give
them context.

Harry

>> Christian.
> 
> Sebastian



Re: [PATCH 1/5] drm/amd/display: Remove migrate_en/dis from dc_fpu_begin().

2023-10-03 Thread Harry Wentland
On 2023-09-21 10:15, Sebastian Andrzej Siewior wrote:
> This is a revert of the commit mentioned below while it is not wrong, as
> in the kernel will explode, having migrate_disable() here it is
> complete waste of resources.
> 
> Additionally commit message is plain wrong the review tag does not make

Not sure I follow what's unhelpful about the review tag with
0c316556d1249 ("drm/amd/display: Disable migration to ensure consistency of 
per-CPU variable")

I do wish the original patch showed the splat it's attempting
to fix. It apparently made a difference for something, whether
inadvertently or not. I wish I knew what that "something" was.

Harry

> it any better. The migrate_disable() interface has a fat comment
> describing it and it includes the word "undesired" in the headline which
> should tickle people to read it before using it.
> Initially I assumed it is worded too harsh but now I beg to differ.
> 
> The reviewer of the original commit, even not understanding what
> migrate_disable() does should ask the following:
> 
> - migrate_disable() is added only to the CONFIG_X86 block and it claims
>   to protect fpu_recursion_depth. Why are the other the architectures
>   excluded?
> 
> - migrate_disable() is added after fpu_recursion_depth was modified.
>   Shouldn't it be added before the modification or referencing takes
>   place?
> 
> Moving on.
> Disabling preemption DOES prevent CPU migration. A task, that can not be
> pushed away from the CPU by the scheduler (due to disabled preemption)
> can not be pushed or migrated to another CPU.
> 
> Disabling migration DOES NOT ensure consistency of per-CPU variables. It
> only ensures that the task acts always on the same per-CPU variable. The
> task remains preemptible meaning multiple tasks can access the same
> per-CPU variable. This in turn leads to inconsistency for the statement
> 
>   *pcpu -= 1;
> 
> with two tasks on one CPU and a preemption point during the RMW
> operation:
> 
>  Task A   Task B
>  read pcpu to reg  # 0
>  inc reg   # 0 -> 1
>   read pcpu to reg  # 0
>   inc reg   # 0 -> 1
>   write reg to pcpu # 1
>  write reg to pcpu # 1
> 
> At the end pcpu reads 1 but should read 2 instead. Boom.
> 
> get_cpu_ptr() already contains a preempt_disable() statement. That means
> that the per-CPU variable can only be referenced by a single task which
> is currently running. The only inconsistency that can occur if the
> variable is additionally accessed from an interrupt.
> 
> Remove migrate_disable/enable() from dc_fpu_begin/end().
> 
> Cc: Tianci Yin 
> Cc: Aurabindo Pillai 
> Fixes: 0c316556d1249 ("drm/amd/display: Disable migration to ensure 
> consistency of per-CPU variable")
> Signed-off-by: Sebastian Andrzej Siewior 
> ---
>  drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 2 --
>  1 file changed, 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
> index 172aa10a8800f..86f4c0e046548 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
> @@ -91,7 +91,6 @@ void dc_fpu_begin(const char *function_name, const int line)
>  
>   if (*pcpu == 1) {
>  #if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH)
> - migrate_disable();
>   kernel_fpu_begin();
>  #elif defined(CONFIG_PPC64)
>   if (cpu_has_feature(CPU_FTR_VSX_COMP)) {
> @@ -132,7 +131,6 @@ void dc_fpu_end(const char *function_name, const int line)
>   if (*pcpu <= 0) {
>  #if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH)
>   kernel_fpu_end();
> - migrate_enable();
>  #elif defined(CONFIG_PPC64)
>   if (cpu_has_feature(CPU_FTR_VSX_COMP)) {
>   disable_kernel_vsx();



Re: [PATCH drm-misc-next v5 4/6] drm/gpuvm: track/lock/validate external/evicted objects

2023-10-03 Thread Thomas Hellström



On 10/3/23 18:55, Danilo Krummrich wrote:

It seems like we're mostly aligned on this series, except for the key
controversy we're discussing for a few versions now: locking of the internal
lists. Hence, let's just re-iterate the options we have to get this out of the
way.

(1) The spinlock dance. This basically works for every use case, updating the VA
 space from the IOCTL, from the fence signaling path or anywhere else.
 However, it has the downside of requiring spin_lock() / spin_unlock() for
 *each* list element when locking all external objects and validating all
 evicted objects. Typically, the amount of extobjs and evicted objects
 shouldn't be excessive, but there might be exceptions, e.g. Xe.

(2) The dma-resv lock dance. This is convinient for drivers updating the VA
 space from a VM_BIND ioctl() and is especially efficient if such drivers
 have a huge amount of external and/or evicted objects to manage. However,
 the downsides are that it requires a few tricks in drivers updating the VA
 space from the fence signaling path (e.g. job_run()). Design wise, I'm 
still
 skeptical that it is a good idea to protect internal data structures with
 external locks in a way that it's not clear to callers that a certain
 function would access one of those resources and hence needs protection.
 E.g. it is counter intuitive that drm_gpuvm_bo_put() would require both the
 dma-resv lock of the corresponding object and the VM's dma-resv lock held.
 (Additionally, there were some concerns from amdgpu regarding flexibility 
in
 terms of using GPUVM for non-VM_BIND uAPIs and compute, however, AFAICS
 those discussions did not complete and to me it's still unclear why it
 wouldn't work.)

(3) Simply use an internal mutex per list. This adds a tiny (IMHO negligible)
 overhead for drivers updating the VA space from a VM_BIND ioctl(), namely
 a *single* mutex_lock()/mutex_unlock() when locking all external objects
 and validating all evicted objects. And it still requires some tricks for
 drivers updating the VA space from the fence signaling path. However, it's
 as simple as it can be and hence way less error prone as well as
 self-contained and hence easy to use. Additionally, it's flexible in a way
 that we don't have any expections on drivers to already hold certain locks
 that the driver in some situation might not be able to acquire in the first
 place.

(4) Arbitrary combinations of the above. For instance, the current V5 implements
 both (1) and (2) (as either one or the other). But also (1) and (3) (as in
 (1) additionally to (3)) would be an option, where a driver could opt-in 
for
 the spinlock dance in case it updates the VA space from the fence signaling
 path.

I also considered a few other options as well, however, they don't seem to be
flexible enough. For instance, as by now we could use SRCU for the external
object list. However, this falls apart once a driver wants to remove and re-add
extobjs for the same VM_BO instance. (For the same reason it wouldn't work for
evicted objects.)

Personally, after seeing the weird implications of (1), (2) and a combination of
both, I tend to go with (3). Optionally, with an opt-in for (1). The reason for
the latter is that with (3) the weirdness of (1) by its own mostly disappears.

Please let me know what you think, and, of course, other ideas than the
mentioned ones above are still welcome.

- Danilo

Here are the locking principles Daniel put together and Dave once called 
out for us to be applying when reviewing DRM code. These were prompted 
by very fragile and hard to understand locking patterns in the i915 
driver and I think the xe vm_bind locking design was made with these in 
mind, (not sure exactly who wrote what, though so can't say for sure).


https://blog.ffwll.ch/2022/07/locking-engineering.html
https://blog.ffwll.ch/2022/08/locking-hierarchy.html

At least to me, this motivates using the resv design unless we strictly 
need lower level locks that are taken in the eviction paths or userptr 
invalidation paths, but doesn't rule out spinlocks or lock dropping 
tricks where these are really necessary. But pretty much rules out RCU / 
SRCU from what I can tell.


It also calls for documenting how individual members of structs are 
protected when ever possible.


Thanks,
Thomas




Re: [PATCH 01/10] drm/mediatek: Add interface to allocate MediaTek GEM buffer.

2023-10-03 Thread Jeffrey Kardatzke
You can remove the DRIVER_RENDER flag from this patchset. That should
not be upstreamed. The IOCTLs are still needed though because of the
flag for allocating a secure surface that is in the next patch. If
that flag wasn't needed, then dumb buffer allocations could be used
instead.

Thanks,
Jeff Kardatzke


Re: [PATCH v4 8/8] drm/msm/dp: move of_dp_aux_populate_bus() to eDP probe()

2023-10-03 Thread Dmitry Baryshkov

On 03/10/2023 20:25, Kuogee Hsieh wrote:


On 9/27/2023 2:57 PM, Dmitry Baryshkov wrote:
On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  
wrote:

Currently eDP population is done at msm_dp_modeset_init() which happen
at binding time. Move eDP population to be done at display probe time
so that probe deferral cases can be handled effectively.
wait_for_hpd_asserted callback is added during drm_dp_aux_init()
to ensure eDP's HPD is up before proceeding eDP population.

Changes in v4:
-- delete duplicate initialize code to dp_aux before 
drm_dp_aux_register()
-- delete of_get_child_by_name(dev->of_node, "aux-bus") and inline 
the function

-- not initialize rc = 0

Changes in v3:
-- add done_probing callback into devm_of_dp_aux_populate_bus()

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/dp/dp_aux.c | 34 ++
  drivers/gpu/drm/msm/dp/dp_display.c | 69 
++---

  2 files changed, 60 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c 
b/drivers/gpu/drm/msm/dp/dp_aux.c

index 22eb774..425b5c5 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -480,7 +480,6 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux)

  int dp_aux_register(struct drm_dp_aux *dp_aux)
  {
-   struct dp_aux_private *aux;
 int ret;

 if (!dp_aux) {
@@ -488,12 +487,7 @@ int dp_aux_register(struct drm_dp_aux *dp_aux)
 return -EINVAL;
 }

-   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
-   aux->dp_aux.name = "dpu_dp_aux";
-   aux->dp_aux.dev = aux->dev;
-   aux->dp_aux.transfer = dp_aux_transfer;
-   ret = drm_dp_aux_register(&aux->dp_aux);
+   ret = drm_dp_aux_register(dp_aux);
 if (ret) {
 DRM_ERROR("%s: failed to register drm aux: %d\n", 
__func__,

 ret);
@@ -508,6 +502,21 @@ void dp_aux_unregister(struct drm_dp_aux *dp_aux)
 drm_dp_aux_unregister(dp_aux);
  }

+static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux,
+    unsigned long wait_us)
+{
+   int ret;
+   struct dp_aux_private *aux;
+
+   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+   pm_runtime_get_sync(aux->dev);
+   ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog);
+   pm_runtime_put_sync(aux->dev);

Ok, so here you have used put_sync instead of autosuspend. Can we have
some uniformity? (I'd prefer to see put_sync or just put everywhere)



my point is,

since display is user interface,

if there has any inputs before timer expire then there is no reason to 
execute  pm_runtime_suspend().


otherwise pm_runtime_suspend() should be executed.

Therefore I used autosuspend  at aux_transfer() an 
ddp_bridge_atomic_post_disable().


here is not related to user interface so that i use put_sysn() directly.

is my point make sense?

  or should I drop all autosuspend and replace them with put_sync()?


This was my question from the beginning: what was the reason for using 
autosuspend? Did it bring any sensible improvement in the disable & 
reenable path?








+
+   return ret;
+}
+
  struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog 
*catalog,

   bool is_edp)
  {
@@ -531,6 +540,17 @@ struct drm_dp_aux *dp_aux_get(struct device 
*dev, struct dp_catalog *catalog,

 aux->catalog = catalog;
 aux->retry_cnt = 0;

+   /*
+    * Use the drm_dp_aux_init() to use the aux adapter
+    * before registering aux with the DRM device so that
+    * msm edp panel can be detected by generic_dep_panel_probe().

eDP, AUX, generic_edp_panel_probe().


+    */
+   aux->dp_aux.name = "dpu_dp_aux";
+   aux->dp_aux.dev = dev;
+   aux->dp_aux.transfer = dp_aux_transfer;
+   aux->dp_aux.wait_hpd_asserted = dp_wait_hpd_asserted;
+   drm_dp_aux_init(&aux->dp_aux);
+
 return &aux->dp_aux;
  }

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c

index 711d262..9a2b403 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1203,6 +1203,28 @@ static const struct msm_dp_desc 
*dp_display_get_desc(struct platform_device *pde

 return NULL;
  }

+static int dp_auxbus_done_probe(struct drm_dp_aux *aux)
+{
+   int rc;
+
+   rc = component_add(aux->dev, &dp_display_comp_ops);
+   if (rc)
+   DRM_ERROR("eDP component add failed, rc=%d\n", rc);

drop.


+
+   return rc;
+}
+
+static inline int dp_display_auxbus_population(struct 
dp_display_private *dp)

It's not `population`. It is just `populate`.

Also please inline this function.



+{
+   int ret;
+
+   ret = devm_of_dp_aux_populate_bus(dp->aux, 
dp_auxbus_done_probe);

+   if (ret == -ENODEV)
+   DRM_ERROR("aux-bus not found\n");
+
+   return ret;
+}
+
  static int dp_displa

Re: [PATCH v4 7/8] drm/msm/dp: add pm_runtime_force_suspend()/resume()

2023-10-03 Thread Dmitry Baryshkov
On Tue, 3 Oct 2023 at 19:44, Kuogee Hsieh  wrote:
>
>
> On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote:
> > On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  wrote:
> >> After incorporated pm_runtime framework into eDP/DP driver, the
> > incorporating
> >
> >
> >> original dp_pm_suspend() to handle power off both DP phy and
> >> controller during suspend and dp_pm_resume() to handle power on
> >> both DP phy and controller during resume are not necessary since
> >> those function are replaced by dp_pm_runtime_suspend() and
> >> dp_pm_runtime_resume() through pm runtime framework.
> >> Therefore add pm framework provides functions,
> >> pm_runtime_force_suspend()/resume() to complete incorporating pm
> >> runtime framework into DP driver.
> >>
> >> Changes in v4:
> >> -- drop both dp_pm_prepare() and dp_pm_compete() from this change
> >> -- delete ST_SUSPENDED state
> >> -- rewording commit text to add more details regrading the purpose
> >> of this change
> >>
> >> Changes in v3:
> >> -- replace dp_pm_suspend() with pm_runtime_force_suspend()
> >> -- replace dp_pm_resume() with pm_runtime_force_resume()
> >>
> >> Signed-off-by: Kuogee Hsieh 
> >> ---
> >>   drivers/gpu/drm/msm/dp/dp_display.c | 113 
> >> ++--
> >>   1 file changed, 5 insertions(+), 108 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
> >> b/drivers/gpu/drm/msm/dp/dp_display.c
> >> index 9158a2c..711d262 100644
> >> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> >> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> >> @@ -49,7 +49,6 @@ enum {
> >>  ST_CONNECTED,
> >>  ST_DISCONNECT_PENDING,
> >>  ST_DISPLAY_OFF,
> >> -   ST_SUSPENDED,
> >>   };
> >>
> >>   enum {
> >> @@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct 
> >> dp_display_private *dp, u32 data)
> >>  drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
> >>  dp->dp_display.connector_type, state);
> >>
> >> -   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
> >> +   if (state == ST_DISPLAY_OFF) {
> >>  mutex_unlock(&dp->event_mutex);
> >>  return 0;
> >>  }
> >> @@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private 
> >> *dp, u32 data)
> >>  drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
> >>  dp->dp_display.connector_type, state);
> >>
> >> -   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
> >> +   if (state == ST_DISPLAY_OFF) {
> >>  mutex_unlock(&dp->event_mutex);
> >>  return 0;
> >>  }
> >> @@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device 
> >> *dev)
> >>  return 0;
> >>   }
> >>
> >> -static int dp_pm_resume(struct device *dev)
> >> -{
> >> -   struct platform_device *pdev = to_platform_device(dev);
> >> -   struct msm_dp *dp_display = platform_get_drvdata(pdev);
> >> -   struct dp_display_private *dp;
> >> -   int sink_count = 0;
> >> -
> >> -   dp = container_of(dp_display, struct dp_display_private, 
> >> dp_display);
> >> -
> >> -   mutex_lock(&dp->event_mutex);
> >> -
> >> -   drm_dbg_dp(dp->drm_dev,
> >> -   "Before, type=%d core_inited=%d phy_inited=%d 
> >> power_on=%d\n",
> >> -   dp->dp_display.connector_type, dp->core_initialized,
> >> -   dp->phy_initialized, dp_display->power_on);
> >> -
> >> -   /* start from disconnected state */
> >> -   dp->hpd_state = ST_DISCONNECTED;
> >> -
> >> -   /* turn on dp ctrl/phy */
> >> -   dp_display_host_init(dp);
> >> -
> >> -   if (dp_display->is_edp)
> >> -   dp_catalog_ctrl_hpd_enable(dp->catalog);
> >> -
> >> -   if (dp_catalog_link_is_connected(dp->catalog)) {
> >> -   /*
> >> -* set sink to normal operation mode -- D0
> >> -* before dpcd read
> >> -*/
> >> -   dp_display_host_phy_init(dp);
> >> -   dp_link_psm_config(dp->link, &dp->panel->link_info, false);
> >> -   sink_count = drm_dp_read_sink_count(dp->aux);
> >> -   if (sink_count < 0)
> >> -   sink_count = 0;
> >> -
> >> -   dp_display_host_phy_exit(dp);
> >> -   }
> >> -
> >> -   dp->link->sink_count = sink_count;
> >> -   /*
> >> -* can not declared display is connected unless
> >> -* HDMI cable is plugged in and sink_count of
> >> -* dongle become 1
> >> -* also only signal audio when disconnected
> >> -*/
> >> -   if (dp->link->sink_count) {
> >> -   dp->dp_display.link_ready = true;
> >> -   } else {
> >> -   dp->dp_display.link_ready = false;
> >> -   dp_display_handle_plugged_change(dp_display, false);
> >> -   }
> >> -
> >> -   drm_dbg_dp(dp->drm_dev,
> >> -   "After, type=%d sink=%d conn=%

Re: [PATCH drm-misc-next v5 4/6] drm/gpuvm: track/lock/validate external/evicted objects

2023-10-03 Thread Thomas Hellström
Hi, Danilo

On Tue, 2023-10-03 at 18:55 +0200, Danilo Krummrich wrote:
> It seems like we're mostly aligned on this series, except for the key
> controversy we're discussing for a few versions now: locking of the
> internal
> lists. Hence, let's just re-iterate the options we have to get this
> out of the
> way.
> 
> (1) The spinlock dance. This basically works for every use case,
> updating the VA
>     space from the IOCTL, from the fence signaling path or anywhere
> else.
>     However, it has the downside of requiring spin_lock() /
> spin_unlock() for
>     *each* list element when locking all external objects and
> validating all
>     evicted objects. Typically, the amount of extobjs and evicted
> objects
>     shouldn't be excessive, but there might be exceptions, e.g. Xe.
> 
> (2) The dma-resv lock dance. This is convinient for drivers updating
> the VA
>     space from a VM_BIND ioctl() and is especially efficient if such
> drivers
>     have a huge amount of external and/or evicted objects to manage.
> However,
>     the downsides are that it requires a few tricks in drivers
> updating the VA
>     space from the fence signaling path (e.g. job_run()). Design
> wise, I'm still
>     skeptical that it is a good idea to protect internal data
> structures with
>     external locks in a way that it's not clear to callers that a
> certain
>     function would access one of those resources and hence needs
> protection.
>     E.g. it is counter intuitive that drm_gpuvm_bo_put() would
> require both the
>     dma-resv lock of the corresponding object and the VM's dma-resv
> lock held.
>     (Additionally, there were some concerns from amdgpu regarding
> flexibility in
>     terms of using GPUVM for non-VM_BIND uAPIs and compute, however,
> AFAICS
>     those discussions did not complete and to me it's still unclear
> why it
>     wouldn't work.)
> 
> (3) Simply use an internal mutex per list. This adds a tiny (IMHO
> negligible)
>     overhead for drivers updating the VA space from a VM_BIND
> ioctl(), namely
>     a *single* mutex_lock()/mutex_unlock() when locking all external
> objects
>     and validating all evicted objects. And it still requires some
> tricks for
>     drivers updating the VA space from the fence signaling path.
> However, it's
>     as simple as it can be and hence way less error prone as well as
>     self-contained and hence easy to use. Additionally, it's flexible
> in a way
>     that we don't have any expections on drivers to already hold
> certain locks
>     that the driver in some situation might not be able to acquire in
> the first
>     place.

Such an overhead is fully OK IMO, But didn't we conclude at some point
that using a mutex in this way isn't possible due to the fact that
validate() needs to be able to lock dma_resv, and then we have
dma_resv()->mutex->dma_resv()?


> 
> (4) Arbitrary combinations of the above. For instance, the current V5
> implements
>     both (1) and (2) (as either one or the other). But also (1) and
> (3) (as in
>     (1) additionally to (3)) would be an option, where a driver could
> opt-in for
>     the spinlock dance in case it updates the VA space from the fence
> signaling
>     path.
> 
> I also considered a few other options as well, however, they don't
> seem to be
> flexible enough. For instance, as by now we could use SRCU for the
> external
> object list. However, this falls apart once a driver wants to remove
> and re-add
> extobjs for the same VM_BO instance. (For the same reason it wouldn't
> work for
> evicted objects.)
> 
> Personally, after seeing the weird implications of (1), (2) and a
> combination of
> both, I tend to go with (3). Optionally, with an opt-in for (1). The
> reason for
> the latter is that with (3) the weirdness of (1) by its own mostly
> disappears.
> 
> Please let me know what you think, and, of course, other ideas than
> the
> mentioned ones above are still welcome.

Personally, after converting xe to version 5, I think it's pretty
convenient for the driver, (although had to add the evict trick), so I
think I'd vote for this, even if not currently using the opt-in for
(1).

/Thomas


> 
> - Danilo
> 
> On Tue, Oct 03, 2023 at 04:21:43PM +0200, Boris Brezillon wrote:
> > On Tue, 03 Oct 2023 14:25:56 +0200
> > Thomas Hellström  wrote:
> > 
> > > > > > +/**
> > > > > > + * get_next_vm_bo_from_list() - get the next vm_bo element
> > > > > > + * @__gpuvm: The GPU VM
> > > > > > + * @__list_name: The name of the list we're iterating on
> > > > > > + * @__local_list: A pointer to the local list used to
> > > > > > store
> > > > > > already iterated items
> > > > > > + * @__prev_vm_bo: The previous element we got from
> > > > > > drm_gpuvm_get_next_cached_vm_bo()
> > > > > > + *
> > > > > > + * This helper is here to provide lockless list iteration.
> > > > > > Lockless as in, the
> > > > > > + * iterator releases the lock immediately after picking
> > > > > > the
> > > > > > first element from
> > > > > > + * t

Re: [PATCH v4 8/8] drm/msm/dp: move of_dp_aux_populate_bus() to eDP probe()

2023-10-03 Thread Kuogee Hsieh



On 9/27/2023 2:57 PM, Dmitry Baryshkov wrote:

On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  wrote:

Currently eDP population is done at msm_dp_modeset_init() which happen
at binding time. Move eDP population to be done at display probe time
so that probe deferral cases can be handled effectively.
wait_for_hpd_asserted callback is added during drm_dp_aux_init()
to ensure eDP's HPD is up before proceeding eDP population.

Changes in v4:
-- delete duplicate initialize code to dp_aux before drm_dp_aux_register()
-- delete of_get_child_by_name(dev->of_node, "aux-bus") and inline the function
-- not initialize rc = 0

Changes in v3:
-- add done_probing callback into devm_of_dp_aux_populate_bus()

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/dp/dp_aux.c | 34 ++
  drivers/gpu/drm/msm/dp/dp_display.c | 69 ++---
  2 files changed, 60 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 22eb774..425b5c5 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -480,7 +480,6 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux)

  int dp_aux_register(struct drm_dp_aux *dp_aux)
  {
-   struct dp_aux_private *aux;
 int ret;

 if (!dp_aux) {
@@ -488,12 +487,7 @@ int dp_aux_register(struct drm_dp_aux *dp_aux)
 return -EINVAL;
 }

-   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
-   aux->dp_aux.name = "dpu_dp_aux";
-   aux->dp_aux.dev = aux->dev;
-   aux->dp_aux.transfer = dp_aux_transfer;
-   ret = drm_dp_aux_register(&aux->dp_aux);
+   ret = drm_dp_aux_register(dp_aux);
 if (ret) {
 DRM_ERROR("%s: failed to register drm aux: %d\n", __func__,
 ret);
@@ -508,6 +502,21 @@ void dp_aux_unregister(struct drm_dp_aux *dp_aux)
 drm_dp_aux_unregister(dp_aux);
  }

+static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux,
+unsigned long wait_us)
+{
+   int ret;
+   struct dp_aux_private *aux;
+
+   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+   pm_runtime_get_sync(aux->dev);
+   ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog);
+   pm_runtime_put_sync(aux->dev);

Ok, so here you have used put_sync instead of autosuspend. Can we have
some uniformity? (I'd prefer to see put_sync or just put everywhere)



my point is,

since display is user interface,

if there has any inputs before timer expire then there is no reason to 
execute  pm_runtime_suspend().


otherwise pm_runtime_suspend() should be executed.

Therefore I used autosuspend  at aux_transfer() an 
ddp_bridge_atomic_post_disable().


here is not related to user interface so that i use put_sysn() directly.

is my point make sense?

 or should I drop all autosuspend and replace them with put_sync()?





+
+   return ret;
+}
+
  struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
   bool is_edp)
  {
@@ -531,6 +540,17 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, struct 
dp_catalog *catalog,
 aux->catalog = catalog;
 aux->retry_cnt = 0;

+   /*
+* Use the drm_dp_aux_init() to use the aux adapter
+* before registering aux with the DRM device so that
+* msm edp panel can be detected by generic_dep_panel_probe().

eDP, AUX, generic_edp_panel_probe().


+*/
+   aux->dp_aux.name = "dpu_dp_aux";
+   aux->dp_aux.dev = dev;
+   aux->dp_aux.transfer = dp_aux_transfer;
+   aux->dp_aux.wait_hpd_asserted = dp_wait_hpd_asserted;
+   drm_dp_aux_init(&aux->dp_aux);
+
 return &aux->dp_aux;
  }

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 711d262..9a2b403 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1203,6 +1203,28 @@ static const struct msm_dp_desc 
*dp_display_get_desc(struct platform_device *pde
 return NULL;
  }

+static int dp_auxbus_done_probe(struct drm_dp_aux *aux)
+{
+   int rc;
+
+   rc = component_add(aux->dev, &dp_display_comp_ops);
+   if (rc)
+   DRM_ERROR("eDP component add failed, rc=%d\n", rc);

drop.


+
+   return rc;
+}
+
+static inline int dp_display_auxbus_population(struct dp_display_private *dp)

It's not `population`. It is just `populate`.

Also please inline this function.



+{
+   int ret;
+
+   ret = devm_of_dp_aux_populate_bus(dp->aux, dp_auxbus_done_probe);
+   if (ret == -ENODEV)
+   DRM_ERROR("aux-bus not found\n");
+
+   return ret;
+}
+
  static int dp_display_probe(struct platform_device *pdev)
  {
 int rc = 0;
@@ -1271,10 +1293,16 @@ static int dp_display_probe(struct platform_device 
*pdev)
 if (rc)
 return rc;

-   rc = component_add(&

Re: [PATCH v4 8/8] drm/msm/dp: move of_dp_aux_populate_bus() to eDP probe()

2023-10-03 Thread Dmitry Baryshkov
On Tue, 3 Oct 2023 at 20:16, Kuogee Hsieh  wrote:
>
>
> On 9/27/2023 2:57 PM, Dmitry Baryshkov wrote:
> > On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  wrote:
> >> Currently eDP population is done at msm_dp_modeset_init() which happen
> >> at binding time. Move eDP population to be done at display probe time
> >> so that probe deferral cases can be handled effectively.
> >> wait_for_hpd_asserted callback is added during drm_dp_aux_init()
> >> to ensure eDP's HPD is up before proceeding eDP population.
> >>
> >> Changes in v4:
> >> -- delete duplicate initialize code to dp_aux before drm_dp_aux_register()
> >> -- delete of_get_child_by_name(dev->of_node, "aux-bus") and inline the 
> >> function
> >> -- not initialize rc = 0
> >>
> >> Changes in v3:
> >> -- add done_probing callback into devm_of_dp_aux_populate_bus()
> >>
> >> Signed-off-by: Kuogee Hsieh 
> >> ---
> >>   drivers/gpu/drm/msm/dp/dp_aux.c | 34 ++
> >>   drivers/gpu/drm/msm/dp/dp_display.c | 69 
> >> ++---
> >>   2 files changed, 60 insertions(+), 43 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c 
> >> b/drivers/gpu/drm/msm/dp/dp_aux.c
> >> index 22eb774..425b5c5 100644
> >> --- a/drivers/gpu/drm/msm/dp/dp_aux.c
> >> +++ b/drivers/gpu/drm/msm/dp/dp_aux.c
> >> @@ -480,7 +480,6 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux)
> >>
> >>   int dp_aux_register(struct drm_dp_aux *dp_aux)
> >>   {
> >> -   struct dp_aux_private *aux;
> >>  int ret;
> >>
> >>  if (!dp_aux) {
> >> @@ -488,12 +487,7 @@ int dp_aux_register(struct drm_dp_aux *dp_aux)
> >>  return -EINVAL;
> >>  }
> >>
> >> -   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
> >> -
> >> -   aux->dp_aux.name = "dpu_dp_aux";
> >> -   aux->dp_aux.dev = aux->dev;
> >> -   aux->dp_aux.transfer = dp_aux_transfer;
> >> -   ret = drm_dp_aux_register(&aux->dp_aux);
> >> +   ret = drm_dp_aux_register(dp_aux);
> >>  if (ret) {
> >>  DRM_ERROR("%s: failed to register drm aux: %d\n", 
> >> __func__,
> >>  ret);
> >> @@ -508,6 +502,21 @@ void dp_aux_unregister(struct drm_dp_aux *dp_aux)
> >>  drm_dp_aux_unregister(dp_aux);
> >>   }
> >>
> >> +static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux,
> >> +unsigned long wait_us)
> >> +{
> >> +   int ret;
> >> +   struct dp_aux_private *aux;
> >> +
> >> +   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
> >> +
> >> +   pm_runtime_get_sync(aux->dev);
> >> +   ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog);
> >> +   pm_runtime_put_sync(aux->dev);
> > Ok, so here you have used put_sync instead of autosuspend. Can we have
> > some uniformity? (I'd prefer to see put_sync or just put everywhere)
> >
> >> +
> >> +   return ret;
> >> +}
> >> +
> >>   struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog 
> >> *catalog,
> >>bool is_edp)
> >>   {
> >> @@ -531,6 +540,17 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, 
> >> struct dp_catalog *catalog,
> >>  aux->catalog = catalog;
> >>  aux->retry_cnt = 0;
> >>
> >> +   /*
> >> +* Use the drm_dp_aux_init() to use the aux adapter
> >> +* before registering aux with the DRM device so that
> >> +* msm edp panel can be detected by generic_dep_panel_probe().
> > eDP, AUX, generic_edp_panel_probe().
> >
> >> +*/
> >> +   aux->dp_aux.name = "dpu_dp_aux";
> >> +   aux->dp_aux.dev = dev;
> >> +   aux->dp_aux.transfer = dp_aux_transfer;
> >> +   aux->dp_aux.wait_hpd_asserted = dp_wait_hpd_asserted;
> >> +   drm_dp_aux_init(&aux->dp_aux);
> >> +
> >>  return &aux->dp_aux;
> >>   }
> >>
> >> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
> >> b/drivers/gpu/drm/msm/dp/dp_display.c
> >> index 711d262..9a2b403 100644
> >> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> >> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> >> @@ -1203,6 +1203,28 @@ static const struct msm_dp_desc 
> >> *dp_display_get_desc(struct platform_device *pde
> >>  return NULL;
> >>   }
> >>
> >> +static int dp_auxbus_done_probe(struct drm_dp_aux *aux)
> >> +{
> >> +   int rc;
> >> +
> >> +   rc = component_add(aux->dev, &dp_display_comp_ops);
> >> +   if (rc)
> >> +   DRM_ERROR("eDP component add failed, rc=%d\n", rc);
> > drop.
> are you mean dropping this line?
> >> +
> >> +   return rc;
> >> +}
> >> +
> >> +static inline int dp_display_auxbus_population(struct dp_display_private 
> >> *dp)
> > It's not `population`. It is just `populate`.
> >
> > Also please inline this function.
> Are you means moving this function to header file?

No. I mean inlining this function.

-- 
With best wishes
Dmitry


Re: [PATCH v4 8/8] drm/msm/dp: move of_dp_aux_populate_bus() to eDP probe()

2023-10-03 Thread Kuogee Hsieh



On 9/27/2023 2:57 PM, Dmitry Baryshkov wrote:

On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  wrote:

Currently eDP population is done at msm_dp_modeset_init() which happen
at binding time. Move eDP population to be done at display probe time
so that probe deferral cases can be handled effectively.
wait_for_hpd_asserted callback is added during drm_dp_aux_init()
to ensure eDP's HPD is up before proceeding eDP population.

Changes in v4:
-- delete duplicate initialize code to dp_aux before drm_dp_aux_register()
-- delete of_get_child_by_name(dev->of_node, "aux-bus") and inline the function
-- not initialize rc = 0

Changes in v3:
-- add done_probing callback into devm_of_dp_aux_populate_bus()

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/dp/dp_aux.c | 34 ++
  drivers/gpu/drm/msm/dp/dp_display.c | 69 ++---
  2 files changed, 60 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 22eb774..425b5c5 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -480,7 +480,6 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux)

  int dp_aux_register(struct drm_dp_aux *dp_aux)
  {
-   struct dp_aux_private *aux;
 int ret;

 if (!dp_aux) {
@@ -488,12 +487,7 @@ int dp_aux_register(struct drm_dp_aux *dp_aux)
 return -EINVAL;
 }

-   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
-   aux->dp_aux.name = "dpu_dp_aux";
-   aux->dp_aux.dev = aux->dev;
-   aux->dp_aux.transfer = dp_aux_transfer;
-   ret = drm_dp_aux_register(&aux->dp_aux);
+   ret = drm_dp_aux_register(dp_aux);
 if (ret) {
 DRM_ERROR("%s: failed to register drm aux: %d\n", __func__,
 ret);
@@ -508,6 +502,21 @@ void dp_aux_unregister(struct drm_dp_aux *dp_aux)
 drm_dp_aux_unregister(dp_aux);
  }

+static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux,
+unsigned long wait_us)
+{
+   int ret;
+   struct dp_aux_private *aux;
+
+   aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+   pm_runtime_get_sync(aux->dev);
+   ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog);
+   pm_runtime_put_sync(aux->dev);

Ok, so here you have used put_sync instead of autosuspend. Can we have
some uniformity? (I'd prefer to see put_sync or just put everywhere)


+
+   return ret;
+}
+
  struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
   bool is_edp)
  {
@@ -531,6 +540,17 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, struct 
dp_catalog *catalog,
 aux->catalog = catalog;
 aux->retry_cnt = 0;

+   /*
+* Use the drm_dp_aux_init() to use the aux adapter
+* before registering aux with the DRM device so that
+* msm edp panel can be detected by generic_dep_panel_probe().

eDP, AUX, generic_edp_panel_probe().


+*/
+   aux->dp_aux.name = "dpu_dp_aux";
+   aux->dp_aux.dev = dev;
+   aux->dp_aux.transfer = dp_aux_transfer;
+   aux->dp_aux.wait_hpd_asserted = dp_wait_hpd_asserted;
+   drm_dp_aux_init(&aux->dp_aux);
+
 return &aux->dp_aux;
  }

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 711d262..9a2b403 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1203,6 +1203,28 @@ static const struct msm_dp_desc 
*dp_display_get_desc(struct platform_device *pde
 return NULL;
  }

+static int dp_auxbus_done_probe(struct drm_dp_aux *aux)
+{
+   int rc;
+
+   rc = component_add(aux->dev, &dp_display_comp_ops);
+   if (rc)
+   DRM_ERROR("eDP component add failed, rc=%d\n", rc);

drop.

are you mean dropping this line?

+
+   return rc;
+}
+
+static inline int dp_display_auxbus_population(struct dp_display_private *dp)

It's not `population`. It is just `populate`.

Also please inline this function.

Are you means moving this function to header file?




+{
+   int ret;
+
+   ret = devm_of_dp_aux_populate_bus(dp->aux, dp_auxbus_done_probe);
+   if (ret == -ENODEV)
+   DRM_ERROR("aux-bus not found\n");
+
+   return ret;
+}
+
  static int dp_display_probe(struct platform_device *pdev)
  {
 int rc = 0;
@@ -1271,10 +1293,16 @@ static int dp_display_probe(struct platform_device 
*pdev)
 if (rc)
 return rc;

-   rc = component_add(&pdev->dev, &dp_display_comp_ops);
-   if (rc) {
-   DRM_ERROR("component add failed, rc=%d\n", rc);
-   dp_display_deinit_sub_modules(dp);
+   if (dp->dp_display.is_edp) {
+   rc = dp_display_auxbus_population(dp);
+   if (rc)
+   DRM_ERROR("eDP auxbus population failed, rc=%d\n", rc);
+   } else {

Re: [PATCH 2/2] drm: add documentation for drm_buddy_test kUnit test

2023-10-03 Thread Jonathan Corbet
One other little thing...

Mauro Carvalho Chehab  writes:

> As an example for the new documentation tool, add a documentation
> for drm_buddy_test.
>
> I opted to place this on a completely different directory, in order
> to make easier to test the feature with:
>
>   $ make SPHINXDIRS="tests" htmldocs
>
> Acked-by: Christian König 
> Reviewed-by: Arunpravin Paneer Selvam 
> Signed-off-by: Mauro Carvalho Chehab 
> ---
>  Documentation/index.rst|  2 +-
>  Documentation/tests/index.rst  |  6 ++
>  Documentation/tests/kunit.rst  |  5 +
>  drivers/gpu/drm/tests/drm_buddy_test.c | 12 
>  4 files changed, 24 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/tests/index.rst
>  create mode 100644 Documentation/tests/kunit.rst
>
> diff --git a/Documentation/index.rst b/Documentation/index.rst
> index 9dfdc826618c..80a6ce14a61a 100644
> --- a/Documentation/index.rst
> +++ b/Documentation/index.rst
> @@ -60,7 +60,7 @@ Various other manuals with useful information for all 
> kernel developers.
> fault-injection/index
> livepatch/index
> rust/index
> -
> +   test/index

Since you called the directory "tests", this generates a couple of
warnings in the htmldocs build.

(but, again, I think it should be dev-tools/tests, and perhaps
referenced from the selftest docs already there)

jon


Re: [PATCH 0/2] Add support for inlined documentation for kunit and kselftests

2023-10-03 Thread Jonathan Corbet
Mauro Carvalho Chehab  writes:

> This is a follow-up of the discussions taken here:
>
>
> https://lore.kernel.org/linux-doc/20230704132812.02ba97ba@maurocar-mobl2/T/#t
>
> I sent a previous version as RFC. This is basically what we had there, with 
> some
> improvements at test_list.py.
>
> It adds a new extension that allows documenting tests using the same tool 
> we're
> using for DRM unit tests at IGT GPU tools: 
> https://gitlab.freedesktop.org/drm/igt-gpu-tools.
>
> While kernel-doc has provided documentation for in-lined functions/struct 
> comments,
> it was not meant to document tests.
>
> Tests need to be grouped by the test functions. It should also be possible to 
> produce
> other outputs from the documentation, to integrate it with test suites. For 
> instance, 
> Internally at Intel, we use the comments to generate DOT files hierarchically 
> grouped
> per feature categories.
>
> This is meant to be an initial series to start documenting kunit.

I've played with this a bit...a couple of quick impressions:

- That's quite a chunk of Python code to be adding.  I've not yet had
  the chance to read it through properly, will hopefully be able to do
  so soon.  A bit more commenting would not have gone amiss here...

- I kind of think that this should go under dev-tools rather than being
  a new top-level directory.  Is there a reason not to put it there?

Thanks,

jon


Re: [PATCH drm-misc-next v5 4/6] drm/gpuvm: track/lock/validate external/evicted objects

2023-10-03 Thread Danilo Krummrich
It seems like we're mostly aligned on this series, except for the key
controversy we're discussing for a few versions now: locking of the internal
lists. Hence, let's just re-iterate the options we have to get this out of the
way.

(1) The spinlock dance. This basically works for every use case, updating the VA
space from the IOCTL, from the fence signaling path or anywhere else.
However, it has the downside of requiring spin_lock() / spin_unlock() for
*each* list element when locking all external objects and validating all
evicted objects. Typically, the amount of extobjs and evicted objects
shouldn't be excessive, but there might be exceptions, e.g. Xe.

(2) The dma-resv lock dance. This is convinient for drivers updating the VA
space from a VM_BIND ioctl() and is especially efficient if such drivers
have a huge amount of external and/or evicted objects to manage. However,
the downsides are that it requires a few tricks in drivers updating the VA
space from the fence signaling path (e.g. job_run()). Design wise, I'm still
skeptical that it is a good idea to protect internal data structures with
external locks in a way that it's not clear to callers that a certain
function would access one of those resources and hence needs protection.
E.g. it is counter intuitive that drm_gpuvm_bo_put() would require both the
dma-resv lock of the corresponding object and the VM's dma-resv lock held.
(Additionally, there were some concerns from amdgpu regarding flexibility in
terms of using GPUVM for non-VM_BIND uAPIs and compute, however, AFAICS
those discussions did not complete and to me it's still unclear why it
wouldn't work.)

(3) Simply use an internal mutex per list. This adds a tiny (IMHO negligible)
overhead for drivers updating the VA space from a VM_BIND ioctl(), namely
a *single* mutex_lock()/mutex_unlock() when locking all external objects
and validating all evicted objects. And it still requires some tricks for
drivers updating the VA space from the fence signaling path. However, it's
as simple as it can be and hence way less error prone as well as
self-contained and hence easy to use. Additionally, it's flexible in a way
that we don't have any expections on drivers to already hold certain locks
that the driver in some situation might not be able to acquire in the first
place.

(4) Arbitrary combinations of the above. For instance, the current V5 implements
both (1) and (2) (as either one or the other). But also (1) and (3) (as in
(1) additionally to (3)) would be an option, where a driver could opt-in for
the spinlock dance in case it updates the VA space from the fence signaling
path.

I also considered a few other options as well, however, they don't seem to be
flexible enough. For instance, as by now we could use SRCU for the external
object list. However, this falls apart once a driver wants to remove and re-add
extobjs for the same VM_BO instance. (For the same reason it wouldn't work for
evicted objects.)

Personally, after seeing the weird implications of (1), (2) and a combination of
both, I tend to go with (3). Optionally, with an opt-in for (1). The reason for
the latter is that with (3) the weirdness of (1) by its own mostly disappears.

Please let me know what you think, and, of course, other ideas than the
mentioned ones above are still welcome.

- Danilo

On Tue, Oct 03, 2023 at 04:21:43PM +0200, Boris Brezillon wrote:
> On Tue, 03 Oct 2023 14:25:56 +0200
> Thomas Hellström  wrote:
> 
> > > > > +/**
> > > > > + * get_next_vm_bo_from_list() - get the next vm_bo element
> > > > > + * @__gpuvm: The GPU VM
> > > > > + * @__list_name: The name of the list we're iterating on
> > > > > + * @__local_list: A pointer to the local list used to store
> > > > > already iterated items
> > > > > + * @__prev_vm_bo: The previous element we got from
> > > > > drm_gpuvm_get_next_cached_vm_bo()
> > > > > + *
> > > > > + * This helper is here to provide lockless list iteration.
> > > > > Lockless as in, the
> > > > > + * iterator releases the lock immediately after picking the
> > > > > first element from
> > > > > + * the list, so list insertion deletion can happen concurrently.
> > > > > + *
> > > > > + * Elements popped from the original list are kept in a local
> > > > > list, so removal
> > > > > + * and is_empty checks can still happen while we're iterating
> > > > > the list.
> > > > > + */
> > > > > +#define get_next_vm_bo_from_list(__gpuvm, __list_name,
> > > > > __local_list, __prev_vm_bo) \
> > > > > +   ({   
> > > > >    \
> > > > > +   struct drm_gpuvm_bo *__vm_bo =
> > > > > NULL;\
> > > > > +
> > > > >    \
> > > > > +   drm_gpuvm_bo_put(__prev_vm_bo);

Re: [PATCH v4 7/8] drm/msm/dp: add pm_runtime_force_suspend()/resume()

2023-10-03 Thread Kuogee Hsieh



On 9/27/2023 3:00 PM, Dmitry Baryshkov wrote:

On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  wrote:

After incorporated pm_runtime framework into eDP/DP driver, the

incorporating



original dp_pm_suspend() to handle power off both DP phy and
controller during suspend and dp_pm_resume() to handle power on
both DP phy and controller during resume are not necessary since
those function are replaced by dp_pm_runtime_suspend() and
dp_pm_runtime_resume() through pm runtime framework.
Therefore add pm framework provides functions,
pm_runtime_force_suspend()/resume() to complete incorporating pm
runtime framework into DP driver.

Changes in v4:
-- drop both dp_pm_prepare() and dp_pm_compete() from this change
-- delete ST_SUSPENDED state
-- rewording commit text to add more details regrading the purpose
of this change

Changes in v3:
-- replace dp_pm_suspend() with pm_runtime_force_suspend()
-- replace dp_pm_resume() with pm_runtime_force_resume()

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/dp/dp_display.c | 113 ++--
  1 file changed, 5 insertions(+), 108 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 9158a2c..711d262 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -49,7 +49,6 @@ enum {
 ST_CONNECTED,
 ST_DISCONNECT_PENDING,
 ST_DISPLAY_OFF,
-   ST_SUSPENDED,
  };

  enum {
@@ -560,7 +559,7 @@ static int dp_hpd_plug_handle(struct dp_display_private 
*dp, u32 data)
 drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
 dp->dp_display.connector_type, state);

-   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
+   if (state == ST_DISPLAY_OFF) {
 mutex_unlock(&dp->event_mutex);
 return 0;
 }
@@ -674,7 +673,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, 
u32 data)
 drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
 dp->dp_display.connector_type, state);

-   if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
+   if (state == ST_DISPLAY_OFF) {
 mutex_unlock(&dp->event_mutex);
 return 0;
 }
@@ -1321,110 +1320,10 @@ static int dp_pm_runtime_resume(struct device *dev)
 return 0;
  }

-static int dp_pm_resume(struct device *dev)
-{
-   struct platform_device *pdev = to_platform_device(dev);
-   struct msm_dp *dp_display = platform_get_drvdata(pdev);
-   struct dp_display_private *dp;
-   int sink_count = 0;
-
-   dp = container_of(dp_display, struct dp_display_private, dp_display);
-
-   mutex_lock(&dp->event_mutex);
-
-   drm_dbg_dp(dp->drm_dev,
-   "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n",
-   dp->dp_display.connector_type, dp->core_initialized,
-   dp->phy_initialized, dp_display->power_on);
-
-   /* start from disconnected state */
-   dp->hpd_state = ST_DISCONNECTED;
-
-   /* turn on dp ctrl/phy */
-   dp_display_host_init(dp);
-
-   if (dp_display->is_edp)
-   dp_catalog_ctrl_hpd_enable(dp->catalog);
-
-   if (dp_catalog_link_is_connected(dp->catalog)) {
-   /*
-* set sink to normal operation mode -- D0
-* before dpcd read
-*/
-   dp_display_host_phy_init(dp);
-   dp_link_psm_config(dp->link, &dp->panel->link_info, false);
-   sink_count = drm_dp_read_sink_count(dp->aux);
-   if (sink_count < 0)
-   sink_count = 0;
-
-   dp_display_host_phy_exit(dp);
-   }
-
-   dp->link->sink_count = sink_count;
-   /*
-* can not declared display is connected unless
-* HDMI cable is plugged in and sink_count of
-* dongle become 1
-* also only signal audio when disconnected
-*/
-   if (dp->link->sink_count) {
-   dp->dp_display.link_ready = true;
-   } else {
-   dp->dp_display.link_ready = false;
-   dp_display_handle_plugged_change(dp_display, false);
-   }
-
-   drm_dbg_dp(dp->drm_dev,
-   "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d 
power=%d\n",
-   dp->dp_display.connector_type, dp->link->sink_count,
-   dp->dp_display.link_ready, dp->core_initialized,
-   dp->phy_initialized, dp_display->power_on);
-
-   mutex_unlock(&dp->event_mutex);
-
-   return 0;
-}
-
-static int dp_pm_suspend(struct device *dev)
-{
-   struct platform_device *pdev = to_platform_device(dev);
-   struct msm_dp *dp_display = platform_get_drvdata(pdev);
-   struct dp_display_private *dp;
-
-   dp = container_of(dp_display, struct dp_display_private, dp_display);
-
-   mutex_lock(&dp->event_mutex);
-
-   drm_dbg_dp(dp->d

[PATCH V4 1/2] dt-bindings: display: newvision, nv3051d: Add Anbernic 351V

2023-10-03 Thread Chris Morgan
From: Chris Morgan 

Document the Anbernic RG351V panel, which is identical to the panel
used in their 353 series except for in inclusion of an additional DSI
format flag.

Signed-off-by: Chris Morgan 
Acked-by: Conor Dooley 
---
 .../devicetree/bindings/display/panel/newvision,nv3051d.yaml | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml 
b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml
index 116c1b6030a2..cce775a87f87 100644
--- a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml
+++ b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml
@@ -7,9 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: NewVision NV3051D based LCD panel
 
 description: |
-  The NewVision NV3051D is a driver chip used to drive DSI panels. For now,
-  this driver only supports the 640x480 panels found in the Anbernic RG353
-  based devices.
+  The NewVision NV3051D is a driver chip used to drive DSI panels.
 
 maintainers:
   - Chris Morgan 
@@ -21,6 +19,7 @@ properties:
   compatible:
 items:
   - enum:
+  - anbernic,rg351v-panel
   - anbernic,rg353p-panel
   - anbernic,rg353v-panel
   - const: newvision,nv3051d
-- 
2.34.1



[PATCH V4 0/2] Support Anbernic RG351V Panel

2023-10-03 Thread Chris Morgan
From: Chris Morgan 

Add support for the Anbernic RG351V panel. This panel is mostly
identical to the one used in the 353 series, except it has a different
panel ID when queried (0x4000 for the 351V, 0x3052 for the 353 panel)
and will not work without the inclusion of the
MIPI_DSI_CLOCK_NON_CONTINUOUS flag.

Updates from V3:
 - Removed need for defined variable in probe function.

Updates from V2:
 - Modified the driver so that we only apply the
   MIPI_DSI_CLOCK_NON_CONTINUOUS flag when the compatible matches
   a panel (the 351v) that needs it.
 - Updated the binding documentation to be consistent with existing
   panels.

Updates from V1:
 - Revised text in devicetree documentation to remove references to
   specific hardware.


Chris Morgan (2):
  dt-bindings: display: newvision,nv3051d: Add Anbernic  351V
  drm/panel: nv3051d: Add Support for Anbernic 351V

 .../bindings/display/panel/newvision,nv3051d.yaml  | 5 ++---
 drivers/gpu/drm/panel/panel-newvision-nv3051d.c| 7 +++
 2 files changed, 9 insertions(+), 3 deletions(-)

-- 
2.34.1



[PATCH V4 2/2] drm/panel: nv3051d: Add Support for Anbernic 351V

2023-10-03 Thread Chris Morgan
From: Chris Morgan 

Add support for the Anbernic 351V. Just like the 353 series the
underlying vendor is unknown/unmarked (at least not visible in a
non-destructive manner). The panel had slightly different init
sequences and timings in the BSP kernel, but works fine with the
same ones used in the existing driver. The panel will not work without
the inclusion of the MIPI_DSI_CLOCK_NON_CONTINUOUS flag, and this flag
prevents the 353 series from working correctly, so a new compatible
string is added.

Tested colors and timings using modetest and all seem to work identical
to the 353 otherwise.

Signed-off-by: Chris Morgan 
---
 drivers/gpu/drm/panel/panel-newvision-nv3051d.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c 
b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c
index ad98dd9322b4..79de6c886292 100644
--- a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c
+++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c
@@ -388,6 +388,13 @@ static int panel_nv3051d_probe(struct mipi_dsi_device *dsi)
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
  MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
 
+   /*
+* The panel in the RG351V is identical to the 353P, except it
+* requires MIPI_DSI_CLOCK_NON_CONTINUOUS to operate correctly.
+*/
+   if (of_device_is_compatible(dev->of_node, "anbernic,rg351v-panel"))
+   dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
drm_panel_init(&ctx->panel, &dsi->dev, &panel_nv3051d_funcs,
   DRM_MODE_CONNECTOR_DSI);
 
-- 
2.34.1



Re: [PATCH v3 09/32] drm/amd/display: add plane 3D LUT driver-specific properties

2023-10-03 Thread Melissa Wen
On 09/27, Harry Wentland wrote:
> 
> 
> On 2023-09-25 15:49, Melissa Wen wrote:
> > Add 3D LUT property for plane color transformations using a 3D lookup
> > table. 3D LUT allows for highly accurate and complex color
> > transformations and is suitable to adjust the balance between color
> > channels. It's also more complex to manage and require more
> > computational resources. Since a 3D LUT has a limited number of entries
> > in each dimension we want to use them in an optimal fashion. This means
> > using the 3D LUT in a colorspace that is optimized for human vision,
> > such as sRGB, PQ, or another non-linear space. Therefore, userpace may
> > need one 1D LUT (shaper) before it to delinearize content and another 1D
> > LUT after 3D LUT (blend) to linearize content again for blending. The
> > next patches add these 1D LUTs to the plane color mgmt pipeline.
> > 
> > v3:
> > - improve commit message about 3D LUT
> > - describe the 3D LUT entries and size (Harry)
> > 
> > Signed-off-by: Melissa Wen 
> > ---
> >  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 17 ++
> >  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  9 
> >  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 14 +++
> >  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 23 +++
> >  4 files changed, 63 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
> > b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > index 66bae0eed80c..1b5f25989f7f 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > @@ -363,6 +363,23 @@ struct amdgpu_mode_info {
> >  * @plane_hdr_mult_property:
> >  */
> > struct drm_property *plane_hdr_mult_property;
> > +   /**
> > +* @plane_lut3d_property: Plane property for color transformation using
> > +* a 3D LUT (pre-blending), a three-dimensional array where each
> > +* element is an RGB triplet. Each dimension has a size of the cubed
> > +* root of lut3d_size. The array contains samples from the approximated
> > +* function. On AMD, values between samples are estimated by
> > +* tetrahedral interpolation. The array is accessed with three indices,
> > +* one for each input dimension (color channel), blue being the
> > +* outermost dimension, red the innermost.
> > +*/
> > +   struct drm_property *plane_lut3d_property;
> > +   /**
> > +* @plane_degamma_lut_size_property: Plane property to define the max
> > +* size of 3D LUT as supported by the driver (read-only). The max size
> > +* is the max size of one dimension cubed.
> > +*/
> 
> I've been thinking about this some more and don't particulary
> like that we're reporting the size as the dimension cubed, e.g.,
> 4913 (17^3) instead of 17. This works for an AMD private API
> (and I'm okay with keeping it as-is if changing it is a lot of
> effort at this point) but in a generic API it would be a source
> of bugs or undefined behavior if a driver mistakenly reported
> a size that doesn't have an even cubed root.
> 
> Reporting the size of a single dimension (e.g., 17 in the case
> of the current AMD driver) would be clearer.
> 
> Could we still change that?

I understand your points, makes sense. I'll send a version that fits the
single-dimension size.

Thanks for the suggestion.

Melissa

> 
> Harry
> 
> 
> > +   struct drm_property *plane_lut3d_size_property;
> >  };
> >  
> >  #define AMDGPU_MAX_BL_LEVEL 0xFF
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > index 7ca594c7dfbe..dbd36fc24eca 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > @@ -773,6 +773,11 @@ struct dm_plane_state {
> >  * S31.32 sign-magnitude.
> >  */
> > __u64 hdr_mult;
> > +   /**
> > +* @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
> > +* &struct drm_color_lut.
> > +*/
> > +   struct drm_property_blob *lut3d;
> >  };
> >  
> >  struct dm_crtc_state {
> > @@ -858,6 +863,10 @@ void amdgpu_dm_update_freesync_caps(struct 
> > drm_connector *connector,
> >  
> >  void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
> >  
> > +/* 3D LUT max size is 17x17x17 */
> > +#define MAX_COLOR_3DLUT_ENTRIES 4913
> > +#define MAX_COLOR_3DLUT_BITDEPTH 12
> > +/* 1D LUT size */
> >  #define MAX_COLOR_LUT_ENTRIES 4096
> >  /* Legacy gamm LUT users such as X doesn't like large LUT sizes */
> >  #define MAX_COLOR_LEGACY_LUT_ENTRIES 256
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > index f274909c0c7e..e2f3f2099cac 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > @@ -207,6 +207,20 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
> > *adev)

RE: [PATCH v3 1/2] dt-bindings: backlight: Add MPS MP3309C

2023-10-03 Thread Flavio Suligoi
Hi Daniel,

...
> > > > +required:
> > > > +  - compatible
> > > > +  - reg
> > > > +  - max-brightness
> > >
> > > Why is this mandatory?
> > >
> > > There's no point in setting max-brightness when running in I2C mode
> > > (max- brightness should default to 31 in that case).
> > >
> > >
> > > > +  - default-brightness
> > >
> > > Again. I'm not clear why this needs to be mandatory.
> > >
> > >
> >
> > Ok, you are right, I'll remove max-brightness and default-brightness
> > from required properties list. I think to change these properties, for
> > the pwm dimming, into a clearer:
> >
> > - brightness-levels (uint32)
> > - default-brightness-levels (uint32).
> >
> > For example:
> >
> >   brightness-levels:
> > description:
> >   Number of brightness levels. The actual brightness
> >   level (PWM duty cycle) will be interpolated from 0 to this value.
> >   0 means a  0% duty cycle (darkest/off), while the brightness-levels
> represents
> >   a 100% duty cycle (brightest).
> > $ref: /schemas/types.yaml#/definitions/uint32
> >
> >   default-brightness-level:
> > description:
> >   The default brightness level (from 0 to brightness-levels)
> > $ref: /schemas/types.yaml#/definitions/uint32
> >
> > Example:
> > brightness-levels = <10>;
> > default-brightness-level = <6>;
> >
> > What do you think about this solution?
> 
> If you want to introduce a brightness-levels property then I would expect it 
> to
> be defined with the same meaning as pwm-backlight (it's not relevant to the
> bindings but ideally it would be implemented by refactoring and reusing the
> code from pwm_bl.c).

ok, I'll use the brightness-levels property as used in pwm-backlight

> 
> Same with default-brightness-level although I'm not sure why one wouldn't
> just use default-brightness for new bindings (doesn't default-brightness-level
> simply do exactly the same thing as default-brightness).

ok for default-brightness instead of default-brightness-level

> 
> 
> Daniel.

Thanks an best regards,
Flavio


Re: [PATCH v4 1/4] drm/format-helper: Export line conversion helper for drm_panic

2023-10-03 Thread kernel test robot
Hi Jocelyn,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 2dde18cd1d8fac735875f2e4987f11817cc0bc2c]

url:
https://github.com/intel-lab-lkp/linux/commits/Jocelyn-Falempe/drm-format-helper-Export-line-conversion-helper-for-drm_panic/20231003-222642
base:   2dde18cd1d8fac735875f2e4987f11817cc0bc2c
patch link:
https://lore.kernel.org/r/20231003142508.190246-2-jfalempe%40redhat.com
patch subject: [PATCH v4 1/4] drm/format-helper: Export line conversion helper 
for drm_panic
config: m68k-allyesconfig 
(https://download.01.org/0day-ci/archive/20231003/202310032302.dqsglde3-...@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): 
(https://download.01.org/0day-ci/archive/20231003/202310032302.dqsglde3-...@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot 
| Closes: 
https://lore.kernel.org/oe-kbuild-all/202310032302.dqsglde3-...@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/gpu/drm/drm_format_helper.c:436: warning: expecting prototype for 
>> drm_fb_xrgb_to_rgb565_line(). Prototype was for 
>> drm_fb_xrgb_to_xrgb1555_line() instead
>> drivers/gpu/drm/drm_format_helper.c:494: warning: expecting prototype for 
>> drm_fb_xrgb_to_rgb565_line(). Prototype was for 
>> drm_fb_xrgb_to_argb1555_line() instead
>> drivers/gpu/drm/drm_format_helper.c:777: warning: expecting prototype for 
>> drm_fb_xrgb_to_rgb888_line(). Prototype was for 
>> drm_fb_xrgb_to_xrgb2101010_line() instead
>> drivers/gpu/drm/drm_format_helper.c:836: warning: expecting prototype for 
>> drm_fb_xrgb_to_rgb888_line(). Prototype was for 
>> drm_fb_xrgb_to_argb2101010_line() instead


vim +436 drivers/gpu/drm/drm_format_helper.c

7415287e1f3675 Gerd Hoffmann 2019-04-05  428  
ce913131bdeb03 Jocelyn Falempe   2023-10-03  429  /**
ce913131bdeb03 Jocelyn Falempe   2023-10-03  430   * 
drm_fb_xrgb_to_rgb565_line - Convert one line from XRGB to XRGB1555
ce913131bdeb03 Jocelyn Falempe   2023-10-03  431   * @dbuf: Pointer to the 
destination line (in XRGB1555)
ce913131bdeb03 Jocelyn Falempe   2023-10-03  432   * @sbuf: Pointer to the 
source line (in XRGB)
ce913131bdeb03 Jocelyn Falempe   2023-10-03  433   * @pixels: Number of pixels 
to convert.
ce913131bdeb03 Jocelyn Falempe   2023-10-03  434   */
ce913131bdeb03 Jocelyn Falempe   2023-10-03  435  void 
drm_fb_xrgb_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int 
pixels)
10cd592e639edc Thomas Zimmermann 2023-01-02 @436  {
10cd592e639edc Thomas Zimmermann 2023-01-02  437__le16 *dbuf16 = dbuf;
10cd592e639edc Thomas Zimmermann 2023-01-02  438const __le32 *sbuf32 = 
sbuf;
10cd592e639edc Thomas Zimmermann 2023-01-02  439unsigned int x;
10cd592e639edc Thomas Zimmermann 2023-01-02  440u16 val16;
10cd592e639edc Thomas Zimmermann 2023-01-02  441u32 pix;
10cd592e639edc Thomas Zimmermann 2023-01-02  442  
10cd592e639edc Thomas Zimmermann 2023-01-02  443for (x = 0; x < pixels; 
x++) {
10cd592e639edc Thomas Zimmermann 2023-01-02  444pix = 
le32_to_cpu(sbuf32[x]);
10cd592e639edc Thomas Zimmermann 2023-01-02  445val16 = ((pix & 
0x00f8) >> 9) |
10cd592e639edc Thomas Zimmermann 2023-01-02  446((pix & 
0xf800) >> 6) |
10cd592e639edc Thomas Zimmermann 2023-01-02  447((pix & 
0x00f8) >> 3);
10cd592e639edc Thomas Zimmermann 2023-01-02  448dbuf16[x] = 
cpu_to_le16(val16);
10cd592e639edc Thomas Zimmermann 2023-01-02  449}
10cd592e639edc Thomas Zimmermann 2023-01-02  450  }
ce913131bdeb03 Jocelyn Falempe   2023-10-03  451  
EXPORT_SYMBOL(drm_fb_xrgb_to_xrgb1555_line);
10cd592e639edc Thomas Zimmermann 2023-01-02  452  
10cd592e639edc Thomas Zimmermann 2023-01-02  453  /**
10cd592e639edc Thomas Zimmermann 2023-01-02  454   * 
drm_fb_xrgb_to_xrgb1555 - Convert XRGB to XRGB1555 clip buffer
10cd592e639edc Thomas Zimmermann 2023-01-02  455   * @dst: Array of XRGB1555 
destination buffers
10cd592e639edc Thomas Zimmermann 2023-01-02  456   * @dst_pitch: Array of 
numbers of bytes between the start of two consecutive scanlines
10cd592e639edc Thomas Zimmermann 2023-01-02  457   * within @dst; 
can be NULL if scanlines are stored next to each other.
10cd592e639edc Thomas Zimmermann 2023-01-02  458   * @src: Array of XRGB 
source buffer
10cd592e639edc Thomas Zimmermann 2023-01-02  459   * @fb: DRM framebuffer
10cd592e639edc Thomas Zimmermann 2023-01-02  460   * @clip: Clip rectangle area 
to copy
10cd592e639edc Thomas Zimmermann 2023-01-02  461   *
10cd592e639edc Thomas Zimmermann 2023-01-02  462   * This function copies parts 
of a framebuffer t

Re: [PATCH v8 4/5] drm/drm_file: Add DRM obj's RSS reporting function for fdinfo

2023-10-03 Thread Rob Clark
On Fri, Sep 29, 2023 at 11:16 AM Adrián Larumbe
 wrote:
>
> Some BO's might be mapped onto physical memory chunkwise and on demand,
> like Panfrost's tiler heap. In this case, even though the
> drm_gem_shmem_object page array might already be allocated, only a very
> small fraction of the BO is currently backed by system memory, but
> drm_show_memory_stats will then proceed to add its entire virtual size to
> the file's total resident size regardless.
>
> This led to very unrealistic RSS sizes being reckoned for Panfrost, where
> said tiler heap buffer is initially allocated with a virtual size of 128
> MiB, but only a small part of it will eventually be backed by system memory
> after successive GPU page faults.
>
> Provide a new DRM object generic function that would allow drivers to
> return a more accurate RSS and purgeable sizes for their BOs.
>
> Signed-off-by: Adrián Larumbe 
> Reviewed-by: Boris Brezillon 
> Reviewed-by: Steven Price 
> Reviewed-by: AngeloGioacchino Del Regno 
> 

Reviewed-by: Rob Clark 

> ---
>  drivers/gpu/drm/drm_file.c | 8 +---
>  include/drm/drm_gem.h  | 9 +
>  2 files changed, 14 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
> index 883d83bc0e3d..9a1bd8d0d785 100644
> --- a/drivers/gpu/drm/drm_file.c
> +++ b/drivers/gpu/drm/drm_file.c
> @@ -930,6 +930,8 @@ void drm_show_memory_stats(struct drm_printer *p, struct 
> drm_file *file)
> spin_lock(&file->table_lock);
> idr_for_each_entry (&file->object_idr, obj, id) {
> enum drm_gem_object_status s = 0;
> +   size_t add_size = (obj->funcs && obj->funcs->rss) ?
> +   obj->funcs->rss(obj) : obj->size;
>
> if (obj->funcs && obj->funcs->status) {
> s = obj->funcs->status(obj);
> @@ -944,7 +946,7 @@ void drm_show_memory_stats(struct drm_printer *p, struct 
> drm_file *file)
> }
>
> if (s & DRM_GEM_OBJECT_RESIDENT) {
> -   status.resident += obj->size;
> +   status.resident += add_size;
> } else {
> /* If already purged or not yet backed by pages, don't
>  * count it as purgeable:
> @@ -953,14 +955,14 @@ void drm_show_memory_stats(struct drm_printer *p, 
> struct drm_file *file)
> }
>
> if (!dma_resv_test_signaled(obj->resv, 
> dma_resv_usage_rw(true))) {
> -   status.active += obj->size;
> +   status.active += add_size;
>
> /* If still active, don't count as purgeable: */
> s &= ~DRM_GEM_OBJECT_PURGEABLE;
> }
>
> if (s & DRM_GEM_OBJECT_PURGEABLE)
> -   status.purgeable += obj->size;
> +   status.purgeable += add_size;
> }
> spin_unlock(&file->table_lock);
>
> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> index bc9f6aa2f3fe..16364487fde9 100644
> --- a/include/drm/drm_gem.h
> +++ b/include/drm/drm_gem.h
> @@ -208,6 +208,15 @@ struct drm_gem_object_funcs {
>  */
> enum drm_gem_object_status (*status)(struct drm_gem_object *obj);
>
> +   /**
> +* @rss:
> +*
> +* Return resident size of the object in physical memory.
> +*
> +* Called by drm_show_memory_stats().
> +*/
> +   size_t (*rss)(struct drm_gem_object *obj);
> +
> /**
>  * @vm_ops:
>  *
> --
> 2.42.0
>


Re: [PATCH] drm/mediatek: Correctly free sg_table in gem prime vmap

2023-10-03 Thread Fei Shao
Hi,

On Mon, Oct 2, 2023 at 5:21 PM Chen-Yu Tsai  wrote:
>
> The MediaTek DRM driver implements GEM PRIME vmap by fetching the
> sg_table for the object, iterating through the pages, and then
> vmapping them. In essence, unlike the GEM DMA helpers which vmap
> when the object is first created or imported, the MediaTek version
> does it on request.
>
> Unfortunately, the code never correctly frees the sg_table contents.
> This results in a kernel memory leak. On a Hayato device with a text
> console on the internal display, this results in the system running
> out of memory in a few days from all the console screen cursor updates.
>
> Add sg_free_table() to correctly free the contents of the sg_table. This
> was missing despite explicitly required by mtk_gem_prime_get_sg_table().
>
> Fixes: 3df64d7b0a4f ("drm/mediatek: Implement gem prime vmap/vunmap function")
> Cc: 
> Signed-off-by: Chen-Yu Tsai 
> ---
> Please merge for v6.6 fixes.
>
> Also, I was wondering why the MediaTek DRM driver implements a lot of
> the GEM functionality itself, instead of using the GEM DMA helpers.
> From what I could tell, the code closely follows the DMA helpers, except
> that it vmaps the buffers only upon request.
>
>
>  drivers/gpu/drm/mediatek/mtk_drm_gem.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c 
> b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> index 9f364df52478..297ee090e02e 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> @@ -239,6 +239,7 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, 
> struct iosys_map *map)
> npages = obj->size >> PAGE_SHIFT;
> mtk_gem->pages = kcalloc(npages, sizeof(*mtk_gem->pages), GFP_KERNEL);
> if (!mtk_gem->pages) {
> +   sg_free_table(sgt);
> kfree(sgt);
> return -ENOMEM;
> }
> @@ -248,11 +249,13 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, 
> struct iosys_map *map)
> mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,
>pgprot_writecombine(PAGE_KERNEL));
> if (!mtk_gem->kvaddr) {
> +   sg_free_table(sgt);
> kfree(sgt);
> kfree(mtk_gem->pages);
> return -ENOMEM;
> }
>  out:
> +   sg_free_table(sgt);

I think this will cause invalid access from the "goto out" path -
sg_free_table() accesses the provided sg table pointer, but it doesn't
handle NULL pointers like kfree() does.

Regards,
Fei


> kfree(sgt);
> iosys_map_set_vaddr(map, mtk_gem->kvaddr);
>
> --
> 2.42.0.582.g8ccd20d70d-goog
>
>


Re: [PATCH] dma-buf: heaps: Fix off by one in cma_heap_vm_fault()

2023-10-03 Thread T.J. Mercier
On Tue, Oct 3, 2023 at 1:30 AM Dan Carpenter  wrote:
>
> On Mon, Oct 02, 2023 at 10:16:24AM -0700, T.J. Mercier wrote:
> > On Mon, Oct 2, 2023 at 12:04 AM Dan Carpenter  
> > wrote:
> > >
> > > The buffer->pages[] has "buffer->pagecount" elements so this > comparison
> > > has to be changed to >= to avoid reading beyond the end of the array.
> > > The buffer->pages[] array is allocated in cma_heap_allocate().
> > >
> > > Fixes: a5d2d29e24be ("dma-buf: heaps: Move heap-helper logic into the 
> > > cma_heap implementation")
> > > Signed-off-by: Dan Carpenter 
> > > ---
> > >  drivers/dma-buf/heaps/cma_heap.c | 2 +-
> > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/dma-buf/heaps/cma_heap.c 
> > > b/drivers/dma-buf/heaps/cma_heap.c
> > > index ee899f8e6721..bea7e574f916 100644
> > > --- a/drivers/dma-buf/heaps/cma_heap.c
> > > +++ b/drivers/dma-buf/heaps/cma_heap.c
> > > @@ -165,7 +165,7 @@ static vm_fault_t cma_heap_vm_fault(struct vm_fault 
> > > *vmf)
> > > struct vm_area_struct *vma = vmf->vma;
> > > struct cma_heap_buffer *buffer = vma->vm_private_data;
> > >
> > > -   if (vmf->pgoff > buffer->pagecount)
> > > +   if (vmf->pgoff >= buffer->pagecount)
> > > return VM_FAULT_SIGBUS;
> > >
> > Hi Dan,
> >
> > Your fix looks correct to me, but I'm curious if you observed this
> > problem on a device? The mmap in dma-buf.c looks like it prevents
> > creating a mapping that is too large, and I think an access beyond the
> > VMA should segfault before reaching here.
>
> This is from static analysis and not from testing.  You could be correct
> that this bug can't affect real life.
>
> regards,
> dan carpenter

Ok, thanks Dan.

Reviewed-by: T.J. Mercier 


[PATCH v4 4/4] drm/mgag200: Add drm_panic support

2023-10-03 Thread Jocelyn Falempe
Add support for the drm_panic module, which displays a message to
the screen when a kernel panic occurs.

Signed-off-by: Jocelyn Falempe 
---
 drivers/gpu/drm/mgag200/mgag200_drv.c | 24 
 1 file changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c 
b/drivers/gpu/drm/mgag200/mgag200_drv.c
index 976f0ab2006b..229d9c116b42 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -12,10 +12,12 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "mgag200_drv.h"
@@ -83,6 +85,27 @@ resource_size_t mgag200_probe_vram(void __iomem *mem, 
resource_size_t size)
return offset - 65536;
 }
 
+static int mgag200_get_scanout_buffer(struct drm_device *dev,
+ struct drm_scanout_buffer *sb)
+{
+   struct drm_plane *plane;
+   struct mga_device *mdev = to_mga_device(dev);
+   struct iosys_map map = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram);
+
+   /* mgag200 has only one plane */
+   drm_for_each_plane(plane, dev) {
+   if (!plane->state || !plane->state->fb)
+   return -ENODEV;
+   sb->format = plane->state->fb->format;
+   sb->width = plane->state->fb->width;
+   sb->height = plane->state->fb->height;
+   sb->pitch = plane->state->fb->pitches[0];
+   sb->map = map;
+   return 0;
+   }
+   return -ENODEV;
+}
+
 /*
  * DRM driver
  */
@@ -98,6 +121,7 @@ static const struct drm_driver mgag200_driver = {
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
+   .get_scanout_buffer = mgag200_get_scanout_buffer,
DRM_GEM_SHMEM_DRIVER_OPS,
 };
 
-- 
2.41.0



[PATCH v4 3/4] drm/simpledrm: Add drm_panic support

2023-10-03 Thread Jocelyn Falempe
Add support for the drm_panic module, which displays a user-friendly
message to the screen when a kernel panic occurs.

Signed-off-by: Jocelyn Falempe 
---
 drivers/gpu/drm/tiny/simpledrm.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 25e11ef11c4c..ee62303ef68a 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -842,6 +843,19 @@ static struct simpledrm_device 
*simpledrm_device_create(struct drm_driver *drv,
return sdev;
 }
 
+static int simpledrm_get_scanout_buffer(struct drm_device *dev,
+   struct drm_scanout_buffer *sb)
+{
+   struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+
+   sb->width = sdev->mode.hdisplay;
+   sb->height = sdev->mode.vdisplay;
+   sb->pitch = sdev->pitch;
+   sb->format = sdev->format;
+   sb->map = sdev->screen_base;
+   return 0;
+}
+
 /*
  * DRM driver
  */
@@ -857,6 +871,7 @@ static struct drm_driver simpledrm_driver = {
.minor  = DRIVER_MINOR,
.driver_features= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
.fops   = &simpledrm_fops,
+   .get_scanout_buffer = simpledrm_get_scanout_buffer,
 };
 
 /*
-- 
2.41.0



[PATCH v4 2/4] drm/panic: Add a drm panic handler

2023-10-03 Thread Jocelyn Falempe
This module displays a user friendly message when a kernel panic
occurs. It currently doesn't contain any debug information,
but that can be added later.

v2
 * Use get_scanout_buffer() instead of the drm client API.
  (Thomas Zimmermann)
 * Add the panic reason to the panic message (Nerdopolis)
 * Add an exclamation mark (Nerdopolis)

v3
 * Rework the drawing functions, to write the pixels line by line and
 to use the drm conversion helper to support other formats.
 (Thomas Zimmermann)

v4
 * Use drm_fb_r1_to_32bit for fonts (Thomas Zimmermann)
 * Remove the default y to DRM_PANIC config option (Thomas Zimmermann)
 * Add foreground/background color config option
 * Fix the bottom lines not painted if the framebuffer height
   is not a multiple of the font height.
 * Automatically register the device to drm_panic, if the function
   get_scanout_buffer exists. (Thomas Zimmermann)

Signed-off-by: Jocelyn Falempe 
---
 drivers/gpu/drm/Kconfig |  22 ++
 drivers/gpu/drm/Makefile|   1 +
 drivers/gpu/drm/drm_drv.c   |   8 +
 drivers/gpu/drm/drm_panic.c | 413 
 include/drm/drm_drv.h   |  14 ++
 include/drm/drm_panic.h |  41 
 6 files changed, 499 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_panic.c
 create mode 100644 include/drm/drm_panic.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index afb3b2f5f425..17986f630a86 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -99,6 +99,28 @@ config DRM_KMS_HELPER
help
  CRTC helpers for KMS drivers.
 
+config DRM_PANIC
+   bool "Display a user-friendly message when a kernel panic occurs"
+   depends on DRM && !FRAMEBUFFER_CONSOLE
+   select FONT_SUPPORT
+   help
+ Enable a drm panic handler, which will display a user-friendly message
+ when a kernel panic occurs. It's useful when using a user-space
+ console instead of fbcon.
+ It will only work if your graphic driver supports this feature.
+ To support Hi-DPI Display, you can enable bigger fonts like
+ FONT_TER16x32
+
+config DRM_PANIC_FOREGROUND_COLOR
+   hex "Drm panic screen foreground color, in RGB"
+   depends on DRM_PANIC
+   default 0xff
+
+config DRM_PANIC_BACKGROUND_COLOR
+   hex "Drm panic screen background color, in RGB"
+   depends on DRM_PANIC
+   default 0x00
+
 config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
 bool "Enable refcount backtrace history in the DP MST helpers"
depends on STACKTRACE_SUPPORT
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 7a09a89b493b..a525dd9a2751 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -72,6 +72,7 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \
drm_privacy_screen_x86.o
 drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o
 obj-$(CONFIG_DRM)  += drm.o
+drm-$(CONFIG_DRM_PANIC) += drm_panic.o
 
 obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
 
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 12687dd9e1ac..41e211aadb15 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -43,6 +43,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -943,6 +944,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long 
flags)
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_modeset_register_all(dev);
 
+   if (driver->get_scanout_buffer)
+   drm_panic_register(dev);
+
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
 driver->name, driver->major, driver->minor,
 driver->patchlevel, driver->date,
@@ -986,6 +990,8 @@ void drm_dev_unregister(struct drm_device *dev)
 
dev->registered = false;
 
+   drm_panic_unregister(dev);
+
drm_client_dev_unregister(dev);
 
if (drm_core_check_feature(dev, DRIVER_MODESET))
@@ -1067,6 +1073,7 @@ static void drm_core_exit(void)
unregister_chrdev(DRM_MAJOR, "drm");
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
+   drm_panic_exit();
idr_destroy(&drm_minors_idr);
drm_connector_ida_destroy();
 }
@@ -1078,6 +1085,7 @@ static int __init drm_core_init(void)
drm_connector_ida_init();
idr_init(&drm_minors_idr);
drm_memcpy_init_early();
+   drm_panic_init();
 
ret = drm_sysfs_init();
if (ret < 0) {
diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
new file mode 100644
index ..1b7ba7ebe725
--- /dev/null
+++ b/drivers/gpu/drm/drm_panic.c
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+/*
+ * Copyright (c) 2023 Jocelyn Falempe 
+ * inspired by the drm_log driver from David Herrmann 
+ * Tux Ascii art taken from cowsay written by Tony Monroe
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include

[PATCH v4 1/4] drm/format-helper: Export line conversion helper for drm_panic

2023-10-03 Thread Jocelyn Falempe
drm_panic will need the low-level drm_fb__line functions.
Also add drm_fb_r1_to_xrgb to render the fonts.

Signed-off-by: Jocelyn Falempe 
---
 drivers/gpu/drm/drm_format_helper.c | 88 ++---
 include/drm/drm_format_helper.h |  9 +++
 2 files changed, 89 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_format_helper.c 
b/drivers/gpu/drm/drm_format_helper.c
index f93a4efcee90..c238e5d84f1f 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -270,7 +270,30 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int 
*dst_pitch,
 
drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, swab_line);
 }
-EXPORT_SYMBOL(drm_fb_swab);
+
+/**
+ * drm_fb_r1_to_32bit_line - Convert one line from monochrome to any 32bit 
pixel format
+ * @dbuf: Pointer to the destination line (in any 32bit format)
+ * @sbuf: Pointer to the source line (in monochrome)
+ * @pixels: Number of pixels to convert.
+ * @fg_color: Foreground color, applied when R1 is 1
+ * @bg_color: Background color, applied when R1 is 0
+ *
+ * Convert monochrome to any format with 32bit pixel.
+ * There is a limitation, as sbuf is a pointer, it can only points to a 
multiple
+ * of 8 pixels in the source buffer.
+ */
+void drm_fb_r1_to_32bit_line(void *dbuf, const void *sbuf, unsigned int pixels,
+   u32 fg_color, u32 bg_color)
+{
+   unsigned int x;
+   const u8 *sbuf8 = sbuf;
+   u32 *dubf32 = dbuf;
+
+   for (x = 0; x < pixels; x++)
+   dubf32[x] = (sbuf8[x / 8] & (0x80 >> (x % 8))) ? fg_color : 
bg_color;
+}
+EXPORT_SYMBOL(drm_fb_r1_to_32bit_line);
 
 static void drm_fb_xrgb_to_rgb332_line(void *dbuf, const void *sbuf, 
unsigned int pixels)
 {
@@ -320,7 +343,13 @@ void drm_fb_xrgb_to_rgb332(struct iosys_map *dst, 
const unsigned int *dst_pi
 }
 EXPORT_SYMBOL(drm_fb_xrgb_to_rgb332);
 
-static void drm_fb_xrgb_to_rgb565_line(void *dbuf, const void *sbuf, 
unsigned int pixels)
+/**
+ * drm_fb_xrgb_to_rgb565_line - Convert one line from XRGB to RGB565
+ * @dbuf: Pointer to the destination line (in RGB565)
+ * @sbuf: Pointer to the source line (in XRGB)
+ * @pixels: Number of pixels to convert.
+ */
+void drm_fb_xrgb_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int 
pixels)
 {
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
@@ -336,6 +365,7 @@ static void drm_fb_xrgb_to_rgb565_line(void *dbuf, 
const void *sbuf, unsigne
dbuf16[x] = cpu_to_le16(val16);
}
 }
+EXPORT_SYMBOL(drm_fb_xrgb_to_rgb565_line);
 
 /* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */
 static void drm_fb_xrgb_to_rgb565_swab_line(void *dbuf, const void *sbuf,
@@ -396,7 +426,13 @@ void drm_fb_xrgb_to_rgb565(struct iosys_map *dst, 
const unsigned int *dst_pi
 }
 EXPORT_SYMBOL(drm_fb_xrgb_to_rgb565);
 
-static void drm_fb_xrgb_to_xrgb1555_line(void *dbuf, const void *sbuf, 
unsigned int pixels)
+/**
+ * drm_fb_xrgb_to_rgb565_line - Convert one line from XRGB to XRGB1555
+ * @dbuf: Pointer to the destination line (in XRGB1555)
+ * @sbuf: Pointer to the source line (in XRGB)
+ * @pixels: Number of pixels to convert.
+ */
+void drm_fb_xrgb_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned 
int pixels)
 {
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
@@ -412,6 +448,7 @@ static void drm_fb_xrgb_to_xrgb1555_line(void *dbuf, 
const void *sbuf, unsig
dbuf16[x] = cpu_to_le16(val16);
}
 }
+EXPORT_SYMBOL(drm_fb_xrgb_to_xrgb1555_line);
 
 /**
  * drm_fb_xrgb_to_xrgb1555 - Convert XRGB to XRGB1555 clip buffer
@@ -447,7 +484,13 @@ void drm_fb_xrgb_to_xrgb1555(struct iosys_map *dst, 
const unsigned int *dst_
 }
 EXPORT_SYMBOL(drm_fb_xrgb_to_xrgb1555);
 
-static void drm_fb_xrgb_to_argb1555_line(void *dbuf, const void *sbuf, 
unsigned int pixels)
+/**
+ * drm_fb_xrgb_to_rgb565_line - Convert one line from XRGB to ARGB1555
+ * @dbuf: Pointer to the destination line (in ARGB1555)
+ * @sbuf: Pointer to the source line (in XRGB)
+ * @pixels: Number of pixels to convert.
+ */
+void drm_fb_xrgb_to_argb1555_line(void *dbuf, const void *sbuf, unsigned 
int pixels)
 {
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
@@ -464,6 +507,7 @@ static void drm_fb_xrgb_to_argb1555_line(void *dbuf, 
const void *sbuf, unsig
dbuf16[x] = cpu_to_le16(val16);
}
 }
+EXPORT_SYMBOL(drm_fb_xrgb_to_argb1555_line);
 
 /**
  * drm_fb_xrgb_to_argb1555 - Convert XRGB to ARGB1555 clip buffer
@@ -499,7 +543,13 @@ void drm_fb_xrgb_to_argb1555(struct iosys_map *dst, 
const unsigned int *dst_
 }
 EXPORT_SYMBOL(drm_fb_xrgb_to_argb1555);
 
-static void drm_fb_xrgb_to_rgba5551_line(void *dbuf, const void *sbuf, 
unsigned int pixels)
+/**
+ * drm_fb_xrgb_to_rgba5551_line - Convert one lin

[RFC][PATCH v4 0/4] drm/panic: Add a drm panic handler

2023-10-03 Thread Jocelyn Falempe
This introduces a new drm panic handler, which displays a message when a panic 
occurs.
So when fbcon is disabled, you can still see a kernel panic.

This is one of the missing feature, when disabling VT/fbcon in the kernel:
https://www.reddit.com/r/linux/comments/10eccv9/config_vtn_in_2023/
Fbcon can be replaced by a userspace kms console, but the panic screen must be 
done in the kernel.

This is a proof of concept, and works with simpledrm and mgag200, using a new 
get_scanout_buffer() api

To test it, make sure you're using the simpledrm driver, and trigger a panic:
echo c > /proc/sysrq-trigger

v2:
 * Use get_scanout_buffer() instead of the drm client API. (Thomas Zimmermann)
 * Add the panic reason to the panic message (Nerdopolis)
 * Add an exclamation mark (Nerdopolis)
 
v3:
 * Rework the drawing functions, to write the pixels line by line and
 to use the drm conversion helper to support other formats.
 (Thomas Zimmermann)
 
v4:
 * Fully support all simpledrm formats using drm conversion helpers
 * Rename dpanic_* to drm_panic_*, and have more coherent function name.
   (Thomas Zimmermann)
 * Use drm_fb_r1_to_32bit for fonts (Thomas Zimmermann)
 * Remove the default y to DRM_PANIC config option (Thomas Zimmermann)
 * Add foreground/background color config option
 * Fix the bottom lines not painted if the framebuffer height
   is not a multiple of the font height.
 * Automatically register the driver to drm_panic, if the function
   get_scanout_buffer() exists. (Thomas Zimmermann)
 * Add mgag200 support.
 
With mgag200 support, I was able to test that the xrgb to rgb565 conversion 
is working.

A few more though:
 1) what about gpu with multiple monitor connected ?
maybe get_scanout_buffer() could return a list of scanout buffers ?
 2) I think for some GPU drivers, there might need a flush_scanout_buffer() 
function, that should be called after the scanout buffer has been filled ?


Best regards,


Jocelyn Falempe (4):
  drm/format-helper: Export line conversion helper for drm_panic
  drm/panic: Add a drm panic handler
  drm/simpledrm: Add drm_panic support
  drm/mgag200: Add drm_panic support

 drivers/gpu/drm/Kconfig   |  22 ++
 drivers/gpu/drm/Makefile  |   1 +
 drivers/gpu/drm/drm_drv.c |   8 +
 drivers/gpu/drm/drm_format_helper.c   |  88 +-
 drivers/gpu/drm/drm_panic.c   | 413 ++
 drivers/gpu/drm/mgag200/mgag200_drv.c |  24 ++
 drivers/gpu/drm/tiny/simpledrm.c  |  15 +
 include/drm/drm_drv.h |  14 +
 include/drm/drm_format_helper.h   |   9 +
 include/drm/drm_panic.h   |  41 +++
 10 files changed, 627 insertions(+), 8 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_panic.c
 create mode 100644 include/drm/drm_panic.h


base-commit: 2dde18cd1d8fac735875f2e4987f11817cc0bc2c
-- 
2.41.0



Re: [PATCH drm-misc-next v5 4/6] drm/gpuvm: track/lock/validate external/evicted objects

2023-10-03 Thread Boris Brezillon
On Tue, 03 Oct 2023 14:25:56 +0200
Thomas Hellström  wrote:

> > > > +/**
> > > > + * get_next_vm_bo_from_list() - get the next vm_bo element
> > > > + * @__gpuvm: The GPU VM
> > > > + * @__list_name: The name of the list we're iterating on
> > > > + * @__local_list: A pointer to the local list used to store
> > > > already iterated items
> > > > + * @__prev_vm_bo: The previous element we got from
> > > > drm_gpuvm_get_next_cached_vm_bo()
> > > > + *
> > > > + * This helper is here to provide lockless list iteration.
> > > > Lockless as in, the
> > > > + * iterator releases the lock immediately after picking the
> > > > first element from
> > > > + * the list, so list insertion deletion can happen concurrently.
> > > > + *
> > > > + * Elements popped from the original list are kept in a local
> > > > list, so removal
> > > > + * and is_empty checks can still happen while we're iterating
> > > > the list.
> > > > + */
> > > > +#define get_next_vm_bo_from_list(__gpuvm, __list_name,
> > > > __local_list, __prev_vm_bo) \
> > > > +   ({   
> > > >    \
> > > > +   struct drm_gpuvm_bo *__vm_bo =
> > > > NULL;\
> > > > +
> > > >    \
> > > > +   drm_gpuvm_bo_put(__prev_vm_bo);  
> > > >    \
> > > > +
> > > >    \
> > > > +   spin_lock(&(__gpuvm)-  
> > > > >__list_name.lock);\    
> > > 
> > > Here we unconditionally take the spinlocks while iterating, and the
> > > main 
> > > point of DRM_GPUVM_RESV_PROTECTED was really to avoid that?
> > > 
> > >   
> > > > +   if (!(__gpuvm)-  
> > > > >__list_name.local_list) \  
> > > > +   (__gpuvm)->__list_name.local_list =
> > > > __local_list;   \
> > > > +   else 
> > > >    \
> > > > +   WARN_ON((__gpuvm)->__list_name.local_list
> > > > != __local_list); \
> > > > +
> > > >    \
> > > > +   while (!list_empty(&(__gpuvm)->__list_name.list))
> > > > { \
> > > > +   __vm_bo = list_first_entry(&(__gpuvm)-  
> > > > >__list_name.list,\  
> > > > +  struct
> > > > drm_gpuvm_bo, \
> > > > + 
> > > > list.entry.__list_name); \
> > > > +   if (kref_get_unless_zero(&__vm_bo->kref))
> > > > {    
> > > And unnecessarily grab a reference in the RESV_PROTECTED case.  
> > > > \
> > > > +   list_move_tail(&(__vm_bo)-  
> > > > >list.entry.__list_name,  \  
> > > > + 
> > > > __local_list);   \
> > > > +   break;   
> > > >    \
> > > > +   } else
> > > > {\
> > > > +   list_del_init(&(__vm_bo)-  
> > > > >list.entry.__list_name);  \  
> > > > +   __vm_bo =
> > > > NULL; \
> > > > +   }
> > > >    \
> > > > +   }
> > > >    \
> > > > +   spin_unlock(&(__gpuvm)-  
> > > > >__list_name.lock);  \  
> > > > +
> > > >    \
> > > > +   __vm_bo; 
> > > >    \
> > > > +   })    
> > > 
> > > IMHO this lockless list iteration looks very complex and should be 
> > > pretty difficult to maintain while moving forward, also since it
> > > pulls 
> > > the gpuvm_bos off the list, list iteration needs to be protected by
> > > an 
> > > outer lock anyway.  
> > 
> > As being partly responsible for this convoluted list iterator, I must
> > say I agree with you. There's so many ways this can go wrong if the
> > user doesn't call it the right way, or doesn't protect concurrent
> > list
> > iterations with a separate lock (luckily, this is a private
> > iterator). I
> > mean, it works, so there's certainly a way to get it right, but gosh,
> > this is so far from the simple API I had hoped for.
> >   
> > > Also from what I understand from Boris, th

Re: [PATCH] drm/bridge: ti-sn65dsi86: Associate DSI device lifetime with auxiliary device

2023-10-03 Thread Neil Armstrong

On 03/10/2023 01:54, Stephen Boyd wrote:

The kernel produces a warning splat and the DSI device fails to register
in this driver if the i2c driver probes, populates child auxiliary
devices, and then somewhere in ti_sn_bridge_probe() a function call
returns -EPROBE_DEFER. When the auxiliary driver probe defers, the dsi
device created by devm_mipi_dsi_device_register_full() is left
registered because the devm managed device used to manage the lifetime
of the DSI device is the parent i2c device, not the auxiliary device
that is being probed.

Associate the DSI device created and managed by this driver to the
lifetime of the auxiliary device, not the i2c device, so that the DSI
device is removed when the auxiliary driver unbinds. Similarly change
the device pointer used for dev_err_probe() so the deferred probe errors
are associated with the auxiliary device instead of the parent i2c
device so we can narrow down future problems faster.

Cc: Douglas Anderson 
Cc: Maxime Ripard 
Fixes: c3b75d4734cb ("drm/bridge: sn65dsi86: Register and attach our DSI device at 
probe")
Signed-off-by: Stephen Boyd 
---
  drivers/gpu/drm/bridge/ti-sn65dsi86.c | 14 +++---
  1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c 
b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index f448b903e190..84148a79414b 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -692,7 +692,7 @@ static struct ti_sn65dsi86 *bridge_to_ti_sn65dsi86(struct 
drm_bridge *bridge)
return container_of(bridge, struct ti_sn65dsi86, bridge);
  }
  
-static int ti_sn_attach_host(struct ti_sn65dsi86 *pdata)

+static int ti_sn_attach_host(struct auxiliary_device *adev, struct 
ti_sn65dsi86 *pdata)
  {
int val;
struct mipi_dsi_host *host;
@@ -707,7 +707,7 @@ static int ti_sn_attach_host(struct ti_sn65dsi86 *pdata)
if (!host)
return -EPROBE_DEFER;
  
-	dsi = devm_mipi_dsi_device_register_full(dev, host, &info);

+   dsi = devm_mipi_dsi_device_register_full(&adev->dev, host, &info);
if (IS_ERR(dsi))
return PTR_ERR(dsi);
  
@@ -725,7 +725,7 @@ static int ti_sn_attach_host(struct ti_sn65dsi86 *pdata)
  
  	pdata->dsi = dsi;
  
-	return devm_mipi_dsi_attach(dev, dsi);

+   return devm_mipi_dsi_attach(&adev->dev, dsi);
  }
  
  static int ti_sn_bridge_attach(struct drm_bridge *bridge,

@@ -1298,9 +1298,9 @@ static int ti_sn_bridge_probe(struct auxiliary_device 
*adev,
struct device_node *np = pdata->dev->of_node;
int ret;
  
-	pdata->next_bridge = devm_drm_of_get_bridge(pdata->dev, np, 1, 0);

+   pdata->next_bridge = devm_drm_of_get_bridge(&adev->dev, np, 1, 0);
if (IS_ERR(pdata->next_bridge))
-   return dev_err_probe(pdata->dev, PTR_ERR(pdata->next_bridge),
+   return dev_err_probe(&adev->dev, PTR_ERR(pdata->next_bridge),
 "failed to create panel bridge\n");
  
  	ti_sn_bridge_parse_lanes(pdata, np);

@@ -1319,9 +1319,9 @@ static int ti_sn_bridge_probe(struct auxiliary_device 
*adev,
  
  	drm_bridge_add(&pdata->bridge);
  
-	ret = ti_sn_attach_host(pdata);

+   ret = ti_sn_attach_host(adev, pdata);
if (ret) {
-   dev_err_probe(pdata->dev, ret, "failed to attach dsi host\n");
+   dev_err_probe(&adev->dev, ret, "failed to attach dsi host\n");
goto err_remove_bridge;
}
  


base-commit: 0bb80ecc33a8fb5a682236443c1e740d5c917d1d


This looks reasonable

Reviewed-by: Neil Armstrong 


Re: [LINUX KERNEL PATCH v5 1/2] virtio_pci: Add freeze_mode for virtio_pci_common_cfg

2023-10-03 Thread Michael S. Tsirkin
On Tue, Sep 19, 2023 at 06:46:06PM +0800, Jiqian Chen wrote:
> When guest vm does S3, Qemu will reset and clear some things of virtio
> devices, but guest can't aware that, so that may cause some problems.
> For excample, Qemu calls virtio_reset->virtio_gpu_gl_reset, that will
> destroy render resources of virtio-gpu. As a result, after guest resume,
> the display can't come back and we only saw a black screen. Due to guest
> can't re-create all the resources, so we need to let Qemu not to destroy
> them when S3.
> 
> For above purpose, this patch add a new parameter named freeze_mode to
> struct virtio_pci_common_cfg, and when guest suspends, it can set
> freeze_mode to be FREEZE_S3, so that virtio devices can change their
> reset behavior on Qemu side according to that mode.
> 
> Signed-off-by: Jiqian Chen 
> ---
>  drivers/virtio/virtio.c| 13 +
>  drivers/virtio/virtio_pci_modern.c |  9 +
>  drivers/virtio/virtio_pci_modern_dev.c | 16 
>  include/linux/virtio_config.h  |  1 +
>  include/linux/virtio_pci_modern.h  |  2 ++
>  include/uapi/linux/virtio_pci.h| 16 ++--
>  6 files changed, 55 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
> index 3893dc29eb26..b4eb8369d5a1 100644
> --- a/drivers/virtio/virtio.c
> +++ b/drivers/virtio/virtio.c
> @@ -7,6 +7,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  /* Unique numbering for virtio devices. */
>  static DEFINE_IDA(virtio_index_ida);
> @@ -486,10 +487,20 @@ void unregister_virtio_device(struct virtio_device *dev)
>  EXPORT_SYMBOL_GPL(unregister_virtio_device);
>  
>  #ifdef CONFIG_PM_SLEEP
> +static void virtio_set_freeze_mode(struct virtio_device *dev, u16 mode)
> +{
> + if (!dev->config->set_freeze_mode)
> + return;
> + might_sleep();
> + dev->config->set_freeze_mode(dev, mode);
> +}
> +
>  int virtio_device_freeze(struct virtio_device *dev)
>  {
>   struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
>  
> + virtio_set_freeze_mode(dev, VIRTIO_PCI_FREEZE_MODE_FREEZE_S3);
> +
>   virtio_config_disable(dev);
>  
>   dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
> @@ -544,6 +555,8 @@ int virtio_device_restore(struct virtio_device *dev)
>  
>   virtio_config_enable(dev);
>  
> + virtio_set_freeze_mode(dev, VIRTIO_PCI_FREEZE_MODE_UNFREEZE);
> +
>   return 0;
>  
>  err:
> diff --git a/drivers/virtio/virtio_pci_modern.c 
> b/drivers/virtio/virtio_pci_modern.c
> index d6bb68ba84e5..846b70919cbd 100644
> --- a/drivers/virtio/virtio_pci_modern.c
> +++ b/drivers/virtio/virtio_pci_modern.c
> @@ -491,6 +491,13 @@ static bool vp_get_shm_region(struct virtio_device *vdev,
>   return true;
>  }
>  
> +static void vp_set_freeze_mode(struct virtio_device *vdev, u16 mode)
> +{
> + struct virtio_pci_device *vp_dev = to_vp_device(vdev);
> +
> + vp_modern_set_freeze_mode(&vp_dev->mdev, mode);
> +}
> +
>  static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
>   .get= NULL,
>   .set= NULL,
> @@ -509,6 +516,7 @@ static const struct virtio_config_ops 
> virtio_pci_config_nodev_ops = {
>   .get_shm_region  = vp_get_shm_region,
>   .disable_vq_and_reset = vp_modern_disable_vq_and_reset,
>   .enable_vq_after_reset = vp_modern_enable_vq_after_reset,
> + .set_freeze_mode = vp_set_freeze_mode,
>  };
>  
>  static const struct virtio_config_ops virtio_pci_config_ops = {
> @@ -529,6 +537,7 @@ static const struct virtio_config_ops 
> virtio_pci_config_ops = {
>   .get_shm_region  = vp_get_shm_region,
>   .disable_vq_and_reset = vp_modern_disable_vq_and_reset,
>   .enable_vq_after_reset = vp_modern_enable_vq_after_reset,
> + .set_freeze_mode = vp_set_freeze_mode,
>  };
>  
>  /* the PCI probing function */
> diff --git a/drivers/virtio/virtio_pci_modern_dev.c 
> b/drivers/virtio/virtio_pci_modern_dev.c
> index aad7d9296e77..4a6f7d130b6e 100644
> --- a/drivers/virtio/virtio_pci_modern_dev.c
> +++ b/drivers/virtio/virtio_pci_modern_dev.c
> @@ -203,6 +203,8 @@ static inline void check_offsets(void)
>offsetof(struct virtio_pci_common_cfg, queue_used_lo));
>   BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_USEDHI !=
>offsetof(struct virtio_pci_common_cfg, queue_used_hi));
> + BUILD_BUG_ON(VIRTIO_PCI_COMMON_F_MODE !=
> +  offsetof(struct virtio_pci_common_cfg, freeze_mode));
>  }
>  
>  /*
> @@ -714,6 +716,20 @@ void __iomem *vp_modern_map_vq_notify(struct 
> virtio_pci_modern_device *mdev,
>  }
>  EXPORT_SYMBOL_GPL(vp_modern_map_vq_notify);
>  
> +/*
> + * vp_modern_set_freeze_mode - set freeze mode to device
> + * @mdev: the modern virtio-pci device
> + * @mode: the mode set to device
> + */
> +void vp_modern_set_freeze_mode(struct virtio_pci_modern_device *mdev,
> +  u16 mode)
> +{
> + str

Re: [PATCH drm-misc-next v5 4/6] drm/gpuvm: track/lock/validate external/evicted objects

2023-10-03 Thread Thomas Hellström
Hi, Boris,

On Tue, 2023-10-03 at 12:05 +0200, Boris Brezillon wrote:
> Hello Thomas,
> 
> On Tue, 3 Oct 2023 10:36:10 +0200
> Thomas Hellström  wrote:
> 
> > > +/**
> > > + * get_next_vm_bo_from_list() - get the next vm_bo element
> > > + * @__gpuvm: The GPU VM
> > > + * @__list_name: The name of the list we're iterating on
> > > + * @__local_list: A pointer to the local list used to store
> > > already iterated items
> > > + * @__prev_vm_bo: The previous element we got from
> > > drm_gpuvm_get_next_cached_vm_bo()
> > > + *
> > > + * This helper is here to provide lockless list iteration.
> > > Lockless as in, the
> > > + * iterator releases the lock immediately after picking the
> > > first element from
> > > + * the list, so list insertion deletion can happen concurrently.
> > > + *
> > > + * Elements popped from the original list are kept in a local
> > > list, so removal
> > > + * and is_empty checks can still happen while we're iterating
> > > the list.
> > > + */
> > > +#define get_next_vm_bo_from_list(__gpuvm, __list_name,
> > > __local_list, __prev_vm_bo) \
> > > +   ({   
> > >    \
> > > +   struct drm_gpuvm_bo *__vm_bo =
> > > NULL;\
> > > +
> > >    \
> > > +   drm_gpuvm_bo_put(__prev_vm_bo);  
> > >    \
> > > +
> > >    \
> > > +   spin_lock(&(__gpuvm)-
> > > >__list_name.lock);\  
> > 
> > Here we unconditionally take the spinlocks while iterating, and the
> > main 
> > point of DRM_GPUVM_RESV_PROTECTED was really to avoid that?
> > 
> > 
> > > +   if (!(__gpuvm)-
> > > >__list_name.local_list) \
> > > +   (__gpuvm)->__list_name.local_list =
> > > __local_list;   \
> > > +   else 
> > >    \
> > > +   WARN_ON((__gpuvm)->__list_name.local_list
> > > != __local_list); \
> > > +
> > >    \
> > > +   while (!list_empty(&(__gpuvm)->__list_name.list))
> > > { \
> > > +   __vm_bo = list_first_entry(&(__gpuvm)-
> > > >__list_name.list,\
> > > +  struct
> > > drm_gpuvm_bo, \
> > > + 
> > > list.entry.__list_name); \
> > > +   if (kref_get_unless_zero(&__vm_bo->kref))
> > > {  
> > And unnecessarily grab a reference in the RESV_PROTECTED case.
> > > \
> > > +   list_move_tail(&(__vm_bo)-
> > > >list.entry.__list_name,  \
> > > + 
> > > __local_list);   \
> > > +   break;   
> > >    \
> > > +   } else
> > > {\
> > > +   list_del_init(&(__vm_bo)-
> > > >list.entry.__list_name);  \
> > > +   __vm_bo =
> > > NULL; \
> > > +   }
> > >    \
> > > +   }
> > >    \
> > > +   spin_unlock(&(__gpuvm)-
> > > >__list_name.lock);  \
> > > +
> > >    \
> > > +   __vm_bo; 
> > >    \
> > > +   })  
> > 
> > IMHO this lockless list iteration looks very complex and should be 
> > pretty difficult to maintain while moving forward, also since it
> > pulls 
> > the gpuvm_bos off the list, list iteration needs to be protected by
> > an 
> > outer lock anyway.
> 
> As being partly responsible for this convoluted list iterator, I must
> say I agree with you. There's so many ways this can go wrong if the
> user doesn't call it the right way, or doesn't protect concurrent
> list
> iterations with a separate lock (luckily, this is a private
> iterator). I
> mean, it works, so there's certainly a way to get it right, but gosh,
> this is so far from the simple API I had hoped for.
> 
> > Also from what I understand from Boris, the extobj 
> > list would typically not need the fine-grained locking; only the
> > evict 
> > list?
> 
> Right, I'm adding the gpuvm_bo to extobj li

Re: [PATCH v6 1/7] drm: atmel-hlcdc: add flag and driver ops to differentiate XLCDC and HLCDC IP

2023-10-03 Thread claudiu beznea



On 03.10.2023 07:18, manikanda...@microchip.com wrote:
> On 28/09/23 11:31 am, claudiu beznea wrote:
>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the 
>> content is safe
>>
>> Hi, Manikandan,
>>
>> On 27.09.2023 12:47, Manikandan Muralidharan wrote:
>>> +void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
>>> + struct atmel_hlcdc_plane_state *state);
>>> +void atmel_xlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
>>> + struct atmel_hlcdc_plane_state *state);
>>> +void update_hlcdc_buffers(struct atmel_hlcdc_plane *plane,
>>> +   struct atmel_hlcdc_plane_state *state,
>>> +   u32 sr, int i);
>>> +void update_xlcdc_buffers(struct atmel_hlcdc_plane *plane,
>>> +   struct atmel_hlcdc_plane_state *state,
>>> +   u32 sr, int i);
>>> +void hlcdc_atomic_disable(struct atmel_hlcdc_plane *plane);
>>> +void xlcdc_atomic_disable(struct atmel_hlcdc_plane *plane);
>>> +void
>>> +atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
>>> +   struct atmel_hlcdc_plane_state 
>>> *state);
>>> +void
>>> +atmel_xlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
>>> +   struct atmel_hlcdc_plane_state 
>>> *state);
>>> +void hlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
>>> +  struct atmel_hlcdc_dc *dc);
>>> +void xlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
>>> +  struct atmel_hlcdc_dc *dc);
>>> +void hlcdc_csc_init(struct atmel_hlcdc_plane *plane,
>>> + const struct atmel_hlcdc_layer_desc *desc);
>>> +void xlcdc_csc_init(struct atmel_hlcdc_plane *plane,
>>> + const struct atmel_hlcdc_layer_desc *desc);
>>> +void hlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
>>> +const struct atmel_hlcdc_layer_desc *desc);
>>> +void xlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
>>> +const struct atmel_hlcdc_layer_desc *desc);
>>> +
>>
>> These are still here... Isn't the solution I proposed to you in the
>> previous version good enough?
> Hi Claudiu
> 
> These changes were integrated in the current patch set based on the 
> solution which you proposed in the previous series.
> The XLCDC and HLCDC functions calls are moved to IP specific driver->ops
> and their function declarations are made here in atmel_hlcdc_dc.h
> Rest of the changes are integrated in Patch 4/7.

I still think (and I've checked it last time) you can remove these
declaration. See comment from previous version:

"You can get rid of these and keep the function definitions static to
atmel_hlcdc_plane.c if you define struct atmel_lcdc_dc_ops objects directly
to atmel_hlcdc_plane.c. In atmel_hlcdc_dc.c you can have something like:

extern const struct atmel_lcdc_dc_ops  atmel_hlcdc_ops;
extern const struct atmel_lcdc_dc_ops  atmel_xlcdc_ops;
"

>>
>> Thank you,
>> Claudiu Beznea
> 


RE: [PATCH v3 1/2] dt-bindings: backlight: Add MPS MP3309C

2023-10-03 Thread Flavio Suligoi
Hi Daniel,

...

> > +required:
> > +  - compatible
> > +  - reg
> > +  - max-brightness
> 
> Why is this mandatory?
> 
> There's no point in setting max-brightness when running in I2C mode (max-
> brightness should default to 31 in that case).
> 
> 
> > +  - default-brightness
> 
> Again. I'm not clear why this needs to be mandatory.
> 
> 

Ok, you are right, I'll remove max-brightness and default-brightness from 
required properties list.
I think to change these properties, for the pwm dimming, into a clearer:

- brightness-levels (uint32) 
- default-brightness-levels (uint32).

For example:

  brightness-levels:
description:
  Number of brightness levels. The actual brightness
  level (PWM duty cycle) will be interpolated from 0 to this value.
  0 means a  0% duty cycle (darkest/off), while the brightness-levels 
represents
  a 100% duty cycle (brightest).
$ref: /schemas/types.yaml#/definitions/uint32

  default-brightness-level:
description:
  The default brightness level (from 0 to brightness-levels)
$ref: /schemas/types.yaml#/definitions/uint32

Example:
brightness-levels = <10>;
default-brightness-level = <6>;

What do you think about this solution?

> Daniel.

Thanks for your help,
Flavio


RE: [PATCH v3 2/2] backlight: mp3309c: Add support for MPS MP3309C

2023-10-03 Thread Flavio Suligoi
Hi Daniel,

...

> > +static int mp3309c_bl_update_status(struct backlight_device *bl) {
> > +   struct mp3309c_chip *chip = bl_get_data(bl);
> > +   int brightness = backlight_get_brightness(bl);
> > +   struct pwm_state pwmstate;
> > +   unsigned int analog_val, bits_val;
> > +   int i, ret;
> > +
> > +   if (chip->pdata->dimming_mode == DIMMING_PWM) {
> > +   /*
> > +* PWM dimming mode
> > +*/
> > +   pwm_get_state(chip->pwmd, &pwmstate);
> > +   pwm_set_relative_duty_cycle(&pwmstate, brightness,
> > +   chip->pdata->max_brightness);
> > +   pwmstate.enabled = true;
> > +   ret = pwm_apply_state(chip->pwmd, &pwmstate);
> > +   if (ret)
> > +   return ret;
> > +
> > +   switch (chip->pdata->status) {
> > +   case FIRST_POWER_ON:
> > +   case BACKLIGHT_OFF:
> > +   /*
> > +* After 20ms of low pwm signal level, the chip turns
> > +  off automatically. In this case, before enabling the
> > +  chip again, we must wait about 10ms for pwm signal
> to
> > +  stabilize.
> > +*/
> > +   if (brightness > 0) {
> > +   msleep(10);
> > +   mp3309c_enable_device(chip);
> > +   chip->pdata->status = BACKLIGHT_ON;
> > +   } else {
> > +   chip->pdata->status = BACKLIGHT_OFF;
> > +   }
> > +   break;
> > +   case BACKLIGHT_ON:
> > +   if (brightness == 0)
> > +   chip->pdata->status = BACKLIGHT_OFF;
> > +   break;
> > +   }
> > +   } else {
> > +   /*
> > +* Analog dimming (by I2C command) dimming mode
> > +*
> > +* The first time, before setting brightness, we must enable the
> > +* device
> > +*/
> > +   if (chip->pdata->status == FIRST_POWER_ON)
> > +   mp3309c_enable_device(chip);
> > +
> > +   /*
> > +* Dimming mode I2C command
> > +*
> > +* The 5 bits of the dimming analog value D4..D0 is allocated
> > +* in the I2C register #0, in the following way:
> > +*
> > +* +--+--+--+--+--+--+--+--+
> > +* |EN|D0|D1|D2|D3|D4|XX|XX|
> > +* +--+--+--+--+--+--+--+--+
> > +*/
> > +   analog_val = DIV_ROUND_UP(ANALOG_MAX_VAL *
> brightness,
> > + chip->pdata->max_brightness);
> 
> Sorry to only notice after sharing a Reviewed-by:[1] but...
> 
> Scaling brightness here isn't right. When running in I2C dimming mode then
> max_brightness *must* be 31 or lower, meaning the value in brightness can
> be applied directly to the hardware without scaling.

ok, right; max brightness is 31, fixed

> 
> Quoting the DT binding docs about how max-brightness should be
> interpretted:
> 
>   Normally the maximum brightness is determined by the hardware and this
>   property is not required. This property is used to put a software
>   limit on the brightness apart from what the driver says, as it could
>   happen that a LED can be made so bright that it gets damaged or causes
>   damage due to restrictions in a specific system, such as mounting
>   conditions.
> 

ok

> 
> Daniel.
> 
> 
> [1] I remember checking if this code could overflow the field but I was
> so distracted by that I ended up missing the obvious!

Thanks and best regards,
Flavio


Re: [PATCH v14 RESEND 5/6] drm/imx: Introduce i.MX8qm/qxp DPU DRM

2023-10-03 Thread Maxime Ripard
On Tue, Sep 26, 2023 at 03:55:35AM +, Ying Liu wrote:
> > > > > + cf->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
> > > > > + if (!cf->pec_base)
> > > > > + return -ENOMEM;
> > > > > +
> > > > > + cf->base = devm_ioremap(dpu->dev, base, SZ_32);
> > > > > + if (!cf->base)
> > > > > + return -ENOMEM;
> > > >
> > > > For the same reason, you need to protect any access to a device managed
> > > > resource (so clocks, registers, regulators, etc.) by a call to
> > > > drm_dev_enter/drm_dev_exit and you need to call drm_dev_unplug
> > instead
> > > > of drm_dev_unregister.
> > >
> > > That's a good point. I've tried to do that, but it turns out that the
> > > display controller cannot be enabled again after binding the dpu-core
> > > driver manually again. It seems that the display controller requires a
> > > proper disablement procedure, but the "driver instance overview " kdoc
> > > mentions the shortcoming of no proper disablement if drm_dev_unplug()
> > > is used:
> > >
> > > """
> > > * Drivers that want to support device unplugging (USB, DT overlay unload)
> > should
> > >  * use drm_dev_unplug() instead of drm_dev_unregister(). The driver must
> > protect
> > >  * regions that is accessing device resources to prevent use after they're
> > >  * released. This is done using drm_dev_enter() and drm_dev_exit(). There
> > is one
> > >  * shortcoming however, drm_dev_unplug() marks the drm_device as
> > unplugged before
> > >  * drm_atomic_helper_shutdown() is called. This means that if the disable
> > code
> > >  * paths are protected, they will not run on regular driver module unload,
> > >  * possibly leaving the hardware enabled.
> > > """
> > >
> > > A DPU reset in dpu_core() might be helpful, but I'm not sure if there is 
> > > any
> > > reset line provided by the embodying system.
> > 
> > Generally speaking, you shouldn't rely on the device being in any
> > particuliar state before your driver loads. So a reset at probe/bind
> > time is a good idea.
> 
> Yes. I'll drop the platform device creations for CRTCs from dpu-core.c 
> and drop the aggregation of CRTC components from different DPU
> instances into one DRM device.  This way, there will be only two CRTCs
> of one DPU in one DRM device.

Ok.

> Then, the driver will be simpler and users cannot unbind the driver of
> one of the two DPU instances,

Uh? They would still be able to do that.

> which means drm_dev_unplug() won't be needed any more(?)

So this would still be needed

> and the reset issue will be gone. The controller will be shutdown
> properly through drm_atomic_helper_shutdown() when the driver module
> is removed.

Again, you shouldn't rely on a particular state at boot. For all you
know, you could have been reset by some watchdog or been kexec'd.

> > > Even if the reset works, the 2nd DPU instance in i.MX8qm would be a
> > > problem, because it won't be reset or properly disabled if the 1st DPU
> > > instance is unbound.
> > 
> > Why it wouldn't be reset?
> 
> Because dpu_core_remove() is not called for the 2nd DPU instance.
> Anyway, with the above new design, this doesn't seem to be a problem
> any more.

Ok.

> > 
> > > Although the two DPU instances could be wrapped by two DRM devices, I
> > > tend not to do that because downstream bridges in future SoCs might be
> > > able to mux to different DPU instances at runtime.
> > >
> > > Due to the disablement issue, can we set drm_dev_enter/exit/unplug
> > > aside first?
> > 
> > I'd rather have that figured out prior to merging.
> 
> I'm assuming that drm_dev_enter/exit/unplug won't be needed with the above
> new design - one DPU instance wrapped by one DRM device.

I'm not sure why you are making that claim. And again, that's good
practice: it does no harm while preventing unsafe behaviour in the
future.

> > > > > +static void dpu_atomic_put_plane_state(struct drm_atomic_state
> > *state,
> > > > > +struct drm_plane *plane)
> > > > > +{
> > > > > + int index = drm_plane_index(plane);
> > > > > +
> > > > > + plane->funcs->atomic_destroy_state(plane, state-
> > >planes[index].state);
> > > > > + state->planes[index].ptr = NULL;
> > > > > + state->planes[index].state = NULL;
> > > > > + state->planes[index].old_state = NULL;
> > > > > + state->planes[index].new_state = NULL;
> > > > > +
> > > > > + drm_modeset_unlock(&plane->mutex);
> > > > > +
> > > > > + dpu_plane_dbg(plane, "put state\n");
> > > > > +}
> > > > > +
> > > > > +static void dpu_atomic_put_crtc_state(struct drm_atomic_state *state,
> > > > > +   struct drm_crtc *crtc)
> > > > > +{
> > > > > + int index = drm_crtc_index(crtc);
> > > > > +
> > > > > + crtc->funcs->atomic_destroy_state(crtc, 
> > > > > state->crtcs[index].state);
> > > > > + state->crtcs[index].ptr = NULL;
> > > > > + state->crtcs[index].state = NULL;
> > > > > + state->crtcs[index].old_st

[PATCH v11 3/5] drm/etnaviv: Allow bypass component framework

2023-10-03 Thread Sui Jingfeng
Component framework is used to bind multiple GPU cores to a virtual master,
but there are SoC/chipset that contain only one GPU core. In those case,
component framework can be avoided. The reason is that usperspace programs
(such as X server and Mesa) will search the PCI device to use precedently.
Creating a virtual master device for PCI(e) GPUs is unnecessary and
incurring troubles.

This patch add additional code paths to allow bypassing the component
frameworks, which pave the way for us to introduce the PCI device driver
wrapper. The goal is to share the code between the PCI driver and the
platform driver as much as possible. Platforms with a single GPU core could
also try non-component code path.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 48 +++-
 drivers/gpu/drm/etnaviv/etnaviv_drv.h |  1 +
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 83 +--
 drivers/gpu/drm/etnaviv/etnaviv_gpu.h |  7 +++
 4 files changed, 96 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 41ef7a8b7839..0b68c76d117e 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -25,6 +25,8 @@
 #include "etnaviv_mmu.h"
 #include "etnaviv_perfmon.h"
 
+static struct etnaviv_drm_private *etna_drm_priv_ptr;
+
 /*
  * DRM operations:
  */
@@ -545,10 +547,7 @@ static const struct drm_driver etnaviv_drm_driver = {
.minor  = 3,
 };
 
-/*
- * Platform driver:
- */
-static int etnaviv_bind(struct device *dev)
+static int etnaviv_drm_bind(struct device *dev, bool component)
 {
struct etnaviv_drm_private *priv;
struct drm_device *drm;
@@ -564,13 +563,17 @@ static int etnaviv_bind(struct device *dev)
goto out_put;
}
 
+   priv->drm = drm;
drm->dev_private = priv;
+   etna_drm_priv_ptr = priv;
 
dma_set_max_seg_size(dev, SZ_2G);
 
-   dev_set_drvdata(dev, drm);
+   if (component)
+   ret = component_bind_all(dev, drm);
+   else
+   ret = etnaviv_gpu_bind(dev, NULL, drm);
 
-   ret = component_bind_all(dev, drm);
if (ret < 0)
goto out_free_priv;
 
@@ -583,7 +586,10 @@ static int etnaviv_bind(struct device *dev)
return 0;
 
 out_unbind:
-   component_unbind_all(dev, drm);
+   if (component)
+   component_unbind_all(dev, drm);
+   else
+   etnaviv_gpu_unbind(dev, NULL, drm);
 out_free_priv:
etnaviv_free_private(priv);
 out_put:
@@ -592,14 +598,17 @@ static int etnaviv_bind(struct device *dev)
return ret;
 }
 
-static void etnaviv_unbind(struct device *dev)
+static void etnaviv_drm_unbind(struct device *dev, bool component)
 {
-   struct drm_device *drm = dev_get_drvdata(dev);
-   struct etnaviv_drm_private *priv = drm->dev_private;
+   struct etnaviv_drm_private *priv = etna_drm_priv_ptr;
+   struct drm_device *drm = priv->drm;
 
drm_dev_unregister(drm);
 
-   component_unbind_all(dev, drm);
+   if (component)
+   component_unbind_all(dev, drm);
+   else
+   etnaviv_gpu_unbind(dev, NULL, drm);
 
etnaviv_free_private(priv);
 
@@ -608,9 +617,22 @@ static void etnaviv_unbind(struct device *dev)
drm_dev_put(drm);
 }
 
+/*
+ * Platform driver:
+ */
+static int etnaviv_master_bind(struct device *dev)
+{
+   return etnaviv_drm_bind(dev, true);
+}
+
+static void etnaviv_master_unbind(struct device *dev)
+{
+   return etnaviv_drm_unbind(dev, true);
+}
+
 static const struct component_master_ops etnaviv_master_ops = {
-   .bind = etnaviv_bind,
-   .unbind = etnaviv_unbind,
+   .bind = etnaviv_master_bind,
+   .unbind = etnaviv_master_unbind,
 };
 
 static int etnaviv_pdev_probe(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index b3eb1662e90c..e58f82e698de 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -35,6 +35,7 @@ struct etnaviv_file_private {
 };
 
 struct etnaviv_drm_private {
+   struct drm_device *drm;
int num_gpus;
struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
gfp_t shm_gfp_mask;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 4aa7c59ae581..330f8a272184 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1756,8 +1756,7 @@ static const struct thermal_cooling_device_ops 
cooling_ops = {
.set_cur_state = etnaviv_gpu_cooling_set_cur_state,
 };
 
-static int etnaviv_gpu_bind(struct device *dev, struct device *master,
-   void *data)
+int etnaviv_gpu_bind(struct device *dev, struct device *master, void *data)
 {
struct drm_device *drm = data;
struct etnaviv_drm_private *priv = drm->dev_private;
@@ -1812,8 +181

[PATCH v11 0/5] drm/etnaviv: Add pci device driver wrapper

2023-10-03 Thread Sui Jingfeng
This series is add PCI device driver wrapper, to support the Vivante GC1000
GPU in LS2K1000 and LS7A1000.

The whole serie have been tested on LS3A5000+LS7A1000 board, with another
trivial patchset [1] applied beforehand.

[1] https://patchwork.freedesktop.org/series/119825/

v6:
* Fix build issue on system without CONFIG_PCI enabled
v7:
* Add a separate patch for the platform driver rearrangement (Bjorn)
* Switch to runtime check if the GPU is dma coherent or not (Lucas)
* Add ETNAVIV_PARAM_GPU_COHERENT to allow userspace to query (Lucas)
* Remove etnaviv_gpu.no_clk member (Lucas)
* Various Typos and coding style fixed (Bjorn)
v8:
* Fix typos and remove unnecessary header included (Bjorn).
* Add a dedicated function to create the virtual master platform
  device.
v9:
* Use PCI_VDEVICE() macro (Bjorn)
* Add trivial stubs for the PCI driver (Bjorn)
* Remove a redundant dev_err() usage (Bjorn)
* Clean up etnaviv_pdev_probe() with etnaviv_of_first_available_node()
v10:
* Add one more cleanup patch
* Resolve the conflict with a patch from Rob
* Make the dummy PCI stub inlined
* Print only if the platform is dma-coherrent
V11:
* Drop unnecessary changes (Lucas)
* Tweak according to other reviews of v10.

Sui Jingfeng (5):
  drm/etnaviv: Add a dedicated function to get various clocks
  drm/etnaviv: Add constructor and destructor function for
etnaviv_drm_private
  drm/etnaviv: Allow bypass component framework
  drm/etnaviv: Add driver support for the PCI devices
  drm/etnaviv: Add support for cached coherent caching mode

 drivers/gpu/drm/etnaviv/Kconfig   |   8 ++
 drivers/gpu/drm/etnaviv/Makefile  |   2 +
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 131 ++---
 drivers/gpu/drm/etnaviv/etnaviv_drv.h |  12 ++
 drivers/gpu/drm/etnaviv/etnaviv_gem.c |  16 ++-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 134 ++
 drivers/gpu/drm/etnaviv/etnaviv_gpu.h |   7 ++
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c |  74 
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h |  18 +++
 include/uapi/drm/etnaviv_drm.h|   1 +
 10 files changed, 314 insertions(+), 89 deletions(-)
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h

-- 
2.34.1



[PATCH v11 1/5] drm/etnaviv: Add a dedicated function to get various clocks

2023-10-03 Thread Sui Jingfeng
Because the current implement is platform-dependent, there are systems
which don't has the DT-based clock device drivers support. Such as x86
and Loongarch desktop platform. Don't rage quit if so. For the GPU in
LS7A1000/LS2K1000, the working frequency of the GPU is control by the GFX
PLL hardware. Typically, the GFX PLL will be configured by the platform
BIOS(either UEFI or PMON) on per boot time.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 53 ---
 1 file changed, 32 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 9276756e1397..4aa7c59ae581 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1586,6 +1586,35 @@ static irqreturn_t irq_handler(int irq, void *data)
return ret;
 }
 
+static int etnaviv_gpu_clk_get(struct etnaviv_gpu *gpu)
+{
+   struct device *dev = gpu->dev;
+
+   gpu->clk_reg = devm_clk_get_optional(dev, "reg");
+   DBG("clk_reg: %p", gpu->clk_reg);
+   if (IS_ERR(gpu->clk_reg))
+   return PTR_ERR(gpu->clk_reg);
+
+   gpu->clk_bus = devm_clk_get_optional(dev, "bus");
+   DBG("clk_bus: %p", gpu->clk_bus);
+   if (IS_ERR(gpu->clk_bus))
+   return PTR_ERR(gpu->clk_bus);
+
+   gpu->clk_core = devm_clk_get(dev, "core");
+   DBG("clk_core: %p", gpu->clk_core);
+   if (IS_ERR(gpu->clk_core))
+   return PTR_ERR(gpu->clk_core);
+   gpu->base_rate_core = clk_get_rate(gpu->clk_core);
+
+   gpu->clk_shader = devm_clk_get_optional(dev, "shader");
+   DBG("clk_shader: %p", gpu->clk_shader);
+   if (IS_ERR(gpu->clk_shader))
+   return PTR_ERR(gpu->clk_shader);
+   gpu->base_rate_shader = clk_get_rate(gpu->clk_shader);
+
+   return 0;
+}
+
 static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu)
 {
int ret;
@@ -1861,27 +1890,9 @@ static int etnaviv_gpu_platform_probe(struct 
platform_device *pdev)
}
 
/* Get Clocks: */
-   gpu->clk_reg = devm_clk_get_optional(&pdev->dev, "reg");
-   DBG("clk_reg: %p", gpu->clk_reg);
-   if (IS_ERR(gpu->clk_reg))
-   return PTR_ERR(gpu->clk_reg);
-
-   gpu->clk_bus = devm_clk_get_optional(&pdev->dev, "bus");
-   DBG("clk_bus: %p", gpu->clk_bus);
-   if (IS_ERR(gpu->clk_bus))
-   return PTR_ERR(gpu->clk_bus);
-
-   gpu->clk_core = devm_clk_get(&pdev->dev, "core");
-   DBG("clk_core: %p", gpu->clk_core);
-   if (IS_ERR(gpu->clk_core))
-   return PTR_ERR(gpu->clk_core);
-   gpu->base_rate_core = clk_get_rate(gpu->clk_core);
-
-   gpu->clk_shader = devm_clk_get_optional(&pdev->dev, "shader");
-   DBG("clk_shader: %p", gpu->clk_shader);
-   if (IS_ERR(gpu->clk_shader))
-   return PTR_ERR(gpu->clk_shader);
-   gpu->base_rate_shader = clk_get_rate(gpu->clk_shader);
+   err = etnaviv_gpu_clk_get(gpu);
+   if (err)
+   return err;
 
/* TODO: figure out max mapped size */
dev_set_drvdata(dev, gpu);
-- 
2.34.1



[PATCH v11 4/5] drm/etnaviv: Add driver support for the PCI devices

2023-10-03 Thread Sui Jingfeng
There is a Vivante GC1000 GPU (v5037) in Loongson LS2K1000 (0x0014:0x7a05)
and LS7A1000 (0x0014:0x7a15), the GPU in these chips is a PCI(e) device.
This patch adds PCI driver wrapper for this gpu. This GPU has only one GPU
core, there no need to bind to anything for now. Hence, the component
framework get bypassed.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/Kconfig   |  8 +++
 drivers/gpu/drm/etnaviv/Makefile  |  2 +
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 10 ++-
 drivers/gpu/drm/etnaviv/etnaviv_drv.h |  3 +
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c | 74 +++
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h | 18 ++
 6 files changed, 113 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h

diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig
index faa7fc68b009..38c251585ec1 100644
--- a/drivers/gpu/drm/etnaviv/Kconfig
+++ b/drivers/gpu/drm/etnaviv/Kconfig
@@ -15,6 +15,14 @@ config DRM_ETNAVIV
help
  DRM driver for Vivante GPUs.
 
+config DRM_ETNAVIV_PCI_DRIVER
+   bool "enable ETNAVIV PCI driver support"
+   depends on DRM_ETNAVIV
+   depends on PCI
+   help
+ Compile in support for Vivante GPUs attached via PCI(e).
+ Say Y if you have such hardwares.
+
 config DRM_ETNAVIV_THERMAL
bool "enable ETNAVIV thermal throttling"
depends on DRM_ETNAVIV
diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
index 46e5ffad69a6..6829e1ebf2db 100644
--- a/drivers/gpu/drm/etnaviv/Makefile
+++ b/drivers/gpu/drm/etnaviv/Makefile
@@ -16,4 +16,6 @@ etnaviv-y := \
etnaviv_perfmon.o \
etnaviv_sched.o
 
+etnaviv-$(CONFIG_DRM_ETNAVIV_PCI_DRIVER) += etnaviv_pci_drv.o
+
 obj-$(CONFIG_DRM_ETNAVIV)  += etnaviv.o
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 0b68c76d117e..8db86120b11d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -23,6 +23,7 @@
 #include "etnaviv_gpu.h"
 #include "etnaviv_gem.h"
 #include "etnaviv_mmu.h"
+#include "etnaviv_pci_drv.h"
 #include "etnaviv_perfmon.h"
 
 static struct etnaviv_drm_private *etna_drm_priv_ptr;
@@ -547,7 +548,7 @@ static const struct drm_driver etnaviv_drm_driver = {
.minor  = 3,
 };
 
-static int etnaviv_drm_bind(struct device *dev, bool component)
+int etnaviv_drm_bind(struct device *dev, bool component)
 {
struct etnaviv_drm_private *priv;
struct drm_device *drm;
@@ -598,7 +599,7 @@ static int etnaviv_drm_bind(struct device *dev, bool 
component)
return ret;
 }
 
-static void etnaviv_drm_unbind(struct device *dev, bool component)
+void etnaviv_drm_unbind(struct device *dev, bool component)
 {
struct etnaviv_drm_private *priv = etna_drm_priv_ptr;
struct drm_device *drm = priv->drm;
@@ -758,6 +759,10 @@ static int __init etnaviv_init(void)
if (ret != 0)
goto unregister_gpu_driver;
 
+   ret = etnaviv_register_pci_driver();
+   if (ret != 0)
+   goto unregister_platform_driver;
+
/*
 * If the DT contains at least one available GPU device, instantiate
 * the DRM platform device.
@@ -786,6 +791,7 @@ static void __exit etnaviv_exit(void)
etnaviv_destroy_platform_device(&etnaviv_drm);
platform_driver_unregister(&etnaviv_platform_driver);
platform_driver_unregister(&etnaviv_gpu_driver);
+   etnaviv_unregister_pci_driver();
 }
 module_exit(etnaviv_exit);
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index e58f82e698de..9cd72948cfad 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -83,6 +83,9 @@ bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
u32 *stream, unsigned int size,
struct drm_etnaviv_gem_submit_reloc *relocs, unsigned int reloc_size);
 
+int etnaviv_drm_bind(struct device *dev, bool component);
+void etnaviv_drm_unbind(struct device *dev, bool component);
+
 #ifdef CONFIG_DEBUG_FS
 void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
struct seq_file *m);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
new file mode 100644
index ..37de661844d8
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+
+#include "etnaviv_drv.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_pci_drv.h"
+
+static int etnaviv_pci_probe(struct pci_dev *pdev,
+const struct pci_device_id *ent)
+{
+   struct device *dev = &pdev->dev;
+   void __iomem *mmio;
+   int ret;
+
+   ret = pcim_enable_device(pdev);
+   if (ret) {
+   dev_err(dev, 

[PATCH v11 2/5] drm/etnaviv: Add constructor and destructor function for etnaviv_drm_private

2023-10-03 Thread Sui Jingfeng
Noticed that there are a lot of members in the struct etnaviv_drm_private,
which are intended to be shared by all GPU core. This patch introduces two
helper functions for the construction and destruction of the instances of
it. A side benefit is that the error handling needed can be simplified.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 70 +--
 1 file changed, 44 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index a9a1659840ec..41ef7a8b7839 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -41,6 +41,43 @@ static struct device_node 
*etnaviv_of_first_available_node(void)
return NULL;
 }
 
+static struct etnaviv_drm_private *etnaviv_alloc_private(struct device *dev)
+{
+   struct etnaviv_drm_private *priv;
+
+   priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+   if (!priv)
+   return ERR_PTR(-ENOMEM);
+
+   xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);
+
+   mutex_init(&priv->gem_lock);
+   INIT_LIST_HEAD(&priv->gem_list);
+   priv->num_gpus = 0;
+   priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
+
+   priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(dev);
+   if (IS_ERR(priv->cmdbuf_suballoc)) {
+   kfree(priv);
+   dev_err(dev, "Failed to create cmdbuf suballocator\n");
+   return ERR_PTR(-ENOMEM);
+   }
+
+   return priv;
+}
+
+static void etnaviv_free_private(struct etnaviv_drm_private *priv)
+{
+   if (!priv)
+   return;
+
+   etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
+
+   xa_destroy(&priv->active_contexts);
+
+   kfree(priv);
+}
+
 static void load_gpu(struct drm_device *dev)
 {
struct etnaviv_drm_private *priv = dev->dev_private;
@@ -521,35 +558,21 @@ static int etnaviv_bind(struct device *dev)
if (IS_ERR(drm))
return PTR_ERR(drm);
 
-   priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-   if (!priv) {
-   dev_err(dev, "failed to allocate private data\n");
-   ret = -ENOMEM;
+   priv = etnaviv_alloc_private(dev);
+   if (IS_ERR(priv)) {
+   ret = PTR_ERR(priv);
goto out_put;
}
+
drm->dev_private = priv;
 
dma_set_max_seg_size(dev, SZ_2G);
 
-   xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);
-
-   mutex_init(&priv->gem_lock);
-   INIT_LIST_HEAD(&priv->gem_list);
-   priv->num_gpus = 0;
-   priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
-
-   priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev);
-   if (IS_ERR(priv->cmdbuf_suballoc)) {
-   dev_err(drm->dev, "Failed to create cmdbuf suballocator\n");
-   ret = PTR_ERR(priv->cmdbuf_suballoc);
-   goto out_free_priv;
-   }
-
dev_set_drvdata(dev, drm);
 
ret = component_bind_all(dev, drm);
if (ret < 0)
-   goto out_destroy_suballoc;
+   goto out_free_priv;
 
load_gpu(drm);
 
@@ -561,10 +584,8 @@ static int etnaviv_bind(struct device *dev)
 
 out_unbind:
component_unbind_all(dev, drm);
-out_destroy_suballoc:
-   etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
 out_free_priv:
-   kfree(priv);
+   etnaviv_free_private(priv);
 out_put:
drm_dev_put(drm);
 
@@ -580,12 +601,9 @@ static void etnaviv_unbind(struct device *dev)
 
component_unbind_all(dev, drm);
 
-   etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
-
-   xa_destroy(&priv->active_contexts);
+   etnaviv_free_private(priv);
 
drm->dev_private = NULL;
-   kfree(priv);
 
drm_dev_put(drm);
 }
-- 
2.34.1



[PATCH v11 5/5] drm/etnaviv: Add support for cached coherent caching mode

2023-10-03 Thread Sui Jingfeng
Loongson CPUs maintain cache coherency by hardware, which means that the
data in the CPU cache is identical to the data in main system memory.
As for the peripheral device, most of Loongson chips choose to define the
peripherals as DMA coherent by default, device drivers do not need to
maintain the coherency between a processor and an I/O device manually.

The above sttement is true for *cached* buffers only, this patch say
nothing about WC buffers, it is likely implement-dependent. WC buffers
can be DMA non-coherent on specific platform.

Also because vivante GPU IP has been integrated into various platform, we
need to do the probe work. this patch add code to test if a specific
platform is cached coherent, utilize such hardware feature where suitable.
And allow userspace to query.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c |  7 +++
 drivers/gpu/drm/etnaviv/etnaviv_drv.h |  8 
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 16 ++--
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c |  4 
 include/uapi/drm/etnaviv_drm.h|  1 +
 5 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 8db86120b11d..3598e2f840b3 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -5,6 +5,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -66,6 +67,12 @@ static struct etnaviv_drm_private 
*etnaviv_alloc_private(struct device *dev)
return ERR_PTR(-ENOMEM);
}
 
+   /*
+* The device_get_dma_attr(dev) == DEV_DMA_COHERENT don't work
+* on LoongArch platform, so still use dev_is_dma_coherent(dev).
+*/
+   priv->cached_coherent = dev_is_dma_coherent(dev);
+
return priv;
 }
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 9cd72948cfad..760048c35481 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -46,6 +46,14 @@ struct etnaviv_drm_private {
struct xarray active_contexts;
u32 next_context_id;
 
+   /*
+* If true, the GPU is capable of snooping CPU's cache. It means
+* that cached buffer is coherent for both of the CPU and GPU's
+* access. And the coherency is guaranteed by platform hardware.
+* Software enforced coherency does not count here.
+*/
+   bool cached_coherent;
+
/* list of GEM objects: */
struct mutex gem_lock;
struct list_head gem_list;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 71a6d2b1c80f..a72ca0a6883e 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -342,6 +342,7 @@ void *etnaviv_gem_vmap(struct drm_gem_object *obj)
 static void *etnaviv_gem_vmap_impl(struct etnaviv_gem_object *obj)
 {
struct page **pages;
+   pgprot_t prot;
 
lockdep_assert_held(&obj->lock);
 
@@ -349,8 +350,19 @@ static void *etnaviv_gem_vmap_impl(struct 
etnaviv_gem_object *obj)
if (IS_ERR(pages))
return NULL;
 
-   return vmap(pages, obj->base.size >> PAGE_SHIFT,
-   VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+   switch (obj->flags) {
+   case ETNA_BO_CACHED:
+   prot = PAGE_KERNEL;
+   break;
+   case ETNA_BO_UNCACHED:
+   prot = pgprot_noncached(PAGE_KERNEL);
+   break;
+   case ETNA_BO_WC:
+   default:
+   prot = pgprot_writecombine(PAGE_KERNEL);
+   }
+
+   return vmap(pages, obj->base.size >> PAGE_SHIFT, VM_MAP, prot);
 }
 
 static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 330f8a272184..95304273 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -164,6 +164,10 @@ int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 
param, u64 *value)
*value = gpu->identity.eco_id;
break;
 
+   case ETNAVIV_PARAM_CACHED_COHERENT:
+   *value = priv->cached_coherent;
+   break;
+
default:
DBG("%s: invalid param: %u", dev_name(gpu->dev), param);
return -EINVAL;
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
index af024d90453d..61eaa8cd0f5e 100644
--- a/include/uapi/drm/etnaviv_drm.h
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -77,6 +77,7 @@ struct drm_etnaviv_timespec {
 #define ETNAVIV_PARAM_GPU_PRODUCT_ID0x1c
 #define ETNAVIV_PARAM_GPU_CUSTOMER_ID   0x1d
 #define ETNAVIV_PARAM_GPU_ECO_ID0x1e
+#define ETNAVIV_PARAM_CACHED_COHERENT   0x1f
 
 #define ETNA_MAX_PIPES 4
 
-- 
2.34.1



Re: [PATCH v2 3/6] dt-bindings: display: msm: Add SDM670 MDSS

2023-10-03 Thread Krzysztof Kozlowski
On 03/10/2023 12:31, Dmitry Baryshkov wrote:
>>> +patternProperties:
>>> +  "^display-controller@[0-9a-f]+$":
>>> +type: object
>>> +additionalProperties: true
>>> +
>>> +properties:
>>> +  compatible:
>>> +const: qcom,sdm670-dpu
>>> +
>>> +  "^displayport-controller@[0-9a-f]+$":
>>> +type: object
>>> +additionalProperties: true
>>> +
>>> +properties:
>>> +  compatible:
>>> +const: qcom,sdm670-dp
>>> +
>>> +  "^dsi@[0-9a-f]+$":
>>> +type: object
>>> +additionalProperties: true
>>> +
>>> +properties:
>>> +  compatible:
>>> +contains:
>>> +  const: qcom,sdm670-dsi-ctrl
>>> +
>>> +  "^phy@[0-9a-f]+$":
>>> +type: object
>>> +additionalProperties: true
>>> +
>>> +properties:
>>> +  compatible:
>>> +const: qcom,dsi-phy-10nm
>>
>> This does not look right. Why the compatible is generic, not SoC-specific?
> 
> Because for 10nm DSI PHY we don't have SoC-specific compatibles other
> than the ugly 8998 compat string.

OK.


Best regards,
Krzysztof



Re: [PATCH v2] drm: panel-orientation-quirks: Add quirk for One Mix 2S

2023-10-03 Thread Liviu Dudau
On Sun, Oct 01, 2023 at 02:21:43PM +0200, Hans de Goede wrote:
> Hi,
> 
> On 10/1/23 13:47, Kai Uwe Broulik wrote:
> > The One Mix 2S is a mini laptop with a 1200x1920 portrait screen
> > mounted in a landscape oriented clamshell case. Because of the too
> > generic DMI strings this entry is also doing bios-date matching.
> > 
> > Signed-off-by: Kai Uwe Broulik 
> > ---
> > Changes since v1:
> > * Got two more BIOS dates reported
> 
> Thanks, patch still looks good to me:
> 
> Reviewed-by: Hans de Goede 
> 
> drm-misc maintainers, I'm currently traveling can
> one of you push this to drm-misc-fixes please?

Done. Have a safe trip.

Best regards,
Liviu

> 
> Regards,
> 
> Hans
> 
> 
> 
> 
> > 
> >  drivers/gpu/drm/drm_panel_orientation_quirks.c | 16 
> >  1 file changed, 16 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c 
> > b/drivers/gpu/drm/drm_panel_orientation_quirks.c
> > index 0cb646cb04ee..d5c15292ae93 100644
> > --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
> > +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
> > @@ -38,6 +38,14 @@ static const struct drm_dmi_panel_orientation_data 
> > gpd_micropc = {
> > .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
> >  };
> >  
> > +static const struct drm_dmi_panel_orientation_data gpd_onemix2s = {
> > +   .width = 1200,
> > +   .height = 1920,
> > +   .bios_dates = (const char * const []){ "05/21/2018", "10/26/2018",
> > +   "03/04/2019", NULL },
> > +   .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
> > +};
> > +
> >  static const struct drm_dmi_panel_orientation_data gpd_pocket = {
> > .width = 1200,
> > .height = 1920,
> > @@ -401,6 +409,14 @@ static const struct dmi_system_id orientation_data[] = 
> > {
> >   DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LTH17"),
> > },
> > .driver_data = (void *)&lcd800x1280_rightside_up,
> > +   }, {/* One Mix 2S (generic strings, also match on bios date) */
> > +   .matches = {
> > + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
> > + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
> > + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string"),
> > + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
> > +   },
> > +   .driver_data = (void *)&gpd_onemix2s,
> > },
> > {}
> >  };
> 

-- 

| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---
¯\_(ツ)_/¯


Re: [PATCH v17 13/18] drm/shmem-helper: Add memory shrinker

2023-10-03 Thread Boris Brezillon
On Mon, 2 Oct 2023 22:28:13 +0300
Dmitry Osipenko  wrote:

> On 9/26/23 10:35, Boris Brezillon wrote:
> >> On 9/15/23 11:46, Boris Brezillon wrote:  
> >>> The naming becomes quite confusing, with drm_gem_shmem_unpin_locked()
> >>> and drm_gem_shmem_unpin_pages_locked(). By the look of it, it seems to
> >>> do exactly the opposite of drm_gem_shmem_swapin_locked(), except for
> >>> the missing ->evicted = true, which we can move here anyway, given
> >>> drm_gem_shmem_purge_locked() explicitly set it to false anyway. The
> >>> other thing that's missing is the
> >>> drm_gem_shmem_update_pages_state_locked(), but it can also be moved
> >>> there I think, if the the ->madv update happens before the
> >>> drm_gem_shmem_unpin_pages_locked() call in
> >>> drm_gem_shmem_purge_locked().
> >>>
> >>> So, how about renaming this function drm_gem_shmem_swapout_locked()?
> >> The swapout name would be misleading to me because pages aren't moved to
> >> swap, but allowed to be moved. I'll rename it to
> >> drm_gem_shmem_shrinker_unpin_locked().  
> > If you go this way, I would argue that drm_gem_shmem_swapin_locked() is
> > just as incorrect as drm_gem_shmem_swapout_locked(), in that
> > drm_gem_get_pages() might just return pages that were flagged
> > reclaimable but never reclaimed/swapped-out. I do think that having
> > some symmetry in the naming makes more sense than being 100% accurate.  
> 
> That function is internal to drm-shmem and is used for both eviction and
> purging. Having "swap-out" invoked by the purging also doesn't sound good.

The part that discards the GEM in the shmem file is outside this
function (shmem_truncate_range()), so all this function does in practice
is flag the pages as evictable (or rather, clear the unevictable flag),
so they can be reclaimed. The swapout suggesting was mostly based on
the fact it does exactly the opposite of swapin().

> 
> Given that the function in question mainly "unmaps" the pages, what
> about drm_gem_shmem_shkinker_unmap_pages_locked()?

Unmap tends to refer to a VM related operation (removing a mapping in
the CPU or GPU VM), so it's confusing too IMHO. What we do here is
return pages to the shmem file logic, so they can be reclaimed.

Given the drm_gem function doing that is called drm_gem_put_pages(),
maybe rename it drm_gem_shmem_shrinker_put_pages_locked(), and rename
drm_gem_shmem_swapin_locked() into
drm_gem_shmem_shrinker_get_pages_locked(), to be consistent.

> 
>   {
>   struct drm_gem_object *obj = &shmem->base;
>   struct drm_device *dev = obj->dev;
>   
>   dma_resv_assert_held(shmem->base.resv);
>   
>  -drm_WARN_ON(obj->dev, !drm_gem_shmem_is_purgeable(shmem));
>  +if (shmem->evicted)
>  +return;
>   
>   dma_unmap_sgtable(dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0);  
>    
> >>> Are we sure we'll always have sgt != NULL? IIRC, if the GEM is only
> >>> mmap-ed in userspace, get_sgt() is not necessarily called by the driver
> >>> (needed to map in GPU space), and we have a potential NULL deref here.
> >>> Maybe that changed at some point in the series, and sgt is
> >>> unconditionally populated when get_pages() is called now.
> >> The sgt is always set in this function because it's part of shrinker and
> >> shrinker doesn't touch GEMs without sgt.  
> > Okay, that's questionable. Why would we not want to reclaim BOs that
> > are only mapped in userspace (sgt == NULL && pages_use_count > 0 &&
> > pages_pin_count == 0)? I agree that creating such a BO would be
> > pointless (why create a buffer through DRM if it's not passed to the
> > GPU), but that's still something the API allows...  
> 
> This is a pre-existing behaviour. There is no driver that uses pages
> without sgt, hence there is nobody to test such code paths.
> 
> Maybe will worth to explicitly prohibit usage of get_pages() without
> having sgt for clarity.

Nope, I don't think we should. Panthor is dissociating the BO creation
for the GPU VM map operation, meaning we only get to ask for an sgt when
the BO is first mapped in GPU space. In the meantime, the shrinker logic
might decide to evict an object that has been already CPU-mapped (using
mmap()).

> But this should be separate to this patchset, IMO.

FYI, I'm not being picky just for fun, I do intend to use the
shmem-shrinker in panthor at some point, and I think it's important to
get it right from the beginning, even if all your existing users don't
care. I mean, I would understand if what I was asking was requiring
heavy changes to the existing logic, but, unless I'm wrong, I don't
think it does.


Re: [PATCH v2 3/6] dt-bindings: display: msm: Add SDM670 MDSS

2023-10-03 Thread Dmitry Baryshkov
On Tue, 3 Oct 2023 at 11:48, Krzysztof Kozlowski
 wrote:
>
> On 03/10/2023 03:21, Richard Acayan wrote:
> > Add documentation for the SDM670 display subsystem, adapted from the
> > SDM845 and SM6125 documentation.
> >
> > Signed-off-by: Richard Acayan 
> > ---
> >  .../display/msm/qcom,sdm670-mdss.yaml | 287 ++
> >  1 file changed, 287 insertions(+)
> >  create mode 100644 
> > Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml
> >
> > diff --git 
> > a/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml 
> > b/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml
> > new file mode 100644
> > index ..9995b018cd9e
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml
> > @@ -0,0 +1,287 @@
> > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/display/msm/qcom,sdm670-mdss.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Qualcomm SDM670 Display MDSS
> > +
> > +maintainers:
> > +  - Richard Acayan 
> > +
> > +description:
> > +  SDM670 MSM Mobile Display Subsystem (MDSS), which encapsulates sub-blocks
> > +  like DPU display controller, DSI and DP interfaces etc.
> > +
> > +$ref: /schemas/display/msm/mdss-common.yaml#
> > +
> > +properties:
> > +  compatible:
> > +const: qcom,sdm670-mdss
> > +
> > +  clocks:
> > +items:
> > +  - description: Display AHB clock from gcc
> > +  - description: Display core clock
> > +
> > +  clock-names:
> > +items:
> > +  - const: iface
> > +  - const: core
> > +
> > +  iommus:
> > +maxItems: 2
> > +
> > +  interconnects:
> > +maxItems: 2
> > +
> > +  interconnect-names:
> > +maxItems: 2
> > +
> > +patternProperties:
> > +  "^display-controller@[0-9a-f]+$":
> > +type: object
> > +additionalProperties: true
> > +
> > +properties:
> > +  compatible:
> > +const: qcom,sdm670-dpu
> > +
> > +  "^displayport-controller@[0-9a-f]+$":
> > +type: object
> > +additionalProperties: true
> > +
> > +properties:
> > +  compatible:
> > +const: qcom,sdm670-dp
> > +
> > +  "^dsi@[0-9a-f]+$":
> > +type: object
> > +additionalProperties: true
> > +
> > +properties:
> > +  compatible:
> > +contains:
> > +  const: qcom,sdm670-dsi-ctrl
> > +
> > +  "^phy@[0-9a-f]+$":
> > +type: object
> > +additionalProperties: true
> > +
> > +properties:
> > +  compatible:
> > +const: qcom,dsi-phy-10nm
>
> This does not look right. Why the compatible is generic, not SoC-specific?

Because for 10nm DSI PHY we don't have SoC-specific compatibles other
than the ugly 8998 compat string.

>
> > +
> > +required:
> > +  - compatible
> > +
> > +unevaluatedProperties: false
> > +
> > +examples:
> > +  - |
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +display-subsystem@ae0 {
> > +compatible = "qcom,sdm670-mdss";
> > +reg = <0x0ae0 0x1000>;
> > +reg-names = "mdss";
> > +power-domains = <&dispcc MDSS_GDSC>;
> > +
> > +clocks = <&gcc GCC_DISP_AHB_CLK>,
> > + <&dispcc DISP_CC_MDSS_MDP_CLK>;
> > +clock-names = "iface", "core";
> > +
> > +interrupts = ;
> > +interrupt-controller;
> > +#interrupt-cells = <1>;
> > +
>
> Please add interconnects. They do not have to be 100% exact with DTS
> (unless interconnect header is not merged?). This is just an example.
>
> > +iommus = <&apps_smmu 0x880 0x8>,
> > + <&apps_smmu 0xc80 0x8>;
>
> > +
> > +#address-cells = <1>;
> > +#size-cells = <1>;
> > +ranges;
> > +
>
> Best regards,
> Krzysztof
>


-- 
With best wishes
Dmitry


Re: [PATCH v3 1/2] dt-bindings: backlight: Add MPS MP3309C

2023-10-03 Thread Daniel Thompson
On Tue, Oct 03, 2023 at 09:43:15AM +, Flavio Suligoi wrote:
> Hi Daniel,
>
> ...
>
> > > +required:
> > > +  - compatible
> > > +  - reg
> > > +  - max-brightness
> >
> > Why is this mandatory?
> >
> > There's no point in setting max-brightness when running in I2C mode (max-
> > brightness should default to 31 in that case).
> >
> >
> > > +  - default-brightness
> >
> > Again. I'm not clear why this needs to be mandatory.
> >
> >
>
> Ok, you are right, I'll remove max-brightness and default-brightness
> from required properties list. I think to change these properties,
> for the pwm dimming, into a clearer:
>
> - brightness-levels (uint32)
> - default-brightness-levels (uint32).
>
> For example:
>
>   brightness-levels:
> description:
>   Number of brightness levels. The actual brightness
>   level (PWM duty cycle) will be interpolated from 0 to this value.
>   0 means a  0% duty cycle (darkest/off), while the brightness-levels 
> represents
>   a 100% duty cycle (brightest).
> $ref: /schemas/types.yaml#/definitions/uint32
>
>   default-brightness-level:
> description:
>   The default brightness level (from 0 to brightness-levels)
> $ref: /schemas/types.yaml#/definitions/uint32
>
> Example:
> brightness-levels = <10>;
> default-brightness-level = <6>;
>
> What do you think about this solution?

If you want to introduce a brightness-levels property then I would
expect it to be defined with the same meaning as pwm-backlight (it's not
relevant to the bindings but ideally it would be implemented by
refactoring and reusing the code from pwm_bl.c).

Same with default-brightness-level although I'm not sure why one
wouldn't just use default-brightness for new bindings (doesn't
default-brightness-level simply do exactly the same thing as
default-brightness).


Daniel.


Re: [PATCH drm-misc-next v5 4/6] drm/gpuvm: track/lock/validate external/evicted objects

2023-10-03 Thread Boris Brezillon
Hello Thomas,

On Tue, 3 Oct 2023 10:36:10 +0200
Thomas Hellström  wrote:

> > +/**
> > + * get_next_vm_bo_from_list() - get the next vm_bo element
> > + * @__gpuvm: The GPU VM
> > + * @__list_name: The name of the list we're iterating on
> > + * @__local_list: A pointer to the local list used to store already 
> > iterated items
> > + * @__prev_vm_bo: The previous element we got from 
> > drm_gpuvm_get_next_cached_vm_bo()
> > + *
> > + * This helper is here to provide lockless list iteration. Lockless as in, 
> > the
> > + * iterator releases the lock immediately after picking the first element 
> > from
> > + * the list, so list insertion deletion can happen concurrently.
> > + *
> > + * Elements popped from the original list are kept in a local list, so 
> > removal
> > + * and is_empty checks can still happen while we're iterating the list.
> > + */
> > +#define get_next_vm_bo_from_list(__gpuvm, __list_name, __local_list, 
> > __prev_vm_bo) \
> > +   ({  
> > \
> > +   struct drm_gpuvm_bo *__vm_bo = NULL;
> > \
> > +   
> > \
> > +   drm_gpuvm_bo_put(__prev_vm_bo); 
> > \
> > +   
> > \
> > +   spin_lock(&(__gpuvm)->__list_name.lock);
> > \  
> 
> Here we unconditionally take the spinlocks while iterating, and the main 
> point of DRM_GPUVM_RESV_PROTECTED was really to avoid that?
> 
> 
> > +   if (!(__gpuvm)->__list_name.local_list) 
> > \
> > +   (__gpuvm)->__list_name.local_list = __local_list;   
> > \
> > +   else
> > \
> > +   WARN_ON((__gpuvm)->__list_name.local_list != 
> > __local_list); \
> > +   
> > \
> > +   while (!list_empty(&(__gpuvm)->__list_name.list)) { 
> > \
> > +   __vm_bo = 
> > list_first_entry(&(__gpuvm)->__list_name.list,\
> > +  struct drm_gpuvm_bo, 
> > \
> > +  list.entry.__list_name); 
> > \
> > +   if (kref_get_unless_zero(&__vm_bo->kref)) {  
> And unnecessarily grab a reference in the RESV_PROTECTED case.
> > \
> > +   
> > list_move_tail(&(__vm_bo)->list.entry.__list_name,  \
> > +  __local_list);   
> > \
> > +   break;  
> > \
> > +   } else {
> > \
> > +   
> > list_del_init(&(__vm_bo)->list.entry.__list_name);  \
> > +   __vm_bo = NULL; 
> > \
> > +   }   
> > \
> > +   }   
> > \
> > +   spin_unlock(&(__gpuvm)->__list_name.lock);  
> > \
> > +   
> > \
> > +   __vm_bo;
> > \
> > +   })  
> 
> IMHO this lockless list iteration looks very complex and should be 
> pretty difficult to maintain while moving forward, also since it pulls 
> the gpuvm_bos off the list, list iteration needs to be protected by an 
> outer lock anyway.

As being partly responsible for this convoluted list iterator, I must
say I agree with you. There's so many ways this can go wrong if the
user doesn't call it the right way, or doesn't protect concurrent list
iterations with a separate lock (luckily, this is a private iterator). I
mean, it works, so there's certainly a way to get it right, but gosh,
this is so far from the simple API I had hoped for.

> Also from what I understand from Boris, the extobj 
> list would typically not need the fine-grained locking; only the evict 
> list?

Right, I'm adding the gpuvm_bo to extobj list in the ioctl path, when
the GEM and VM resvs are held, and I'm deferring the drm_gpuvm_bo_put()
call to a work that's not in the dma-signalling path. This being said,
I'm still not comfortable with the

gem = drm_gem_object_get(vm_bo->gem);
dma_resv_lock(gem->resv);
drm_gpuvm_bo_put(vm_bo);
dma_resv_unlock(gem->resv);
drm_gem_object_put(gem);

dance that's needed to avoid a UAF when the gpuvm_bo is the last GEM

Re: [RFC PATCH v1 03/12] drm/connector: extend PATH property to covert Type-C case

2023-10-03 Thread Simon Ser
On Sunday, September 3rd, 2023 at 23:41, Dmitry Baryshkov 
 wrote:

> To facilitate this, reuse the 'PATH' property, which was used to
> describe the DP port in the DP MST configuration. Use either
> 'typec:portN' to point out to the Type-C port class device, or just
> 'typec:' if the corresponding port can not be identified.

Typo: should be "typec" without the colon I think?

What are the situations where the port cannot be identified? It seems
weird to use the PATH property in that case.


Re: [PATCH drm-misc-next v5 4/6] drm/gpuvm: track/lock/validate external/evicted objects

2023-10-03 Thread Thomas Hellström

Hi Again,


On 10/3/23 10:36, Thomas Hellström wrote:

Hi, Danilo,

On 9/28/23 21:16, Danilo Krummrich wrote:

Currently the DRM GPUVM offers common infrastructure to track GPU VA
allocations and mappings, generically connect GPU VA mappings to their
backing buffers and perform more complex mapping operations on the 
GPU VA

space.

However, there are more design patterns commonly used by drivers, which
can potentially be generalized in order to make the DRM GPUVM represent
a basis for GPU-VM implementations. In this context, this patch aims
at generalizing the following elements.

1) Provide a common dma-resv for GEM objects not being used outside of
    this GPU-VM.

2) Provide tracking of external GEM objects (GEM objects which are
    shared with other GPU-VMs).

3) Provide functions to efficiently lock all GEM objects dma-resv the
    GPU-VM contains mappings of.

4) Provide tracking of evicted GEM objects the GPU-VM contains mappings
    of, such that validation of evicted GEM objects is accelerated.

5) Provide some convinience functions for common patterns.

Big thanks to Boris Brezillon for his help to figure out locking for
drivers updating the GPU VA space within the fence signalling path.

Suggested-by: Matthew Brost 
Signed-off-by: Danilo Krummrich 
---
  drivers/gpu/drm/drm_gpuvm.c | 642 
  include/drm/drm_gpuvm.h | 240 ++
  2 files changed, 882 insertions(+)

diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c
index 27100423154b..770bb3d68d1f 100644
--- a/drivers/gpu/drm/drm_gpuvm.c
+++ b/drivers/gpu/drm/drm_gpuvm.c
@@ -82,6 +82,21 @@
   * &drm_gem_object list of &drm_gpuvm_bos for an existing instance 
of this
   * particular combination. If not existent a new instance is 
created and linked

   * to the &drm_gem_object.
+ *
+ * &drm_gpuvm_bo structures, since unique for a given &drm_gpuvm, 
are also used
+ * as entry for the &drm_gpuvm's lists of external and evicted 
objects. Those
+ * list are maintained in order to accelerate locking of dma-resv 
locks and
+ * validation of evicted objects bound in a &drm_gpuvm. For 
instance, all
+ * &drm_gem_object's &dma_resv of a given &drm_gpuvm can be locked 
by calling
+ * drm_gpuvm_exec_lock(). Once locked drivers can call 
drm_gpuvm_validate() in
+ * order to validate all evicted &drm_gem_objects. It is also 
possible to lock
+ * additional &drm_gem_objects by providing the corresponding 
parameters to
+ * drm_gpuvm_exec_lock() as well as open code the &drm_exec loop 
while making

+ * use of helper functions such as drm_gpuvm_prepare_range() or
+ * drm_gpuvm_prepare_objects().
+ *
+ * Every bound &drm_gem_object is treated as external object when 
its &dma_resv
+ * structure is different than the &drm_gpuvm's common &dma_resv 
structure.

   */
    /**
@@ -429,6 +444,20 @@
   * Subsequent calls to drm_gpuvm_bo_obtain() for the same 
&drm_gpuvm and
   * &drm_gem_object must be able to observe previous creations and 
destructions

   * of &drm_gpuvm_bos in order to keep instances unique.
+ *
+ * The &drm_gpuvm's lists for keeping track of external and evicted 
objects are
+ * protected against concurrent insertion / removal and iteration 
internally.

+ *
+ * However, drivers still need ensure to protect concurrent calls to 
functions

+ * iterating those lists, namely drm_gpuvm_prepare_objects() and
+ * drm_gpuvm_validate().
+ *
+ * Alternatively, drivers can set the &DRM_GPUVM_RESV_PROTECTED flag 
to indicate
+ * that the corresponding &dma_resv locks are held in order to 
protect the
+ * lists. If &DRM_GPUVM_RESV_PROTECTED is set, internal locking is 
disabled and
+ * the corresponding lockdep checks are enabled. This is an 
optimization for
+ * drivers which are capable of taking the corresponding &dma_resv 
locks and

+ * hence do not require internal locking.
   */
    /**
@@ -641,6 +670,195 @@
   *    }
   */
  +/**
+ * get_next_vm_bo_from_list() - get the next vm_bo element
+ * @__gpuvm: The GPU VM
+ * @__list_name: The name of the list we're iterating on
+ * @__local_list: A pointer to the local list used to store already 
iterated items
+ * @__prev_vm_bo: The previous element we got from 
drm_gpuvm_get_next_cached_vm_bo()

+ *
+ * This helper is here to provide lockless list iteration. Lockless 
as in, the
+ * iterator releases the lock immediately after picking the first 
element from

+ * the list, so list insertion deletion can happen concurrently.
+ *
+ * Elements popped from the original list are kept in a local list, 
so removal

+ * and is_empty checks can still happen while we're iterating the list.
+ */
+#define get_next_vm_bo_from_list(__gpuvm, __list_name, __local_list, 
__prev_vm_bo)    \

+    ({    \
+    struct drm_gpuvm_bo *__vm_bo = NULL; \
+    \
+    drm_gpuvm_bo_put(__prev_vm_bo); \
+    \
+ spin_lock(&(__gpuvm)->__list_nam

Re: [PATCH v1] drm/msm/dp: do not reinitialize phy unless retry during link training

2023-10-03 Thread Johan Hovold
On Tue, Aug 08, 2023 at 03:19:50PM -0700, Kuogee Hsieh wrote:
> DP PHY re-initialization done using dp_ctrl_reinitialize_mainlink() will
> cause PLL unlocked initially and then PLL gets locked at the end of
> initialization. PLL_UNLOCKED interrupt will fire during this time if the
> interrupt mask is enabled.
> However currently DP driver link training implementation incorrectly
> re-initializes PHY unconditionally during link training as the PHY was
> already configured in dp_ctrl_enable_mainlink_clocks().
> 
> Fix this by re-initializing the PHY only if the previous link training
> failed.
> 
> [drm:dp_aux_isr] *ERROR* Unexpected DP AUX IRQ 0x0100 when not busy
> 
> Fixes: c943b4948b58 ("drm/msm/dp: add displayPort driver support")
> Closes: https://gitlab.freedesktop.org/drm/msm/-/issues/30
> Signed-off-by: Kuogee Hsieh 

This fixes the above warning and avoids the unnecessary PHY power-off
and power-on during boot of the ThinkPad X13s:

Reviewed-by: Johan Hovold 
Tested-by: Johan Hovold 

I guess this one should go to stable as well:

Cc: sta...@vger.kernel.org  # 5.10

Is anyone planning on getting this fixed in 6.6-rc? I noticed that this
one still hasn't shown up linux-next.

> ---
>  drivers/gpu/drm/msm/dp/dp_ctrl.c | 13 ++---
>  1 file changed, 6 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c 
> b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index a7a5c7e..77a8d93 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -1774,13 +1774,6 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
>   return rc;
>  
>   while (--link_train_max_retries) {
> - rc = dp_ctrl_reinitialize_mainlink(ctrl);
> - if (rc) {
> - DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n",
> - rc);
> - break;
> - }
> -
>   training_step = DP_TRAINING_NONE;
>   rc = dp_ctrl_setup_main_link(ctrl, &training_step);
>   if (rc == 0) {
> @@ -1832,6 +1825,12 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
>   /* stop link training before start re training  */
>   dp_ctrl_clear_training_pattern(ctrl);
>   }
> +
> + rc = dp_ctrl_reinitialize_mainlink(ctrl);
> + if (rc) {
> + DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n", 
> rc);
> + break;
> + }
>   }
>  
>   if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)

Johan


Re: [PATCH v17 13/18] drm/shmem-helper: Add memory shrinker

2023-10-03 Thread Boris Brezillon
Hello Dmitry,

On Tue, 3 Oct 2023 03:31:32 +0300
Dmitry Osipenko  wrote:

> On 9/26/23 10:35, Boris Brezillon wrote:
>  +__drm_gem_shmem_release_pages(shmem);
> >>> Make sure you drop the implicit pages_use_count ref the sgt had, this
> >>> way you can still tie the necessity to drop the pages to sgt != NULL in
> >>> drm_gem_shmem_free().
> >> This will require further refcnt re-initialization when pages are
> >> restored if it's dropped to zero. I don't see how this will improve
> >> anything.  
> > Sorry to disagree, but I do think it matters to have a clear ownership
> > model, and if I look at the code (drm_gem_shmem_get_pages_sgt_locked()),
> > the sgt clearly owns a reference to the pages it points to.  
> 
> It creates too much unnecessary trouble because, again, pages_use_count
> can't drop to zero easily.

Not saying pages_use_count should drop to zero, I'm just saying the
reference that was owned by the sgt should be released when this sgt is
freed, no matter if this sgt destruction is triggered by a GEM eviction,
or because the GEM object is freed entirely.

> Shrinker doesn't own the refcnt and not
> allowed to touch it.

I'm not asking the shrinker to own a reference on the pages either.
It's really the sgt that owns this reference.

> The pages_use_count is then used by things like
> mmap() and etc that use get_pages(), which can be invoked for evicted GEM.

Yes, and I still have a hard time seeing how this interferes with what
I'm suggesting to be honest.

> 
> I'd prefer to keep refcounting as is, don't see how to implement your
> suggestion.

Can you be more specific? I don't really see what the problem is with
decrementing pages_use_count when you free the sgt (eviction), and
re-incrementing it when the sgt is restored (swapin).

Regards,

Boris


Re: [PATCH v2 3/6] dt-bindings: display: msm: Add SDM670 MDSS

2023-10-03 Thread Krzysztof Kozlowski
On 03/10/2023 03:21, Richard Acayan wrote:
> Add documentation for the SDM670 display subsystem, adapted from the
> SDM845 and SM6125 documentation.
> 
> Signed-off-by: Richard Acayan 
> ---
>  .../display/msm/qcom,sdm670-mdss.yaml | 287 ++
>  1 file changed, 287 insertions(+)
>  create mode 100644 
> Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml
> 
> diff --git 
> a/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml 
> b/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml
> new file mode 100644
> index ..9995b018cd9e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml
> @@ -0,0 +1,287 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/msm/qcom,sdm670-mdss.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm SDM670 Display MDSS
> +
> +maintainers:
> +  - Richard Acayan 
> +
> +description:
> +  SDM670 MSM Mobile Display Subsystem (MDSS), which encapsulates sub-blocks
> +  like DPU display controller, DSI and DP interfaces etc.
> +
> +$ref: /schemas/display/msm/mdss-common.yaml#
> +
> +properties:
> +  compatible:
> +const: qcom,sdm670-mdss
> +
> +  clocks:
> +items:
> +  - description: Display AHB clock from gcc
> +  - description: Display core clock
> +
> +  clock-names:
> +items:
> +  - const: iface
> +  - const: core
> +
> +  iommus:
> +maxItems: 2
> +
> +  interconnects:
> +maxItems: 2
> +
> +  interconnect-names:
> +maxItems: 2
> +
> +patternProperties:
> +  "^display-controller@[0-9a-f]+$":
> +type: object
> +additionalProperties: true
> +
> +properties:
> +  compatible:
> +const: qcom,sdm670-dpu
> +
> +  "^displayport-controller@[0-9a-f]+$":
> +type: object
> +additionalProperties: true
> +
> +properties:
> +  compatible:
> +const: qcom,sdm670-dp
> +
> +  "^dsi@[0-9a-f]+$":
> +type: object
> +additionalProperties: true
> +
> +properties:
> +  compatible:
> +contains:
> +  const: qcom,sdm670-dsi-ctrl
> +
> +  "^phy@[0-9a-f]+$":
> +type: object
> +additionalProperties: true
> +
> +properties:
> +  compatible:
> +const: qcom,dsi-phy-10nm

This does not look right. Why the compatible is generic, not SoC-specific?

> +
> +required:
> +  - compatible
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +display-subsystem@ae0 {
> +compatible = "qcom,sdm670-mdss";
> +reg = <0x0ae0 0x1000>;
> +reg-names = "mdss";
> +power-domains = <&dispcc MDSS_GDSC>;
> +
> +clocks = <&gcc GCC_DISP_AHB_CLK>,
> + <&dispcc DISP_CC_MDSS_MDP_CLK>;
> +clock-names = "iface", "core";
> +
> +interrupts = ;
> +interrupt-controller;
> +#interrupt-cells = <1>;
> +

Please add interconnects. They do not have to be 100% exact with DTS
(unless interconnect header is not merged?). This is just an example.

> +iommus = <&apps_smmu 0x880 0x8>,
> + <&apps_smmu 0xc80 0x8>;

> +
> +#address-cells = <1>;
> +#size-cells = <1>;
> +ranges;
> +

Best regards,
Krzysztof



Re: [PATCH v2 00/15] sysctl: Remove sentinel elements from drivers

2023-10-03 Thread Joel Granados
On Mon, Oct 02, 2023 at 12:27:18PM +, Christophe Leroy wrote:
> 
> 
> Le 02/10/2023 à 10:55, Joel Granados via B4 Relay a écrit :
> > From: Joel Granados 
> > 
<--- snip --->
> >  - The "yesall" config saves 2432 bytes [4]
> >  - The "tiny" config saves 64 bytes [5]
> >  * memory usage:
> >  In this case there were no bytes saved because I do not have any
> >  of the drivers in the patch. To measure it comment the printk in
> >  `new_dir` and uncomment the if conditional in `new_links` [3].
> > 
> > ---
> > Changes in v2:
> > - Left the dangling comma in the ctl_table arrays.
> > - Link to v1: 
> > https://lore.kernel.org/r/20230928-jag-sysctl_remove_empty_elem_drivers-v1-0-e59120fca...@samsung.com
> > 
> > Comments/feedback greatly appreciated
> 
> Same problem on powerpc CI tests, all boot target failed, most of them 
> with similar OOPS, see 
> https://patchwork.ozlabs.org/project/linuxppc-dev/patch/20231002-jag-sysctl_remove_empty_elem_drivers-v2-15-02dd0d46f...@samsung.com/
I found the culprit!. Here you are rebasing on top of v6.5.0-rc6 "INFO:
Looking for kernel version: 6.5.0-rc6-gbf2ac4d7d596". The error makes
sense becuase in that version we have not introduced the stopping
criteria based on the ctl_table array size, so the loop continues
looking for an empty sentinel past valid memory (and does not find it).
The ctl_table check catches it but then fails to do a proper error
because we have already tried to access invalid memory. The solution
here is to make sure to rebase in on top of the latest rc in v6.6.

> 
> What is strange is that I pushed your series into my github account, and 
> got no failure, see https://github.com/chleroy/linux/actions/runs/6378951278
And here it works because you use the latest rc : "INFO: Looking for
kernel version: 6.6.0-rc3-g23d4b5db743c"

> 
> Christophe
> 
> > 
> > Best
> > 
> > Joel
> > 
> > [1]
> > We are able to remove a sentinel table without behavioral change by
> > introducing a table_size argument in the same place where procname is
> > checked for NULL. The idea is for it to keep stopping when it hits
> > ->procname == NULL, while the sentinel is still present. And when the
> > sentinel is removed, it will stop on the table_size. You can go to
> > (https://lore.kernel.org/all/20230809105006.1198165-1-j.grana...@samsung.com/)
> > for more information.
> > 
> > [2]
> > Links Related to the ctl_table sentinel removal:
> > * Good summary from Luis sent with the "pull request" for the
> >preparation patches.
> >https://lore.kernel.org/all/zo5yx5jfoggi%2f...@bombadil.infradead.org/
> > * Another very good summary from Luis.
> >https://lore.kernel.org/all/zmfizkfkvxuft...@bombadil.infradead.org/
> > * This is a patch set that replaces register_sysctl_table with 
> > register_sysctl
> >https://lore.kernel.org/all/20230302204612.782387-1-mcg...@kernel.org/
> > * Patch set to deprecate register_sysctl_paths()
> >https://lore.kernel.org/all/20230302202826.776286-1-mcg...@kernel.org/
> > * Here there is an explicit expectation for the removal of the sentinel 
> > element.
> >https://lore.kernel.org/all/20230321130908.6972-1-frank...@vivo.com
> > * The "ARRAY_SIZE" approach was mentioned (proposed?) in this thread
> >https://lore.kernel.org/all/20220220060626.15885-1-tangm...@uniontech.com
> > 
> > [3]
> > To measure the in memory savings apply this on top of this patchset.
> > 
> > "
> > diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
> > index c88854df0b62..e0073a627bac 100644
> > --- a/fs/proc/proc_sysctl.c
> > +++ b/fs/proc/proc_sysctl.c
> > @@ -976,6 +976,8 @@ static struct ctl_dir *new_dir(struct ctl_table_set 
> > *set,
> >  table[0].procname = new_name;
> >  table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
> >  init_header(&new->header, set->dir.header.root, set, node, table, 
> > 1);
> > +   // Counts additional sentinel used for each new dir.
> > +   printk("%ld sysctl saved mem kzalloc \n", sizeof(struct ctl_table));
> > 
> >  return new;
> >   }
> > @@ -1199,6 +1201,9 @@ static struct ctl_table_header *new_links(struct 
> > ctl_dir *dir, struct ctl_table_
> >  link_name += len;
> >  link++;
> >  }
> > +   // Counts additional sentinel used for each new registration
> > +   //if ((head->ctl_table + head->ctl_table_size)->procname)
> > +   printk("%ld sysctl saved mem kzalloc \n", sizeof(struct 
> > ctl_table));
> >  init_header(links, dir->header.root, dir->header.set, node, 
> > link_table,
> >  head->ctl_table_size);
> >  links->nreg = nr_entries;
> > "
> > and then run the following bash script in the kernel:
> > 
> > accum=0
> > for n in $(dmesg | grep kzalloc | awk '{print $3}') ; do
> >  echo $n
> >  accum=$(calc "$accum + $n")
> > done
> > echo $accum
> > 
> > [4]
> > add/remove: 0/0 grow/shrink: 0/21 up/down: 0/-2432 (-2432)
> > 

Re: [PATCH v2] drm/ttm: Make sure the mapped tt pages are decrypted when needed

2023-10-03 Thread Thomas Hellström



On 10/3/23 06:13, Zack Rusin wrote:

On Mon, 2023-10-02 at 16:27 +0200, Thomas Hellström wrote:

!! External Email

On Mon, 2023-10-02 at 10:16 +0200, Thomas Hellström wrote:

Hi, Zack

On 9/26/23 19:51, Zack Rusin wrote:

From: Zack Rusin 

Some drivers require the mapped tt pages to be decrypted. In an
ideal
world this would have been handled by the dma layer, but the TTM
page
fault handling would have to be rewritten to able to do that.

A side-effect of the TTM page fault handling is using a dma
allocation
per order (via ttm_pool_alloc_page) which makes it impossible to
just
trivially use dma_mmap_attrs. As a result ttm has to be very
careful
about trying to make its pgprot for the mapped tt pages match what
the dma layer thinks it is. At the ttm layer it's possible to
deduce the requirement to have tt pages decrypted by checking
whether coherent dma allocations have been requested and the system
is running with confidential computing technologies.

This approach isn't ideal but keeping TTM matching DMAs
expectations
for the page properties is in general fragile, unfortunately proper
fix would require a rewrite of TTM's page fault handling.

Fixes vmwgfx with SEV enabled.

v2: Explicitly include cc_platform.h

Signed-off-by: Zack Rusin 
Fixes: 3bf3710e3718 ("drm/ttm: Add a generic TTM memcpy move for
page-based iomem")
Cc: Christian König 
Cc: Thomas Hellström 
Cc: Huang Rui 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
Cc:  # v5.14+
---
   drivers/gpu/drm/ttm/ttm_bo_util.c | 13 +++--
   drivers/gpu/drm/ttm/ttm_tt.c  |  8 
   include/drm/ttm/ttm_tt.h  |  9 -
   3 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c
b/drivers/gpu/drm/ttm/ttm_bo_util.c
index fd9fd3d15101..0b3f4267130c 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -294,7 +294,13 @@ pgprot_t ttm_io_prot(struct ttm_buffer_object
*bo, struct ttm_resource *res,
     enum ttm_caching caching;

     man = ttm_manager_type(bo->bdev, res->mem_type);
-   caching = man->use_tt ? bo->ttm->caching : res-

bus.caching;

+   if (man->use_tt) {
+   caching = bo->ttm->caching;
+   if (bo->ttm->page_flags & TTM_TT_FLAG_DECRYPTED)
+   tmp = pgprot_decrypted(tmp);
+   } else  {
+   caching = res->bus.caching;
+   }

     return ttm_prot_from_caching(caching, tmp);
   }
@@ -337,6 +343,8 @@ static int ttm_bo_kmap_ttm(struct
ttm_buffer_object *bo,
     .no_wait_gpu = false
     };
     struct ttm_tt *ttm = bo->ttm;
+   struct ttm_resource_manager *man =
+   ttm_manager_type(bo->bdev, bo->resource-

mem_type);

     pgprot_t prot;
     int ret;

@@ -346,7 +354,8 @@ static int ttm_bo_kmap_ttm(struct
ttm_buffer_object *bo,
     if (ret)
     return ret;

-   if (num_pages == 1 && ttm->caching == ttm_cached) {
+   if (num_pages == 1 && ttm->caching == ttm_cached &&
+   !(man->use_tt && (ttm->page_flags &
TTM_TT_FLAG_DECRYPTED))) {
     /*
  * We're mapping a single page, and the desired
  * page protection is consistent with the bo.
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c
b/drivers/gpu/drm/ttm/ttm_tt.c
index e0a77671edd6..e4966e2c988d 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -31,6 +31,7 @@

   #define pr_fmt(fmt) "[TTM] " fmt

+#include 
   #include 
   #include 
   #include 
@@ -81,6 +82,13 @@ int ttm_tt_create(struct ttm_buffer_object *bo,
bool zero_alloc)
     pr_err("Illegal buffer object type\n");
     return -EINVAL;
     }
+   /*
+    * When using dma_alloc_coherent with memory encryption the
+    * mapped TT pages need to be decrypted or otherwise the
drivers
+    * will end up sending encrypted mem to the gpu.
+    */
+   if (bdev->pool.use_dma_alloc &&
cc_platform_has(CC_ATTR_MEM_ENCRYPT))

You need to use CC_ATTR_GUEST_MEM_ENCRYPT here rather than
CC_ATTR_MEM_ENCRYPT to avoid touching and breaking the SME case and
only
fix the SEV / SEV-ES case. I'd also hold off the stable inclusion
until
it's completely verified that this doesn't break anything because if
it
does, I suspect all hell will break loose.

With that said, for the functionality

Reviewed-by: Thomas Hellström 

But I think this needs a wider Ack at the ttm / drm level for the
approach taken.

/Thomas.

FWIW, I think that if TTM_TT_FLAG_DECRYPTED is set, it should be
possible to add a debug WARN_ON_ONCE() if the first PTE of the dma
page's kernel virtual address does not use a decrypted pgprot_t. One
way of accessing the PTEs in a platform-generic fashion is
apply_to_page_range().

Good point.

Another, trivial solution to that problem of possible regression would simply be
introducing:

#define TTM_DEVICE_USE_DMA_ALLOC  BIT(0)
#define TT

Re: [PATCH drm-misc-next v5 4/6] drm/gpuvm: track/lock/validate external/evicted objects

2023-10-03 Thread Thomas Hellström

Hi, Danilo,

On 9/28/23 21:16, Danilo Krummrich wrote:

Currently the DRM GPUVM offers common infrastructure to track GPU VA
allocations and mappings, generically connect GPU VA mappings to their
backing buffers and perform more complex mapping operations on the GPU VA
space.

However, there are more design patterns commonly used by drivers, which
can potentially be generalized in order to make the DRM GPUVM represent
a basis for GPU-VM implementations. In this context, this patch aims
at generalizing the following elements.

1) Provide a common dma-resv for GEM objects not being used outside of
this GPU-VM.

2) Provide tracking of external GEM objects (GEM objects which are
shared with other GPU-VMs).

3) Provide functions to efficiently lock all GEM objects dma-resv the
GPU-VM contains mappings of.

4) Provide tracking of evicted GEM objects the GPU-VM contains mappings
of, such that validation of evicted GEM objects is accelerated.

5) Provide some convinience functions for common patterns.

Big thanks to Boris Brezillon for his help to figure out locking for
drivers updating the GPU VA space within the fence signalling path.

Suggested-by: Matthew Brost 
Signed-off-by: Danilo Krummrich 
---
  drivers/gpu/drm/drm_gpuvm.c | 642 
  include/drm/drm_gpuvm.h | 240 ++
  2 files changed, 882 insertions(+)

diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c
index 27100423154b..770bb3d68d1f 100644
--- a/drivers/gpu/drm/drm_gpuvm.c
+++ b/drivers/gpu/drm/drm_gpuvm.c
@@ -82,6 +82,21 @@
   * &drm_gem_object list of &drm_gpuvm_bos for an existing instance of this
   * particular combination. If not existent a new instance is created and 
linked
   * to the &drm_gem_object.
+ *
+ * &drm_gpuvm_bo structures, since unique for a given &drm_gpuvm, are also used
+ * as entry for the &drm_gpuvm's lists of external and evicted objects. Those
+ * list are maintained in order to accelerate locking of dma-resv locks and
+ * validation of evicted objects bound in a &drm_gpuvm. For instance, all
+ * &drm_gem_object's &dma_resv of a given &drm_gpuvm can be locked by calling
+ * drm_gpuvm_exec_lock(). Once locked drivers can call drm_gpuvm_validate() in
+ * order to validate all evicted &drm_gem_objects. It is also possible to lock
+ * additional &drm_gem_objects by providing the corresponding parameters to
+ * drm_gpuvm_exec_lock() as well as open code the &drm_exec loop while making
+ * use of helper functions such as drm_gpuvm_prepare_range() or
+ * drm_gpuvm_prepare_objects().
+ *
+ * Every bound &drm_gem_object is treated as external object when its &dma_resv
+ * structure is different than the &drm_gpuvm's common &dma_resv structure.
   */
  
  /**

@@ -429,6 +444,20 @@
   * Subsequent calls to drm_gpuvm_bo_obtain() for the same &drm_gpuvm and
   * &drm_gem_object must be able to observe previous creations and destructions
   * of &drm_gpuvm_bos in order to keep instances unique.
+ *
+ * The &drm_gpuvm's lists for keeping track of external and evicted objects are
+ * protected against concurrent insertion / removal and iteration internally.
+ *
+ * However, drivers still need ensure to protect concurrent calls to functions
+ * iterating those lists, namely drm_gpuvm_prepare_objects() and
+ * drm_gpuvm_validate().
+ *
+ * Alternatively, drivers can set the &DRM_GPUVM_RESV_PROTECTED flag to 
indicate
+ * that the corresponding &dma_resv locks are held in order to protect the
+ * lists. If &DRM_GPUVM_RESV_PROTECTED is set, internal locking is disabled and
+ * the corresponding lockdep checks are enabled. This is an optimization for
+ * drivers which are capable of taking the corresponding &dma_resv locks and
+ * hence do not require internal locking.
   */
  
  /**

@@ -641,6 +670,195 @@
   *}
   */
  
+/**

+ * get_next_vm_bo_from_list() - get the next vm_bo element
+ * @__gpuvm: The GPU VM
+ * @__list_name: The name of the list we're iterating on
+ * @__local_list: A pointer to the local list used to store already iterated 
items
+ * @__prev_vm_bo: The previous element we got from 
drm_gpuvm_get_next_cached_vm_bo()
+ *
+ * This helper is here to provide lockless list iteration. Lockless as in, the
+ * iterator releases the lock immediately after picking the first element from
+ * the list, so list insertion deletion can happen concurrently.
+ *
+ * Elements popped from the original list are kept in a local list, so removal
+ * and is_empty checks can still happen while we're iterating the list.
+ */
+#define get_next_vm_bo_from_list(__gpuvm, __list_name, __local_list, 
__prev_vm_bo) \
+   ({  
\
+   struct drm_gpuvm_bo *__vm_bo = NULL;
\
+   
\
+   drm_gpuvm_bo_put(__prev_vm_bo); 

Re: [PATCH] dma-buf: heaps: Fix off by one in cma_heap_vm_fault()

2023-10-03 Thread Dan Carpenter
On Mon, Oct 02, 2023 at 10:16:24AM -0700, T.J. Mercier wrote:
> On Mon, Oct 2, 2023 at 12:04 AM Dan Carpenter  
> wrote:
> >
> > The buffer->pages[] has "buffer->pagecount" elements so this > comparison
> > has to be changed to >= to avoid reading beyond the end of the array.
> > The buffer->pages[] array is allocated in cma_heap_allocate().
> >
> > Fixes: a5d2d29e24be ("dma-buf: heaps: Move heap-helper logic into the 
> > cma_heap implementation")
> > Signed-off-by: Dan Carpenter 
> > ---
> >  drivers/dma-buf/heaps/cma_heap.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/dma-buf/heaps/cma_heap.c 
> > b/drivers/dma-buf/heaps/cma_heap.c
> > index ee899f8e6721..bea7e574f916 100644
> > --- a/drivers/dma-buf/heaps/cma_heap.c
> > +++ b/drivers/dma-buf/heaps/cma_heap.c
> > @@ -165,7 +165,7 @@ static vm_fault_t cma_heap_vm_fault(struct vm_fault 
> > *vmf)
> > struct vm_area_struct *vma = vmf->vma;
> > struct cma_heap_buffer *buffer = vma->vm_private_data;
> >
> > -   if (vmf->pgoff > buffer->pagecount)
> > +   if (vmf->pgoff >= buffer->pagecount)
> > return VM_FAULT_SIGBUS;
> >
> Hi Dan,
> 
> Your fix looks correct to me, but I'm curious if you observed this
> problem on a device? The mmap in dma-buf.c looks like it prevents
> creating a mapping that is too large, and I think an access beyond the
> VMA should segfault before reaching here.

This is from static analysis and not from testing.  You could be correct
that this bug can't affect real life.

regards,
dan carpenter



[PATCH v1 1/3] mm/gup: Introduce pin_user_pages_fd() for pinning shmem/hugetlbfs file pages

2023-10-03 Thread Vivek Kasireddy
For drivers that would like to longterm-pin the pages associated
with a file, the pin_user_pages_fd() API provides an option to
not only FOLL_PIN the pages but also to check and migrate them
if they reside in movable zone or CMA block. For now, this API
can only work with files belonging to shmem or hugetlbfs given
that the udmabuf driver is the only user.

It must be noted that the pages associated with hugetlbfs files
are expected to be found in the page cache. An error is returned
if they are not found. However, shmem pages can be swapped in or
allocated if they are not present in the page cache.

Cc: David Hildenbrand 
Cc: Daniel Vetter 
Cc: Mike Kravetz 
Cc: Hugh Dickins 
Cc: Peter Xu 
Cc: Gerd Hoffmann 
Cc: Dongwon Kim 
Cc: Junxiao Chang 
Suggested-by: Jason Gunthorpe 
Signed-off-by: Vivek Kasireddy 
---
 include/linux/mm.h |  2 ++
 mm/gup.c   | 87 ++
 2 files changed, 89 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index bf5d0b1b16f4..af2121fb8101 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2457,6 +2457,8 @@ long get_user_pages_unlocked(unsigned long start, 
unsigned long nr_pages,
struct page **pages, unsigned int gup_flags);
 long pin_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
struct page **pages, unsigned int gup_flags);
+long pin_user_pages_fd(int fd, pgoff_t start, unsigned long nr_pages,
+  unsigned int gup_flags, struct page **pages);
 
 int get_user_pages_fast(unsigned long start, int nr_pages,
unsigned int gup_flags, struct page **pages);
diff --git a/mm/gup.c b/mm/gup.c
index 2f8a2d89fde1..e34b77a15fa8 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -3400,3 +3400,90 @@ long pin_user_pages_unlocked(unsigned long start, 
unsigned long nr_pages,
 &locked, gup_flags);
 }
 EXPORT_SYMBOL(pin_user_pages_unlocked);
+
+/**
+ * pin_user_pages_fd() - pin user pages associated with a file
+ * @fd: the fd whose pages are to be pinned
+ * @start:  starting file offset
+ * @nr_pages:   number of pages from start to pin
+ * @gup_flags:  flags modifying pin behaviour
+ * @pages:  array that receives pointers to the pages pinned.
+ *  Should be at least nr_pages long.
+ *
+ * Attempt to pin (and migrate) pages associated with a file belonging to
+ * either shmem or hugetlbfs. An error is returned if pages associated with
+ * hugetlbfs files are not present in the page cache. However, shmem pages
+ * are swapped in or allocated if they are not present in the page cache.
+ *
+ * Returns number of pages pinned. This would be equal to the number of
+ * pages requested.
+ * If nr_pages is 0 or negative, returns 0. If no pages were pinned, returns
+ * -errno.
+ */
+long pin_user_pages_fd(int fd, pgoff_t start, unsigned long nr_pages,
+  unsigned int gup_flags, struct page **pages)
+{
+   struct page *page;
+   struct file *filep;
+   unsigned int flags, i;
+   long ret;
+
+   if (nr_pages <= 0)
+   return 0;
+   if (!is_valid_gup_args(pages, NULL, &gup_flags, FOLL_PIN))
+   return 0;
+
+   if (start < 0)
+   return -EINVAL;
+
+   filep = fget(fd);
+   if (!filep)
+   return -EINVAL;
+
+   if (!shmem_file(filep) && !is_file_hugepages(filep))
+   return -EINVAL;
+
+   flags = memalloc_pin_save();
+   do {
+   for (i = 0; i < nr_pages; i++) {
+   if (shmem_mapping(filep->f_mapping)) {
+   page = shmem_read_mapping_page(filep->f_mapping,
+  start + i);
+   if (IS_ERR(page)) {
+   ret = PTR_ERR(page);
+   goto err;
+   }
+   } else {
+   page = find_get_page_flags(filep->f_mapping,
+  start + i,
+  FGP_ACCESSED);
+   if (!page) {
+   ret = -EINVAL;
+   goto err;
+   }
+   }
+   ret = try_grab_page(page, FOLL_PIN);
+   if (unlikely(ret))
+   goto err;
+
+   pages[i] = page;
+   put_page(pages[i]);
+   }
+
+   ret = check_and_migrate_movable_pages(nr_pages, pages);
+   } while (ret == -EAGAIN);
+
+err:
+   memalloc_pin_restore(flags);
+   fput(filep);
+   if (!ret)
+   return nr_pages;
+
+   while (i > 0 && pages[--i]) {
+   unpin_user

[PATCH v1 2/3] udmabuf: Pin the pages using pin_user_pages_fd() API

2023-10-03 Thread Vivek Kasireddy
Using pin_user_pages_fd() will ensure that the pages are pinned
correctly using FOLL_PIN. And, this also ensures that we don't
accidentally break features such as memory hotunplug as it would
not allow pinning pages in the movable zone.

This patch also adds back support for mapping hugetlbfs pages
by noting the subpage offsets within the huge pages and uses
this information while populating the scatterlist.

Cc: David Hildenbrand 
Cc: Daniel Vetter 
Cc: Mike Kravetz 
Cc: Hugh Dickins 
Cc: Peter Xu 
Cc: Jason Gunthorpe 
Cc: Gerd Hoffmann 
Cc: Dongwon Kim 
Cc: Junxiao Chang 
Signed-off-by: Vivek Kasireddy 
---
 drivers/dma-buf/udmabuf.c | 82 +--
 1 file changed, 61 insertions(+), 21 deletions(-)

diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
index 820c993c8659..9ef1eaf4df4b 100644
--- a/drivers/dma-buf/udmabuf.c
+++ b/drivers/dma-buf/udmabuf.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -28,6 +29,7 @@ struct udmabuf {
struct page **pages;
struct sg_table *sg;
struct miscdevice *device;
+   pgoff_t *subpgoff;
 };
 
 static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf)
@@ -90,23 +92,31 @@ static struct sg_table *get_sg_table(struct device *dev, 
struct dma_buf *buf,
 {
struct udmabuf *ubuf = buf->priv;
struct sg_table *sg;
+   struct scatterlist *sgl;
+   pgoff_t offset;
+   unsigned long i = 0;
int ret;
 
sg = kzalloc(sizeof(*sg), GFP_KERNEL);
if (!sg)
return ERR_PTR(-ENOMEM);
-   ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount,
-   0, ubuf->pagecount << PAGE_SHIFT,
-   GFP_KERNEL);
+
+   ret = sg_alloc_table(sg, ubuf->pagecount, GFP_KERNEL);
if (ret < 0)
-   goto err;
+   goto err_alloc;
+
+   for_each_sg(sg->sgl, sgl, ubuf->pagecount, i) {
+   offset = ubuf->subpgoff ? ubuf->subpgoff[i] : 0;
+   sg_set_page(sgl, ubuf->pages[i], PAGE_SIZE, offset);
+   }
ret = dma_map_sgtable(dev, sg, direction, 0);
if (ret < 0)
-   goto err;
+   goto err_map;
return sg;
 
-err:
+err_map:
sg_free_table(sg);
+err_alloc:
kfree(sg);
return ERR_PTR(ret);
 }
@@ -142,7 +152,9 @@ static void release_udmabuf(struct dma_buf *buf)
put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL);
 
for (pg = 0; pg < ubuf->pagecount; pg++)
-   put_page(ubuf->pages[pg]);
+   unpin_user_page(ubuf->pages[pg]);
+
+   kfree(ubuf->subpgoff);
kfree(ubuf->pages);
kfree(ubuf);
 }
@@ -202,12 +214,13 @@ static long udmabuf_create(struct miscdevice *device,
 {
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
struct file *memfd = NULL;
-   struct address_space *mapping = NULL;
struct udmabuf *ubuf;
struct dma_buf *buf;
-   pgoff_t pgoff, pgcnt, pgidx, pgbuf = 0, pglimit;
-   struct page *page;
-   int seals, ret = -EINVAL;
+   pgoff_t pgoff, pgcnt, pgbuf = 0, pglimit, nr_pages;
+   pgoff_t subpgoff, maxsubpgs;
+   struct hstate *hpstate;
+   long ret = -EINVAL;
+   int seals;
u32 i, flags;
 
ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL);
@@ -241,8 +254,7 @@ static long udmabuf_create(struct miscdevice *device,
memfd = fget(list[i].memfd);
if (!memfd)
goto err;
-   mapping = memfd->f_mapping;
-   if (!shmem_mapping(mapping))
+   if (!shmem_file(memfd) && !is_file_hugepages(memfd))
goto err;
seals = memfd_fcntl(memfd, F_GET_SEALS, 0);
if (seals == -EINVAL)
@@ -253,14 +265,41 @@ static long udmabuf_create(struct miscdevice *device,
goto err;
pgoff = list[i].offset >> PAGE_SHIFT;
pgcnt = list[i].size   >> PAGE_SHIFT;
-   for (pgidx = 0; pgidx < pgcnt; pgidx++) {
-   page = shmem_read_mapping_page(mapping, pgoff + pgidx);
-   if (IS_ERR(page)) {
-   ret = PTR_ERR(page);
+   if (is_file_hugepages(memfd)) {
+   if (!ubuf->subpgoff) {
+   ubuf->subpgoff = kmalloc_array(ubuf->pagecount,
+  
sizeof(*ubuf->subpgoff),
+  GFP_KERNEL);
+   if (!ubuf->subpgoff) {
+   ret = -ENOMEM;
+   goto err;
+   }
+   }
+   hpstate = hstate_file(memfd);
+   pgoff = list[i].offset >> h

[PATCH v1 3/3] selftests/dma-buf/udmabuf: Add tests to verify data after page migration

2023-10-03 Thread Vivek Kasireddy
Since the memfd pages associated with a udmabuf may be migrated
as part of udmabuf create, we need to verify the data coherency
after successful migration. The new tests added in this patch try
to do just that using 4k sized pages and also 2 MB sized huge
pages for the memfd.

Successful completion of the tests would mean that there is no
disconnect between the memfd pages and the ones associated with
a udmabuf. And, these tests can also be augmented in the future
to test newer udmabuf features (such as handling memfd hole punch).

Cc: Shuah Khan 
Cc: David Hildenbrand 
Cc: Daniel Vetter 
Cc: Mike Kravetz 
Cc: Hugh Dickins 
Cc: Peter Xu 
Cc: Jason Gunthorpe 
Cc: Gerd Hoffmann 
Cc: Dongwon Kim 
Cc: Junxiao Chang 
Based-on-patch-by: Mike Kravetz 
Signed-off-by: Vivek Kasireddy 
---
 .../selftests/drivers/dma-buf/udmabuf.c   | 151 +-
 1 file changed, 147 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c 
b/tools/testing/selftests/drivers/dma-buf/udmabuf.c
index c812080e304e..d76c813fe652 100644
--- a/tools/testing/selftests/drivers/dma-buf/udmabuf.c
+++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c
@@ -9,26 +9,132 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
+#include 
 #include 
 #include 
 
 #define TEST_PREFIX"drivers/dma-buf/udmabuf"
 #define NUM_PAGES   4
+#define NUM_ENTRIES 4
+#define MEMFD_SIZE  1024 /* in pages */
 
-static int memfd_create(const char *name, unsigned int flags)
+static unsigned int page_size;
+
+static int create_memfd_with_seals(off64_t size, bool hpage)
+{
+   int memfd, ret;
+   unsigned int flags = MFD_ALLOW_SEALING;
+
+   if (hpage)
+   flags |= MFD_HUGETLB;
+
+   memfd = memfd_create("udmabuf-test", flags);
+   if (memfd < 0) {
+   printf("%s: [skip,no-memfd]\n", TEST_PREFIX);
+   exit(77);
+   }
+
+   ret = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);
+   if (ret < 0) {
+   printf("%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);
+   exit(77);
+   }
+
+   ret = ftruncate(memfd, size);
+   if (ret == -1) {
+   printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);
+   exit(1);
+   }
+
+   return memfd;
+}
+
+static int create_udmabuf_list(int devfd, int memfd, off64_t memfd_size)
+{
+   struct udmabuf_create_list *list;
+   int ubuf_fd, i;
+
+   list = malloc(sizeof(struct udmabuf_create_list) +
+ sizeof(struct udmabuf_create_item) * NUM_ENTRIES);
+   if (!list) {
+   printf("%s: [FAIL, udmabuf-malloc]\n", TEST_PREFIX);
+   exit(1);
+   }
+
+   for (i = 0; i < NUM_ENTRIES; i++) {
+   list->list[i].memfd  = memfd;
+   list->list[i].offset = i * (memfd_size / NUM_ENTRIES);
+   list->list[i].size   = getpagesize() * NUM_PAGES;
+   }
+
+   list->count = NUM_ENTRIES;
+   list->flags = UDMABUF_FLAGS_CLOEXEC;
+   ubuf_fd = ioctl(devfd, UDMABUF_CREATE_LIST, list);
+   free(list);
+   if (ubuf_fd < 0) {
+   printf("%s: [FAIL, udmabuf-create]\n", TEST_PREFIX);
+   exit(1);
+   }
+
+   return ubuf_fd;
+}
+
+static void write_to_memfd(void *addr, off64_t size, char chr)
+{
+   int i;
+
+   for (i = 0; i < size / page_size; i++) {
+   *((char *)addr + (i * page_size)) = chr;
+   }
+}
+
+static void *mmap_fd(int fd, off64_t size)
 {
-   return syscall(__NR_memfd_create, name, flags);
+   void *addr;
+
+   addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+   if (addr == MAP_FAILED) {
+   printf("%s: ubuf_fd mmap fail\n", TEST_PREFIX);
+   exit(1);
+   }
+
+   return addr;
+}
+
+static int compare_chunks(void *addr1, void *addr2, off64_t memfd_size)
+{
+   off64_t off;
+   int i = 0, j, k = 0, ret = 0;
+   char char1, char2;
+
+   while (i < NUM_ENTRIES) {
+   off = i * (memfd_size / NUM_ENTRIES);
+   for (j = 0; j < NUM_PAGES; j++, k++) {
+   char1 = *((char *)addr1 + off + (j * getpagesize()));
+   char2 = *((char *)addr2 + (k * getpagesize()));
+   if (char1 != char2) {
+   ret = -1;
+   goto err;
+   }
+   }
+   i++;
+   }
+err:
+   munmap(addr1, memfd_size);
+   munmap(addr2, NUM_ENTRIES * NUM_PAGES * getpagesize());
+   return ret;
 }
 
 int main(int argc, char *argv[])
 {
struct udmabuf_create create;
int devfd, memfd, buf, ret;
-   off_t size;
-   void *mem;
+   off64_t size;
+   void *addr1, *addr2;
 
devfd = open("/dev/udmabuf", O_RDWR);
if (devfd < 0) {
@@ -90,6 +196,9 @@ int main(int argc, char *argv[])
}
 
/* should work */
+   

[PATCH v1 0/3] mm/gup: Introduce pin_user_pages_fd() for pinning shmem/hugetlbfs file pages

2023-10-03 Thread Vivek Kasireddy
The first patch introduces pin_user_pages_fd() API and the second
patch shows how the udmabuf driver can use it to longterm-pin the
the pages. The last patch adds two new udmabuf selftests to verify
data coherency after page migration.

Cc: David Hildenbrand 
Cc: Daniel Vetter 
Cc: Mike Kravetz 
Cc: Hugh Dickins 
Cc: Peter Xu 
Cc: Jason Gunthorpe 
Cc: Gerd Hoffmann 
Cc: Dongwon Kim 
Cc: Junxiao Chang 

Vivek Kasireddy (3):
  mm/gup: Introduce pin_user_pages_fd() for pinning shmem/hugetlbfs file
pages
  udmabuf: Pin the pages using pin_user_pages_fd() API
  selftests/dma-buf/udmabuf: Add tests to verify data after page
migration

 drivers/dma-buf/udmabuf.c |  82 +++---
 include/linux/mm.h|   2 +
 mm/gup.c  |  87 ++
 .../selftests/drivers/dma-buf/udmabuf.c   | 151 +-
 4 files changed, 297 insertions(+), 25 deletions(-)

-- 
2.39.2



Re: [PATCH v4 5/8] drm/msm/dp: incorporate pm_runtime framework into DP driver

2023-10-03 Thread Dmitry Baryshkov
On Tue, 3 Oct 2023 at 01:48, Kuogee Hsieh  wrote:
>
>
> On 9/27/2023 2:41 PM, Dmitry Baryshkov wrote:
> > On Wed, 27 Sept 2023 at 23:54, Kuogee Hsieh  wrote:
> >> Currently DP driver is executed independent of PM runtime framework.
> >> This lead to msm edp panel can not be detected by edp_panel driver at
> >> generic_edp_panel_probe() due to aux dpcd read failed at msm edp driver.
> > eDP, AUX, DPCD. leads. not being detected, s/at/during.
> >
> > Also there is no msm eDP driver.
> >
> >> Incorporating pm runtime framework into DP driver so that both power and
> > Incorporate. PM
> >
> >> clocks to enable/disable host controller fits with PM runtime mechanism.
> > Ugh?
> >
> >> Once pm runtime framework is incorporated into DP driver, wake up device
> > waking
> >
> >> from power up path is not necessary. Hence remove it.
> >> Since DP is part of user interface, we choice to use autosuspend feature
> >> with timer of one second. pm runtime suspends is prevented from happening
> >> until timer expired.
> > No, this is not the right reason to use autosuspend. Please use normal
> > suspend unless there is a performance regression caused by the
> > suspend/resume paths.
> >
> >> Changes in v4:
> >> -- reworded commit text to explain why pm_framework is required for edp 
> >> panel
> >> -- reworded commit text to explain autosuspend is choiced
> >> -- delete EV_POWER_PM_GET and PM_EV_POWER_PUT from changes #3
> >> -- delete dp_display_pm_get() and dp_display_pm_Put() from changes #3
> >> -- return value from pm_runtime_resume_and_get() directly
> >> -- check return value of devm_pm_runtime_enable()
> >> -- delete pm_runtime_xxx from dp_display_remove()
> >> -- drop dp_display_host_init() from EV_HPD_INIT_SETUP
> >>
> >> Changes in v3:
> >> -- incorporate removing pm_runtime_xx() from dp_pwer.c to this patch
> >> -- use pm_runtime_resume_and_get() instead of pm_runtime_get()
> >> -- error checking pm_runtime_resume_and_get() return value
> >> -- add EV_POWER_PM_GET and PM_EV_POWER_PUT to handle HPD_GPIO case
> >>
> >> Signed-off-by: Kuogee Hsieh 
> >> Reported-by: kernel test robot 
> >> ---
> >>   drivers/gpu/drm/msm/dp/dp_aux.c |  6 +++
> >>   drivers/gpu/drm/msm/dp/dp_display.c | 95 
> >> +++--
> >>   drivers/gpu/drm/msm/dp/dp_power.c   | 16 ---
> >>   drivers/gpu/drm/msm/dp/dp_power.h   | 11 -
> >>   4 files changed, 77 insertions(+), 51 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c 
> >> b/drivers/gpu/drm/msm/dp/dp_aux.c
> >> index 8e3b677..22eb774 100644
> >> --- a/drivers/gpu/drm/msm/dp/dp_aux.c
> >> +++ b/drivers/gpu/drm/msm/dp/dp_aux.c
> >> @@ -291,6 +291,10 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux 
> >> *dp_aux,
> >>  return -EINVAL;
> >>  }
> >>
> >> +   ret = pm_runtime_resume_and_get(dp_aux->dev);
> >> +   if (ret)
> >> +   return  ret;
> >> +
> >>  mutex_lock(&aux->mutex);
> >>  if (!aux->initted) {
> >>  ret = -EIO;
> >> @@ -364,6 +368,8 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux 
> >> *dp_aux,
> >>
> >>   exit:
> >>  mutex_unlock(&aux->mutex);
> >> +   pm_runtime_mark_last_busy(dp_aux->dev);
> >> +   pm_runtime_put_autosuspend(dp_aux->dev);
> >>
> >>  return ret;
> >>   }
> >> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
> >> b/drivers/gpu/drm/msm/dp/dp_display.c
> >> index 3ef141c..bfb4692 100644
> >> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> >> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> >> @@ -276,8 +276,6 @@ static int dp_display_bind(struct device *dev, struct 
> >> device *master,
> >>  dp->dp_display.drm_dev = drm;
> >>  priv->dp[dp->id] = &dp->dp_display;
> >>
> >> -
> >> -
> > Is this also a part of pm_runtime support? No, it is not.
> >
> >>  dp->drm_dev = drm;
> >>  dp->aux->drm_dev = drm;
> >>  rc = dp_aux_register(dp->aux);
> >> @@ -286,7 +284,6 @@ static int dp_display_bind(struct device *dev, struct 
> >> device *master,
> >>  goto end;
> >>  }
> >>
> >> -
> > And this. If you want to clean up stray empty lines, please split that
> > to a separate patch.
> >
> >>  rc = dp_register_audio_driver(dev, dp->audio);
> >>  if (rc) {
> >>  DRM_ERROR("Audio registration Dp failed\n");
> >> @@ -310,15 +307,10 @@ static void dp_display_unbind(struct device *dev, 
> >> struct device *master,
> >>  struct dp_display_private *dp = dev_get_dp_display_private(dev);
> >>  struct msm_drm_private *priv = dev_get_drvdata(master);
> >>
> >> -   /* disable all HPD interrupts */
> >> -   if (dp->core_initialized)
> >> -   dp_catalog_hpd_config_intr(dp->catalog, 
> >> DP_DP_HPD_INT_MASK, false);
> >> -
> >>  kthread_stop(dp->ev_tsk);
> >>
> >>  of_dp_aux_depopulate_bus(dp->aux);
> >>
> >> -   dp_power_client_deinit(dp->power);
> >>  dp_unregister_audio_drive

Re: [PATCH v3 6/7] drm/msm/dp: add pm_runtime_force_suspend()/resume()

2023-10-03 Thread Dmitry Baryshkov
On Tue, 3 Oct 2023 at 04:33, Abhinav Kumar  wrote:
>
>
>
> On 10/2/2023 3:58 PM, Stephen Boyd wrote:
> > Quoting Abhinav Kumar (2023-09-28 17:46:11)
> >> On 9/27/2023 3:01 PM, Stephen Boyd wrote:
> >>> Quoting Kuogee Hsieh (2023-09-25 09:07:18)
> 
>  However for external DP case, link training can not be guarantee always
>  success without link rate or lane being reduced as Abhinav mentioned.
> 
>  In addition,  CTS (compliance test) it required to complete link
>  training within 10ms after hpd asserted.
> >>>
> >>> Is it possible to change that timeout? I have to look around for the CTS
> >>> parameters because I'm pretty confused how it can work. What do we do if
> >>> DP wakes the system from suspend and asserts HPD? We need resume time to
> >>> be < 10ms?  That's not realistic.
> >>>
> >>
> >> No, the CTS doesnt say we need to finish link training within 10ms after
> >> HPD is asserted. It says it must be completed in 10ms after
> >> TRAINING_PATTERN_SET dpcd write.
> >>
> >> "Wait until the Source DUT writes 00h to the TRAINING_PATTERN_SET byte
> >> of Reference Sink DPCD Link Configuration Field to indicate the end of
> >> the link training. Stop the link training timer. Verify that link
> >> training completed in 10ms or less"
> >>
> >> That needs to be done independent of HPD so we can ignore the CTS point.
> >
> > Great!
> >
> >>
> 
>  I am not sure do link training at atomic_enable() can meet this timing
>  requirement.
> >
> > Why? It's putting some time bound on link training in general to only
> > take 10ms, right?
> >
>
> Like I said, CTS is mentioning 10ms to finish link training after the
> DUT writes 00h to the TRAINING_PATTERN_SET byte. So for this discussion
> lets leave out CTS for now.
>
> 
> >>>
> >>> At least in the DP spec itself it doesn't require the link to be trained
> >>> within 10ms of HPD being asserted. Instead it simply recommends that the
> >>> OS start configuring the display promptly after HPD is asserted, e.g.
> >>> within 100ms. There's some strict timing on IRQ_HPD, so the driver must
> >>> read DPCD registers within 100ms of IRQ_HPD rising edge; maybe that is
> >>> what CTS is checking for?
> >>>
> >>> TL;DR: I don't see why CTS should stop us from link training in
> >>> atomic_enable(). It would be beneficial to do so to make eDP and DP the
> >>> same. It would also help to report a drm connector being connected
> >>> _before_ link training so that userspace knows the link itself is the
> >>> bad part of the equation (and not that the DP connector looks
> >>> disconnected to userspace when in fact it really is connected and the
> >>> monitor is asserting HPD, just the link training failed).
> >>
> >> Its the corrective action of the userspace when it finds link is bad is
> >> the concern as I highlighted in the other response. Just reading and
> >> resetting link_status is not enough to recover.
> >
> > What needs to be done to recover? Userspace will try to set a mode on
> > the connector again if the link status is bad and there were some modes
> > available. If there are zero modes and the link is bad, then it ignores
> > the connector. I'm not sure what else could be done to recover besides
> > try again and stop trying if no modes exist.
> >
>
> Let me re-explain if I didnt make this clear last time.
>
> You are right. Thats all the "userspace" can do which is basically retry
> the mode. And like I said, its again only going to fail. All the
> corrective actions you mentioned below like ignoring the connector
> entirely or consider that the display has link training problems are not
> something we decided to go with on a commercial device where we expect
> things to be more reliable.

I have had link training issues with one of my laptops (x86) and USB-C
dock. Usually switching to lower resolution works in such cases.
Moreover, in some cases after switching to low res, I can successfully
switch to high res.

>
> Let me re-explain what I explained in the prev response.
>
> If driver issues hot-plug after link-training:
>
> It would have implemented all the link training mechanisms such as
> trying lower rates/number of lanes and made sure that when the usermode
> queries the list of modes, only the modes which fit into the link rate
> which was link trained successfully will be exposed and the chances of a
> user ending up with a blank screen on connection are pretty high.
>
> This reduces the dependency on usermodes to be smart enough to implement
> such policies and we would rather not depend on those unless we have
> some reference to a compositor which is more sturdy. I do not think the
> CrOS code you have pointed to is more sturdy than the driver mechanism
> explained above.
>
> As opposed to this, if we just issue hotplug without any of this,
> usermode does not know which mode to retry as we do not remove or edit
> the mode list once link training fails.

I think we are trying to be overprotective here. From my po