]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blobdiff - drivers/video/fbdev/efifb.c
Merge tag 'fbdev-v4.19' of https://github.com/bzolnier/linux
[mirror_ubuntu-focal-kernel.git] / drivers / video / fbdev / efifb.c
index 52bf39f93888ddb28e38a78b3c100f056b0c89f9..3946649b85c8908f4e9874b837ccdad274af8499 100644 (file)
@@ -43,7 +43,7 @@ struct bmp_dib_header {
 } __packed;
 
 static bool request_mem_succeeded = false;
-static bool nowc = false;
+static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
 
 static struct fb_var_screeninfo efifb_defined = {
        .activate               = FB_ACTIVATE_NOW,
@@ -249,8 +249,12 @@ static inline void efifb_show_boot_graphics(struct fb_info *info) {}
 
 static void efifb_destroy(struct fb_info *info)
 {
-       if (info->screen_base)
-               iounmap(info->screen_base);
+       if (info->screen_base) {
+               if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
+                       iounmap(info->screen_base);
+               else
+                       memunmap(info->screen_base);
+       }
        if (request_mem_succeeded)
                release_mem_region(info->apertures->ranges[0].base,
                                   info->apertures->ranges[0].size);
@@ -285,7 +289,7 @@ static int efifb_setup(char *options)
                        else if (!strncmp(this_opt, "width:", 6))
                                screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
                        else if (!strcmp(this_opt, "nowc"))
-                               nowc = true;
+                               mem_flags &= ~EFI_MEMORY_WC;
                }
        }
 
@@ -345,6 +349,7 @@ static int efifb_probe(struct platform_device *dev)
        unsigned int size_remap;
        unsigned int size_total;
        char *option = NULL;
+       efi_memory_desc_t md;
 
        if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
                return -ENODEV;
@@ -453,12 +458,35 @@ static int efifb_probe(struct platform_device *dev)
        info->apertures->ranges[0].base = efifb_fix.smem_start;
        info->apertures->ranges[0].size = size_remap;
 
-       if (nowc)
-               info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
-       else
-               info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len);
+       if (!efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
+               if ((efifb_fix.smem_start + efifb_fix.smem_len) >
+                   (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) {
+                       pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n",
+                              efifb_fix.smem_start);
+                       err = -EIO;
+                       goto err_release_fb;
+               }
+               /*
+                * If the UEFI memory map covers the efifb region, we may only
+                * remap it using the attributes the memory map prescribes.
+                */
+               mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB;
+               mem_flags &= md.attribute;
+       }
+       if (mem_flags & EFI_MEMORY_WC)
+               info->screen_base = ioremap_wc(efifb_fix.smem_start,
+                                              efifb_fix.smem_len);
+       else if (mem_flags & EFI_MEMORY_UC)
+               info->screen_base = ioremap(efifb_fix.smem_start,
+                                           efifb_fix.smem_len);
+       else if (mem_flags & EFI_MEMORY_WT)
+               info->screen_base = memremap(efifb_fix.smem_start,
+                                            efifb_fix.smem_len, MEMREMAP_WT);
+       else if (mem_flags & EFI_MEMORY_WB)
+               info->screen_base = memremap(efifb_fix.smem_start,
+                                            efifb_fix.smem_len, MEMREMAP_WB);
        if (!info->screen_base) {
-               pr_err("efifb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
+               pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n",
                        efifb_fix.smem_len, efifb_fix.smem_start);
                err = -EIO;
                goto err_release_fb;
@@ -554,7 +582,10 @@ err_fb_dealoc:
 err_groups:
        sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
 err_unmap:
-       iounmap(info->screen_base);
+       if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
+               iounmap(info->screen_base);
+       else
+               memunmap(info->screen_base);
 err_release_fb:
        framebuffer_release(info);
 err_release_mem: