This series adds support to use devcoredump for DPU driver. It introduces the dpu_dbg module which assists in the capturing of register dumps during error scenarios. When a display related error happens, the dpu_dbg module captures all the relevant register dumps along with the snapshot of the drm atomic state and triggers a devcoredump.
Abhinav Kumar (4): drm: allow drm_atomic_print_state() to accept any drm_printer disp/msm/dpu: add support to dump dpu registers drm/msm: register the base address with dpu_dbg module drm/msm/dpu: add dpu_dbg points across dpu driver
drivers/gpu/drm/drm_atomic.c | 17 +- drivers/gpu/drm/drm_atomic_uapi.c | 4 +- drivers/gpu/drm/drm_crtc_internal.h | 4 +- drivers/gpu/drm/msm/Makefile | 2 + drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c | 316 ++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h | 273 +++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c | 313 +++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 12 +- .../drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 5 +- .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 5 +- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 6 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c | 7 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 5 +- .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c | 6 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 8 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c | 7 +- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 12 +- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 +- drivers/gpu/drm/msm/dp/dp_catalog.c | 12 + drivers/gpu/drm/msm/dp/dp_catalog.h | 4 + drivers/gpu/drm/msm/dp/dp_display.c | 2 + drivers/gpu/drm/msm/dsi/dsi_host.c | 10 +- drivers/gpu/drm/msm/msm_drv.c | 30 +- drivers/gpu/drm/msm/msm_drv.h | 3 +- 25 files changed, 1045 insertions(+), 26 deletions(-) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c
Currently drm_atomic_print_state() internally allocates and uses a drm_info printer. Allow it to accept any drm_printer type so that the API can be leveraged even for taking drm snapshot.
Signed-off-by: Abhinav Kumar abhinavk@codeaurora.org --- drivers/gpu/drm/drm_atomic.c | 17 ++++++++++++----- drivers/gpu/drm/drm_atomic_uapi.c | 4 +++- drivers/gpu/drm/drm_crtc_internal.h | 4 +++- 3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 58527f151984..e7079a5f439c 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2014 Red Hat * Copyright (C) 2014 Intel Corp. + * Copyright (c) 2020, The Linux Foundation. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -1543,9 +1544,9 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, } EXPORT_SYMBOL(__drm_atomic_helper_set_config);
-void drm_atomic_print_state(const struct drm_atomic_state *state) +void drm_atomic_print_state(const struct drm_atomic_state *state, + struct drm_printer *p) { - struct drm_printer p = drm_info_printer(state->dev->dev); struct drm_plane *plane; struct drm_plane_state *plane_state; struct drm_crtc *crtc; @@ -1554,17 +1555,23 @@ void drm_atomic_print_state(const struct drm_atomic_state *state) struct drm_connector_state *connector_state; int i;
+ if (!p) { + DRM_ERROR("invalid drm printer\n"); + return; + } + DRM_DEBUG_ATOMIC("checking %p\n", state);
for_each_new_plane_in_state(state, plane, plane_state, i) - drm_atomic_plane_print_state(&p, plane_state); + drm_atomic_plane_print_state(p, plane_state);
for_each_new_crtc_in_state(state, crtc, crtc_state, i) - drm_atomic_crtc_print_state(&p, crtc_state); + drm_atomic_crtc_print_state(p, crtc_state);
for_each_new_connector_in_state(state, connector, connector_state, i) - drm_atomic_connector_print_state(&p, connector_state); + drm_atomic_connector_print_state(p, connector_state); } +EXPORT_SYMBOL(drm_atomic_print_state);
static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, bool take_locks) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 25c269bc4681..d9ae86c92608 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -2,6 +2,7 @@ * Copyright (C) 2014 Red Hat * Copyright (C) 2014 Intel Corp. * Copyright (C) 2018 Intel Corp. + * Copyright (c) 2020, The Linux Foundation. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -1294,6 +1295,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_out_fence_state *fence_state; int ret = 0; unsigned int i, j, num_fences; + struct drm_printer p = drm_info_printer(dev->dev);
/* disallow for drivers not supporting atomic: */ if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) @@ -1413,7 +1415,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, ret = drm_atomic_nonblocking_commit(state); } else { if (drm_debug_enabled(DRM_UT_STATE)) - drm_atomic_print_state(state); + drm_atomic_print_state(state, &p);
ret = drm_atomic_commit(state); } diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index da96b2f64d7e..d34215366936 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -5,6 +5,7 @@ * Jesse Barnes jesse.barnes@intel.com * Copyright © 2014 Intel Corporation * Daniel Vetter daniel.vetter@ffwll.ch + * Copyright (c) 2020, The Linux Foundation. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -233,7 +234,8 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane, int __drm_atomic_helper_set_config(struct drm_mode_set *set, struct drm_atomic_state *state);
-void drm_atomic_print_state(const struct drm_atomic_state *state); +void drm_atomic_print_state(const struct drm_atomic_state *state, + struct drm_printer *p);
/* drm_atomic_uapi.c */ int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
Hi Abhinav,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on drm-exynos/exynos-drm-next] [also build test WARNING on drm-intel/for-linux-next tegra-drm/drm/tegra/for-next drm-tip/drm-tip linus/master v5.9 next-20201022] [cannot apply to drm/drm-next] [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]
url: https://github.com/0day-ci/linux/commits/Abhinav-Kumar/Add-devcoredump-suppo... base: https://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git exynos-drm-next config: microblaze-randconfig-r003-20201022 (attached as .config) compiler: microblaze-linux-gcc (GCC) 9.3.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/76add8f28420cad0b0d2977abed6e031ef30... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Abhinav-Kumar/Add-devcoredump-support-for-DPU/20201022-130507 git checkout 76add8f28420cad0b0d2977abed6e031ef307f32 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=microblaze
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All warnings (new ones prefixed by >>):
In file included from drivers/gpu/drm/selftests/test-drm_framebuffer.c:12:
drivers/gpu/drm/selftests/../drm_crtc_internal.h:238:10: warning: 'struct drm_printer' declared inside parameter list will not be visible outside of this definition or declaration
238 | struct drm_printer *p); | ^~~~~~~~~~~ drivers/gpu/drm/selftests/test-drm_framebuffer.c: In function 'execute_drm_mode_fb_cmd2': drivers/gpu/drm/selftests/test-drm_framebuffer.c:333:26: warning: variable 'fb' set but not used [-Wunused-but-set-variable] 333 | struct drm_framebuffer *fb; | ^~
vim +238 drivers/gpu/drm/selftests/../drm_crtc_internal.h
231 232 int __drm_atomic_helper_disable_plane(struct drm_plane *plane, 233 struct drm_plane_state *plane_state); 234 int __drm_atomic_helper_set_config(struct drm_mode_set *set, 235 struct drm_atomic_state *state); 236 237 void drm_atomic_print_state(const struct drm_atomic_state *state,
238 struct drm_printer *p);
239
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On Wed, Oct 21, 2020 at 10:01:45PM -0700, Abhinav Kumar wrote:
Currently drm_atomic_print_state() internally allocates and uses a drm_info printer. Allow it to accept any drm_printer type so that the API can be leveraged even for taking drm snapshot.
Signed-off-by: Abhinav Kumar abhinavk@codeaurora.org
drivers/gpu/drm/drm_atomic.c | 17 ++++++++++++----- drivers/gpu/drm/drm_atomic_uapi.c | 4 +++- drivers/gpu/drm/drm_crtc_internal.h | 4 +++- 3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 58527f151984..e7079a5f439c 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1,6 +1,7 @@ /*
- Copyright (C) 2014 Red Hat
- Copyright (C) 2014 Intel Corp.
- Copyright (c) 2020, The Linux Foundation. All rights reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
@@ -1543,9 +1544,9 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, } EXPORT_SYMBOL(__drm_atomic_helper_set_config);
-void drm_atomic_print_state(const struct drm_atomic_state *state) +void drm_atomic_print_state(const struct drm_atomic_state *state,
struct drm_printer *p)
Please add a nice kerneldoc for this newly exported function. Specifically this kerneldoc needs to include a warning that state updates after call drm_atomic_state_helper_commit_hw_done() is unsafe to print using this function, because it looks at the new state objects. Only the old state structures will stay like this.
So maybe rename the function to say print_new_state() to make this completely clear. That way we can eventually add a print_old_state() when needed.
Otherwise I think this makes sense, and nicely avoids the locking issue of looking at ->state pointers without the right locking. -Daniel
{
- struct drm_printer p = drm_info_printer(state->dev->dev); struct drm_plane *plane; struct drm_plane_state *plane_state; struct drm_crtc *crtc;
@@ -1554,17 +1555,23 @@ void drm_atomic_print_state(const struct drm_atomic_state *state) struct drm_connector_state *connector_state; int i;
if (!p) {
DRM_ERROR("invalid drm printer\n");
return;
}
DRM_DEBUG_ATOMIC("checking %p\n", state);
for_each_new_plane_in_state(state, plane, plane_state, i)
drm_atomic_plane_print_state(&p, plane_state);
drm_atomic_plane_print_state(p, plane_state);
for_each_new_crtc_in_state(state, crtc, crtc_state, i)
drm_atomic_crtc_print_state(&p, crtc_state);
drm_atomic_crtc_print_state(p, crtc_state);
for_each_new_connector_in_state(state, connector, connector_state, i)
drm_atomic_connector_print_state(&p, connector_state);
drm_atomic_connector_print_state(p, connector_state);
} +EXPORT_SYMBOL(drm_atomic_print_state);
static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, bool take_locks) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 25c269bc4681..d9ae86c92608 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -2,6 +2,7 @@
- Copyright (C) 2014 Red Hat
- Copyright (C) 2014 Intel Corp.
- Copyright (C) 2018 Intel Corp.
- Copyright (c) 2020, The Linux Foundation. All rights reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
@@ -1294,6 +1295,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_out_fence_state *fence_state; int ret = 0; unsigned int i, j, num_fences;
struct drm_printer p = drm_info_printer(dev->dev);
/* disallow for drivers not supporting atomic: */ if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
@@ -1413,7 +1415,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, ret = drm_atomic_nonblocking_commit(state); } else { if (drm_debug_enabled(DRM_UT_STATE))
drm_atomic_print_state(state);
drm_atomic_print_state(state, &p);
ret = drm_atomic_commit(state); }
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index da96b2f64d7e..d34215366936 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -5,6 +5,7 @@
- Jesse Barnes jesse.barnes@intel.com
- Copyright © 2014 Intel Corporation
- Daniel Vetter daniel.vetter@ffwll.ch
- Copyright (c) 2020, The Linux Foundation. All rights reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
@@ -233,7 +234,8 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane, int __drm_atomic_helper_set_config(struct drm_mode_set *set, struct drm_atomic_state *state);
-void drm_atomic_print_state(const struct drm_atomic_state *state); +void drm_atomic_print_state(const struct drm_atomic_state *state,
struct drm_printer *p);
/* drm_atomic_uapi.c */ int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state, -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Hi Daniel
On 2020-10-22 03:38, Daniel Vetter wrote:
On Wed, Oct 21, 2020 at 10:01:45PM -0700, Abhinav Kumar wrote:
Currently drm_atomic_print_state() internally allocates and uses a drm_info printer. Allow it to accept any drm_printer type so that the API can be leveraged even for taking drm snapshot.
Signed-off-by: Abhinav Kumar abhinavk@codeaurora.org
drivers/gpu/drm/drm_atomic.c | 17 ++++++++++++----- drivers/gpu/drm/drm_atomic_uapi.c | 4 +++- drivers/gpu/drm/drm_crtc_internal.h | 4 +++- 3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 58527f151984..e7079a5f439c 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1,6 +1,7 @@ /*
- Copyright (C) 2014 Red Hat
- Copyright (C) 2014 Intel Corp.
- Copyright (c) 2020, The Linux Foundation. All rights reserved.
- Permission is hereby granted, free of charge, to any person
obtaining a
- copy of this software and associated documentation files (the
"Software"), @@ -1543,9 +1544,9 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, } EXPORT_SYMBOL(__drm_atomic_helper_set_config);
-void drm_atomic_print_state(const struct drm_atomic_state *state) +void drm_atomic_print_state(const struct drm_atomic_state *state,
struct drm_printer *p)
Please add a nice kerneldoc for this newly exported function. Specifically this kerneldoc needs to include a warning that state updates after call drm_atomic_state_helper_commit_hw_done() is unsafe to print using this function, because it looks at the new state objects. Only the old state structures will stay like this.
So maybe rename the function to say print_new_state() to make this completely clear. That way we can eventually add a print_old_state() when needed.
Otherwise I think this makes sense, and nicely avoids the locking issue of looking at ->state pointers without the right locking. -Daniel
Thanks for the review, I have addressed these comments and posted a V2. -Abhinav
{
- struct drm_printer p = drm_info_printer(state->dev->dev); struct drm_plane *plane; struct drm_plane_state *plane_state; struct drm_crtc *crtc;
@@ -1554,17 +1555,23 @@ void drm_atomic_print_state(const struct drm_atomic_state *state) struct drm_connector_state *connector_state; int i;
if (!p) {
DRM_ERROR("invalid drm printer\n");
return;
}
DRM_DEBUG_ATOMIC("checking %p\n", state);
for_each_new_plane_in_state(state, plane, plane_state, i)
drm_atomic_plane_print_state(&p, plane_state);
drm_atomic_plane_print_state(p, plane_state);
for_each_new_crtc_in_state(state, crtc, crtc_state, i)
drm_atomic_crtc_print_state(&p, crtc_state);
drm_atomic_crtc_print_state(p, crtc_state);
for_each_new_connector_in_state(state, connector, connector_state,
i)
drm_atomic_connector_print_state(&p, connector_state);
drm_atomic_connector_print_state(p, connector_state);
} +EXPORT_SYMBOL(drm_atomic_print_state);
static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, bool take_locks) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 25c269bc4681..d9ae86c92608 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -2,6 +2,7 @@
- Copyright (C) 2014 Red Hat
- Copyright (C) 2014 Intel Corp.
- Copyright (C) 2018 Intel Corp.
- Copyright (c) 2020, The Linux Foundation. All rights reserved.
- Permission is hereby granted, free of charge, to any person
obtaining a
- copy of this software and associated documentation files (the
"Software"), @@ -1294,6 +1295,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_out_fence_state *fence_state; int ret = 0; unsigned int i, j, num_fences;
struct drm_printer p = drm_info_printer(dev->dev);
/* disallow for drivers not supporting atomic: */ if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
@@ -1413,7 +1415,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, ret = drm_atomic_nonblocking_commit(state); } else { if (drm_debug_enabled(DRM_UT_STATE))
drm_atomic_print_state(state);
drm_atomic_print_state(state, &p);
ret = drm_atomic_commit(state); }
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index da96b2f64d7e..d34215366936 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -5,6 +5,7 @@
- Jesse Barnes jesse.barnes@intel.com
- Copyright © 2014 Intel Corporation
- Daniel Vetter daniel.vetter@ffwll.ch
- Copyright (c) 2020, The Linux Foundation. All rights reserved.
- Permission is hereby granted, free of charge, to any person
obtaining a
- copy of this software and associated documentation files (the
"Software"), @@ -233,7 +234,8 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane, int __drm_atomic_helper_set_config(struct drm_mode_set *set, struct drm_atomic_state *state);
-void drm_atomic_print_state(const struct drm_atomic_state *state); +void drm_atomic_print_state(const struct drm_atomic_state *state,
struct drm_printer *p);
/* drm_atomic_uapi.c */ int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state, -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Hi Abhinav,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on drm-exynos/exynos-drm-next] [also build test WARNING on drm-intel/for-linux-next tegra-drm/drm/tegra/for-next drm-tip/drm-tip linus/master v5.10-rc1 next-20201026] [cannot apply to drm/drm-next] [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]
url: https://github.com/0day-ci/linux/commits/Abhinav-Kumar/Add-devcoredump-suppo... base: https://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git exynos-drm-next config: mips-randconfig-r014-20201026 (attached as .config) compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project f2c25c70791de95d2466e09b5b58fc37f6ccd7a4) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install mips cross compiling tool for clang build # apt-get install binutils-mips-linux-gnu # https://github.com/0day-ci/linux/commit/76add8f28420cad0b0d2977abed6e031ef30... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Abhinav-Kumar/Add-devcoredump-support-for-DPU/20201022-130507 git checkout 76add8f28420cad0b0d2977abed6e031ef307f32 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=mips
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All warnings (new ones prefixed by >>):
In file included from drivers/gpu/drm/selftests/test-drm_framebuffer.c:12:
drivers/gpu/drm/selftests/../drm_crtc_internal.h:238:10: warning: declaration of 'struct drm_printer' will not be visible outside of this function [-Wvisibility]
struct drm_printer *p); ^ 1 warning generated.
vim +238 drivers/gpu/drm/selftests/../drm_crtc_internal.h
231 232 int __drm_atomic_helper_disable_plane(struct drm_plane *plane, 233 struct drm_plane_state *plane_state); 234 int __drm_atomic_helper_set_config(struct drm_mode_set *set, 235 struct drm_atomic_state *state); 236 237 void drm_atomic_print_state(const struct drm_atomic_state *state,
238 struct drm_printer *p);
239
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Add the dpu_dbg module which adds supports to dump dpu registers which can be used in case of error conditions.
Signed-off-by: Abhinav Kumar abhinavk@codeaurora.org --- drivers/gpu/drm/msm/Makefile | 2 + drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c | 316 ++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h | 273 +++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c | 313 +++++++++++++++++ .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 4 +- drivers/gpu/drm/msm/msm_drv.c | 6 +- 6 files changed, 912 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 340682cd0f32..96bd1398edac 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -54,6 +54,8 @@ msm-y := \ disp/dpu1/dpu_core_irq.o \ disp/dpu1/dpu_core_perf.o \ disp/dpu1/dpu_crtc.o \ + disp/dpu1/dpu_dbg.o \ + disp/dpu1/dpu_dbg_util.o \ disp/dpu1/dpu_encoder.o \ disp/dpu1/dpu_encoder_phys_cmd.o \ disp/dpu1/dpu_encoder_phys_vid.o \ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c new file mode 100644 index 000000000000..6703e1555194 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2009-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include "dpu_dbg.h" +#include "dpu_hw_catalog.h" + +/* global dpu debug base structure */ +static struct dpu_dbg_base dpu_dbg; + + +#ifdef CONFIG_DEV_COREDUMP +static ssize_t dpu_devcoredump_read(char *buffer, loff_t offset, + size_t count, void *data, size_t datalen) +{ + struct drm_print_iterator iter; + struct drm_printer p; + + iter.data = buffer; + iter.offset = 0; + iter.start = offset; + iter.remain = count; + + p = drm_coredump_printer(&iter); + + drm_printf(&p, "---\n"); + + drm_printf(&p, "module: " KBUILD_MODNAME "\n"); + drm_printf(&p, "dpu devcoredump\n"); + drm_printf(&p, "timestamp %lld\n", ktime_to_ns(dpu_dbg.timestamp)); + + dpu_dbg.dpu_dbg_printer = &p; + dpu_dbg.enable_reg_dump = DPU_DBG_DUMP_IN_COREDUMP; + + drm_printf(&p, "===================dpu regs================\n"); + + _dpu_dump_array(&dpu_dbg, dpu_dbg.req_dump_blks, + ARRAY_SIZE(dpu_dbg.req_dump_blks), + dpu_dbg.work_panic, "evtlog_workitem", + dpu_dbg.dump_all); + + drm_printf(&p, "===================dpu drm state================\n"); + + if (dpu_dbg.atomic_state) + drm_atomic_print_state(dpu_dbg.atomic_state, + &p); + + return count - iter.remain; +} + +static void dpu_devcoredump_free(void *data) +{ + if (dpu_dbg.atomic_state) { + drm_atomic_state_put(dpu_dbg.atomic_state); + dpu_dbg.atomic_state = NULL; + } + dpu_dbg.coredump_pending = false; +} + +static void dpu_devcoredump_capture_state(void) +{ + struct drm_device *ddev; + struct drm_modeset_acquire_ctx ctx; + + dpu_dbg.timestamp = ktime_get(); + + ddev = dpu_dbg.drm_dev; + + drm_modeset_acquire_init(&ctx, 0); + + while (drm_modeset_lock_all_ctx(ddev, &ctx) != 0) + drm_modeset_backoff(&ctx); + + dpu_dbg.atomic_state = drm_atomic_helper_duplicate_state(ddev, + &ctx); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} +#else +static void dpu_devcoredump_capture_state(void) +{ +} +#endif /* CONFIG_DEV_COREDUMP */ + +/** + * _dpu_dump_work - deferred dump work function + * @work: work structure + */ +static void _dpu_dump_work(struct kthread_work *work) +{ + /* reset the enable_reg_dump to default before every dump */ + dpu_dbg.enable_reg_dump = DEFAULT_REGDUMP; + + _dpu_dump_array(&dpu_dbg, dpu_dbg.req_dump_blks, + ARRAY_SIZE(dpu_dbg.req_dump_blks), + dpu_dbg.work_panic, "evtlog_workitem", + dpu_dbg.dump_all); + + dpu_devcoredump_capture_state(); + +#ifdef CONFIG_DEV_COREDUMP + if (dpu_dbg.enable_reg_dump & DPU_DBG_DUMP_IN_MEM) { + dev_coredumpm(dpu_dbg.dev, THIS_MODULE, &dpu_dbg, 0, GFP_KERNEL, + dpu_devcoredump_read, dpu_devcoredump_free); + dpu_dbg.coredump_pending = true; + } +#endif +} + +void dpu_dbg_dump(enum dpu_dbg_dump_context dump_mode, const char *name, ...) +{ + int i, index = 0; + bool do_panic = false; + bool dump_all = false; + va_list args; + char *blk_name = NULL; + struct dpu_dbg_reg_base *blk_base = NULL; + struct dpu_dbg_reg_base **blk_arr; + u32 blk_len; + + /* + * if there is a coredump pending return immediately till dump + * if read by userspace or timeout happens + */ + if (((dpu_dbg.enable_reg_dump == DPU_DBG_DUMP_IN_MEM) || + (dpu_dbg.enable_reg_dump == DPU_DBG_DUMP_IN_COREDUMP)) && + dpu_dbg.coredump_pending) { + pr_debug("coredump is pending read\n"); + return; + } + + blk_arr = &dpu_dbg.req_dump_blks[0]; + blk_len = ARRAY_SIZE(dpu_dbg.req_dump_blks); + + memset(dpu_dbg.req_dump_blks, 0, + sizeof(dpu_dbg.req_dump_blks)); + dpu_dbg.dump_all = false; + dpu_dbg.dump_mode = dump_mode; + + va_start(args, name); + i = 0; + while ((blk_name = va_arg(args, char*))) { + + if (IS_ERR_OR_NULL(blk_name)) + break; + + blk_base = _dpu_dump_get_blk_addr(&dpu_dbg, blk_name); + if (blk_base) { + if (index < blk_len) { + blk_arr[index] = blk_base; + index++; + } else { + pr_err("insufficient space to dump %s\n", + blk_name); + } + } + + if (!strcmp(blk_name, "all")) + dump_all = true; + + if (!strcmp(blk_name, "panic")) + do_panic = true; + + } + va_end(args); + + dpu_dbg.work_panic = do_panic; + dpu_dbg.dump_all = dump_all; + + kthread_queue_work(dpu_dbg.dump_worker, + &dpu_dbg.dump_work); + +} + +int dpu_dbg_init(struct device *dev) +{ + if (!dev) { + pr_err("invalid params\n"); + return -EINVAL; + } + + mutex_init(&dpu_dbg.mutex); + INIT_LIST_HEAD(&dpu_dbg.reg_base_list); + dpu_dbg.dev = dev; + + dpu_dbg.work_panic = false; + dpu_dbg.enable_reg_dump = DEFAULT_REGDUMP; + + dpu_dbg.dump_worker = kthread_create_worker(0, "%s", "dpu_dbg"); + if (IS_ERR(dpu_dbg.dump_worker)) + dev_err(dev, "failed to create dpu dbg task\n"); + + kthread_init_work(&dpu_dbg.dump_work, _dpu_dump_work); + + pr_info("dump:%d\n", dpu_dbg.enable_reg_dump); + + return 0; +} + +void dpu_dbg_register_drm_dev(struct drm_device *ddev) +{ + dpu_dbg.drm_dev = ddev; +} + +static void dpu_dbg_reg_base_destroy(void) +{ + struct dpu_dbg_reg_range *range_node, *range_tmp; + struct dpu_dbg_reg_base *blk_base, *blk_tmp; + struct dpu_dbg_base *dbg_base = &dpu_dbg; + + /* if the dbg init failed or was never called */ + if (!dbg_base || !dpu_dbg.dev) + return; + + list_for_each_entry_safe(blk_base, blk_tmp, &dbg_base->reg_base_list, + reg_base_head) { + list_for_each_entry_safe(range_node, range_tmp, + &blk_base->sub_range_list, head) { + list_del(&range_node->head); + kfree(range_node); + } + list_del(&blk_base->reg_base_head); + kfree(blk_base); + } +} + +/** + * dpu_dbg_destroy - destroy dpu debug facilities + */ +void dpu_dbg_destroy(void) +{ + if (dpu_dbg.dump_worker) + kthread_destroy_worker(dpu_dbg.dump_worker); + dpu_dbg_reg_base_destroy(); + mutex_destroy(&dpu_dbg.mutex); +} + +int dpu_dbg_reg_register_base(const char *name, void __iomem *base, + size_t max_offset) +{ + struct dpu_dbg_base *dbg_base = &dpu_dbg; + struct dpu_dbg_reg_base *reg_base; + + if (!name || !strlen(name)) { + pr_err("no debug name provided\n"); + return -EINVAL; + } + + reg_base = kzalloc(sizeof(*reg_base), GFP_KERNEL); + if (!reg_base) + return -ENOMEM; + + strlcpy(reg_base->name, name, sizeof(reg_base->name)); + reg_base->base = base; + reg_base->max_offset = max_offset; + reg_base->off = 0; + reg_base->cnt = DEFAULT_BASE_REG_CNT; + reg_base->reg_dump = NULL; + + /* Initialize list to make sure check for null list will be valid */ + INIT_LIST_HEAD(®_base->sub_range_list); + + pr_debug("%s base: %pK max_offset 0x%zX\n", reg_base->name, + reg_base->base, reg_base->max_offset); + + list_add(®_base->reg_base_head, &dbg_base->reg_base_list); + + return 0; +} + +void dpu_dbg_reg_register_dump_range(const char *base_name, + const char *range_name, u32 offset_start, u32 offset_end, + uint32_t xin_id) +{ + struct dpu_dbg_reg_base *reg_base; + struct dpu_dbg_reg_range *range; + + reg_base = _dpu_dump_get_blk_addr(&dpu_dbg, base_name); + if (!reg_base) { + pr_err("error: for range %s unable to locate base %s\n", + range_name, base_name); + return; + } + + if (!range_name || strlen(range_name) == 0) { + pr_err("%pS: bad range name, base_name %s, offset_start 0x%X, end 0x%X\n", + __builtin_return_address(0), base_name, + offset_start, offset_end); + return; + } + + if (offset_end - offset_start < REG_DUMP_ALIGN || + offset_start > offset_end) { + pr_err("%pS: bad range, base_name %s, range_name %s, offset_start 0x%X, end 0x%X\n", + __builtin_return_address(0), base_name, + range_name, offset_start, offset_end); + return; + } + + range = kzalloc(sizeof(*range), GFP_KERNEL); + if (!range) + return; + + strlcpy(range->range_name, range_name, sizeof(range->range_name)); + range->offset.start = offset_start; + range->offset.end = offset_end; + range->xin_id = xin_id; + list_add_tail(&range->head, ®_base->sub_range_list); + + pr_debug("base %s, range %s, start 0x%X, end 0x%X\n", + base_name, range->range_name, + range->offset.start, range->offset.end); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h new file mode 100644 index 000000000000..2cea13288cef --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef DPU_DBG_H_ +#define DPU_DBG_H_ + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_device.h> +#include "../../../drm_crtc_internal.h" +#include <drm/drm_print.h> +#include <drm/drm_atomic.h> +#include <linux/debugfs.h> +#include <linux/list.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/ktime.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/dma-buf.h> +#include <linux/slab.h> +#include <linux/list_sort.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/kthread.h> +#include <linux/devcoredump.h> +#include <stdarg.h> + +#define DPU_DBG_DUMP_DATA_LIMITER (NULL) + +enum dpu_dbg_dump_flag { + DPU_DBG_DUMP_IN_LOG = BIT(0), + DPU_DBG_DUMP_IN_MEM = BIT(1), + DPU_DBG_DUMP_IN_COREDUMP = BIT(2), +}; + +enum dpu_dbg_dump_context { + DPU_DBG_DUMP_PROC_CTX, + DPU_DBG_DUMP_CLK_ENABLED_CTX, +}; + +#define DPU_DBG_BASE_MAX 10 + +#define DEFAULT_PANIC 0 +#define DEFAULT_REGDUMP DPU_DBG_DUMP_IN_MEM +#define DEFAULT_BASE_REG_CNT DEFAULT_MDSS_HW_BLOCK_SIZE +#define ROW_BYTES 16 +#define RANGE_NAME_LEN 40 +#define REG_BASE_NAME_LEN 80 + +/* print debug ranges in groups of 4 u32s */ +#define REG_DUMP_ALIGN 16 + +/** + * struct dpu_dbg_reg_offset - tracking for start and end of region + * @start: start offset + * @start: end offset + */ +struct dpu_dbg_reg_offset { + u32 start; + u32 end; +}; + +/** + * struct dpu_dbg_reg_range - register dumping named sub-range + * @head: head of this node + * @reg_dump: address for the mem dump + * @range_name: name of this range + * @offset: offsets for range to dump + * @xin_id: client xin id + */ +struct dpu_dbg_reg_range { + struct list_head head; + u32 *reg_dump; + char range_name[RANGE_NAME_LEN]; + struct dpu_dbg_reg_offset offset; + uint32_t xin_id; +}; + +/** + * struct dpu_dbg_reg_base - register region base. + * may sub-ranges: sub-ranges are used for dumping + * or may not have sub-ranges: dumping is base -> max_offset + * @reg_base_head: head of this node + * @sub_range_list: head to the list with dump ranges + * @name: register base name + * @base: base pointer + * @off: cached offset of region for manual register dumping + * @cnt: cached range of region for manual register dumping + * @max_offset: length of region + * @buf: buffer used for manual register dumping + * @buf_len: buffer length used for manual register dumping + * @reg_dump: address for the mem dump if no ranges used + * @cb: callback for external dump function, null if not defined + * @cb_ptr: private pointer to callback function + */ +struct dpu_dbg_reg_base { + struct list_head reg_base_head; + struct list_head sub_range_list; + char name[REG_BASE_NAME_LEN]; + void __iomem *base; + size_t off; + size_t cnt; + size_t max_offset; + char *buf; + size_t buf_len; + u32 *reg_dump; + void (*cb)(void *ptr); + void *cb_ptr; +}; + +/** + * struct dpu_dbg_base - global sde debug base structure + * @evtlog: event log instance + * @reg_base_list: list of register dumping regions + * @dev: device pointer + * @drm_dev: drm device pointer + * @mutex: mutex to serialize access to serialze dumps, debugfs access + * @req_dump_blks: list of blocks requested for dumping + * @work_panic: panic after dump if internal user passed "panic" special region + * @enable_reg_dump: whether to dump registers into memory, kernel log, or both + * @dump_all: dump all entries in register dump + * @coredump_pending: coredump is pending read from userspace + * @atomic_state: atomic state duplicated at the time of the error + * @dump_worker: kworker thread which runs the dump work + * @dump_work: kwork which dumps the registers and drm state + * @timestamp: timestamp at which the coredump was captured + * @dpu_dbg_printer: drm printer handle used to take drm snapshot + * @dump_mode: decides whether the data is dumped in memory or logs + */ +struct dpu_dbg_base { + struct list_head reg_base_list; + struct device *dev; + struct drm_device *drm_dev; + struct mutex mutex; + + struct dpu_dbg_reg_base *req_dump_blks[DPU_DBG_BASE_MAX]; + + bool work_panic; + u32 enable_reg_dump; + + bool dump_all; + bool coredump_pending; + + struct drm_atomic_state *atomic_state; + + struct kthread_worker *dump_worker; + struct kthread_work dump_work; + ktime_t timestamp; + + struct drm_printer *dpu_dbg_printer; + + enum dpu_dbg_dump_context dump_mode; +}; + +struct dpu_dbg_power_ctrl { + void *handle; + void *client; + int (*enable_fn)(void *handle, void *client, bool enable); +}; + + +/** + * DPU_DBG_DUMP - trigger dumping of all dpu_dbg facilities + * @va_args: list of named register dump ranges and regions to dump, as + * registered previously through dpu_dbg_reg_register_base and + * dpu_dbg_reg_register_dump_range. + * Including the special name "panic" will trigger a panic after + * the dumping work has completed. + */ +#define DPU_DBG_DUMP(...) dpu_dbg_dump(DPU_DBG_DUMP_PROC_CTX, __func__, \ + ##__VA_ARGS__, DPU_DBG_DUMP_DATA_LIMITER) + +/** + * DPU_DBG_DUMP_CLK_EN - trigger dumping of all dpu_dbg facilities, without clk + * @va_args: list of named register dump ranges and regions to dump, as + * registered previously through dpu_dbg_reg_register_base and + * dpu_dbg_reg_register_dump_range. + * Including the special name "panic" will trigger a panic after + * the dumping work has completed. + */ +#define DPU_DBG_DUMP_CLK_EN(...) dpu_dbg_dump(DPU_DBG_DUMP_CLK_ENABLED_CTX, \ + __func__, ##__VA_ARGS__, DPU_DBG_DUMP_DATA_LIMITER) + +/** + * dpu_dbg_init - initialize global sde debug facilities: evtlog, regdump + * @dev: device handle + * Returns: 0 or -ERROR + */ +int dpu_dbg_init(struct device *dev); + +/** + * dpu_dbg_register_drm_dev - register a drm device with the dpu dbg module + * @ddev: drm device hangle + * Returns: void + */ +void dpu_dbg_register_drm_dev(struct drm_device *ddev); + +/** + * dpu_dbg_destroy - destroy the global sde debug facilities + * Returns: none + */ +void dpu_dbg_destroy(void); + +/** + * dpu_dbg_dump - trigger dumping of all dpu_dbg facilities + * @queue_work: whether to queue the dumping work to the work_struct + * @name: string indicating origin of dump + * @va_args: list of named register dump ranges and regions to dump, as + * registered previously through dpu_dbg_reg_register_base and + * dpu_dbg_reg_register_dump_range. + * Including the special name "panic" will trigger a panic after + * the dumping work has completed. + * Returns: none + */ +void dpu_dbg_dump(enum dpu_dbg_dump_context mode, const char *name, ...); + +/** + * dpu_dbg_reg_register_base - register a hw register address section for later + * dumping. call this before calling dpu_dbg_reg_register_dump_range + * to be able to specify sub-ranges within the base hw range. + * @name: name of base region + * @base: base pointer of region + * @max_offset: length of region + * Returns: 0 or -ERROR + */ +int dpu_dbg_reg_register_base(const char *name, void __iomem *base, + size_t max_offset); + +/** + * dpu_dbg_reg_register_dump_range - register a hw register sub-region for + * later register dumping associated with base specified by + * dpu_dbg_reg_register_base + * @base_name: name of base region + * @range_name: name of sub-range within base region + * @offset_start: sub-range's start offset from base's base pointer + * @offset_end: sub-range's end offset from base's base pointer + * @xin_id: xin id + * Returns: none + */ +void dpu_dbg_reg_register_dump_range(const char *base_name, + const char *range_name, u32 offset_start, u32 offset_end, + uint32_t xin_id); + +/** + * dpu_dbg_set_sde_top_offset - set the target specific offset from mdss base + * address of the top registers. Used for accessing debug bus controls. + * @blk_off: offset from mdss base of the top block + */ +void dpu_dbg_set_sde_top_offset(u32 blk_off); + +/** + * _dpu_dump_array - dump array of register bases + * @blk_arr: array of register base pointers + * @len: length of blk_arr + * @do_panic: whether to trigger a panic after dumping + * @name: string indicating origin of dump + * @dump_all: dump all regs + */ +void _dpu_dump_array(struct dpu_dbg_base *dbg_base, + struct dpu_dbg_reg_base *blk_arr[], + u32 len, bool do_panic, const char *name, bool dump_all); + +/** + * _dpu_dump_get_blk_addr - retrieve register block address by name + * @blk_name: register blk name + * @Return: register blk base, or NULL + */ +struct dpu_dbg_reg_base *_dpu_dump_get_blk_addr(struct dpu_dbg_base *dbg_base, + const char *blk_name); + +#endif /* DPU_DBG_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c new file mode 100644 index 000000000000..a54bea108020 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include "dpu_dbg.h" +#include "dpu_hw_catalog.h" + +/** + * _sde_power_check - check if power needs to enabled + * @dump_mode: to check if power need to be enabled + * Return: true if success; false otherwise + */ +static inline bool _dpu_power_check(enum dpu_dbg_dump_context dump_mode) +{ + return (dump_mode == DPU_DBG_DUMP_CLK_ENABLED_CTX) ? false : true; +} + +/** + * _dpu_dump_reg - helper function for dumping rotator register set content + * @dump_name: register set name + * @reg_dump_flag: dumping flag controlling in-log/memory dump location + * @base_addr: starting address of io region for calculating offsets to print + * @addr: starting address offset for dumping + * @len_bytes: range of the register set + * @dump_mem: output buffer for memory dump location option + * @from_isr: whether being called from isr context + */ +static void _dpu_dump_reg(struct dpu_dbg_base *dbg_base, + const char *dump_name, u32 reg_dump_flag, + char *base_addr, char *addr, size_t len_bytes, u32 **dump_mem) +{ + u32 in_log, in_mem, len_align, len_padded, in_dump; + u32 *dump_addr = NULL; + char *end_addr; + int i; + int rc; + + if (!len_bytes) + return; + + in_log = (reg_dump_flag & DPU_DBG_DUMP_IN_LOG); + in_mem = (reg_dump_flag & DPU_DBG_DUMP_IN_MEM); + in_dump = (reg_dump_flag & DPU_DBG_DUMP_IN_COREDUMP); + + pr_debug("%s: reg_dump_flag=%d in_log=%d in_mem=%d\n", + dump_name, reg_dump_flag, in_log, in_mem); + + if (!in_log && !in_mem && !in_dump) + return; + + if (in_log) + dev_info(dbg_base->dev, "%s: start_offset 0x%lx len 0x%zx\n", + dump_name, (unsigned long)(addr - base_addr), + len_bytes); + + len_align = (len_bytes + REG_DUMP_ALIGN - 1) / REG_DUMP_ALIGN; + len_padded = len_align * REG_DUMP_ALIGN; + end_addr = addr + len_bytes; + + if (in_mem || in_dump) { + if (dump_mem && !(*dump_mem)) + *dump_mem = devm_kzalloc(dbg_base->dev, len_padded, + GFP_KERNEL); + + if (dump_mem && *dump_mem) { + dump_addr = *dump_mem; + dev_info(dbg_base->dev, + "%s: start_addr:0x%pK len:0x%x reg_offset=0x%lx\n", + dump_name, dump_addr, len_padded, + (unsigned long)(addr - base_addr)); + if (in_dump) + drm_printf(dbg_base->dpu_dbg_printer, + "%s: start_addr:0x%pK len:0x%x reg_offset=0x%lx\n", + dump_name, dump_addr, + len_padded, + (unsigned long)(addr - + base_addr)); + } else { + in_mem = 0; + pr_err("dump_mem: kzalloc fails!\n"); + } + } + + if (_dpu_power_check(dbg_base->dump_mode)) { + rc = pm_runtime_get_sync(dbg_base->dev); + if (rc < 0) { + pr_err("failed to enable power %d\n", rc); + return; + } + } + + for (i = 0; i < len_align; i++) { + u32 x0, x4, x8, xc; + + if (in_log || in_mem) { + x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0; + x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + + 0x4) : 0; + x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + + 0x8) : 0; + xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + + 0xc) : 0; + } + + if (in_log) + dev_info(dbg_base->dev, + "0x%lx : %08x %08x %08x %08x\n", + (unsigned long)(addr - base_addr), + x0, x4, x8, xc); + + if (dump_addr && in_mem) { + dump_addr[i * 4] = x0; + dump_addr[i * 4 + 1] = x4; + dump_addr[i * 4 + 2] = x8; + dump_addr[i * 4 + 3] = xc; + } + + if (in_dump) { + drm_printf(dbg_base->dpu_dbg_printer, + "0x%lx : %08x %08x %08x %08x\n", + (unsigned long)(addr - base_addr), + dump_addr[i * 4], + dump_addr[i * 4 + 1], + dump_addr[i * 4 + 2], + dump_addr[i * 4 + 3]); + + } + + addr += REG_DUMP_ALIGN; + } + + if (_dpu_power_check(dbg_base->dump_mode)) + pm_runtime_put_sync(dbg_base->dev); +} + +/** + * _dpu_dbg_get_dump_range - helper to retrieve dump length for a range node + * @range_node: range node to dump + * @max_offset: max offset of the register base + * @Return: length + */ +static u32 _dpu_dbg_get_dump_range(struct dpu_dbg_reg_offset *range_node, + size_t max_offset) +{ + u32 length = 0; + + if (range_node->start == 0 && range_node->end == 0) { + length = max_offset; + } else if (range_node->start < max_offset) { + if (range_node->end > max_offset) + length = max_offset - range_node->start; + else if (range_node->start < range_node->end) + length = range_node->end - range_node->start; + } + + return length; +} + +static int _dpu_dump_reg_range_cmp(void *priv, struct list_head *a, + struct list_head *b) +{ + struct dpu_dbg_reg_range *ar, *br; + + if (!a || !b) + return 0; + + ar = container_of(a, struct dpu_dbg_reg_range, head); + br = container_of(b, struct dpu_dbg_reg_range, head); + + return ar->offset.start - br->offset.start; +} + +/** + * _dpu_dump_reg_by_ranges - dump ranges or full range of the register blk base + * @dbg: register blk base structure + * @reg_dump_flag: dump target, memory, kernel log, or both + */ +static void _dpu_dump_reg_by_ranges(struct dpu_dbg_base *dbg_base, + struct dpu_dbg_reg_base *dbg, + u32 reg_dump_flag) +{ + char *addr; + size_t len; + struct dpu_dbg_reg_range *range_node; + + if (!dbg || !(dbg->base || dbg->cb)) { + pr_err("dbg base is null!\n"); + return; + } + + dev_info(dbg_base->dev, "%s:=========%s DUMP=========\n", __func__, + dbg->name); + + if (reg_dump_flag & DPU_DBG_DUMP_IN_COREDUMP) + drm_printf(dbg_base->dpu_dbg_printer, + "%s:=========%s DUMP=========\n", + __func__, dbg->name); + + if (dbg->cb) { + dbg->cb(dbg->cb_ptr); + /* If there is a list to dump the registers by ranges, use the ranges */ + } else if (!list_empty(&dbg->sub_range_list)) { + /* sort the list by start address first */ + list_sort(NULL, &dbg->sub_range_list, _dpu_dump_reg_range_cmp); + list_for_each_entry(range_node, &dbg->sub_range_list, head) { + len = _dpu_dbg_get_dump_range(&range_node->offset, + dbg->max_offset); + addr = dbg->base + range_node->offset.start; + + pr_debug("%s: range_base=0x%pK start=0x%x end=0x%x\n", + range_node->range_name, + addr, range_node->offset.start, + range_node->offset.end); + + _dpu_dump_reg(dbg_base, range_node->range_name, + reg_dump_flag, + dbg->base, addr, len, + &range_node->reg_dump); + } + } else { + /* If there is no list to dump ranges, dump all registers */ + dev_info(dbg_base->dev, + "Ranges not found, will dump full registers\n"); + dev_info(dbg_base->dev, "base:0x%pK len:0x%zx\n", dbg->base, + dbg->max_offset); + addr = dbg->base; + len = dbg->max_offset; + _dpu_dump_reg(dbg_base, dbg->name, reg_dump_flag, + dbg->base, addr, len, + &dbg->reg_dump); + } +} + +/** + * _dpu_dump_reg_by_blk - dump a named register base region + * @blk_name: register blk name + */ +static void _dpu_dump_reg_by_blk(struct dpu_dbg_base *dbg_base, + const char *blk_name) +{ + struct dpu_dbg_reg_base *blk_base; + + if (!dbg_base) + return; + + list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head) { + if (strlen(blk_base->name) && + !strcmp(blk_base->name, blk_name)) { + _dpu_dump_reg_by_ranges(dbg_base, blk_base, + dbg_base->enable_reg_dump); + break; + } + } +} + +/** + * _dpu_dump_reg_all - dump all register regions + */ +static void _dpu_dump_reg_all(struct dpu_dbg_base *dbg_base) +{ + struct dpu_dbg_reg_base *blk_base; + + if (!dbg_base) + return; + + list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head) { + + if (!strlen(blk_base->name)) + continue; + + _dpu_dump_reg_by_blk(dbg_base, blk_base->name); + } +} + +struct dpu_dbg_reg_base *_dpu_dump_get_blk_addr(struct dpu_dbg_base *dbg_base, + const char *blk_name) +{ + struct dpu_dbg_reg_base *blk_base; + + list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head) + if (strlen(blk_base->name) && !strcmp(blk_base->name, blk_name)) + return blk_base; + + return NULL; +} + +void _dpu_dump_array(struct dpu_dbg_base *dbg_base, + struct dpu_dbg_reg_base *blk_arr[], + u32 len, bool do_panic, const char *name, bool dump_all) +{ + int i; + + mutex_lock(&dbg_base->mutex); + + if (dump_all || !blk_arr || !len) { + _dpu_dump_reg_all(dbg_base); + } else { + for (i = 0; i < len; i++) { + if (blk_arr[i] != NULL) + _dpu_dump_reg_by_ranges(dbg_base, + blk_arr[i], + dbg_base->enable_reg_dump); + } + } + + if (do_panic) + panic(name); + + mutex_unlock(&dbg_base->mutex); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 3544af1a45c5..b2ab22be4c55 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */
#ifndef _DPU_HW_CATALOG_H @@ -52,6 +52,8 @@
#define DPU_HW_BLK_NAME_LEN 16 +/* default size of valid register space for MDSS_HW block (offset 0) */ +#define DEFAULT_MDSS_HW_BLOCK_SIZE 0x5C
#define MAX_IMG_WIDTH 0x3fff #define MAX_IMG_HEIGHT 0x3fff diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 49685571dc0e..f6fb0187388f 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, 2020 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark robdclark@gmail.com */ @@ -17,6 +17,7 @@ #include <drm/drm_prime.h> #include <drm/drm_of.h> #include <drm/drm_vblank.h> +#include "dpu_dbg.h"
#include "msm_drv.h" #include "msm_debugfs.h" @@ -268,6 +269,8 @@ static int msm_drm_uninit(struct device *dev) msm_fbdev_free(ddev); #endif
+ dpu_dbg_destroy(); + drm_mode_config_cleanup(ddev);
pm_runtime_get_sync(dev); @@ -1303,6 +1306,7 @@ static int msm_pdev_probe(struct platform_device *pdev)
fail: of_platform_depopulate(&pdev->dev); + dpu_dbg_destroy(); return ret; }
Hi Abhinav,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on drm-exynos/exynos-drm-next] [also build test WARNING on drm-intel/for-linux-next tegra-drm/drm/tegra/for-next drm-tip/drm-tip linus/master v5.9 next-20201022] [cannot apply to drm/drm-next] [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]
url: https://github.com/0day-ci/linux/commits/Abhinav-Kumar/Add-devcoredump-suppo... base: https://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git exynos-drm-next config: arm-defconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/a7e6907c303a46ea8422fc3c414c22fdfb45... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Abhinav-Kumar/Add-devcoredump-support-for-DPU/20201022-130507 git checkout a7e6907c303a46ea8422fc3c414c22fdfb45d49f # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All warnings (new ones prefixed by >>):
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c: In function 'dpu_dbg_dump':
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c:115:6: warning: variable 'i' set but not used [-Wunused-but-set-variable]
115 | int i, index = 0; | ^
vim +/i +115 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c
112 113 void dpu_dbg_dump(enum dpu_dbg_dump_context dump_mode, const char *name, ...) 114 {
115 int i, index = 0;
116 bool do_panic = false; 117 bool dump_all = false; 118 va_list args; 119 char *blk_name = NULL; 120 struct dpu_dbg_reg_base *blk_base = NULL; 121 struct dpu_dbg_reg_base **blk_arr; 122 u32 blk_len; 123 124 /* 125 * if there is a coredump pending return immediately till dump 126 * if read by userspace or timeout happens 127 */ 128 if (((dpu_dbg.enable_reg_dump == DPU_DBG_DUMP_IN_MEM) || 129 (dpu_dbg.enable_reg_dump == DPU_DBG_DUMP_IN_COREDUMP)) && 130 dpu_dbg.coredump_pending) { 131 pr_debug("coredump is pending read\n"); 132 return; 133 } 134 135 blk_arr = &dpu_dbg.req_dump_blks[0]; 136 blk_len = ARRAY_SIZE(dpu_dbg.req_dump_blks); 137 138 memset(dpu_dbg.req_dump_blks, 0, 139 sizeof(dpu_dbg.req_dump_blks)); 140 dpu_dbg.dump_all = false; 141 dpu_dbg.dump_mode = dump_mode; 142 143 va_start(args, name); 144 i = 0; 145 while ((blk_name = va_arg(args, char*))) { 146 147 if (IS_ERR_OR_NULL(blk_name)) 148 break; 149 150 blk_base = _dpu_dump_get_blk_addr(&dpu_dbg, blk_name); 151 if (blk_base) { 152 if (index < blk_len) { 153 blk_arr[index] = blk_base; 154 index++; 155 } else { 156 pr_err("insufficient space to dump %s\n", 157 blk_name); 158 } 159 } 160 161 if (!strcmp(blk_name, "all")) 162 dump_all = true; 163 164 if (!strcmp(blk_name, "panic")) 165 do_panic = true; 166 167 } 168 va_end(args); 169 170 dpu_dbg.work_panic = do_panic; 171 dpu_dbg.dump_all = dump_all; 172 173 kthread_queue_work(dpu_dbg.dump_worker, 174 &dpu_dbg.dump_work); 175
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hi Abhinav,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on drm-exynos/exynos-drm-next] [also build test WARNING on drm-intel/for-linux-next tegra-drm/drm/tegra/for-next drm-tip/drm-tip linus/master v5.10-rc1 next-20201027] [cannot apply to drm/drm-next] [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]
url: https://github.com/0day-ci/linux/commits/Abhinav-Kumar/Add-devcoredump-suppo... base: https://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git exynos-drm-next config: arm64-randconfig-s032-20201026 (attached as .config) compiler: aarch64-linux-gcc (GCC) 9.3.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # apt-get install sparse # sparse version: v0.6.3-56-gc09e8239-dirty # https://github.com/0day-ci/linux/commit/a7e6907c303a46ea8422fc3c414c22fdfb45... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Abhinav-Kumar/Add-devcoredump-support-for-DPU/20201022-130507 git checkout a7e6907c303a46ea8422fc3c414c22fdfb45d49f # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=arm64
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
"sparse warnings: (new ones prefixed by >>)"
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:99:50: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got char * @@ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:99:50: sparse: expected void const volatile [noderef] __iomem *addr drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:99:50: sparse: got char *
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:100:56: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got char * @@ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:100:56: sparse: expected void const volatile [noderef] __iomem *addr drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:100:56: sparse: got char * drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:102:56: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got char * @@ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:102:56: sparse: expected void const volatile [noderef] __iomem *addr drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:102:56: sparse: got char * drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:104:56: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile [noderef] __iomem *addr @@ got char * @@ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:104:56: sparse: expected void const volatile [noderef] __iomem *addr drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:104:56: sparse: got char *
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:211:30: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected char *addr @@ got void [noderef] __iomem * @@ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:211:30: sparse: expected char *addr drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:211:30: sparse: got void [noderef] __iomem * drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:220:44: sparse: sparse: incorrect type in argument 4 (different address spaces) @@ expected char *base_addr @@ got void [noderef] __iomem *base @@ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:220:44: sparse: expected char *base_addr drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:220:44: sparse: got void [noderef] __iomem *base drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:229:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected char *addr @@ got void [noderef] __iomem *base @@
drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:229:22: sparse: expected char *addr drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:229:22: sparse: got void [noderef] __iomem *base drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:232:36: sparse: sparse: incorrect type in argument 4 (different address spaces) @@ expected char *base_addr @@ got void [noderef] __iomem *base @@ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:232:36: sparse: expected char *base_addr drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c:232:36: sparse: got void [noderef] __iomem *base
vim +99 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg_util.c
20 21 /** 22 * _dpu_dump_reg - helper function for dumping rotator register set content 23 * @dump_name: register set name 24 * @reg_dump_flag: dumping flag controlling in-log/memory dump location 25 * @base_addr: starting address of io region for calculating offsets to print 26 * @addr: starting address offset for dumping 27 * @len_bytes: range of the register set 28 * @dump_mem: output buffer for memory dump location option 29 * @from_isr: whether being called from isr context 30 */ 31 static void _dpu_dump_reg(struct dpu_dbg_base *dbg_base, 32 const char *dump_name, u32 reg_dump_flag, 33 char *base_addr, char *addr, size_t len_bytes, u32 **dump_mem) 34 { 35 u32 in_log, in_mem, len_align, len_padded, in_dump; 36 u32 *dump_addr = NULL; 37 char *end_addr; 38 int i; 39 int rc; 40 41 if (!len_bytes) 42 return; 43 44 in_log = (reg_dump_flag & DPU_DBG_DUMP_IN_LOG); 45 in_mem = (reg_dump_flag & DPU_DBG_DUMP_IN_MEM); 46 in_dump = (reg_dump_flag & DPU_DBG_DUMP_IN_COREDUMP); 47 48 pr_debug("%s: reg_dump_flag=%d in_log=%d in_mem=%d\n", 49 dump_name, reg_dump_flag, in_log, in_mem); 50 51 if (!in_log && !in_mem && !in_dump) 52 return; 53 54 if (in_log) 55 dev_info(dbg_base->dev, "%s: start_offset 0x%lx len 0x%zx\n", 56 dump_name, (unsigned long)(addr - base_addr), 57 len_bytes); 58 59 len_align = (len_bytes + REG_DUMP_ALIGN - 1) / REG_DUMP_ALIGN; 60 len_padded = len_align * REG_DUMP_ALIGN; 61 end_addr = addr + len_bytes; 62 63 if (in_mem || in_dump) { 64 if (dump_mem && !(*dump_mem)) 65 *dump_mem = devm_kzalloc(dbg_base->dev, len_padded, 66 GFP_KERNEL); 67 68 if (dump_mem && *dump_mem) { 69 dump_addr = *dump_mem; 70 dev_info(dbg_base->dev, 71 "%s: start_addr:0x%pK len:0x%x reg_offset=0x%lx\n", 72 dump_name, dump_addr, len_padded, 73 (unsigned long)(addr - base_addr)); 74 if (in_dump) 75 drm_printf(dbg_base->dpu_dbg_printer, 76 "%s: start_addr:0x%pK len:0x%x reg_offset=0x%lx\n", 77 dump_name, dump_addr, 78 len_padded, 79 (unsigned long)(addr - 80 base_addr)); 81 } else { 82 in_mem = 0; 83 pr_err("dump_mem: kzalloc fails!\n"); 84 } 85 } 86 87 if (_dpu_power_check(dbg_base->dump_mode)) { 88 rc = pm_runtime_get_sync(dbg_base->dev); 89 if (rc < 0) { 90 pr_err("failed to enable power %d\n", rc); 91 return; 92 } 93 } 94 95 for (i = 0; i < len_align; i++) { 96 u32 x0, x4, x8, xc; 97 98 if (in_log || in_mem) {
99 x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0;
100 x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + 101 0x4) : 0; 102 x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + 103 0x8) : 0; 104 xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + 105 0xc) : 0; 106 } 107 108 if (in_log) 109 dev_info(dbg_base->dev, 110 "0x%lx : %08x %08x %08x %08x\n", 111 (unsigned long)(addr - base_addr), 112 x0, x4, x8, xc); 113 114 if (dump_addr && in_mem) { 115 dump_addr[i * 4] = x0; 116 dump_addr[i * 4 + 1] = x4; 117 dump_addr[i * 4 + 2] = x8; 118 dump_addr[i * 4 + 3] = xc; 119 } 120 121 if (in_dump) { 122 drm_printf(dbg_base->dpu_dbg_printer, 123 "0x%lx : %08x %08x %08x %08x\n", 124 (unsigned long)(addr - base_addr), 125 dump_addr[i * 4], 126 dump_addr[i * 4 + 1], 127 dump_addr[i * 4 + 2], 128 dump_addr[i * 4 + 3]); 129 130 } 131 132 addr += REG_DUMP_ALIGN; 133 } 134 135 if (_dpu_power_check(dbg_base->dump_mode)) 136 pm_runtime_put_sync(dbg_base->dev); 137 } 138 139 /** 140 * _dpu_dbg_get_dump_range - helper to retrieve dump length for a range node 141 * @range_node: range node to dump 142 * @max_offset: max offset of the register base 143 * @Return: length 144 */ 145 static u32 _dpu_dbg_get_dump_range(struct dpu_dbg_reg_offset *range_node, 146 size_t max_offset) 147 { 148 u32 length = 0; 149 150 if (range_node->start == 0 && range_node->end == 0) { 151 length = max_offset; 152 } else if (range_node->start < max_offset) { 153 if (range_node->end > max_offset) 154 length = max_offset - range_node->start; 155 else if (range_node->start < range_node->end) 156 length = range_node->end - range_node->start; 157 } 158 159 return length; 160 } 161 162 static int _dpu_dump_reg_range_cmp(void *priv, struct list_head *a, 163 struct list_head *b) 164 { 165 struct dpu_dbg_reg_range *ar, *br; 166 167 if (!a || !b) 168 return 0; 169 170 ar = container_of(a, struct dpu_dbg_reg_range, head); 171 br = container_of(b, struct dpu_dbg_reg_range, head); 172 173 return ar->offset.start - br->offset.start; 174 } 175 176 /** 177 * _dpu_dump_reg_by_ranges - dump ranges or full range of the register blk base 178 * @dbg: register blk base structure 179 * @reg_dump_flag: dump target, memory, kernel log, or both 180 */ 181 static void _dpu_dump_reg_by_ranges(struct dpu_dbg_base *dbg_base, 182 struct dpu_dbg_reg_base *dbg, 183 u32 reg_dump_flag) 184 { 185 char *addr; 186 size_t len; 187 struct dpu_dbg_reg_range *range_node; 188 189 if (!dbg || !(dbg->base || dbg->cb)) { 190 pr_err("dbg base is null!\n"); 191 return; 192 } 193 194 dev_info(dbg_base->dev, "%s:=========%s DUMP=========\n", __func__, 195 dbg->name); 196 197 if (reg_dump_flag & DPU_DBG_DUMP_IN_COREDUMP) 198 drm_printf(dbg_base->dpu_dbg_printer, 199 "%s:=========%s DUMP=========\n", 200 __func__, dbg->name); 201 202 if (dbg->cb) { 203 dbg->cb(dbg->cb_ptr); 204 /* If there is a list to dump the registers by ranges, use the ranges */ 205 } else if (!list_empty(&dbg->sub_range_list)) { 206 /* sort the list by start address first */ 207 list_sort(NULL, &dbg->sub_range_list, _dpu_dump_reg_range_cmp); 208 list_for_each_entry(range_node, &dbg->sub_range_list, head) { 209 len = _dpu_dbg_get_dump_range(&range_node->offset, 210 dbg->max_offset);
211 addr = dbg->base + range_node->offset.start;
212 213 pr_debug("%s: range_base=0x%pK start=0x%x end=0x%x\n", 214 range_node->range_name, 215 addr, range_node->offset.start, 216 range_node->offset.end); 217 218 _dpu_dump_reg(dbg_base, range_node->range_name, 219 reg_dump_flag,
220 dbg->base, addr, len,
221 &range_node->reg_dump); 222 } 223 } else { 224 /* If there is no list to dump ranges, dump all registers */ 225 dev_info(dbg_base->dev, 226 "Ranges not found, will dump full registers\n"); 227 dev_info(dbg_base->dev, "base:0x%pK len:0x%zx\n", dbg->base, 228 dbg->max_offset);
229 addr = dbg->base;
230 len = dbg->max_offset; 231 _dpu_dump_reg(dbg_base, dbg->name, reg_dump_flag, 232 dbg->base, addr, len, 233 &dbg->reg_dump); 234 } 235 } 236
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Register the base address of various dpu sub-modules with the dpu_dbg module so that it can be dumped out during error scenarios.
Signed-off-by: Abhinav Kumar abhinavk@codeaurora.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c | 4 +-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 6 ++++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c | 7 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 5 +++- .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c | 6 ++++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 8 +++++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c | 7 ++++- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 12 +++++++-- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 ++- drivers/gpu/drm/msm/dp/dp_catalog.c | 12 +++++++++ drivers/gpu/drm/msm/dp/dp_catalog.h | 4 +++ drivers/gpu/drm/msm/dp/dp_display.c | 2 ++ drivers/gpu/drm/msm/dsi/dsi_host.c | 10 ++++++- drivers/gpu/drm/msm/msm_drv.c | 26 ++++++++++++++++++- drivers/gpu/drm/msm/msm_drv.h | 3 ++- 15 files changed, 101 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c index 6703e1555194..62f49e60a4ca 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c @@ -263,7 +263,7 @@ int dpu_dbg_reg_register_base(const char *name, void __iomem *base, /* Initialize list to make sure check for null list will be valid */ INIT_LIST_HEAD(®_base->sub_range_list);
- pr_debug("%s base: %pK max_offset 0x%zX\n", reg_base->name, + pr_info("%s base: %pK max_offset 0x%zX\n", reg_base->name, reg_base->base, reg_base->max_offset);
list_add(®_base->reg_base_head, &dbg_base->reg_base_list); @@ -310,7 +310,7 @@ void dpu_dbg_reg_register_dump_range(const char *base_name, range->xin_id = xin_id; list_add_tail(&range->head, ®_base->sub_range_list);
- pr_debug("base %s, range %s, start 0x%X, end 0x%X\n", + pr_info("base_name %s, range_name %s, start 0x%X, end 0x%X\n", base_name, range->range_name, range->offset.start, range->offset.end); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index 758c355b4fd8..3a827ea96723 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */
#include <linux/delay.h> @@ -7,6 +7,7 @@ #include "dpu_hw_ctl.h" #include "dpu_kms.h" #include "dpu_trace.h" +#include "dpu_dbg.h"
#define CTL_LAYER(lm) \ (((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004)) @@ -588,6 +589,9 @@ struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx,
dpu_hw_blk_init(&c->base, DPU_HW_BLK_CTL, idx, &dpu_hw_ops);
+ dpu_dbg_reg_register_dump_range(DPU_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + return c; }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c index a7a24539921f..ee9ae02f5e7f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */
#include "dpu_hwio.h" @@ -7,7 +7,7 @@ #include "dpu_hw_lm.h" #include "dpu_hw_dspp.h" #include "dpu_kms.h" - +#include "dpu_dbg.h"
/* DSPP_PCC */ #define PCC_EN BIT(0) @@ -115,6 +115,9 @@ struct dpu_hw_dspp *dpu_hw_dspp_init(enum dpu_dspp idx,
dpu_hw_blk_init(&c->base, DPU_HW_BLK_DSPP, idx, &dpu_hw_ops);
+ dpu_dbg_reg_register_dump_range(DPU_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + return c; }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c index 6f0f54588124..d8198d4d42bc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */
#include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_intf.h" #include "dpu_kms.h" +#include "dpu_dbg.h"
#define INTF_TIMING_ENGINE_EN 0x000 #define INTF_CONFIG 0x004 @@ -319,6 +320,8 @@ struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx,
dpu_hw_blk_init(&c->base, DPU_HW_BLK_INTF, idx, &dpu_hw_ops);
+ dpu_dbg_reg_register_dump_range(DPU_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); return c; }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c index bea4ab5c58c5..0dc6d161e890 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */
#include <linux/iopoll.h> @@ -10,6 +10,7 @@ #include "dpu_hw_pingpong.h" #include "dpu_kms.h" #include "dpu_trace.h" +#include "dpu_dbg.h"
#define PP_TEAR_CHECK_EN 0x000 #define PP_SYNC_CONFIG_VSYNC 0x004 @@ -260,6 +261,9 @@ struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx,
dpu_hw_blk_init(&c->base, DPU_HW_BLK_PINGPONG, idx, &dpu_hw_ops);
+ dpu_dbg_reg_register_dump_range(DPU_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + return c; }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index c940b69435e1..873fc828538d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */
#include "dpu_hwio.h" @@ -7,6 +7,7 @@ #include "dpu_hw_lm.h" #include "dpu_hw_sspp.h" #include "dpu_kms.h" +#include "dpu_dbg.h"
#define DPU_FETCH_CONFIG_RESET_VALUE 0x00000087
@@ -736,6 +737,11 @@ struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx,
dpu_hw_blk_init(&hw_pipe->base, DPU_HW_BLK_SSPP, idx, &dpu_hw_ops);
+ dpu_dbg_reg_register_dump_range(DPU_DBG_NAME, cfg->name, + hw_pipe->hw.blk_off, + hw_pipe->hw.blk_off + hw_pipe->hw.length, + hw_pipe->hw.xin_id); + return hw_pipe; }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c index 01b76766a9a8..f042471815cc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */
#include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_top.h" #include "dpu_kms.h" +#include "dpu_dbg.h"
#define SSPP_SPARE 0x28
@@ -326,6 +327,10 @@ struct dpu_hw_mdp *dpu_hw_mdptop_init(enum dpu_mdp idx,
dpu_hw_blk_init(&mdp->base, DPU_HW_BLK_TOP, idx, &dpu_hw_ops);
+ dpu_dbg_reg_register_dump_range(DPU_DBG_NAME, cfg->name, + mdp->hw.blk_off, mdp->hw.blk_off + mdp->hw.length, + mdp->hw.xin_id); + return mdp; }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index d93c44f6996d..dc64e032d82f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, 2020 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark robdclark@gmail.com */ @@ -27,6 +27,7 @@ #include "dpu_encoder.h" #include "dpu_plane.h" #include "dpu_crtc.h" +#include "dpu_dbg.h"
#define CREATE_TRACE_POINTS #include "dpu_trace.h" @@ -908,7 +909,14 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dpu_kms->mmio = NULL; goto error; } - DRM_DEBUG("mapped dpu address space @%pK\n", dpu_kms->mmio); + + dpu_kms->mmio_len = msm_iomap_size(dpu_kms->pdev, "mdp"); + + DRM_DEBUG("mapped dpu address space @%pK len = 0x%lx\n", + dpu_kms->mmio, dpu_kms->mmio_len); + + dpu_dbg_reg_register_base(DPU_DBG_NAME, + dpu_kms->mmio, dpu_kms->mmio_len);
dpu_kms->vbif[VBIF_RT] = msm_ioremap(dpu_kms->pdev, "vbif", "vbif"); if (IS_ERR(dpu_kms->vbif[VBIF_RT])) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 1c0e4c0c9ffb..a478b40868dd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark robdclark@gmail.com */ @@ -103,6 +103,8 @@ struct dpu_kms { /* io/register spaces: */ void __iomem *mmio, *vbif[VBIF_MAX], *reg_dma;
+ unsigned long mmio_len; + struct regulator *vdd; struct regulator *mmagic; struct regulator *venus; diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index b15b4ce4ba35..efde98a3d9ab 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -63,6 +63,18 @@ struct dp_catalog_private { u8 aux_lut_cfg_index[PHY_AUX_CFG_MAX]; };
+void dp_catalog_register_dbg_base(struct dp_catalog *dp_catalog) +{ + char dbg_name[32]; + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + snprintf(dbg_name, 32, "dp_ctrl"); + + dpu_dbg_reg_register_base(dbg_name, catalog->io->dp_controller.base, + catalog->io->dp_controller.len); +} + static inline u32 dp_read_aux(struct dp_catalog_private *catalog, u32 offset) { offset += MSM_DP_CONTROLLER_AUX_OFFSET; diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h index 4b7666f1fe6f..af48590913e3 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.h +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h @@ -9,6 +9,7 @@ #include <drm/drm_modes.h>
#include "dp_parser.h" +#include "dpu_dbg.h"
/* interrupts */ #define DP_INTR_HPD BIT(0) @@ -71,6 +72,9 @@ struct dp_catalog { u32 audio_data; };
+/* Debug module */ +void dp_catalog_register_dbg_base(struct dp_catalog *dp_catalog); + /* AUX APIs */ u32 dp_catalog_aux_read_data(struct dp_catalog *dp_catalog); int dp_catalog_aux_write_data(struct dp_catalog *dp_catalog); diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index e175aa3fd3a9..4a5735564be2 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -230,6 +230,8 @@ static int dp_display_bind(struct device *dev, struct device *master, if (rc) DRM_ERROR("Audio registration Dp failed\n");
+ dp_catalog_register_dbg_base(dp->catalog); + end: return rc; } diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index b17ac6c27554..97c04d31f289 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved. */
#include <linux/clk.h> @@ -26,6 +26,8 @@ #include "sfpb.xml.h" #include "dsi_cfg.h" #include "msm_kms.h" +#include "dpu_dbg.h" +#include "msm_drv.h"
#define DSI_RESET_TOGGLE_DELAY_MS 20
@@ -1823,6 +1825,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) struct msm_dsi_host *msm_host = NULL; struct platform_device *pdev = msm_dsi->pdev; int ret; + char dbg_name[32];
msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL); if (!msm_host) { @@ -1912,6 +1915,11 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
msm_dsi->id = msm_host->id;
+ snprintf(dbg_name, 32, "dsi%d_ctrl", + msm_host->id); + dpu_dbg_reg_register_base(dbg_name, msm_host->ctrl_base, + msm_iomap_size(pdev, "dsi_ctrl")); + DBG("Dsi Host %d initialized", msm_host->id); return 0;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index f6fb0187388f..df505a3d53e8 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -17,8 +17,8 @@ #include <drm/drm_prime.h> #include <drm/drm_of.h> #include <drm/drm_vblank.h> -#include "dpu_dbg.h"
+#include "dpu_dbg.h" #include "msm_drv.h" #include "msm_debugfs.h" #include "msm_fence.h" @@ -166,6 +166,24 @@ void __iomem *msm_ioremap_quiet(struct platform_device *pdev, const char *name, return _msm_ioremap(pdev, name, dbgname, true); }
+unsigned long msm_iomap_size(struct platform_device *pdev, const char *name) +{ + struct resource *res; + + if (name) + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + else + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_dbg(&pdev->dev, "failed to get memory resource: %s\n", + name); + return 0; + } + + return resource_size(res); +} + void msm_writel(u32 data, void __iomem *addr) { if (reglog) @@ -535,6 +553,8 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) if (ret) goto err_msm_uninit;
+ dpu_dbg_register_drm_dev(ddev); + drm_mode_config_reset(ddev);
#ifdef CONFIG_DRM_FBDEV_EMULATION @@ -1282,6 +1302,10 @@ static int msm_pdev_probe(struct platform_device *pdev) int ret;
if (get_mdp_ver(pdev)) { + ret = dpu_dbg_init(&pdev->dev); + if (ret) + pr_err("dpu_dbg_init failed ret = %d\n", ret); + ret = add_display_components(&pdev->dev, &match); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index b9dd8f8f4887..211161bdce2f 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, 2020 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark robdclark@gmail.com */ @@ -476,6 +476,7 @@ void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, const char *dbgname); void __iomem *msm_ioremap_quiet(struct platform_device *pdev, const char *name, const char *dbgname); +unsigned long msm_iomap_size(struct platform_device *pdev, const char *name); void msm_writel(u32 data, void __iomem *addr); u32 msm_readl(const void __iomem *addr);
Add dpu_dbg points across dpu driver to trigger dumps when critical errors are hit.
Signed-off-by: Abhinav Kumar abhinavk@codeaurora.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 12 ++++++++++-- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 5 +++-- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 5 ++++- 3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index f7f5c258b553..a2ee1af73c9f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, 2020 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark robdclark@gmail.com */ @@ -26,6 +26,7 @@ #include "dpu_crtc.h" #include "dpu_trace.h" #include "dpu_core_irq.h" +#include "dpu_dbg.h"
#define DPU_DEBUG_ENC(e, fmt, ...) DPU_DEBUG("enc%d " fmt,\ (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) @@ -1313,6 +1314,11 @@ static void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc,
DPU_ATRACE_BEGIN("encoder_underrun_callback"); atomic_inc(&phy_enc->underrun_cnt); + + /* trigger dump only on the first underrun */ + if (atomic_read(&phy_enc->underrun_cnt) == 1) + DPU_DBG_DUMP("all"); + trace_dpu_enc_underrun_cb(DRMID(drm_enc), atomic_read(&phy_enc->underrun_cnt)); DPU_ATRACE_END("encoder_underrun_callback"); @@ -1553,8 +1559,10 @@ static void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc) ctl->idx);
rc = ctl->ops.reset(ctl); - if (rc) + if (rc) { DPU_ERROR_ENC(dpu_enc, "ctl %d reset failure\n", ctl->idx); + DPU_DBG_DUMP("all"); + }
phys_enc->enable_state = DPU_ENC_ENABLED; } 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 8493d68ad841..58f79557b560 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 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -9,6 +9,7 @@ #include "dpu_core_irq.h" #include "dpu_formats.h" #include "dpu_trace.h" +#include "dpu_dbg.h"
#define DPU_DEBUG_CMDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ (e) && (e)->base.parent ? \ @@ -213,7 +214,7 @@ static int _dpu_encoder_phys_cmd_handle_ppdone_timeout( phys_enc->hw_ctl->idx - CTL_0, cmd_enc->pp_timeout_report_cnt, atomic_read(&phys_enc->pending_kickoff_cnt)); - + DPU_DBG_DUMP("all"); dpu_encoder_helper_unregister_irq(phys_enc, INTR_IDX_RDPTR); }
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 805e059b50b7..46c5320150fa 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 @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -8,6 +8,7 @@ #include "dpu_core_irq.h" #include "dpu_formats.h" #include "dpu_trace.h" +#include "dpu_dbg.h"
#define DPU_DEBUG_VIDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ (e) && (e)->parent ? \ @@ -467,6 +468,7 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc) "update pending flush ctl %d flush_mask 0%x intf_mask 0x%x\n", ctl->idx - CTL_0, flush_mask, intf_flush_mask);
+ atomic_set(&phys_enc->underrun_cnt, 0);
/* ctl_flush & timing engine enable will be triggered by framework */ if (phys_enc->enable_state == DPU_ENC_DISABLED) @@ -549,6 +551,7 @@ static void dpu_encoder_phys_vid_prepare_for_kickoff( if (rc) { DPU_ERROR_VIDENC(phys_enc, "ctl %d reset failure: %d\n", ctl->idx, rc); + DPU_DBG_DUMP("all"); dpu_encoder_helper_unregister_irq(phys_enc, INTR_IDX_VSYNC); } }
dri-devel@lists.freedesktop.org