diff options
author | Robby Cai <robby.cai@nxp.com> | 2016-01-12 16:35:12 +0800 |
---|---|---|
committer | Nitin Garg <nitin.garg@nxp.com> | 2016-01-14 11:03:11 -0600 |
commit | d59e4e631fd6e011c6803d6f77b4d711794a35dd (patch) | |
tree | 1e1cb33b9aba5a129e632a18980d0288f81fa1ce /drivers | |
parent | 83c377f8bf3dbe810b0a8b628202e7b32a40af4b (diff) |
MLK-12179 epdc: use outer_flush_range instead of outer_flush_all
l2c210_flush_all, the underlying implementation of outer_flush_all() has the
constraint on 4.1 kernel that, it can not be called under interrupt context.
However the EPDC driver can not guarantee this condition at calling point, thus
it could cause kernel dump. This has been observed on i.MX6SL, and theorically
on other platforms like i.MX6DL (using PL310 L2 cache). So use outer_flush_range
to fix it.
Although we don't have such issue on i.MX7D (not PL310 L2), we still prefer to
use outer_flush_range() for legacy software dithering support and for easy
maintenance. Then we do the change in both EPDC driver.
------------[ cut here ]------------
Kernel BUG at 800204d8 [verbose debug info unavailable]
Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
Modules linked in: galcore(O) evbug
CPU: 0 PID: 842 Comm: kworker/u3:1 Tainted: G O 4.1.8-1.0.0+ge352a0b #1
Hardware name: Freescale i.MX6 SoloLite (Device Tree)
Workqueue: EPDC Submit epdc_submit_work_func
task: a8a8f900 ti: a92a4000 task.ti: a92a4000
PC is at l2c210_flush_all+0x5c/0x60
LR is at epdc_submit_work_func+0x684/0xbf8
pc : [<800204d8>] lr : [<8030702c>] psr: 600b0013
sp : a92a5e90 ip : a9150c8c fp : a8480518
r10: a84a28c0 r9 : 00000008 r8 : a9150644
r7 : a91512e0 r6 : 0000012c r5 : a91512e0 r4 : a91512dc
r3 : a00b0013 r2 : 80b184a0 r1 : 701fe019 r0 : f4a02000
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 10c53c7d Table: a943404a DAC: 00000015
Process kworker/u3:1 (pid: 842, stack limit = 0xa92a4210)
Stack: (0xa92a5e90 to 0xa92a6000)
5e80: a92a5ed0 8005d058 0000bbc2 a851d4c0
5ea0: 00000000 a9150000 a8480000 a8480440 00000190 00000193 55555556 a84a28c0
5ec0: a8480518 a8500000 80b18088 a94f3900 00000000 00000000 00000190 0000012c
5ee0: a94f3900 a8480518 a87e8d80 a8479000 a845a200 00000020 00000000 a8479000
5f00: a8479000 80046458 a92a4000 a8479000 a8479014 a8479000 a87e8d98 a8479014
...
Signed-off-by: Robby Cai <robby.cai@nxp.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/fbdev/mxc/mxc_epdc_fb.c | 36 | ||||
-rw-r--r-- | drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c | 36 |
2 files changed, 50 insertions, 22 deletions
diff --git a/drivers/video/fbdev/mxc/mxc_epdc_fb.c b/drivers/video/fbdev/mxc/mxc_epdc_fb.c index 4ba8e5777409..1497f728468e 100644 --- a/drivers/video/fbdev/mxc/mxc_epdc_fb.c +++ b/drivers/video/fbdev/mxc/mxc_epdc_fb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2016 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -401,12 +401,14 @@ static void draw_mode0(struct mxc_epdc_fb_data *fb_data); static bool is_free_list_full(struct mxc_epdc_fb_data *fb_data); static void do_dithering_processing_Y1_v1_0( - unsigned char *update_region_ptr, + unsigned char *update_region_virt_ptr, + dma_addr_t update_region_phys_ptr, struct mxcfb_rect *update_region, unsigned long update_region_stride, int *err_dist); static void do_dithering_processing_Y4_v1_0( - unsigned char *update_region_ptr, + unsigned char *update_region_virt_ptr, + dma_addr_t update_region_phys_ptr, struct mxcfb_rect *update_region, unsigned long update_region_stride, int *err_dist); @@ -2642,6 +2644,8 @@ static void epdc_submit_work_func(struct work_struct *work) do_dithering_processing_Y1_v1_0( (uint8_t *)(upd_data_list->virt_addr + upd_data_list->update_desc->epdc_offs), + upd_data_list->phys_addr + + upd_data_list->update_desc->epdc_offs, &adj_update_region, (fb_data->rev < 20) ? ALIGN(adj_update_region.width, 8) : @@ -2659,6 +2663,8 @@ static void epdc_submit_work_func(struct work_struct *work) do_dithering_processing_Y4_v1_0( (uint8_t *)(upd_data_list->virt_addr + upd_data_list->update_desc->epdc_offs), + upd_data_list->phys_addr + + upd_data_list->update_desc->epdc_offs, &adj_update_region, (fb_data->rev < 20) ? ALIGN(adj_update_region.width, 8) : @@ -3327,7 +3333,9 @@ static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd, struct mxc_epdc_fb_data *fb_data = info ? (struct mxc_epdc_fb_data *)info:g_fb_data; flush_cache_all(); - outer_flush_all(); + outer_flush_range(fb_data->working_buffer_phys, + fb_data->working_buffer_phys + + fb_data->working_buffer_size); if (copy_to_user((void __user *)arg, (const void *) fb_data->working_buffer_virt, fb_data->working_buffer_size)) @@ -3335,7 +3343,9 @@ static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd, else ret = 0; flush_cache_all(); - outer_flush_all(); + outer_flush_range(fb_data->working_buffer_phys, + fb_data->working_buffer_phys + + fb_data->working_buffer_size); break; } @@ -5461,7 +5471,8 @@ static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat) * Dithering algorithm implementation - Y8->Y1 version 1.0 for i.MX */ static void do_dithering_processing_Y1_v1_0( - unsigned char *update_region_ptr, + unsigned char *update_region_virt_ptr, + dma_addr_t update_region_phys_ptr, struct mxcfb_rect *update_region, unsigned long update_region_stride, int *err_dist) @@ -5483,7 +5494,7 @@ static void do_dithering_processing_Y1_v1_0( err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3); err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3); - y8buf = update_region_ptr + x_offset; + y8buf = update_region_virt_ptr + x_offset; /* scan the line and convert the Y8 to BW */ for (col = 1; col <= update_region->width; col++) { @@ -5509,7 +5520,8 @@ static void do_dithering_processing_Y1_v1_0( } flush_cache_all(); - outer_flush_all(); + outer_flush_range(update_region_phys_ptr, update_region_phys_ptr + + update_region->height * update_region->width); } /* @@ -5517,7 +5529,8 @@ static void do_dithering_processing_Y1_v1_0( */ static void do_dithering_processing_Y4_v1_0( - unsigned char *update_region_ptr, + unsigned char *update_region_virt_ptr, + dma_addr_t update_region_phys_ptr, struct mxcfb_rect *update_region, unsigned long update_region_stride, int *err_dist) @@ -5539,7 +5552,7 @@ static void do_dithering_processing_Y4_v1_0( err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3); err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3); - y8buf = update_region_ptr + x_offset; + y8buf = update_region_virt_ptr + x_offset; /* scan the line and convert the Y8 to Y4 */ for (col = 1; col <= update_region->width; col++) { @@ -5566,7 +5579,8 @@ static void do_dithering_processing_Y4_v1_0( } flush_cache_all(); - outer_flush_all(); + outer_flush_range(update_region_phys_ptr, update_region_phys_ptr + + update_region->height * update_region->width); } static int __init mxc_epdc_fb_init(void) diff --git a/drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c b/drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c index 2f784f012517..bdbf0051d1da 100644 --- a/drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c +++ b/drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. + * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -470,12 +470,14 @@ static void draw_mode0(struct mxc_epdc_fb_data *fb_data); static bool is_free_list_full(struct mxc_epdc_fb_data *fb_data); static void do_dithering_processing_Y1_v1_0( - unsigned char *update_region_ptr, + unsigned char *update_region_virt_ptr, + dma_addr_t update_region_phys_ptr, struct mxcfb_rect *update_region, unsigned long update_region_stride, int *err_dist); static void do_dithering_processing_Y4_v1_0( - unsigned char *update_region_ptr, + unsigned char *update_region_virt_ptr, + dma_addr_t update_region_phys_ptr, struct mxcfb_rect *update_region, unsigned long update_region_stride, int *err_dist); @@ -3016,6 +3018,8 @@ static void epdc_submit_work_func(struct work_struct *work) do_dithering_processing_Y1_v1_0( (uint8_t *)(upd_data_list->virt_addr + upd_data_list->update_desc->epdc_offs), + upd_data_list->phys_addr + + upd_data_list->update_desc->epdc_offs, &adj_update_region, (fb_data->rev < 20) ? ALIGN(adj_update_region.width, 8) : @@ -3033,6 +3037,8 @@ static void epdc_submit_work_func(struct work_struct *work) do_dithering_processing_Y4_v1_0( (uint8_t *)(upd_data_list->virt_addr + upd_data_list->update_desc->epdc_offs), + upd_data_list->phys_addr + + upd_data_list->update_desc->epdc_offs, &adj_update_region, (fb_data->rev < 20) ? ALIGN(adj_update_region.width, 8) : @@ -3713,7 +3719,9 @@ static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd, struct mxc_epdc_fb_data *fb_data = info ? (struct mxc_epdc_fb_data *)info:g_fb_data; flush_cache_all(); - outer_flush_all(); + outer_flush_range(fb_data->working_buffer_phys, + fb_data->working_buffer_phys + + fb_data->working_buffer_size); if (copy_to_user((void __user *)arg, (const void *) fb_data->working_buffer_virt, fb_data->working_buffer_size)) @@ -3721,7 +3729,9 @@ static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd, else ret = 0; flush_cache_all(); - outer_flush_all(); + outer_flush_range(fb_data->working_buffer_phys, + fb_data->working_buffer_phys + + fb_data->working_buffer_size); break; } @@ -6645,7 +6655,8 @@ static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat) * Dithering algorithm implementation - Y8->Y1 version 1.0 for i.MX */ static void do_dithering_processing_Y1_v1_0( - unsigned char *update_region_ptr, + unsigned char *update_region_virt_ptr, + dma_addr_t update_region_phys_ptr, struct mxcfb_rect *update_region, unsigned long update_region_stride, int *err_dist) @@ -6667,7 +6678,7 @@ static void do_dithering_processing_Y1_v1_0( err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3); err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3); - y8buf = update_region_ptr + x_offset; + y8buf = update_region_virt_ptr + x_offset; /* scan the line and convert the Y8 to BW */ for (col = 1; col <= update_region->width; col++) { @@ -6693,7 +6704,8 @@ static void do_dithering_processing_Y1_v1_0( } flush_cache_all(); - outer_flush_all(); + outer_flush_range(update_region_phys_ptr, update_region_phys_ptr + + update_region->height * update_region->width); } /* @@ -6701,7 +6713,8 @@ static void do_dithering_processing_Y1_v1_0( */ static void do_dithering_processing_Y4_v1_0( - unsigned char *update_region_ptr, + unsigned char *update_region_virt_ptr, + dma_addr_t update_region_phys_ptr, struct mxcfb_rect *update_region, unsigned long update_region_stride, int *err_dist) @@ -6723,7 +6736,7 @@ static void do_dithering_processing_Y4_v1_0( err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3); err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3); - y8buf = update_region_ptr + x_offset; + y8buf = update_region_virt_ptr + x_offset; /* scan the line and convert the Y8 to Y4 */ for (col = 1; col <= update_region->width; col++) { @@ -6750,7 +6763,8 @@ static void do_dithering_processing_Y4_v1_0( } flush_cache_all(); - outer_flush_all(); + outer_flush_range(update_region_phys_ptr, update_region_phys_ptr + + update_region->height * update_region->width); } static int __init mxc_epdc_fb_init(void) |