From 331d880b35a76b5de0eec8cbcecbf615d758a5f9 Mon Sep 17 00:00:00 2001 From: John Garry Date: Sat, 22 Sep 2018 01:25:25 +0800 Subject: [PATCH 1/6] drm/hisilicon: hibmc: Do not carry error code in HiBMC framebuffer pointer In hibmc_drm_fb_create(), when the call to hibmc_framebuffer_init() fails with error, do not store the error code in the HiBMC device frame-buffer pointer, as this will be later checked for non-zero value in hibmc_fbdev_destroy() when our intention is to check for a valid function pointer. This fixes the following crash: [ 9.699791] Unable to handle kernel NULL pointer dereference at virtual address 000000000000001a [ 9.708672] Mem abort info: [ 9.711489] ESR = 0x96000004 [ 9.714570] Exception class = DABT (current EL), IL = 32 bits [ 9.720551] SET = 0, FnV = 0 [ 9.723631] EA = 0, S1PTW = 0 [ 9.726799] Data abort info: [ 9.729702] ISV = 0, ISS = 0x00000004 [ 9.733573] CM = 0, WnR = 0 [ 9.736566] [000000000000001a] user address but active_mm is swapper [ 9.742987] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 9.748614] Modules linked in: [ 9.751694] CPU: 16 PID: 293 Comm: kworker/16:1 Tainted: G W 4.19.0-rc4-next-20180920-00001-g9b0012c #322 [ 9.762681] Hardware name: Huawei Taishan 2280 /D05, BIOS Hisilicon D05 IT21 Nemo 2.0 RC0 04/18/2018 [ 9.771915] Workqueue: events work_for_cpu_fn [ 9.776312] pstate: 60000005 (nZCv daif -PAN -UAO) [ 9.781150] pc : drm_mode_object_put+0x0/0x20 [ 9.785547] lr : hibmc_fbdev_fini+0x40/0x58 [ 9.789767] sp : ffff00000af1bcf0 [ 9.793108] x29: ffff00000af1bcf0 x28: 0000000000000000 [ 9.798473] x27: 0000000000000000 x26: ffff000008f66630 [ 9.803838] x25: 0000000000000000 x24: ffff0000095abb98 [ 9.809203] x23: ffff8017db92fe00 x22: ffff8017d2b13000 [ 9.814568] x21: ffffffffffffffea x20: ffff8017d2f80018 [ 9.819933] x19: ffff8017d28a0018 x18: ffffffffffffffff [ 9.825297] x17: 0000000000000000 x16: 0000000000000000 [ 9.830662] x15: ffff0000092296c8 x14: ffff00008939970f [ 9.836026] x13: ffff00000939971d x12: ffff000009229940 [ 9.841391] x11: ffff0000085f8fc0 x10: ffff00000af1b9a0 [ 9.846756] x9 : 000000000000000d x8 : 6620657a696c6169 [ 9.852121] x7 : ffff8017d3340580 x6 : ffff8017d4168000 [ 9.857486] x5 : 0000000000000000 x4 : ffff8017db92fb20 [ 9.862850] x3 : 0000000000002690 x2 : ffff8017d3340480 [ 9.868214] x1 : 0000000000000028 x0 : 0000000000000002 [ 9.873580] Process kworker/16:1 (pid: 293, stack limit = 0x(____ptrval____)) [ 9.880788] Call trace: [ 9.883252] drm_mode_object_put+0x0/0x20 [ 9.887297] hibmc_unload+0x1c/0x80 [ 9.890815] hibmc_pci_probe+0x170/0x3c8 [ 9.894773] local_pci_probe+0x3c/0xb0 [ 9.898555] work_for_cpu_fn+0x18/0x28 [ 9.902337] process_one_work+0x1e0/0x318 [ 9.906382] worker_thread+0x228/0x450 [ 9.910164] kthread+0x128/0x130 [ 9.913418] ret_from_fork+0x10/0x18 [ 9.917024] Code: a94153f3 a8c27bfd d65f03c0 d503201f (f9400c01) [ 9.923180] ---[ end trace 2695ffa0af5be375 ]--- Fixes: d1667b86795a ("drm/hisilicon/hibmc: Add support for frame buffer") Signed-off-by: John Garry Reviewed-by: Xinliang Liu Signed-off-by: Xinliang Liu --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c index b92595c477ef..8bd29075ae4e 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c @@ -122,6 +122,7 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper, hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj); if (IS_ERR(hi_fbdev->fb)) { ret = PTR_ERR(hi_fbdev->fb); + hi_fbdev->fb = NULL; DRM_ERROR("failed to initialize framebuffer: %d\n", ret); goto out_release_fbi; } From 0ff9f49646353ce31312411e7e7bd2281492a40e Mon Sep 17 00:00:00 2001 From: John Garry Date: Sat, 22 Sep 2018 01:25:26 +0800 Subject: [PATCH 2/6] drm/hisilicon: hibmc: Don't overwrite fb helper surface depth Currently the driver overwrites the surface depth provided by the fb helper to give an invalid bpp/surface depth combination. This has been exposed by commit 70109354fed2 ("drm: Reject unknown legacy bpp and depth for drm_mode_addfb ioctl"), which now causes the driver to fail to probe. Fix by not overwriting the surface depth. Fixes: d1667b86795a ("drm/hisilicon/hibmc: Add support for frame buffer") Signed-off-by: John Garry Reviewed-by: Xinliang Liu Signed-off-by: Xinliang Liu --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c index 8bd29075ae4e..edcca1761500 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c @@ -71,7 +71,6 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper, DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n", sizes->surface_width, sizes->surface_height, sizes->surface_bpp); - sizes->surface_depth = 32; bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); From a66dae3a2b179eaba8f2f960271fe9d4c72939cb Mon Sep 17 00:00:00 2001 From: John Garry Date: Sat, 22 Sep 2018 01:25:27 +0800 Subject: [PATCH 3/6] drm/hisilicon: hibmc: Use HUAWEI PCI vendor ID macro Switch to use Huawei PCI vendor ID macro from pci_ids.h file. In addition, switch to use PCI_VDEVICE() instead of open coding. Signed-off-by: John Garry Reviewed-by: Xinliang Liu Signed-off-by: Xinliang Liu --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index d4f6f1f9df5b..79b6bdafdc82 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -402,7 +402,7 @@ static void hibmc_pci_remove(struct pci_dev *pdev) } static struct pci_device_id hibmc_pci_table[] = { - {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VDEVICE(HUAWEI, 0x1711) }, {0,} }; From 081d0571700be0c9f212f18b5c66f40e9c2e70d2 Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Mon, 6 Aug 2018 20:19:01 +0530 Subject: [PATCH 4/6] gpu/drm/hisilicon: Convert drm_atomic_helper_suspend/resume() convert drm_atomic_helper_suspend/resume() to use drm_mode_config_helper_suspend/resume(). Fixed one sparse warning by making hibmc_drm_interrupt static. Signed-off-by: Ajit Negi Signed-off-by: Souptick Joarder Reviewed-by: Xinliang Liu Signed-off-by: Xinliang Liu --- .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 20 +++---------------- .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 1 - 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 79b6bdafdc82..ccecda273112 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -37,7 +37,7 @@ static const struct file_operations hibmc_fops = { .llseek = no_llseek, }; -irqreturn_t hibmc_drm_interrupt(int irq, void *arg) +static irqreturn_t hibmc_drm_interrupt(int irq, void *arg) { struct drm_device *dev = (struct drm_device *)arg; struct hibmc_drm_private *priv = @@ -74,30 +74,16 @@ static int __maybe_unused hibmc_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct hibmc_drm_private *priv = drm_dev->dev_private; - drm_kms_helper_poll_disable(drm_dev); - priv->suspend_state = drm_atomic_helper_suspend(drm_dev); - if (IS_ERR(priv->suspend_state)) { - DRM_ERROR("drm_atomic_helper_suspend failed: %ld\n", - PTR_ERR(priv->suspend_state)); - drm_kms_helper_poll_enable(drm_dev); - return PTR_ERR(priv->suspend_state); - } - - return 0; + return drm_mode_config_helper_suspend(drm_dev); } static int __maybe_unused hibmc_pm_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct hibmc_drm_private *priv = drm_dev->dev_private; - drm_atomic_helper_resume(drm_dev, priv->suspend_state); - drm_kms_helper_poll_enable(drm_dev); - - return 0; + return drm_mode_config_helper_resume(drm_dev); } static const struct dev_pm_ops hibmc_pm_ops = { diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index e195521eb41e..45c25a488f42 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -47,7 +47,6 @@ struct hibmc_drm_private { /* drm */ struct drm_device *dev; bool mode_config_initialized; - struct drm_atomic_state *suspend_state; /* ttm */ struct drm_global_reference mem_global_ref; From 45fcedae849396598aee6686318e7488e852dedf Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 13 Jul 2018 10:48:24 +0200 Subject: [PATCH 5/6] drm/hisilicon: Replace drm_dev_unref with drm_dev_put This patch unifies the naming of DRM functions for reference counting of struct drm_device. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann Reviewed-by: Xinliang Liu Signed-off-by: Xinliang Liu --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 4 ++-- drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index ccecda273112..68c0c297b3a5 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -373,7 +373,7 @@ static int hibmc_pci_probe(struct pci_dev *pdev, err_disable: pci_disable_device(pdev); err_free: - drm_dev_unref(dev); + drm_dev_put(dev); return ret; } @@ -384,7 +384,7 @@ static void hibmc_pci_remove(struct pci_dev *pdev) drm_dev_unregister(dev); hibmc_unload(dev); - drm_dev_unref(dev); + drm_dev_put(dev); } static struct pci_device_id hibmc_pci_table[] = { diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index ddb0403f1975..e6a62d5a00a3 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -193,7 +193,7 @@ static int kirin_drm_bind(struct device *dev) ret = kirin_drm_kms_init(drm_dev); if (ret) - goto err_drm_dev_unref; + goto err_drm_dev_put; ret = drm_dev_register(drm_dev, 0); if (ret) @@ -203,8 +203,8 @@ static int kirin_drm_bind(struct device *dev) err_kms_cleanup: kirin_drm_kms_cleanup(drm_dev); -err_drm_dev_unref: - drm_dev_unref(drm_dev); +err_drm_dev_put: + drm_dev_put(drm_dev); return ret; } @@ -215,7 +215,7 @@ static void kirin_drm_unbind(struct device *dev) drm_dev_unregister(drm_dev); kirin_drm_kms_cleanup(drm_dev); - drm_dev_unref(drm_dev); + drm_dev_put(drm_dev); } static const struct component_master_ops kirin_drm_ops = { From c932c4f831e66fb5bb15229324825a4932ba3992 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 31 Jul 2018 08:33:05 +0200 Subject: [PATCH 6/6] drm/hisilicon: Replace ttm_bo_unref with ttm_bo_put The function ttm_bo_put releases a reference to a TTM buffer object. The function's name is more aligned to the Linux kernel convention of naming ref-counting function _get and _put. A call to ttm_bo_unref takes the address of the TTM BO object's pointer and clears the pointer's value to NULL. This is not necessary in most cases and sometimes even worked around by the calling code. A call to ttm_bo_put only releases the reference without clearing the pointer. The current behaviour of cleaning the pointer is kept in the calling code, but should be removed if not required in a later patch. Signed-off-by: Thomas Zimmermann Reviewed-by: Xinliang Liu Signed-off-by: Xinliang Liu --- drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 4871025f7573..2e3e0bdb8932 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -283,7 +283,7 @@ static void hibmc_bo_unref(struct hibmc_bo **bo) return; tbo = &((*bo)->bo); - ttm_bo_unref(&tbo); + ttm_bo_put(tbo); *bo = NULL; }