From 743c97ca9dc989b0b08ca1fbfd134a83b37fe9ec Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 11 Feb 2021 14:40:58 -0800 Subject: [PATCH 01/13] drm/msm/kms: Use nested locking for crtc lock instead of custom classes We don't need to make up custom lock classes here, we can simply use mutex_lock_nested() and pass in the index of the crtc to the locking APIs instead. This helps lockdep understand that these are really different locks while avoiding having to allocate custom lockdep classes. Cc: Krishna Manikandan Suggested-by: Daniel Vetter Fixes: b3d91800d9ac ("drm/msm: Fix race condition in msm driver with async layer updates") Signed-off-by: Stephen Boyd Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_atomic.c | 7 +++++-- drivers/gpu/drm/msm/msm_kms.h | 8 ++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 6a326761dc4a..edcaccaa27e6 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -57,10 +57,13 @@ static void vblank_put(struct msm_kms *kms, unsigned crtc_mask) static void lock_crtcs(struct msm_kms *kms, unsigned int crtc_mask) { + int crtc_index; struct drm_crtc *crtc; - for_each_crtc_mask(kms->dev, crtc, crtc_mask) - mutex_lock(&kms->commit_lock[drm_crtc_index(crtc)]); + for_each_crtc_mask(kms->dev, crtc, crtc_mask) { + crtc_index = drm_crtc_index(crtc); + mutex_lock_nested(&kms->commit_lock[crtc_index], crtc_index); + } } static void unlock_crtcs(struct msm_kms *kms, unsigned int crtc_mask) diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 4735251a394d..d8151a89e163 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -157,7 +157,6 @@ struct msm_kms { * from the crtc's pending_timer close to end of the frame: */ struct mutex commit_lock[MAX_CRTCS]; - struct lock_class_key commit_lock_keys[MAX_CRTCS]; unsigned pending_crtc_mask; struct msm_pending_timer pending_timers[MAX_CRTCS]; }; @@ -167,11 +166,8 @@ static inline int msm_kms_init(struct msm_kms *kms, { unsigned i, ret; - for (i = 0; i < ARRAY_SIZE(kms->commit_lock); i++) { - lockdep_register_key(&kms->commit_lock_keys[i]); - __mutex_init(&kms->commit_lock[i], "&kms->commit_lock[i]", - &kms->commit_lock_keys[i]); - } + for (i = 0; i < ARRAY_SIZE(kms->commit_lock); i++) + mutex_init(&kms->commit_lock[i]); kms->funcs = funcs; From 65aee407a0f5d0548c560e5fc3cad21e51b6f7fd Mon Sep 17 00:00:00 2001 From: Jonathan Marek Date: Mon, 8 Feb 2021 13:55:54 -0500 Subject: [PATCH 02/13] drm/msm: fix a6xx_gmu_clear_oob The cleanup patch broke a6xx_gmu_clear_oob, fix it by adding the missing bitshift operation. Fixes: 555c50a4a19b ("drm/msm: Clean up GMU OOB set/clear handling") Signed-off-by: Jonathan Marek Reviewed-by: Jordan Crouse Reviewed-by: Eric Anholt Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 9066e98eb8ef..863047b98bf3 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -339,7 +339,7 @@ void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state) else bit = a6xx_gmu_oob_bits[state].ack_new; - gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, bit); + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 1 << bit); } /* Enable CPU control of SPTP power power collapse */ From 8490f02a3ca45fd1bbcadc243b4db9b69d0e3450 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Tue, 9 Feb 2021 17:52:05 -0700 Subject: [PATCH 03/13] drm/msm: a6xx: Make sure the SQE microcode is safe Most a6xx targets have security issues that were fixed with new versions of the microcode(s). Make sure that we are booting with a safe version of the microcode for the target and print a message and error if not. v2: Add more informative error messages and fix typos Signed-off-by: Jordan Crouse Reviewed-by: Akhil P Oommen Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 77 ++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index ba8e9d3cf0fe..064b7face504 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -522,28 +522,73 @@ static int a6xx_cp_init(struct msm_gpu *gpu) return a6xx_idle(gpu, ring) ? 0 : -EINVAL; } -static void a6xx_ucode_check_version(struct a6xx_gpu *a6xx_gpu, +/* + * Check that the microcode version is new enough to include several key + * security fixes. Return true if the ucode is safe. + */ +static bool a6xx_ucode_check_version(struct a6xx_gpu *a6xx_gpu, struct drm_gem_object *obj) { + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + struct msm_gpu *gpu = &adreno_gpu->base; u32 *buf = msm_gem_get_vaddr(obj); + bool ret = false; if (IS_ERR(buf)) - return; + return false; /* - * If the lowest nibble is 0xa that is an indication that this microcode - * has been patched. The actual version is in dword [3] but we only care - * about the patchlevel which is the lowest nibble of dword [3] - * - * Otherwise check that the firmware is greater than or equal to 1.90 - * which was the first version that had this fix built in + * Targets up to a640 (a618, a630 and a640) need to check for a + * microcode version that is patched to support the whereami opcode or + * one that is new enough to include it by default. */ - if (((buf[0] & 0xf) == 0xa) && (buf[2] & 0xf) >= 1) - a6xx_gpu->has_whereami = true; - else if ((buf[0] & 0xfff) > 0x190) - a6xx_gpu->has_whereami = true; + if (adreno_is_a618(adreno_gpu) || adreno_is_a630(adreno_gpu) || + adreno_is_a640(adreno_gpu)) { + /* + * If the lowest nibble is 0xa that is an indication that this + * microcode has been patched. The actual version is in dword + * [3] but we only care about the patchlevel which is the lowest + * nibble of dword [3] + * + * Otherwise check that the firmware is greater than or equal + * to 1.90 which was the first version that had this fix built + * in + */ + if ((((buf[0] & 0xf) == 0xa) && (buf[2] & 0xf) >= 1) || + (buf[0] & 0xfff) >= 0x190) { + a6xx_gpu->has_whereami = true; + ret = true; + goto out; + } + DRM_DEV_ERROR(&gpu->pdev->dev, + "a630 SQE ucode is too old. Have version %x need at least %x\n", + buf[0] & 0xfff, 0x190); + } else { + /* + * a650 tier targets don't need whereami but still need to be + * equal to or newer than 1.95 for other security fixes + */ + if (adreno_is_a650(adreno_gpu)) { + if ((buf[0] & 0xfff) >= 0x195) { + ret = true; + goto out; + } + + DRM_DEV_ERROR(&gpu->pdev->dev, + "a650 SQE ucode is too old. Have version %x need at least %x\n", + buf[0] & 0xfff, 0x195); + } + + /* + * When a660 is added those targets should return true here + * since those have all the critical security fixes built in + * from the start + */ + } +out: msm_gem_put_vaddr(obj); + return ret; } static int a6xx_ucode_init(struct msm_gpu *gpu) @@ -566,7 +611,13 @@ static int a6xx_ucode_init(struct msm_gpu *gpu) } msm_gem_object_set_name(a6xx_gpu->sqe_bo, "sqefw"); - a6xx_ucode_check_version(a6xx_gpu, a6xx_gpu->sqe_bo); + if (!a6xx_ucode_check_version(a6xx_gpu, a6xx_gpu->sqe_bo)) { + msm_gem_unpin_iova(a6xx_gpu->sqe_bo, gpu->aspace); + drm_gem_object_put(a6xx_gpu->sqe_bo); + + a6xx_gpu->sqe_bo = NULL; + return -EPERM; + } } gpu_write64(gpu, REG_A6XX_CP_SQE_INSTR_BASE_LO, From 7bf168c8fe8c6166b5dc10005fe7f250164da0ad Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 26 Feb 2021 16:26:01 -0800 Subject: [PATCH 04/13] drm/msm: Fix speed-bin support not to access outside valid memory When running the latest kernel on an sc7180 with KASAN I got this splat: BUG: KASAN: slab-out-of-bounds in a6xx_gpu_init+0x618/0x644 Read of size 4 at addr ffffff8088f36100 by task kworker/7:1/58 CPU: 7 PID: 58 Comm: kworker/7:1 Not tainted 5.11.0+ #3 Hardware name: Google Lazor (rev1 - 2) with LTE (DT) Workqueue: events deferred_probe_work_func Call trace: dump_backtrace+0x0/0x3a8 show_stack+0x24/0x30 dump_stack+0x174/0x1e0 print_address_description+0x70/0x2e4 kasan_report+0x178/0x1bc __asan_report_load4_noabort+0x44/0x50 a6xx_gpu_init+0x618/0x644 adreno_bind+0x26c/0x438 This is because the speed bin is defined like this: gpu_speed_bin: gpu_speed_bin@1d2 { reg = <0x1d2 0x2>; bits = <5 8>; }; As you can see the "length" is 2 bytes. That means that the nvmem subsystem allocates only 2 bytes. The GPU code, however, was casting the pointer allocated by nvmem to a (u32 *) and dereferencing. That's not so good. Let's fix this to just use the nvmem_cell_read_u16() accessor function which simplifies things and also gets rid of the splat. Let's also put an explicit conversion from little endian in place just to make things clear. The nvmem subsystem today is assuming little endian and this makes it clear. Specifically, the way the above sc7180 cell is interpreted: NVMEM: +--------+--------+--------+--------+--------+ | ...... | 0x1d3 | 0x1d2 | ...... | 0x000 | +--------+--------+--------+--------+--------+ ^ ^ msb lsb You can see that the least significant data is at the lower address which is little endian. NOTE: someone who is truly paying attention might wonder about me picking the "u16" version of this accessor instead of the "u8" (since the value is 8 bits big) or the u32 version (just for fun). At the moment you need to pick the accessor that exactly matches the length the cell was specified as in the device tree. Hopefully future patches to the nvmem subsystem will fix this. Fixes: fe7952c629da ("drm/msm: Add speed-bin support to a618 gpu") Signed-off-by: Douglas Anderson Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 31 +++++++-------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 064b7face504..690409ca8a18 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1401,35 +1401,20 @@ static int a6xx_set_supported_hw(struct device *dev, struct a6xx_gpu *a6xx_gpu, u32 revn) { struct opp_table *opp_table; - struct nvmem_cell *cell; u32 supp_hw = UINT_MAX; - void *buf; + u16 speedbin; + int ret; - cell = nvmem_cell_get(dev, "speed_bin"); - /* - * -ENOENT means that the platform doesn't support speedbin which is - * fine - */ - if (PTR_ERR(cell) == -ENOENT) - return 0; - else if (IS_ERR(cell)) { + ret = nvmem_cell_read_u16(dev, "speed_bin", &speedbin); + if (ret) { DRM_DEV_ERROR(dev, - "failed to read speed-bin. Some OPPs may not be supported by hardware"); + "failed to read speed-bin (%d). Some OPPs may not be supported by hardware", + ret); goto done; } + speedbin = le16_to_cpu(speedbin); - buf = nvmem_cell_read(cell, NULL); - if (IS_ERR(buf)) { - nvmem_cell_put(cell); - DRM_DEV_ERROR(dev, - "failed to read speed-bin. Some OPPs may not be supported by hardware"); - goto done; - } - - supp_hw = fuse_to_supp_hw(dev, revn, *((u32 *) buf)); - - kfree(buf); - nvmem_cell_put(cell); + supp_hw = fuse_to_supp_hw(dev, revn, speedbin); done: opp_table = dev_pm_opp_set_supported_hw(dev, &supp_hw, 1); From 3b24cdfc721a5f1098da22f9f68ff5f4a5efccc9 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 25 Feb 2021 01:47:51 +0300 Subject: [PATCH 05/13] drm/msm/dsi: fix check-before-set in the 7nm dsi_pll code Fix setting min/max DSI PLL rate for the V4.1 7nm DSI PLL (used on sm8250). Current code checks for pll->type before it is set (as it is set in the msm_dsi_pll_init() after calling device-specific functions. Cc: Jonathan Marek Fixes: 1ef7c99d145c ("drm/msm/dsi: add support for 7nm DSI PHY/PLL") Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/pll/dsi_pll.c | 2 +- drivers/gpu/drm/msm/dsi/pll/dsi_pll.h | 6 ++++-- drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c index a45fe95aff49..3dc65877fa10 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c @@ -163,7 +163,7 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, break; case MSM_DSI_PHY_7NM: case MSM_DSI_PHY_7NM_V4_1: - pll = msm_dsi_pll_7nm_init(pdev, id); + pll = msm_dsi_pll_7nm_init(pdev, type, id); break; default: pll = ERR_PTR(-ENXIO); diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h index 3405982a092c..bbecb1de5678 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h @@ -117,10 +117,12 @@ msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) } #endif #ifdef CONFIG_DRM_MSM_DSI_7NM_PHY -struct msm_dsi_pll *msm_dsi_pll_7nm_init(struct platform_device *pdev, int id); +struct msm_dsi_pll *msm_dsi_pll_7nm_init(struct platform_device *pdev, + enum msm_dsi_phy_type type, int id); #else static inline struct msm_dsi_pll * -msm_dsi_pll_7nm_init(struct platform_device *pdev, int id) +msm_dsi_pll_7nm_init(struct platform_device *pdev, + enum msm_dsi_phy_type type, int id) { return ERR_PTR(-ENODEV); } diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c index 93bf142e4a4e..c1f6708367ae 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c @@ -852,7 +852,8 @@ err_base_clk_hw: return ret; } -struct msm_dsi_pll *msm_dsi_pll_7nm_init(struct platform_device *pdev, int id) +struct msm_dsi_pll *msm_dsi_pll_7nm_init(struct platform_device *pdev, + enum msm_dsi_phy_type type, int id) { struct dsi_pll_7nm *pll_7nm; struct msm_dsi_pll *pll; @@ -885,7 +886,7 @@ struct msm_dsi_pll *msm_dsi_pll_7nm_init(struct platform_device *pdev, int id) pll = &pll_7nm->base; pll->min_rate = 1000000000UL; pll->max_rate = 3500000000UL; - if (pll->type == MSM_DSI_PHY_7NM_V4_1) { + if (type == MSM_DSI_PHY_7NM_V4_1) { pll->min_rate = 600000000UL; pll->max_rate = (unsigned long)5000000000ULL; /* workaround for max rate overflowing on 32-bit builds: */ From 19f4a055abf2a69a1c0109456c3758b5697730c9 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 25 Feb 2021 02:01:43 +0300 Subject: [PATCH 06/13] drm/msm/dsi_pll_7nm: Solve TODO for multiplier frac_bits assignment The number of fractional registers bits is known and already set in the frac_bits variable of the dsi_pll_config struct here in 7nm: remove the TODO by simply using that variable. This is a copy of 196145eb1af1 ("drm/msm/dsi_pll_10nm: Solve TODO for multiplier frac_bits assignment"). Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c index c1f6708367ae..0458eda15114 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c @@ -509,6 +509,7 @@ static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw, { struct msm_dsi_pll *pll = hw_clk_to_pll(hw); struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); + struct dsi_pll_config *config = &pll_7nm->pll_configuration; void __iomem *base = pll_7nm->mmio; u64 ref_clk = pll_7nm->vco_ref_clk_rate; u64 vco_rate = 0x0; @@ -529,9 +530,8 @@ static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw, /* * TODO: * 1. Assumes prescaler is disabled - * 2. Multiplier is 2^18. it should be 2^(num_of_frac_bits) */ - multiplier = 1 << 18; + multiplier = 1 << config->frac_bits; pll_freq = dec * (ref_clk * 2); tmp64 = (ref_clk * 2 * frac); pll_freq += div_u64(tmp64, multiplier); From 9daaf31307856defb1070685418ce5a484ecda3a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 25 Feb 2021 02:05:28 +0300 Subject: [PATCH 07/13] drm/msm/dsi_pll_7nm: Fix variable usage for pll_lockdet_rate The PLL_LOCKDET_RATE_1 was being programmed with a hardcoded value directly, but the same value was also being specified in the dsi_pll_regs struct pll_lockdet_rate variable: let's use it! Based on 362cadf34b9f ("drm/msm/dsi_pll_10nm: Fix variable usage for pll_lockdet_rate") Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c index 0458eda15114..e29b3bfd63d1 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c @@ -325,7 +325,7 @@ static void dsi_pll_commit(struct dsi_pll_7nm *pll) pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1, reg->frac_div_start_low); pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1, reg->frac_div_start_mid); pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1, reg->frac_div_start_high); - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCKDET_RATE_1, 0x40); + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCKDET_RATE_1, reg->pll_lockdet_rate); pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); pll_write(base + REG_DSI_7nm_PHY_PLL_CMODE_1, 0x10); /* TODO: 0x00 for CPHY */ pll_write(base + REG_DSI_7nm_PHY_PLL_CLOCK_INVERTERS, reg->pll_clock_inverters); From 413b7a320e238d1a79dfca24c35ce4e1a0e7a8d6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 26 Feb 2021 13:08:21 -0800 Subject: [PATCH 08/13] drm/msm/dp: Restore aux retry tuning logic In commit 9fc418430c65 ("drm/msm/dp: unplug interrupt missed after irq_hpd handler") we dropped a reset of the aux phy during aux transfers because resetting the phy during active communication caused us to miss an hpd irq in some cases. Unfortunately, we also dropped the part of the code that changes the aux phy tuning when an aux transfer fails due to a timeout. That part of the code was calling into the phy driver to reconfigure the aux TX swing controls, working around poor channel quality. Let's restore this phy setting code so that aux channel communication is more reliable. Cc: Kuogee Hsieh Fixes: 9fc418430c65 ("drm/msm/dp: unplug interrupt missed after irq_hpd handler") Signed-off-by: Stephen Boyd Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dp/dp_aux.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index 1c6e1d2b947c..7c22bfe0fc7d 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -32,6 +32,8 @@ struct dp_aux_private { struct drm_dp_aux dp_aux; }; +#define MAX_AUX_RETRIES 5 + static const char *dp_aux_get_error(u32 aux_error) { switch (aux_error) { @@ -377,6 +379,11 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, ret = dp_aux_cmd_fifo_tx(aux, msg); if (ret < 0) { + if (aux->native) { + aux->retry_cnt++; + if (!(aux->retry_cnt % MAX_AUX_RETRIES)) + dp_catalog_aux_update_cfg(aux->catalog); + } usleep_range(400, 500); /* at least 400us to next try */ goto unlock_exit; } From 4a9d36b0610aa7034340e976652e5b43320dd7c5 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sun, 28 Feb 2021 13:36:51 +0100 Subject: [PATCH 09/13] drm/msm/adreno: a5xx_power: Don't apply A540 lm_setup to other GPUs While passing the A530-specific lm_setup func to A530 and A540 to !A530 was fine back when only these two were supported, it certainly is not a good idea to send A540 specifics to smaller GPUs like A508 and friends. Signed-off-by: Konrad Dybcio Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a5xx_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c index 5ccc9da455a1..c35b06b46fcc 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_power.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c @@ -304,7 +304,7 @@ int a5xx_power_init(struct msm_gpu *gpu) /* Set up the limits management */ if (adreno_is_a530(adreno_gpu)) a530_lm_setup(gpu); - else + else if (adreno_is_a540(adreno_gpu)) a540_lm_setup(gpu); /* Set up SP/TP power collpase */ From 7ad48d27a2846bfda29214fb454d001c3e02b9e7 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 17 Mar 2021 09:40:38 -0700 Subject: [PATCH 10/13] drm/msm: Ratelimit invalid-fence message We have seen a couple cases where low memory situations cause something bad to happen, followed by a flood of these messages obscuring the root cause. Lets ratelimit the dmesg spam so that next time it happens we don't lose the kernel traces leading up to this. Signed-off-by: Rob Clark Reviewed-by: Douglas Anderson --- drivers/gpu/drm/msm/msm_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c index ad2703698b05..cd59a5918038 100644 --- a/drivers/gpu/drm/msm/msm_fence.c +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -45,7 +45,7 @@ int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, int ret; if (fence > fctx->last_fence) { - DRM_ERROR("%s: waiting on invalid fence: %u (of %u)\n", + DRM_ERROR_RATELIMITED("%s: waiting on invalid fence: %u (of %u)\n", fctx->name, fence, fctx->last_fence); return -EINVAL; } From 623f279c77811475ac8fd5635cc4e4451aa71291 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 20 Mar 2021 08:56:02 -0300 Subject: [PATCH 11/13] drm/msm: fix shutdown hook in case GPU components failed to bind If GPU components have failed to bind, shutdown callback would fail with the following backtrace. Add safeguard check to stop that oops from happening and allow the board to reboot. [ 66.617046] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 [ 66.626066] Mem abort info: [ 66.628939] ESR = 0x96000006 [ 66.632088] EC = 0x25: DABT (current EL), IL = 32 bits [ 66.637542] SET = 0, FnV = 0 [ 66.640688] EA = 0, S1PTW = 0 [ 66.643924] Data abort info: [ 66.646889] ISV = 0, ISS = 0x00000006 [ 66.650832] CM = 0, WnR = 0 [ 66.653890] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000107f81000 [ 66.660505] [0000000000000000] pgd=0000000100bb2003, p4d=0000000100bb2003, pud=0000000100897003, pmd=0000000000000000 [ 66.671398] Internal error: Oops: 96000006 [#1] PREEMPT SMP [ 66.677115] Modules linked in: [ 66.680261] CPU: 6 PID: 352 Comm: reboot Not tainted 5.11.0-rc2-00309-g79e3faa756b2 #38 [ 66.688473] Hardware name: Qualcomm Technologies, Inc. Robotics RB5 (DT) [ 66.695347] pstate: 60400005 (nZCv daif +PAN -UAO -TCO BTYPE=--) [ 66.701507] pc : msm_atomic_commit_tail+0x78/0x4e0 [ 66.706437] lr : commit_tail+0xa4/0x184 [ 66.710381] sp : ffff8000108f3af0 [ 66.713791] x29: ffff8000108f3af0 x28: ffff418c44337000 [ 66.719242] x27: 0000000000000000 x26: ffff418c40a24490 [ 66.724693] x25: ffffd3a842a4f1a0 x24: 0000000000000008 [ 66.730146] x23: ffffd3a84313f030 x22: ffff418c444ce000 [ 66.735598] x21: ffff418c408a4980 x20: 0000000000000000 [ 66.741049] x19: 0000000000000000 x18: ffff800010710fbc [ 66.746500] x17: 000000000000000c x16: 0000000000000001 [ 66.751954] x15: 0000000000010008 x14: 0000000000000068 [ 66.757405] x13: 0000000000000001 x12: 0000000000000000 [ 66.762855] x11: 0000000000000001 x10: 00000000000009b0 [ 66.768306] x9 : ffffd3a843192000 x8 : ffff418c44337000 [ 66.773757] x7 : 0000000000000000 x6 : 00000000a401b34e [ 66.779210] x5 : 00ffffffffffffff x4 : 0000000000000000 [ 66.784660] x3 : 0000000000000000 x2 : ffff418c444ce000 [ 66.790111] x1 : ffffd3a841dce530 x0 : ffff418c444cf000 [ 66.795563] Call trace: [ 66.798075] msm_atomic_commit_tail+0x78/0x4e0 [ 66.802633] commit_tail+0xa4/0x184 [ 66.806217] drm_atomic_helper_commit+0x160/0x390 [ 66.811051] drm_atomic_commit+0x4c/0x60 [ 66.815082] drm_atomic_helper_disable_all+0x1f4/0x210 [ 66.820355] drm_atomic_helper_shutdown+0x80/0x130 [ 66.825276] msm_pdev_shutdown+0x14/0x20 [ 66.829303] platform_shutdown+0x28/0x40 [ 66.833330] device_shutdown+0x158/0x330 [ 66.837357] kernel_restart+0x40/0xa0 [ 66.841122] __do_sys_reboot+0x228/0x250 [ 66.845148] __arm64_sys_reboot+0x28/0x34 [ 66.849264] el0_svc_common.constprop.0+0x74/0x190 [ 66.854187] do_el0_svc+0x24/0x90 [ 66.857595] el0_svc+0x14/0x20 [ 66.860739] el0_sync_handler+0x1a4/0x1b0 [ 66.864858] el0_sync+0x174/0x180 [ 66.868269] Code: 1ac020a0 2a000273 eb02007f 54ffff01 (f9400285) [ 66.874525] ---[ end trace 20dedb2a3229fec8 ]--- Fixes: 9d5cbf5fe46e ("drm/msm: add shutdown support for display platform_driver") Signed-off-by: Dmitry Baryshkov Signed-off-by: Fabio Estevam Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 94525ac76d4e..fd2ac54caf9f 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1311,6 +1311,10 @@ static int msm_pdev_remove(struct platform_device *pdev) static void msm_pdev_shutdown(struct platform_device *pdev) { struct drm_device *drm = platform_get_drvdata(pdev); + struct msm_drm_private *priv = drm ? drm->dev_private : NULL; + + if (!priv || !priv->kms) + return; drm_atomic_helper_shutdown(drm); } From a9748134ea4aad989e52a6a91479e0acfd306e5b Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Mar 2021 08:56:03 -0300 Subject: [PATCH 12/13] drm/msm: Fix suspend/resume on i.MX5 When putting iMX5 into suspend, the following flow is observed: [ 70.023427] [] (msm_atomic_commit_tail) from [] (commit_tail+0x9c/0x18c) [ 70.031890] [] (commit_tail) from [] (drm_atomic_helper_commit+0x1a0/0x1d4) [ 70.040627] [] (drm_atomic_helper_commit) from [] (drm_atomic_helper_disable_all+0x1c4/0x1d4) [ 70.050913] [] (drm_atomic_helper_disable_all) from [] (drm_atomic_helper_suspend+0xb8/0x170) [ 70.061198] [] (drm_atomic_helper_suspend) from [] (drm_mode_config_helper_suspend+0x24/0x58) In the i.MX5 case, priv->kms is not populated (as i.MX5 does not use any of the Qualcomm display controllers), causing a NULL pointer dereference in msm_atomic_commit_tail(): [ 24.268964] 8<--- cut here --- [ 24.274602] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 24.283434] pgd = (ptrval) [ 24.286387] [00000000] *pgd=ca212831 [ 24.290788] Internal error: Oops: 17 [#1] SMP ARM [ 24.295609] Modules linked in: [ 24.298777] CPU: 0 PID: 197 Comm: init Not tainted 5.11.0-rc2-next-20210111 #333 [ 24.306276] Hardware name: Freescale i.MX53 (Device Tree Support) [ 24.312442] PC is at msm_atomic_commit_tail+0x54/0xb9c [ 24.317743] LR is at commit_tail+0xa4/0x1b0 Fix the problem by calling drm_mode_config_helper_suspend/resume() only when priv->kms is available. Fixes: ca8199f13498 ("drm/msm/dpu: ensure device suspend happens during PM sleep") Signed-off-by: Fabio Estevam Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index fd2ac54caf9f..a5c6b8c23336 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1072,6 +1072,10 @@ static int __maybe_unused msm_pm_resume(struct device *dev) static int __maybe_unused msm_pm_prepare(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); + struct msm_drm_private *priv = ddev ? ddev->dev_private : NULL; + + if (!priv || !priv->kms) + return 0; return drm_mode_config_helper_suspend(ddev); } @@ -1079,6 +1083,10 @@ static int __maybe_unused msm_pm_prepare(struct device *dev) static void __maybe_unused msm_pm_complete(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); + struct msm_drm_private *priv = ddev ? ddev->dev_private : NULL; + + if (!priv || !priv->kms) + return; drm_mode_config_helper_resume(ddev); } From 627dc55c273dab308303a5217bd3e767d7083ddb Mon Sep 17 00:00:00 2001 From: Kalyan Thota Date: Mon, 22 Mar 2021 02:17:12 -0700 Subject: [PATCH 13/13] drm/msm/disp/dpu1: icc path needs to be set before dpu runtime resume DPU runtime resume will request for a min vote on the AXI bus as it is a necessary step before turning ON the AXI clock. The change does below 1) Move the icc path set before requesting runtime get_sync. 2) remove the dependency of hw catalog for min ib vote as it is initialized at a later point. Signed-off-by: Kalyan Thota Tested-by: Matthias Kaehlcke Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 5a8e3e1fc48c..85f2c3564c96 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -43,6 +43,8 @@ #define DPU_DEBUGFS_DIR "msm_dpu" #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask" +#define MIN_IB_BW 400000000ULL /* Min ib vote 400MB */ + static int dpu_kms_hw_init(struct msm_kms *kms); static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms); @@ -931,6 +933,9 @@ static int dpu_kms_hw_init(struct msm_kms *kms) DPU_DEBUG("REG_DMA is not defined"); } + if (of_device_is_compatible(dev->dev->of_node, "qcom,sc7180-mdss")) + dpu_kms_parse_data_bus_icc_path(dpu_kms); + pm_runtime_get_sync(&dpu_kms->pdev->dev); dpu_kms->core_rev = readl_relaxed(dpu_kms->mmio + 0x0); @@ -1032,9 +1037,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dpu_vbif_init_memtypes(dpu_kms); - if (of_device_is_compatible(dev->dev->of_node, "qcom,sc7180-mdss")) - dpu_kms_parse_data_bus_icc_path(dpu_kms); - pm_runtime_put_sync(&dpu_kms->pdev->dev); return 0; @@ -1191,10 +1193,10 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) ddev = dpu_kms->dev; + WARN_ON(!(dpu_kms->num_paths)); /* Min vote of BW is required before turning on AXI clk */ for (i = 0; i < dpu_kms->num_paths; i++) - icc_set_bw(dpu_kms->path[i], 0, - dpu_kms->catalog->perf.min_dram_ib); + icc_set_bw(dpu_kms->path[i], 0, Bps_to_icc(MIN_IB_BW)); rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); if (rc) {