The Mali kernel driver allows the userland code to map a buffer
in physical memory (via the MALI_IOC_MEM_MAP_EXT ioctl). This is
normally used for mapping the framebuffer in the userland Mali
blob and directly accessing it for rendering graphics. Because
of security reasons, the kernel driver has a validation check,
which only permits one chunk of physical memory to be mapped
this way. And the Mali driver initialization code configures the
address and the size of this chunk.

Now the problem is that the sunxi hardware has not just one, but
up to two framebuffers (for example, one VGA and one HDMI monitor).
Previously both framebuffers were allocated from the disp reservation
area. So the Mali validation code was just allowing access to the
whole disp reservation area. But with CMA support, the framebuffers
may be allocated anywhere in the CMA area. And now we have two
disconnected chunks of physical memory, which should be both
supported by the MALI_IOC_MEM_MAP_EXT ioctl.

This patch modifies the MALI_IOC_MEM_MAP_EXT validation code to
support both of the sunxi disp framebuffers.

PS. If the kernel driver does not allow to map physical memory via
the MALI_IOC_MEM_MAP_EXT ioctl at all, then the Mali userland blob
still can work and is able to render 3D graphics. However this
is done by using memcpy to copy data into the framebuffer for each
frame and the performance becomes ridiculously bad.

Signed-off-by: Siarhei Siamashka <siarhei.siamas...@gmail.com>
---
 arch/arm/plat-sunxi/core.c                         | 12 +++++++++++
 drivers/gpu/mali/mali/common/mali_mem_validation.c | 22 +++++++++++++++++--
 .../mali/mali/platform/mali400-pmu/mali_platform.c | 25 ----------------------
 drivers/video/sunxi/disp/dev_fb.c                  | 22 +++++++++++++++++++
 4 files changed, 54 insertions(+), 27 deletions(-)

diff --git a/arch/arm/plat-sunxi/core.c b/arch/arm/plat-sunxi/core.c
index e7da395..89f3187 100644
--- a/arch/arm/plat-sunxi/core.c
+++ b/arch/arm/plat-sunxi/core.c
@@ -135,6 +135,18 @@ static int __init reserve_fb_param(char *s)
 early_param("sunxi_fb_mem_reserve", reserve_fb_param);
 #endif
 
+/*
+ * Physical addresses and sizes of two framebuffers.
+ */
+unsigned long fb0_start;
+unsigned long fb0_size;
+unsigned long fb1_start;
+unsigned long fb1_size;
+EXPORT_SYMBOL(fb0_start);
+EXPORT_SYMBOL(fb0_size);
+EXPORT_SYMBOL(fb1_start);
+EXPORT_SYMBOL(fb1_size);
+
 #if IS_ENABLED(CONFIG_SUNXI_G2D)
 /* The G2D block is used by:
  *
diff --git a/drivers/gpu/mali/mali/common/mali_mem_validation.c 
b/drivers/gpu/mali/mali/common/mali_mem_validation.c
index 2f57459..4a5b88c 100644
--- a/drivers/gpu/mali/mali/common/mali_mem_validation.c
+++ b/drivers/gpu/mali/mali/common/mali_mem_validation.c
@@ -14,6 +14,11 @@
 
 #define MALI_INVALID_MEM_ADDR 0xFFFFFFFF
 
+extern unsigned long fb0_start;
+extern unsigned long fb0_size;
+extern unsigned long fb1_start;
+extern unsigned long fb1_size;
+
 typedef struct
 {
        u32 phys_base;        /**< Mali physical base of the memory, page 
aligned */
@@ -47,7 +52,8 @@ _mali_osk_errcode_t mali_mem_validation_add_range(const 
_mali_osk_resource_t *re
        return _MALI_OSK_ERR_OK;
 }
 
-_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size)
+static _mali_osk_errcode_t validation_check_helper(u32 phys_addr, u32 size,
+                                                  _mali_mem_validation_t 
mali_mem_validator)
 {
        if (phys_addr < (phys_addr + size)) /* Don't allow overflow (or zero 
size) */
        {
@@ -65,7 +71,19 @@ _mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, 
u32 size)
                }
        }
 
