summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRobby Cai <robby.cai@nxp.com>2016-01-12 16:35:12 +0800
committerNitin Garg <nitin.garg@nxp.com>2016-01-14 11:03:11 -0600
commitd59e4e631fd6e011c6803d6f77b4d711794a35dd (patch)
tree1e1cb33b9aba5a129e632a18980d0288f81fa1ce /drivers
parent83c377f8bf3dbe810b0a8b628202e7b32a40af4b (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.c36
-rw-r--r--drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c36
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)