MLK-12179 epdc: use outer_flush_range instead of outer_flush_all
authorRobby Cai <robby.cai@nxp.com>
Tue, 12 Jan 2016 08:35:12 +0000 (16:35 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:49:44 +0000 (14:49 -0500)
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>
drivers/video/fbdev/mxc/mxc_epdc_fb.c
drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c

index 4ba8e57..1497f72 100644 (file)
@@ -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)
index 2f784f0..bdbf005 100644 (file)
@@ -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)