-       MALI_PRINT_ERROR(("MALI PHYSICAL RANGE VALIDATION ERROR: The range 
supplied was: phys_base=0x%08X, size=0x%08X\n", phys_addr, size));
+       return _MALI_OSK_ERR_FAULT;
+}
 
+_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size)
+{
+       _mali_mem_validation_t fb0 = { fb0_start, fb0_size };
+       _mali_mem_validation_t fb1 = { fb1_start, fb1_size };
+
+       if (validation_check_helper(phys_addr, size, fb0) == _MALI_OSK_ERR_OK ||
+           validation_check_helper(phys_addr, size, fb1) == _MALI_OSK_ERR_OK ||
+           validation_check_helper(phys_addr, size, mali_mem_validator) == 
_MALI_OSK_ERR_OK)
+               return _MALI_OSK_ERR_OK;
+
+       MALI_PRINT_ERROR(("MALI PHYSICAL RANGE VALIDATION ERROR: The range 
supplied was: phys_base=0x%08X, size=0x%08X\n", phys_addr, size));
        return _MALI_OSK_ERR_FAULT;
 }
diff --git a/drivers/gpu/mali/mali/platform/mali400-pmu/mali_platform.c 
b/drivers/gpu/mali/mali/platform/mali400-pmu/mali_platform.c
index 290c1f9..d43bde0 100644
--- a/drivers/gpu/mali/mali/platform/mali400-pmu/mali_platform.c
+++ b/drivers/gpu/mali/mali/platform/mali400-pmu/mali_platform.c
@@ -24,13 +24,6 @@
 #include <plat/sys_config.h>
 #include <plat/memory.h>
 
-#ifdef CONFIG_FB_SUNXI_RESERVED_MEM
-extern unsigned long fb_start;
-extern unsigned long fb_size;
-static int fb_validation_range_added;
-#endif
-
-
 int mali_clk_div = 3;
 module_param(mali_clk_div, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | 
S_IROTH);
 MODULE_PARM_DESC(mali_clk_div, "Clock divisor for mali");
@@ -45,24 +38,6 @@ _mali_osk_errcode_t mali_platform_init(void)
        int clk_div;
        int mali_used = 0;
 
-#ifdef CONFIG_FB_SUNXI_RESERVED_MEM
-       /* mali_platform_init() may be called multiple times,
-          but we only need to set the validation range once */
-       if (!fb_validation_range_added) {
-               _mali_osk_resource_t fb_resource = {
-                       .type = MEM_VALIDATION,
-                       .description = "Framebuffer",
-                       .base = fb_start,
-                       .size = fb_size,
-                       .flags = 0
-               };
-               mali_mem_validation_add_range(&fb_resource);
-               MALI_PRINT(("permit MALI_IOC_MEM_MAP_EXT ioctl for framebuffer"
-                           " (paddr=0x%08X, size=%d)\n", fb_start, fb_size));
-               fb_validation_range_added = 1;
-       }
-#endif
-
        //get mali ahb clock
        h_ahb_mali = clk_get(NULL, "ahb_mali");
        if(!h_ahb_mali){
diff --git a/drivers/video/sunxi/disp/dev_fb.c 
b/drivers/video/sunxi/disp/dev_fb.c
index 7500764..6946222 100644
--- a/drivers/video/sunxi/disp/dev_fb.c
+++ b/drivers/video/sunxi/disp/dev_fb.c
@@ -1483,6 +1483,12 @@ static struct fb_ops dispfb_ops = {
        .fb_cursor = Fb_cursor,
 };
 
+/* For Mali addresses validation */
+extern unsigned long fb0_start;
+extern unsigned long fb0_size;
+extern unsigned long fb1_start;
+extern unsigned long fb1_size;
+
 __s32 Display_Fb_Request(__u32 fb_id, __disp_fb_create_para_t * fb_para)
 {
        struct fb_info *info = NULL;
@@ -1510,6 +1516,14 @@ __s32 Display_Fb_Request(__u32 fb_id, 
__disp_fb_create_para_t * fb_para)
                info->fix.line_length * fb_para->height * fb_para->buffer_num);
        Fb_map_video_memory(fb_id, info);
 
+       if (fb_id == 0) {
+               fb0_start = info->fix.smem_start;
+               fb0_size  = info->fix.smem_len;
+       } else if (fb_id == 1) {
+               fb1_start = info->fix.smem_start;
+               fb1_size  = info->fix.smem_len;
+       }
+
        for (sel = 0; sel < 2; sel++) {
                if (((sel == 0) && (fb_para->fb_mode != FB_MODE_SCREEN1)) ||
                    ((sel == 1) && (fb_para->fb_mode != FB_MODE_SCREEN0))) {
@@ -1630,6 +1644,14 @@ __s32 Display_Fb_Release(__u32 fb_id)
        fb_dealloc_cmap(&info->cmap);
        Fb_unmap_video_memory(fb_id, info);
 
+       if (fb_id == 0) {
+               fb0_start = 0;
+               fb0_size  = 0;
+       } else if (fb_id == 1) {
+               fb1_start = 0;
+               fb1_size  = 0;
+       }
+
        return DIS_SUCCESS;
 }
 
-- 
2.4.10

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to