Commit 15fced5b authored by Thomas Zimmermann's avatar Thomas Zimmermann
Browse files

fbdev: Remove conflict-handling code



Remove the call to do_remove_conflicting_framebuffers() from the
framebuffer registration. Aperture helpers take care of removing
conflicting devices. With all ownership information stored in the
aperture datastrcutures, remove remove_conflicting_framebuffers()
entirely.

This change also rectifies DRM generic-framebuffer registration, which
tried to unregister conflicting framebuffers, even though it's entirely
build on top of DRM.

v2:
	* remove internal aperture-overlap helpers, which are
	  now unused

Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarJavier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220718072322.8927-12-tzimmermann@suse.de
parent 72a6a3e0
Loading
Loading
Loading
Loading
+0 −21
Original line number Diff line number Diff line
@@ -2,7 +2,6 @@

#include <linux/aperture.h>
#include <linux/device.h>
#include <linux/fb.h> /* for old fbdev helpers */
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/pci.h>
@@ -286,11 +285,6 @@ static void aperture_detach_devices(resource_size_t base, resource_size_t size)
int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size,
					bool primary, const char *name)
{
#if IS_REACHABLE(CONFIG_FB)
	struct apertures_struct *a;
	int ret;
#endif

	/*
	 * If a driver asked to unregister a platform device registered by
	 * sysfb, then can be assumed that this is a driver for a display
@@ -312,21 +306,6 @@ int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t si
	if (primary)
		aperture_detach_devices(VGA_FB_PHYS_BASE, VGA_FB_PHYS_SIZE);

#if IS_REACHABLE(CONFIG_FB)
	a = alloc_apertures(1);
	if (!a)
		return -ENOMEM;

	a->ranges[0].base = base;
	a->ranges[0].size = size;

	ret = remove_conflicting_framebuffers(a, name, primary);
	kfree(a);

	if (ret)
		return ret;
#endif

	return 0;
}
EXPORT_SYMBOL(aperture_remove_conflicting_devices);
+0 −136
Original line number Diff line number Diff line
@@ -1526,102 +1526,6 @@ static int fb_check_foreignness(struct fb_info *fi)
	return 0;
}

static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
{
	/* is the generic aperture base the same as the HW one */
	if (gen->base == hw->base)
		return true;
	/* is the generic aperture base inside the hw base->hw base+size */
	if (gen->base > hw->base && gen->base < hw->base + hw->size)
		return true;
	return false;
}

static bool fb_do_apertures_overlap(struct apertures_struct *gena,
				    struct apertures_struct *hwa)
{
	int i, j;
	if (!hwa || !gena)
		return false;

	for (i = 0; i < hwa->count; ++i) {
		struct aperture *h = &hwa->ranges[i];
		for (j = 0; j < gena->count; ++j) {
			struct aperture *g = &gena->ranges[j];
			printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n",
				(unsigned long long)g->base,
				(unsigned long long)g->size,
				(unsigned long long)h->base,
				(unsigned long long)h->size);
			if (apertures_overlap(g, h))
				return true;
		}
	}

	return false;
}

static void do_unregister_framebuffer(struct fb_info *fb_info);

static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
					       const char *name, bool primary)
{
	int i;

restart_removal:
	/* check all firmware fbs and kick off if the base addr overlaps */
	for_each_registered_fb(i) {
		struct apertures_struct *gen_aper;
		struct device *device;

		if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
			continue;

		gen_aper = registered_fb[i]->apertures;
		device = registered_fb[i]->device;
		if (fb_do_apertures_overlap(gen_aper, a) ||
			(primary && gen_aper && gen_aper->count &&
			 gen_aper->ranges[0].base == VGA_FB_PHYS_BASE)) {

			printk(KERN_INFO "fb%d: switching to %s from %s\n",
			       i, name, registered_fb[i]->fix.id);

			/*
			 * If we kick-out a firmware driver, we also want to remove
			 * the underlying platform device, such as simple-framebuffer,
			 * VESA, EFI, etc. A native driver will then be able to
			 * allocate the memory range.
			 *
			 * If it's not a platform device, at least print a warning. A
			 * fix would add code to remove the device from the system. For
			 * framebuffers without any Linux device, print a warning as
			 * well.
			 */
			if (!device) {
				pr_warn("fb%d: no device set\n", i);
				do_unregister_framebuffer(registered_fb[i]);
			} else if (dev_is_platform(device)) {
				/*
				 * Drop the lock because if the device is unregistered, its
				 * driver will call to unregister_framebuffer(), that takes
				 * this lock.
				 */
				mutex_unlock(&registration_lock);
				platform_device_unregister(to_platform_device(device));
				mutex_lock(&registration_lock);
			} else {
				pr_warn("fb%d: cannot remove device\n", i);
				do_unregister_framebuffer(registered_fb[i]);
			}
			/*
			 * Restart the removal loop now that the device has been
			 * unregistered and its associated framebuffer gone.
			 */
			goto restart_removal;
		}
	}
}

static int do_register_framebuffer(struct fb_info *fb_info)
{
	int i;
@@ -1630,10 +1534,6 @@ static int do_register_framebuffer(struct fb_info *fb_info)
	if (fb_check_foreignness(fb_info))
		return -ENOSYS;

	do_remove_conflicting_framebuffers(fb_info->apertures,
					   fb_info->fix.id,
					   fb_is_primary_device(fb_info));

	if (num_registered_fb == FB_MAX)
		return -ENXIO;

@@ -1778,42 +1678,6 @@ static int fb_aperture_acquire_for_platform_device(struct fb_info *fb_info)
	return ret;
}

/**
 * remove_conflicting_framebuffers - remove firmware-configured framebuffers
 * @a: memory range, users of which are to be removed
 * @name: requesting driver name
 * @primary: also kick vga16fb if present
 *
 * This function removes framebuffer devices (initialized by firmware/bootloader)
 * which use memory range described by @a. If @a is NULL all such devices are
 * removed.
 */
int remove_conflicting_framebuffers(struct apertures_struct *a,
				    const char *name, bool primary)
{
	bool do_free = false;

	if (!a) {
		a = alloc_apertures(1);
		if (!a)
			return -ENOMEM;

		a->ranges[0].base = 0;
		a->ranges[0].size = ~0;
		do_free = true;
	}

	mutex_lock(&registration_lock);
	do_remove_conflicting_framebuffers(a, name, primary);
	mutex_unlock(&registration_lock);

	if (do_free)
		kfree(a);

	return 0;
}
EXPORT_SYMBOL(remove_conflicting_framebuffers);

/**
 *	register_framebuffer - registers a frame buffer device
 *	@fb_info: frame buffer info structure
+0 −2
Original line number Diff line number Diff line
@@ -615,8 +615,6 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
/* drivers/video/fbmem.c */
extern int register_framebuffer(struct fb_info *fb_info);
extern void unregister_framebuffer(struct fb_info *fb_info);
extern int remove_conflicting_framebuffers(struct apertures_struct *a,
					   const char *name, bool primary);
extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
extern int fb_show_logo(struct fb_info *fb_info, int rotate);
extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);