From cee61f3e321a1695f033d6b6dd2f05b28f94a24a Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Sat, 27 Jun 2020 18:29:35 +0800 Subject: [PATCH] video: rockchip: mpp: Fix panic when mpp service is omit or disabled [ 4.239358] Unable to handle kernel NULL pointer dereference at virtual address 00000050 [ 4.263110] pgd = (ptrval) [ 4.269464] [00000050] *pgd=00000000 [ 4.285610] Internal error: Oops: 5 [#1] PREEMPT SMP ARM [ 4.291283] Modules linked in: [ 4.294795] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.111 #1960 [ 4.301399] Hardware name: Generic DT based system [ 4.306660] PC is at mpp_set_grf+0x8/0x3c [ 4.311054] LR is at mpp_add_driver+0x24/0x44 [ 4.315713] pc : [] lr : [] psr: 20000153 [ 4.322250] sp : bf039ee8 ip : 00000d8c fp : bf7ffd80 [ 4.327740] r10: b0b3003c r9 : 00000007 r8 : 00000000 [ 4.333260] r7 : b0b15914 r6 : b0f21788 r5 : 00000006 r4 : b1022a2c [ 4.340094] r3 : 00000048 r2 : bf5d1e24 r1 : b0f21788 r0 : 00000048 [ 4.346947] Flags: nzCv IRQs on FIQs off Mode SVC_32 ISA ARM Segment user [ 4.354487] Control: 10c5387d Table: 6000406a DAC: 00000055 Change-Id: Idad72d462da59a8af53fd038ceda973da1f4139d Signed-off-by: Sugar Zhang Signed-off-by: Ding Wei --- drivers/video/rockchip/mpp/mpp_common.c | 4 +- drivers/video/rockchip/mpp/mpp_common.h | 2 +- drivers/video/rockchip/mpp/mpp_service.c | 135 +++++++++-------------- drivers/video/rockchip/mpp/mpp_vdpu1.c | 2 +- drivers/video/rockchip/mpp/mpp_vdpu2.c | 2 +- 5 files changed, 58 insertions(+), 87 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index a73a36c96358..1815a86d5283 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -768,15 +768,13 @@ static int mpp_attach_service(struct mpp_dev *mpp, struct device *dev) goto err_put_pdev; } - device_lock(&pdev->dev); /* register current device to mpp service */ mpp->srv->sub_devices[mpp->var->device_type] = mpp; /* set taskqueue which set in dtsi */ mpp->queue = mpp->srv->task_queues[taskqueue_node]; /* set resetgroup which set in dtsi */ mpp->reset_group = mpp->srv->reset_groups[reset_group_node]; - mpp->srv->hw_support |= BIT(mpp->var->device_type); - device_unlock(&pdev->dev); + set_bit(mpp->var->device_type, &mpp->srv->hw_support); return 0; diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index 9af08decad9a..a5a9a629518b 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -342,7 +342,7 @@ struct mpp_service { #ifdef CONFIG_DEBUG_FS struct dentry *debugfs; #endif - u32 hw_support; + unsigned long hw_support; atomic_t shutdown_request; /* follows for device probe */ struct mpp_grf_info grf_infos[MPP_DRIVER_BUTT]; diff --git a/drivers/video/rockchip/mpp/mpp_service.c b/drivers/video/rockchip/mpp/mpp_service.c index 3add901e6cba..d6d34c5180ce 100644 --- a/drivers/video/rockchip/mpp/mpp_service.c +++ b/drivers/video/rockchip/mpp/mpp_service.c @@ -25,26 +25,18 @@ #define MPP_CLASS_NAME "mpp_class" #define MPP_SERVICE_NAME "mpp_service" -#define MPP_REGISTER_GRF(np, X, x) {\ +#define MPP_REGISTER_DRIVER(srv, X, x) {\ if (IS_ENABLED(CONFIG_ROCKCHIP_MPP_##X))\ - mpp_init_grf(np, &srv->grf_infos[MPP_DRIVER_##X], x);\ - } - -#define MPP_REGISTER_DRIVER(X, x) {\ - if (IS_ENABLED(CONFIG_ROCKCHIP_MPP_##X))\ - mpp_add_driver(MPP_DRIVER_##X, &rockchip_##x##_driver);\ + mpp_add_driver(srv, MPP_DRIVER_##X, &rockchip_##x##_driver, "grf_"#x);\ } unsigned int mpp_dev_debug; module_param(mpp_dev_debug, uint, 0644); MODULE_PARM_DESC(mpp_dev_debug, "bit switch for mpp debug information"); -static struct mpp_grf_info *mpp_grf_infos; -static struct platform_driver **mpp_sub_drivers; - static int mpp_init_grf(struct device_node *np, struct mpp_grf_info *grf_info, - const char *name) + const char *grf_name) { int ret; int index; @@ -60,7 +52,7 @@ static int mpp_init_grf(struct device_node *np, if (ret) return -ENODATA; - index = of_property_match_string(np, "rockchip,grf-names", name); + index = of_property_match_string(np, "rockchip,grf-names", grf_name); if (index < 0) return -ENODATA; @@ -73,6 +65,39 @@ static int mpp_init_grf(struct device_node *np, grf_info->offset = grf_offset; grf_info->val = grf_value; + mpp_set_grf(grf_info); + + return 0; +} + +static int mpp_add_driver(struct mpp_service *srv, + enum MPP_DRIVER_TYPE type, + struct platform_driver *driver, + const char *grf_name) +{ + int ret; + + mpp_init_grf(srv->dev->of_node, + &srv->grf_infos[type], + grf_name); + + ret = platform_driver_register(driver); + if (ret) + return ret; + + srv->sub_drivers[type] = driver; + + return 0; +} + +static int mpp_remove_driver(struct mpp_service *srv, int i) +{ + if (srv && srv->sub_drivers[i]) { + mpp_set_grf(&srv->grf_infos[i]); + platform_driver_unregister(srv->sub_drivers[i]); + srv->sub_drivers[i] = NULL; + } + return 0; } @@ -208,23 +233,24 @@ static int mpp_service_probe(struct platform_device *pdev) srv->reset_groups[i] = group; } } - MPP_REGISTER_GRF(np, RKVDEC, "grf_rkvdec"); - MPP_REGISTER_GRF(np, RKVENC, "grf_rkvenc"); - MPP_REGISTER_GRF(np, VEPU1, "grf_vepu1"); - MPP_REGISTER_GRF(np, VDPU1, "grf_vdpu1"); - MPP_REGISTER_GRF(np, VEPU2, "grf_vepu2"); - MPP_REGISTER_GRF(np, VDPU2, "grf_vdpu2"); - MPP_REGISTER_GRF(np, VEPU22, "grf_vepu22"); - - mpp_grf_infos = srv->grf_infos; ret = mpp_register_service(srv, MPP_SERVICE_NAME); if (ret) { dev_err(dev, "register %s device\n", MPP_SERVICE_NAME); goto fail_register; } - mpp_sub_drivers = srv->sub_drivers; mpp_debugfs_init(srv); + + /* register sub drivers */ + MPP_REGISTER_DRIVER(srv, RKVDEC, rkvdec); + MPP_REGISTER_DRIVER(srv, RKVENC, rkvenc); + MPP_REGISTER_DRIVER(srv, VDPU1, vdpu1); + MPP_REGISTER_DRIVER(srv, VEPU1, vepu1); + MPP_REGISTER_DRIVER(srv, VDPU2, vdpu2); + MPP_REGISTER_DRIVER(srv, VEPU2, vepu2); + MPP_REGISTER_DRIVER(srv, VEPU22, vepu22); + MPP_REGISTER_DRIVER(srv, IEP2, iep2); + dev_info(dev, "probe success\n"); return 0; @@ -239,9 +265,14 @@ static int mpp_service_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mpp_service *srv = platform_get_drvdata(pdev); + int i; dev_info(dev, "remove device\n"); + /* remove sub drivers */ + for (i = 0; i < MPP_DRIVER_BUTT; i++) + mpp_remove_driver(srv, i); + mpp_remove_service(srv); class_destroy(srv->cls); mpp_debugfs_remove(srv); @@ -265,65 +296,7 @@ static struct platform_driver mpp_service_driver = { }, }; -static int mpp_add_driver(enum MPP_DRIVER_TYPE type, - struct platform_driver *driver) -{ - int ret; - - mpp_set_grf(&mpp_grf_infos[type]); - - ret = platform_driver_register(driver); - if (ret) - return ret; - - mpp_sub_drivers[type] = driver; - - return 0; -} - -static int mpp_remove_driver(int i, struct platform_driver *driver) -{ - if (driver) { - mpp_set_grf(&mpp_grf_infos[i]); - platform_driver_unregister(driver); - } - - return 0; -} - -static int __init mpp_service_init(void) -{ - int ret; - - ret = platform_driver_register(&mpp_service_driver); - if (ret) { - pr_err("Mpp service device register failed (%d).\n", ret); - return ret; - } - MPP_REGISTER_DRIVER(RKVDEC, rkvdec); - MPP_REGISTER_DRIVER(RKVENC, rkvenc); - MPP_REGISTER_DRIVER(VDPU1, vdpu1); - MPP_REGISTER_DRIVER(VEPU1, vepu1); - MPP_REGISTER_DRIVER(VDPU2, vdpu2); - MPP_REGISTER_DRIVER(VEPU2, vepu2); - MPP_REGISTER_DRIVER(VEPU22, vepu22); - MPP_REGISTER_DRIVER(IEP2, iep2); - - return 0; -} - -static void __exit mpp_service_exit(void) -{ - int i; - - for (i = 0; i < MPP_DRIVER_BUTT; i++) - mpp_remove_driver(i, mpp_sub_drivers[i]); - - platform_driver_unregister(&mpp_service_driver); -} - -module_init(mpp_service_init); -module_exit(mpp_service_exit); +module_platform_driver(mpp_service_driver); MODULE_LICENSE("Dual MIT/GPL"); MODULE_VERSION("1.0.build.201911131848"); diff --git a/drivers/video/rockchip/mpp/mpp_vdpu1.c b/drivers/video/rockchip/mpp/mpp_vdpu1.c index 329f038fba73..184f26cc6810 100644 --- a/drivers/video/rockchip/mpp/mpp_vdpu1.c +++ b/drivers/video/rockchip/mpp/mpp_vdpu1.c @@ -825,7 +825,7 @@ static int vdpu_probe(struct platform_device *pdev) if (mpp->var->device_type == MPP_DEVICE_VDPU1) { mpp->srv->sub_devices[MPP_DEVICE_VDPU1_PP] = mpp; - mpp->srv->hw_support |= BIT(MPP_DEVICE_VDPU1_PP); + set_bit(MPP_DEVICE_VDPU1_PP, &mpp->srv->hw_support); } mpp->session_max_buffers = VDPU1_SESSION_MAX_BUFFERS; diff --git a/drivers/video/rockchip/mpp/mpp_vdpu2.c b/drivers/video/rockchip/mpp/mpp_vdpu2.c index 2783e101fd99..00a1c10815f0 100644 --- a/drivers/video/rockchip/mpp/mpp_vdpu2.c +++ b/drivers/video/rockchip/mpp/mpp_vdpu2.c @@ -723,7 +723,7 @@ static int vdpu_probe(struct platform_device *pdev) if (mpp->var->device_type == MPP_DEVICE_VDPU2) { mpp->srv->sub_devices[MPP_DEVICE_VDPU2_PP] = mpp; - mpp->srv->hw_support |= BIT(MPP_DEVICE_VDPU2_PP); + set_bit(MPP_DEVICE_VDPU2_PP, &mpp->srv->hw_support); } mpp->session_max_buffers = VDPU2_SESSION_MAX_BUFFERS;