cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

efifb.c (19496B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Framebuffer driver for EFI/UEFI based system
      4 *
      5 * (c) 2006 Edgar Hucek <gimli@dark-green.com>
      6 * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
      7 *
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/efi.h>
     12#include <linux/efi-bgrt.h>
     13#include <linux/errno.h>
     14#include <linux/fb.h>
     15#include <linux/pci.h>
     16#include <linux/platform_device.h>
     17#include <linux/printk.h>
     18#include <linux/screen_info.h>
     19#include <linux/pm_runtime.h>
     20#include <video/vga.h>
     21#include <asm/efi.h>
     22#include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */
     23#include <drm/drm_connector.h>  /* For DRM_MODE_PANEL_ORIENTATION_* */
     24
     25struct bmp_file_header {
     26	u16 id;
     27	u32 file_size;
     28	u32 reserved;
     29	u32 bitmap_offset;
     30} __packed;
     31
     32struct bmp_dib_header {
     33	u32 dib_header_size;
     34	s32 width;
     35	s32 height;
     36	u16 planes;
     37	u16 bpp;
     38	u32 compression;
     39	u32 bitmap_size;
     40	u32 horz_resolution;
     41	u32 vert_resolution;
     42	u32 colors_used;
     43	u32 colors_important;
     44} __packed;
     45
     46static bool use_bgrt = true;
     47static bool request_mem_succeeded = false;
     48static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
     49
     50static struct pci_dev *efifb_pci_dev;	/* dev with BAR covering the efifb */
     51
     52static struct fb_var_screeninfo efifb_defined = {
     53	.activate		= FB_ACTIVATE_NOW,
     54	.height			= -1,
     55	.width			= -1,
     56	.right_margin		= 32,
     57	.upper_margin		= 16,
     58	.lower_margin		= 4,
     59	.vsync_len		= 4,
     60	.vmode			= FB_VMODE_NONINTERLACED,
     61};
     62
     63static struct fb_fix_screeninfo efifb_fix = {
     64	.id			= "EFI VGA",
     65	.type			= FB_TYPE_PACKED_PIXELS,
     66	.accel			= FB_ACCEL_NONE,
     67	.visual			= FB_VISUAL_TRUECOLOR,
     68};
     69
     70static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
     71			   unsigned blue, unsigned transp,
     72			   struct fb_info *info)
     73{
     74	/*
     75	 *  Set a single color register. The values supplied are
     76	 *  already rounded down to the hardware's capabilities
     77	 *  (according to the entries in the `var' structure). Return
     78	 *  != 0 for invalid regno.
     79	 */
     80
     81	if (regno >= info->cmap.len)
     82		return 1;
     83
     84	if (regno < 16) {
     85		red   >>= 16 - info->var.red.length;
     86		green >>= 16 - info->var.green.length;
     87		blue  >>= 16 - info->var.blue.length;
     88		((u32 *)(info->pseudo_palette))[regno] =
     89			(red   << info->var.red.offset)   |
     90			(green << info->var.green.offset) |
     91			(blue  << info->var.blue.offset);
     92	}
     93	return 0;
     94}
     95
     96/*
     97 * If fbcon deffered console takeover is configured, the intent is for the
     98 * framebuffer to show the boot graphics (e.g. vendor logo) until there is some
     99 * (error) message to display. But the boot graphics may have been destroyed by
    100 * e.g. option ROM output, detect this and restore the boot graphics.
    101 */
    102#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \
    103    defined CONFIG_ACPI_BGRT
    104static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
    105{
    106	u8 r, g, b;
    107
    108	while (width--) {
    109		b = *src++;
    110		g = *src++;
    111		r = *src++;
    112		*dst++ = (r << si->red_pos)   |
    113			 (g << si->green_pos) |
    114			 (b << si->blue_pos);
    115	}
    116}
    117
    118#ifdef CONFIG_X86
    119/*
    120 * On x86 some firmwares use a low non native resolution for the display when
    121 * they have shown some text messages. While keeping the bgrt filled with info
    122 * for the native resolution. If the bgrt image intended for the native
    123 * resolution still fits, it will be displayed very close to the right edge of
    124 * the display looking quite bad. This function checks for this.
    125 */
    126static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
    127{
    128	/*
    129	 * All x86 firmwares horizontally center the image (the yoffset
    130	 * calculations differ between boards, but xoffset is predictable).
    131	 */
    132	u32 expected_xoffset = (si->lfb_width - bmp_width) / 2;
    133
    134	return bgrt_tab.image_offset_x == expected_xoffset;
    135}
    136#else
    137static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
    138{
    139	return true;
    140}
    141#endif
    142
    143static void efifb_show_boot_graphics(struct fb_info *info)
    144{
    145	u32 bmp_width, bmp_height, bmp_pitch, dst_x, y, src_y;
    146	struct screen_info *si = &screen_info;
    147	struct bmp_file_header *file_header;
    148	struct bmp_dib_header *dib_header;
    149	void *bgrt_image = NULL;
    150	u8 *dst = info->screen_base;
    151
    152	if (!use_bgrt)
    153		return;
    154
    155	if (!bgrt_tab.image_address) {
    156		pr_info("efifb: No BGRT, not showing boot graphics\n");
    157		return;
    158	}
    159
    160	if (bgrt_tab.status & 0x06) {
    161		pr_info("efifb: BGRT rotation bits set, not showing boot graphics\n");
    162		return;
    163	}
    164
    165	/* Avoid flashing the logo if we're going to print std probe messages */
    166	if (console_loglevel > CONSOLE_LOGLEVEL_QUIET)
    167		return;
    168
    169	/* bgrt_tab.status is unreliable, so we don't check it */
    170
    171	if (si->lfb_depth != 32) {
    172		pr_info("efifb: not 32 bits, not showing boot graphics\n");
    173		return;
    174	}
    175
    176	bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size,
    177			      MEMREMAP_WB);
    178	if (!bgrt_image) {
    179		pr_warn("efifb: Ignoring BGRT: failed to map image memory\n");
    180		return;
    181	}
    182
    183	if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header)))
    184		goto error;
    185
    186	file_header = bgrt_image;
    187	if (file_header->id != 0x4d42 || file_header->reserved != 0)
    188		goto error;
    189
    190	dib_header = bgrt_image + sizeof(*file_header);
    191	if (dib_header->dib_header_size != 40 || dib_header->width < 0 ||
    192	    dib_header->planes != 1 || dib_header->bpp != 24 ||
    193	    dib_header->compression != 0)
    194		goto error;
    195
    196	bmp_width = dib_header->width;
    197	bmp_height = abs(dib_header->height);
    198	bmp_pitch = round_up(3 * bmp_width, 4);
    199
    200	if ((file_header->bitmap_offset + bmp_pitch * bmp_height) >
    201				bgrt_image_size)
    202		goto error;
    203
    204	if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width ||
    205	    (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height)
    206		goto error;
    207
    208	if (!efifb_bgrt_sanity_check(si, bmp_width))
    209		goto error;
    210
    211	pr_info("efifb: showing boot graphics\n");
    212
    213	for (y = 0; y < si->lfb_height; y++, dst += si->lfb_linelength) {
    214		/* Only background? */
    215		if (y < bgrt_tab.image_offset_y ||
    216		    y >= (bgrt_tab.image_offset_y + bmp_height)) {
    217			memset(dst, 0, 4 * si->lfb_width);
    218			continue;
    219		}
    220
    221		src_y = y - bgrt_tab.image_offset_y;
    222		/* Positive header height means upside down row order */
    223		if (dib_header->height > 0)
    224			src_y = (bmp_height - 1) - src_y;
    225
    226		memset(dst, 0, bgrt_tab.image_offset_x * 4);
    227		dst_x = bgrt_tab.image_offset_x;
    228		efifb_copy_bmp(bgrt_image + file_header->bitmap_offset +
    229					    src_y * bmp_pitch,
    230			       (u32 *)dst + dst_x, bmp_width, si);
    231		dst_x += bmp_width;
    232		memset((u32 *)dst + dst_x, 0, (si->lfb_width - dst_x) * 4);
    233	}
    234
    235	memunmap(bgrt_image);
    236	return;
    237
    238error:
    239	memunmap(bgrt_image);
    240	pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n");
    241}
    242#else
    243static inline void efifb_show_boot_graphics(struct fb_info *info) {}
    244#endif
    245
    246/*
    247 * fb_ops.fb_destroy is called by the last put_fb_info() call at the end
    248 * of unregister_framebuffer() or fb_release(). Do any cleanup here.
    249 */
    250static void efifb_destroy(struct fb_info *info)
    251{
    252	if (efifb_pci_dev)
    253		pm_runtime_put(&efifb_pci_dev->dev);
    254
    255	if (info->screen_base) {
    256		if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
    257			iounmap(info->screen_base);
    258		else
    259			memunmap(info->screen_base);
    260	}
    261
    262	if (request_mem_succeeded)
    263		release_mem_region(info->apertures->ranges[0].base,
    264				   info->apertures->ranges[0].size);
    265	fb_dealloc_cmap(&info->cmap);
    266
    267	framebuffer_release(info);
    268}
    269
    270static const struct fb_ops efifb_ops = {
    271	.owner		= THIS_MODULE,
    272	.fb_destroy	= efifb_destroy,
    273	.fb_setcolreg	= efifb_setcolreg,
    274	.fb_fillrect	= cfb_fillrect,
    275	.fb_copyarea	= cfb_copyarea,
    276	.fb_imageblit	= cfb_imageblit,
    277};
    278
    279static int efifb_setup(char *options)
    280{
    281	char *this_opt;
    282
    283	if (options && *options) {
    284		while ((this_opt = strsep(&options, ",")) != NULL) {
    285			if (!*this_opt) continue;
    286
    287			efifb_setup_from_dmi(&screen_info, this_opt);
    288
    289			if (!strncmp(this_opt, "base:", 5))
    290				screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
    291			else if (!strncmp(this_opt, "stride:", 7))
    292				screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
    293			else if (!strncmp(this_opt, "height:", 7))
    294				screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
    295			else if (!strncmp(this_opt, "width:", 6))
    296				screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
    297			else if (!strcmp(this_opt, "nowc"))
    298				mem_flags &= ~EFI_MEMORY_WC;
    299			else if (!strcmp(this_opt, "nobgrt"))
    300				use_bgrt = false;
    301		}
    302	}
    303
    304	return 0;
    305}
    306
    307static inline bool fb_base_is_valid(void)
    308{
    309	if (screen_info.lfb_base)
    310		return true;
    311
    312	if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
    313		return false;
    314
    315	if (screen_info.ext_lfb_base)
    316		return true;
    317
    318	return false;
    319}
    320
    321#define efifb_attr_decl(name, fmt)					\
    322static ssize_t name##_show(struct device *dev,				\
    323			   struct device_attribute *attr,		\
    324			   char *buf)					\
    325{									\
    326	return sprintf(buf, fmt "\n", (screen_info.lfb_##name));	\
    327}									\
    328static DEVICE_ATTR_RO(name)
    329
    330efifb_attr_decl(base, "0x%x");
    331efifb_attr_decl(linelength, "%u");
    332efifb_attr_decl(height, "%u");
    333efifb_attr_decl(width, "%u");
    334efifb_attr_decl(depth, "%u");
    335
    336static struct attribute *efifb_attrs[] = {
    337	&dev_attr_base.attr,
    338	&dev_attr_linelength.attr,
    339	&dev_attr_width.attr,
    340	&dev_attr_height.attr,
    341	&dev_attr_depth.attr,
    342	NULL
    343};
    344ATTRIBUTE_GROUPS(efifb);
    345
    346static bool pci_dev_disabled;	/* FB base matches BAR of a disabled device */
    347
    348static struct resource *bar_resource;
    349static u64 bar_offset;
    350
    351static int efifb_probe(struct platform_device *dev)
    352{
    353	struct fb_info *info;
    354	int err, orientation;
    355	unsigned int size_vmode;
    356	unsigned int size_remap;
    357	unsigned int size_total;
    358	char *option = NULL;
    359	efi_memory_desc_t md;
    360
    361	/*
    362	 * Generic drivers must not be registered if a framebuffer exists.
    363	 * If a native driver was probed, the display hardware was already
    364	 * taken and attempting to use the system framebuffer is dangerous.
    365	 */
    366	if (num_registered_fb > 0) {
    367		dev_err(&dev->dev,
    368			"efifb: a framebuffer is already registered\n");
    369		return -EINVAL;
    370	}
    371
    372	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
    373		return -ENODEV;
    374
    375	if (fb_get_options("efifb", &option))
    376		return -ENODEV;
    377	efifb_setup(option);
    378
    379	/* We don't get linelength from UGA Draw Protocol, only from
    380	 * EFI Graphics Protocol.  So if it's not in DMI, and it's not
    381	 * passed in from the user, we really can't use the framebuffer.
    382	 */
    383	if (!screen_info.lfb_linelength)
    384		return -ENODEV;
    385
    386	if (!screen_info.lfb_depth)
    387		screen_info.lfb_depth = 32;
    388	if (!screen_info.pages)
    389		screen_info.pages = 1;
    390	if (!fb_base_is_valid()) {
    391		printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
    392		return -ENODEV;
    393	}
    394	printk(KERN_INFO "efifb: probing for efifb\n");
    395
    396	/* just assume they're all unset if any are */
    397	if (!screen_info.blue_size) {
    398		screen_info.blue_size = 8;
    399		screen_info.blue_pos = 0;
    400		screen_info.green_size = 8;
    401		screen_info.green_pos = 8;
    402		screen_info.red_size = 8;
    403		screen_info.red_pos = 16;
    404		screen_info.rsvd_size = 8;
    405		screen_info.rsvd_pos = 24;
    406	}
    407
    408	efifb_fix.smem_start = screen_info.lfb_base;
    409
    410	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
    411		u64 ext_lfb_base;
    412
    413		ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
    414		efifb_fix.smem_start |= ext_lfb_base;
    415	}
    416
    417	if (bar_resource &&
    418	    bar_resource->start + bar_offset != efifb_fix.smem_start) {
    419		dev_info(&efifb_pci_dev->dev,
    420			 "BAR has moved, updating efifb address\n");
    421		efifb_fix.smem_start = bar_resource->start + bar_offset;
    422	}
    423
    424	efifb_defined.bits_per_pixel = screen_info.lfb_depth;
    425	efifb_defined.xres = screen_info.lfb_width;
    426	efifb_defined.yres = screen_info.lfb_height;
    427	efifb_fix.line_length = screen_info.lfb_linelength;
    428
    429	/*   size_vmode -- that is the amount of memory needed for the
    430	 *                 used video mode, i.e. the minimum amount of
    431	 *                 memory we need. */
    432	size_vmode = efifb_defined.yres * efifb_fix.line_length;
    433
    434	/*   size_total -- all video memory we have. Used for
    435	 *                 entries, ressource allocation and bounds
    436	 *                 checking. */
    437	size_total = screen_info.lfb_size;
    438	if (size_total < size_vmode)
    439		size_total = size_vmode;
    440
    441	/*   size_remap -- the amount of video memory we are going to
    442	 *                 use for efifb.  With modern cards it is no
    443	 *                 option to simply use size_total as that
    444	 *                 wastes plenty of kernel address space. */
    445	size_remap  = size_vmode * 2;
    446	if (size_remap > size_total)
    447		size_remap = size_total;
    448	if (size_remap % PAGE_SIZE)
    449		size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
    450	efifb_fix.smem_len = size_remap;
    451
    452	if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
    453		request_mem_succeeded = true;
    454	} else {
    455		/* We cannot make this fatal. Sometimes this comes from magic
    456		   spaces our resource handlers simply don't know about */
    457		pr_warn("efifb: cannot reserve video memory at 0x%lx\n",
    458			efifb_fix.smem_start);
    459	}
    460
    461	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
    462	if (!info) {
    463		err = -ENOMEM;
    464		goto err_release_mem;
    465	}
    466	platform_set_drvdata(dev, info);
    467	info->pseudo_palette = info->par;
    468	info->par = NULL;
    469
    470	info->apertures = alloc_apertures(1);
    471	if (!info->apertures) {
    472		err = -ENOMEM;
    473		goto err_release_fb;
    474	}
    475	info->apertures->ranges[0].base = efifb_fix.smem_start;
    476	info->apertures->ranges[0].size = size_remap;
    477
    478	if (efi_enabled(EFI_MEMMAP) &&
    479	    !efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
    480		if ((efifb_fix.smem_start + efifb_fix.smem_len) >
    481		    (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) {
    482			pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n",
    483			       efifb_fix.smem_start);
    484			err = -EIO;
    485			goto err_release_fb;
    486		}
    487		/*
    488		 * If the UEFI memory map covers the efifb region, we may only
    489		 * remap it using the attributes the memory map prescribes.
    490		 */
    491		md.attribute &= EFI_MEMORY_UC | EFI_MEMORY_WC |
    492				EFI_MEMORY_WT | EFI_MEMORY_WB;
    493		if (md.attribute) {
    494			mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB;
    495			mem_flags &= md.attribute;
    496		}
    497	}
    498	if (mem_flags & EFI_MEMORY_WC)
    499		info->screen_base = ioremap_wc(efifb_fix.smem_start,
    500					       efifb_fix.smem_len);
    501	else if (mem_flags & EFI_MEMORY_UC)
    502		info->screen_base = ioremap(efifb_fix.smem_start,
    503					    efifb_fix.smem_len);
    504	else if (mem_flags & EFI_MEMORY_WT)
    505		info->screen_base = memremap(efifb_fix.smem_start,
    506					     efifb_fix.smem_len, MEMREMAP_WT);
    507	else if (mem_flags & EFI_MEMORY_WB)
    508		info->screen_base = memremap(efifb_fix.smem_start,
    509					     efifb_fix.smem_len, MEMREMAP_WB);
    510	if (!info->screen_base) {
    511		pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n",
    512			efifb_fix.smem_len, efifb_fix.smem_start);
    513		err = -EIO;
    514		goto err_release_fb;
    515	}
    516
    517	efifb_show_boot_graphics(info);
    518
    519	pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n",
    520	       efifb_fix.smem_start, size_remap/1024, size_total/1024);
    521	pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
    522	       efifb_defined.xres, efifb_defined.yres,
    523	       efifb_defined.bits_per_pixel, efifb_fix.line_length,
    524	       screen_info.pages);
    525
    526	efifb_defined.xres_virtual = efifb_defined.xres;
    527	efifb_defined.yres_virtual = efifb_fix.smem_len /
    528					efifb_fix.line_length;
    529	pr_info("efifb: scrolling: redraw\n");
    530	efifb_defined.yres_virtual = efifb_defined.yres;
    531
    532	/* some dummy values for timing to make fbset happy */
    533	efifb_defined.pixclock     = 10000000 / efifb_defined.xres *
    534					1000 / efifb_defined.yres;
    535	efifb_defined.left_margin  = (efifb_defined.xres / 8) & 0xf8;
    536	efifb_defined.hsync_len    = (efifb_defined.xres / 8) & 0xf8;
    537
    538	efifb_defined.red.offset    = screen_info.red_pos;
    539	efifb_defined.red.length    = screen_info.red_size;
    540	efifb_defined.green.offset  = screen_info.green_pos;
    541	efifb_defined.green.length  = screen_info.green_size;
    542	efifb_defined.blue.offset   = screen_info.blue_pos;
    543	efifb_defined.blue.length   = screen_info.blue_size;
    544	efifb_defined.transp.offset = screen_info.rsvd_pos;
    545	efifb_defined.transp.length = screen_info.rsvd_size;
    546
    547	pr_info("efifb: %s: "
    548	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
    549	       "Truecolor",
    550	       screen_info.rsvd_size,
    551	       screen_info.red_size,
    552	       screen_info.green_size,
    553	       screen_info.blue_size,
    554	       screen_info.rsvd_pos,
    555	       screen_info.red_pos,
    556	       screen_info.green_pos,
    557	       screen_info.blue_pos);
    558
    559	efifb_fix.ypanstep  = 0;
    560	efifb_fix.ywrapstep = 0;
    561
    562	info->fbops = &efifb_ops;
    563	info->var = efifb_defined;
    564	info->fix = efifb_fix;
    565	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
    566
    567	orientation = drm_get_panel_orientation_quirk(efifb_defined.xres,
    568						      efifb_defined.yres);
    569	switch (orientation) {
    570	default:
    571		info->fbcon_rotate_hint = FB_ROTATE_UR;
    572		break;
    573	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
    574		info->fbcon_rotate_hint = FB_ROTATE_UD;
    575		break;
    576	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
    577		info->fbcon_rotate_hint = FB_ROTATE_CCW;
    578		break;
    579	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
    580		info->fbcon_rotate_hint = FB_ROTATE_CW;
    581		break;
    582	}
    583
    584	err = sysfs_create_groups(&dev->dev.kobj, efifb_groups);
    585	if (err) {
    586		pr_err("efifb: cannot add sysfs attrs\n");
    587		goto err_unmap;
    588	}
    589	err = fb_alloc_cmap(&info->cmap, 256, 0);
    590	if (err < 0) {
    591		pr_err("efifb: cannot allocate colormap\n");
    592		goto err_groups;
    593	}
    594
    595	if (efifb_pci_dev)
    596		WARN_ON(pm_runtime_get_sync(&efifb_pci_dev->dev) < 0);
    597
    598	err = register_framebuffer(info);
    599	if (err < 0) {
    600		pr_err("efifb: cannot register framebuffer\n");
    601		goto err_put_rpm_ref;
    602	}
    603	fb_info(info, "%s frame buffer device\n", info->fix.id);
    604	return 0;
    605
    606err_put_rpm_ref:
    607	if (efifb_pci_dev)
    608		pm_runtime_put(&efifb_pci_dev->dev);
    609
    610	fb_dealloc_cmap(&info->cmap);
    611err_groups:
    612	sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
    613err_unmap:
    614	if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
    615		iounmap(info->screen_base);
    616	else
    617		memunmap(info->screen_base);
    618err_release_fb:
    619	framebuffer_release(info);
    620err_release_mem:
    621	if (request_mem_succeeded)
    622		release_mem_region(efifb_fix.smem_start, size_total);
    623	return err;
    624}
    625
    626static int efifb_remove(struct platform_device *pdev)
    627{
    628	struct fb_info *info = platform_get_drvdata(pdev);
    629
    630	/* efifb_destroy takes care of info cleanup */
    631	unregister_framebuffer(info);
    632	sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
    633
    634	return 0;
    635}
    636
    637static struct platform_driver efifb_driver = {
    638	.driver = {
    639		.name = "efi-framebuffer",
    640	},
    641	.probe = efifb_probe,
    642	.remove = efifb_remove,
    643};
    644
    645builtin_platform_driver(efifb_driver);
    646
    647#if defined(CONFIG_PCI)
    648
    649static void record_efifb_bar_resource(struct pci_dev *dev, int idx, u64 offset)
    650{
    651	u16 word;
    652
    653	efifb_pci_dev = dev;
    654
    655	pci_read_config_word(dev, PCI_COMMAND, &word);
    656	if (!(word & PCI_COMMAND_MEMORY)) {
    657		pci_dev_disabled = true;
    658		dev_err(&dev->dev,
    659			"BAR %d: assigned to efifb but device is disabled!\n",
    660			idx);
    661		return;
    662	}
    663
    664	bar_resource = &dev->resource[idx];
    665	bar_offset = offset;
    666
    667	dev_info(&dev->dev, "BAR %d: assigned to efifb\n", idx);
    668}
    669
    670static void efifb_fixup_resources(struct pci_dev *dev)
    671{
    672	u64 base = screen_info.lfb_base;
    673	u64 size = screen_info.lfb_size;
    674	int i;
    675
    676	if (efifb_pci_dev || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
    677		return;
    678
    679	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
    680		base |= (u64)screen_info.ext_lfb_base << 32;
    681
    682	if (!base)
    683		return;
    684
    685	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
    686		struct resource *res = &dev->resource[i];
    687
    688		if (!(res->flags & IORESOURCE_MEM))
    689			continue;
    690
    691		if (res->start <= base && res->end >= base + size - 1) {
    692			record_efifb_bar_resource(dev, i, base - res->start);
    693			break;
    694		}
    695	}
    696}
    697DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY,
    698			       16, efifb_fixup_resources);
    699
    700#endif