From 3fe08a661c106d071afb45ddf3660c2e92fe8b52 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Sun, 29 Mar 2015 17:28:18 +0800 Subject: [PATCH] HDMI: fix crash error when insert HDMI with following log: Unable to handle kernel paging request at virtual address 40ce80f8 pgd = ffffffc001022000 [40ce80f8] *pgd=0000000025b19003, *pmd=000000001cb1f003, *pte=0000000000000000 Internal error: Oops: 96000005 [#1] PREEMPT SMP Modules linked in: pvrsrvkm(O) drmboot(PO) CPU: 7 PID: 2558 Comm: kworker/u16:1 Tainted: P W O 3.10.0 #66 Workqueue: hdmi-ff980000.hdmi hdmi_work_queue task: ffffffc01ca83f00 ti: ffffffc033e00000 task.ti: ffffffc033e00000 PC is at hdmi_wq_insert+0xa4/0x2ac LR is at hdmi_wq_insert+0x74/0x2ac pc : [] lr : [] pstate: 60000145 Use inline fuction hdmi_destroy_modelist replace fb_destroy_modelist. For unkown reason, variable struct hdmi *hdmi is deferent before and after calling fb_destroy_modelist. Signed-off-by: Zheng Yang --- .../video/rockchip/hdmi/rockchip-hdmi-core.c | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c b/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c index 290462d93267..c2c265d8772b 100644 --- a/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c +++ b/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c @@ -23,7 +23,7 @@ struct delayed_work *hdmi_submit_work(struct hdmi *hdmi, { struct hdmi_delayed_work *work; - DBG("%s event %04x delay %d", __func__, event, delay); + DBG("%s event %04x delay %d\n", __func__, event, delay); work = kmalloc(sizeof(*work), GFP_ATOMIC); @@ -59,14 +59,14 @@ static void hdmi_send_uevent(struct hdmi *hdmi, int uevent) static inline void hdmi_wq_set_output(struct hdmi *hdmi, int mute) { - DBG("%s mute %d", __func__, mute); + DBG("%s mute %d\n", __func__, mute); if (hdmi->ops->setmute) hdmi->ops->setmute(hdmi, mute); } static inline void hdmi_wq_set_audio(struct hdmi *hdmi) { - DBG("%s", __func__); + DBG("%s\n", __func__); if (hdmi->ops->setaudio) hdmi->ops->setaudio(hdmi, &hdmi->audio); } @@ -75,7 +75,7 @@ static void hdmi_wq_set_video(struct hdmi *hdmi) { struct hdmi_video video; - DBG("%s", __func__); + DBG("%s\n", __func__); video.vic = hdmi->vic & HDMI_VIC_MASK; video.sink_hdmi = hdmi->edid.sink_hdmi; @@ -120,6 +120,16 @@ static void hdmi_wq_set_video(struct hdmi *hdmi) hdmi->ops->setvideo(hdmi, &video); } +static inline void hdmi_destroy_modelist(struct list_head *head) +{ + struct list_head *pos, *n; + + list_for_each_safe(pos, n, head) { + list_del(pos); + kfree(pos); + } +} + static void hdmi_wq_parse_edid(struct hdmi *hdmi) { struct hdmi_edid *pedid; @@ -129,13 +139,12 @@ static void hdmi_wq_parse_edid(struct hdmi *hdmi) if (hdmi == NULL) return; - DBG("%s", __func__); + DBG("%s\n", __func__); pedid = &(hdmi->edid); - fb_destroy_modelist(&pedid->modelist); + hdmi_destroy_modelist(&(pedid->modelist)); memset(pedid, 0, sizeof(struct hdmi_edid)); INIT_LIST_HEAD(&pedid->modelist); - buff = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL); if (buff == NULL) { dev_err(hdmi->dev, @@ -206,7 +215,7 @@ out: static void hdmi_wq_insert(struct hdmi *hdmi) { - DBG("%s", __func__); + DBG("%s\n", __func__); if (hdmi->ops->insert) hdmi->ops->insert(hdmi); hdmi_wq_parse_edid(hdmi); @@ -235,7 +244,7 @@ static void hdmi_wq_remove(struct hdmi *hdmi) struct list_head *pos, *n; struct rk_screen screen; - DBG("%s", __func__); + DBG("%s\n", __func__); if (hdmi->ops->remove) hdmi->ops->remove(hdmi); #ifdef CONFIG_SWITCH @@ -324,7 +333,7 @@ static void hdmi_work_queue(struct work_struct *work) case HDMI_HPD_CHANGE: if (hdmi->ops->getstatus) hpd = hdmi->ops->getstatus(hdmi); - DBG("hdmi_work_queue() - hpd is %d hotplug is %d", + DBG("hdmi_work_queue() - hpd is %d hotplug is %d\n", hpd, hdmi->hotplug); if (hpd != hdmi->hotplug) { if (hpd == HDMI_HPD_ACTIVED) { @@ -427,7 +436,7 @@ struct hdmi *rockchip_hdmi_register(struct hdmi_property *property, if (i == HDMI_MAX_ID) return NULL; - DBG("hdmi_register() - video source %d display %d", + DBG("hdmi_register() - video source %d display %d\n", property->videosrc, property->display); hdmi = kmalloc(sizeof(*hdmi), GFP_KERNEL); @@ -514,7 +523,7 @@ void rockchip_hdmi_unregister(struct hdmi *hdmi) switch_dev_unregister(&(hdmi->switchdev)); #endif hdmi_unregister_display_sysfs(hdmi); - fb_destroy_modelist(&hdmi->edid.modelist); + hdmi_destroy_modelist(&hdmi->edid.modelist); kfree(hdmi->edid.audio); if (hdmi->edid.specs) { kfree(hdmi->edid.specs->modedb); -- 2.34.1