xref: /freebsd/sys/compat/linuxkpi/common/src/linux_aperture.c (revision 11d79c4756b7c85faf7c4a268c301a41ce0887b9)
1*11d79c47SEmmanuel Vadot // SPDX-License-Identifier: MIT
2*11d79c47SEmmanuel Vadot 
3*11d79c47SEmmanuel Vadot #include <linux/aperture.h>
4*11d79c47SEmmanuel Vadot #include <linux/device.h>
5*11d79c47SEmmanuel Vadot #include <linux/list.h>
6*11d79c47SEmmanuel Vadot #include <linux/mutex.h>
7*11d79c47SEmmanuel Vadot #include <linux/pci.h>
8*11d79c47SEmmanuel Vadot #include <linux/platform_device.h>
9*11d79c47SEmmanuel Vadot #include <linux/slab.h>
10*11d79c47SEmmanuel Vadot #include <linux/sysfb.h>
11*11d79c47SEmmanuel Vadot #include <linux/types.h>
12*11d79c47SEmmanuel Vadot #include <linux/vgaarb.h>
13*11d79c47SEmmanuel Vadot 
14*11d79c47SEmmanuel Vadot #include <video/vga.h>
15*11d79c47SEmmanuel Vadot 
16*11d79c47SEmmanuel Vadot /**
17*11d79c47SEmmanuel Vadot  * DOC: overview
18*11d79c47SEmmanuel Vadot  *
19*11d79c47SEmmanuel Vadot  * A graphics device might be supported by different drivers, but only one
20*11d79c47SEmmanuel Vadot  * driver can be active at any given time. Many systems load a generic
21*11d79c47SEmmanuel Vadot  * graphics drivers, such as EFI-GOP or VESA, early during the boot process.
22*11d79c47SEmmanuel Vadot  * During later boot stages, they replace the generic driver with a dedicated,
23*11d79c47SEmmanuel Vadot  * hardware-specific driver. To take over the device the dedicated driver
24*11d79c47SEmmanuel Vadot  * first has to remove the generic driver. Aperture functions manage
25*11d79c47SEmmanuel Vadot  * ownership of framebuffer memory and hand-over between drivers.
26*11d79c47SEmmanuel Vadot  *
27*11d79c47SEmmanuel Vadot  * Graphics drivers should call aperture_remove_conflicting_devices()
28*11d79c47SEmmanuel Vadot  * at the top of their probe function. The function removes any generic
29*11d79c47SEmmanuel Vadot  * driver that is currently associated with the given framebuffer memory.
30*11d79c47SEmmanuel Vadot  * An example for a graphics device on the platform bus is shown below.
31*11d79c47SEmmanuel Vadot  *
32*11d79c47SEmmanuel Vadot  * .. code-block:: c
33*11d79c47SEmmanuel Vadot  *
34*11d79c47SEmmanuel Vadot  *	static int example_probe(struct platform_device *pdev)
35*11d79c47SEmmanuel Vadot  *	{
36*11d79c47SEmmanuel Vadot  *		struct resource *mem;
37*11d79c47SEmmanuel Vadot  *		resource_size_t base, size;
38*11d79c47SEmmanuel Vadot  *		int ret;
39*11d79c47SEmmanuel Vadot  *
40*11d79c47SEmmanuel Vadot  *		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
41*11d79c47SEmmanuel Vadot  *		if (!mem)
42*11d79c47SEmmanuel Vadot  *			return -ENODEV;
43*11d79c47SEmmanuel Vadot  *		base = mem->start;
44*11d79c47SEmmanuel Vadot  *		size = resource_size(mem);
45*11d79c47SEmmanuel Vadot  *
46*11d79c47SEmmanuel Vadot  *		ret = aperture_remove_conflicting_devices(base, size, false, "example");
47*11d79c47SEmmanuel Vadot  *		if (ret)
48*11d79c47SEmmanuel Vadot  *			return ret;
49*11d79c47SEmmanuel Vadot  *
50*11d79c47SEmmanuel Vadot  *		// Initialize the hardware
51*11d79c47SEmmanuel Vadot  *		...
52*11d79c47SEmmanuel Vadot  *
53*11d79c47SEmmanuel Vadot  *		return 0;
54*11d79c47SEmmanuel Vadot  *	}
55*11d79c47SEmmanuel Vadot  *
56*11d79c47SEmmanuel Vadot  *	static const struct platform_driver example_driver = {
57*11d79c47SEmmanuel Vadot  *		.probe = example_probe,
58*11d79c47SEmmanuel Vadot  *		...
59*11d79c47SEmmanuel Vadot  *	};
60*11d79c47SEmmanuel Vadot  *
61*11d79c47SEmmanuel Vadot  * The given example reads the platform device's I/O-memory range from the
62*11d79c47SEmmanuel Vadot  * device instance. An active framebuffer will be located within this range.
63*11d79c47SEmmanuel Vadot  * The call to aperture_remove_conflicting_devices() releases drivers that
64*11d79c47SEmmanuel Vadot  * have previously claimed ownership of the range and are currently driving
65*11d79c47SEmmanuel Vadot  * output on the framebuffer. If successful, the new driver can take over
66*11d79c47SEmmanuel Vadot  * the device.
67*11d79c47SEmmanuel Vadot  *
68*11d79c47SEmmanuel Vadot  * While the given example uses a platform device, the aperture helpers work
69*11d79c47SEmmanuel Vadot  * with every bus that has an addressable framebuffer. In the case of PCI,
70*11d79c47SEmmanuel Vadot  * device drivers can also call aperture_remove_conflicting_pci_devices() and
71*11d79c47SEmmanuel Vadot  * let the function detect the apertures automatically. Device drivers without
72*11d79c47SEmmanuel Vadot  * knowledge of the framebuffer's location can call
73*11d79c47SEmmanuel Vadot  * aperture_remove_all_conflicting_devices(), which removes all known devices.
74*11d79c47SEmmanuel Vadot  *
75*11d79c47SEmmanuel Vadot  * Drivers that are susceptible to being removed by other drivers, such as
76*11d79c47SEmmanuel Vadot  * generic EFI or VESA drivers, have to register themselves as owners of their
77*11d79c47SEmmanuel Vadot  * framebuffer apertures. Ownership of the framebuffer memory is achieved
78*11d79c47SEmmanuel Vadot  * by calling devm_aperture_acquire_for_platform_device(). If successful, the
79*11d79c47SEmmanuel Vadot  * driveris the owner of the framebuffer range. The function fails if the
80*11d79c47SEmmanuel Vadot  * framebuffer is already owned by another driver. See below for an example.
81*11d79c47SEmmanuel Vadot  *
82*11d79c47SEmmanuel Vadot  * .. code-block:: c
83*11d79c47SEmmanuel Vadot  *
84*11d79c47SEmmanuel Vadot  *	static int generic_probe(struct platform_device *pdev)
85*11d79c47SEmmanuel Vadot  *	{
86*11d79c47SEmmanuel Vadot  *		struct resource *mem;
87*11d79c47SEmmanuel Vadot  *		resource_size_t base, size;
88*11d79c47SEmmanuel Vadot  *
89*11d79c47SEmmanuel Vadot  *		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
90*11d79c47SEmmanuel Vadot  *		if (!mem)
91*11d79c47SEmmanuel Vadot  *			return -ENODEV;
92*11d79c47SEmmanuel Vadot  *		base = mem->start;
93*11d79c47SEmmanuel Vadot  *		size = resource_size(mem);
94*11d79c47SEmmanuel Vadot  *
95*11d79c47SEmmanuel Vadot  *		ret = devm_aperture_acquire_for_platform_device(pdev, base, size);
96*11d79c47SEmmanuel Vadot  *		if (ret)
97*11d79c47SEmmanuel Vadot  *			return ret;
98*11d79c47SEmmanuel Vadot  *
99*11d79c47SEmmanuel Vadot  *		// Initialize the hardware
100*11d79c47SEmmanuel Vadot  *		...
101*11d79c47SEmmanuel Vadot  *
102*11d79c47SEmmanuel Vadot  *		return 0;
103*11d79c47SEmmanuel Vadot  *	}
104*11d79c47SEmmanuel Vadot  *
105*11d79c47SEmmanuel Vadot  *	static int generic_remove(struct platform_device *)
106*11d79c47SEmmanuel Vadot  *	{
107*11d79c47SEmmanuel Vadot  *		// Hot-unplug the device
108*11d79c47SEmmanuel Vadot  *		...
109*11d79c47SEmmanuel Vadot  *
110*11d79c47SEmmanuel Vadot  *		return 0;
111*11d79c47SEmmanuel Vadot  *	}
112*11d79c47SEmmanuel Vadot  *
113*11d79c47SEmmanuel Vadot  *	static const struct platform_driver generic_driver = {
114*11d79c47SEmmanuel Vadot  *		.probe = generic_probe,
115*11d79c47SEmmanuel Vadot  *		.remove = generic_remove,
116*11d79c47SEmmanuel Vadot  *		...
117*11d79c47SEmmanuel Vadot  *	};
118*11d79c47SEmmanuel Vadot  *
119*11d79c47SEmmanuel Vadot  * The similar to the previous example, the generic driver claims ownership
120*11d79c47SEmmanuel Vadot  * of the framebuffer memory from its probe function. This will fail if the
121*11d79c47SEmmanuel Vadot  * memory range, or parts of it, is already owned by another driver.
122*11d79c47SEmmanuel Vadot  *
123*11d79c47SEmmanuel Vadot  * If successful, the generic driver is now subject to forced removal by
124*11d79c47SEmmanuel Vadot  * another driver. This only works for platform drivers that support hot
125*11d79c47SEmmanuel Vadot  * unplugging. When a driver calls aperture_remove_conflicting_devices()
126*11d79c47SEmmanuel Vadot  * et al for the registered framebuffer range, the aperture helpers call
127*11d79c47SEmmanuel Vadot  * platform_device_unregister() and the generic driver unloads itself. The
128*11d79c47SEmmanuel Vadot  * generic driver also has to provide a remove function to make this work.
129*11d79c47SEmmanuel Vadot  * Once hot unplugged fro mhardware, it may not access the device's
130*11d79c47SEmmanuel Vadot  * registers, framebuffer memory, ROM, etc afterwards.
131*11d79c47SEmmanuel Vadot  */
132*11d79c47SEmmanuel Vadot 
133*11d79c47SEmmanuel Vadot struct aperture_range {
134*11d79c47SEmmanuel Vadot 	struct device *dev;
135*11d79c47SEmmanuel Vadot 	resource_size_t base;
136*11d79c47SEmmanuel Vadot 	resource_size_t size;
137*11d79c47SEmmanuel Vadot 	struct list_head lh;
138*11d79c47SEmmanuel Vadot 	void (*detach)(struct device *dev);
139*11d79c47SEmmanuel Vadot };
140*11d79c47SEmmanuel Vadot 
141*11d79c47SEmmanuel Vadot static LIST_HEAD(apertures);
142*11d79c47SEmmanuel Vadot static DEFINE_MUTEX(apertures_lock);
143*11d79c47SEmmanuel Vadot 
144*11d79c47SEmmanuel Vadot static bool overlap(resource_size_t base1, resource_size_t end1,
145*11d79c47SEmmanuel Vadot 		    resource_size_t base2, resource_size_t end2)
146*11d79c47SEmmanuel Vadot {
147*11d79c47SEmmanuel Vadot 	return (base1 < end2) && (end1 > base2);
148*11d79c47SEmmanuel Vadot }
149*11d79c47SEmmanuel Vadot 
150*11d79c47SEmmanuel Vadot static void devm_aperture_acquire_release(void *data)
151*11d79c47SEmmanuel Vadot {
152*11d79c47SEmmanuel Vadot 	struct aperture_range *ap = data;
153*11d79c47SEmmanuel Vadot 	bool detached = !ap->dev;
154*11d79c47SEmmanuel Vadot 
155*11d79c47SEmmanuel Vadot 	if (detached)
156*11d79c47SEmmanuel Vadot 		return;
157*11d79c47SEmmanuel Vadot 
158*11d79c47SEmmanuel Vadot 	mutex_lock(&apertures_lock);
159*11d79c47SEmmanuel Vadot 	list_del(&ap->lh);
160*11d79c47SEmmanuel Vadot 	mutex_unlock(&apertures_lock);
161*11d79c47SEmmanuel Vadot }
162*11d79c47SEmmanuel Vadot 
163*11d79c47SEmmanuel Vadot static int devm_aperture_acquire(struct device *dev,
164*11d79c47SEmmanuel Vadot 				 resource_size_t base, resource_size_t size,
165*11d79c47SEmmanuel Vadot 				 void (*detach)(struct device *))
166*11d79c47SEmmanuel Vadot {
167*11d79c47SEmmanuel Vadot 	size_t end = base + size;
168*11d79c47SEmmanuel Vadot 	struct list_head *pos;
169*11d79c47SEmmanuel Vadot 	struct aperture_range *ap;
170*11d79c47SEmmanuel Vadot 
171*11d79c47SEmmanuel Vadot 	mutex_lock(&apertures_lock);
172*11d79c47SEmmanuel Vadot 
173*11d79c47SEmmanuel Vadot 	list_for_each(pos, &apertures) {
174*11d79c47SEmmanuel Vadot 		ap = container_of(pos, struct aperture_range, lh);
175*11d79c47SEmmanuel Vadot 		if (overlap(base, end, ap->base, ap->base + ap->size)) {
176*11d79c47SEmmanuel Vadot 			mutex_unlock(&apertures_lock);
177*11d79c47SEmmanuel Vadot 			return -EBUSY;
178*11d79c47SEmmanuel Vadot 		}
179*11d79c47SEmmanuel Vadot 	}
180*11d79c47SEmmanuel Vadot 
181*11d79c47SEmmanuel Vadot 	ap = devm_kzalloc(dev, sizeof(*ap), GFP_KERNEL);
182*11d79c47SEmmanuel Vadot 	if (!ap) {
183*11d79c47SEmmanuel Vadot 		mutex_unlock(&apertures_lock);
184*11d79c47SEmmanuel Vadot 		return -ENOMEM;
185*11d79c47SEmmanuel Vadot 	}
186*11d79c47SEmmanuel Vadot 
187*11d79c47SEmmanuel Vadot 	ap->dev = dev;
188*11d79c47SEmmanuel Vadot 	ap->base = base;
189*11d79c47SEmmanuel Vadot 	ap->size = size;
190*11d79c47SEmmanuel Vadot 	ap->detach = detach;
191*11d79c47SEmmanuel Vadot 	INIT_LIST_HEAD(&ap->lh);
192*11d79c47SEmmanuel Vadot 
193*11d79c47SEmmanuel Vadot 	list_add(&ap->lh, &apertures);
194*11d79c47SEmmanuel Vadot 
195*11d79c47SEmmanuel Vadot 	mutex_unlock(&apertures_lock);
196*11d79c47SEmmanuel Vadot 
197*11d79c47SEmmanuel Vadot 	return devm_add_action_or_reset(dev, devm_aperture_acquire_release, ap);
198*11d79c47SEmmanuel Vadot }
199*11d79c47SEmmanuel Vadot 
200*11d79c47SEmmanuel Vadot static void aperture_detach_platform_device(struct device *dev)
201*11d79c47SEmmanuel Vadot {
202*11d79c47SEmmanuel Vadot 	struct platform_device *pdev = to_platform_device(dev);
203*11d79c47SEmmanuel Vadot 
204*11d79c47SEmmanuel Vadot 	/*
205*11d79c47SEmmanuel Vadot 	 * Remove the device from the device hierarchy. This is the right thing
206*11d79c47SEmmanuel Vadot 	 * to do for firmware-based DRM drivers, such as EFI, VESA or VGA. After
207*11d79c47SEmmanuel Vadot 	 * the new driver takes over the hardware, the firmware device's state
208*11d79c47SEmmanuel Vadot 	 * will be lost.
209*11d79c47SEmmanuel Vadot 	 *
210*11d79c47SEmmanuel Vadot 	 * For non-platform devices, a new callback would be required.
211*11d79c47SEmmanuel Vadot 	 *
212*11d79c47SEmmanuel Vadot 	 * If the aperture helpers ever need to handle native drivers, this call
213*11d79c47SEmmanuel Vadot 	 * would only have to unplug the DRM device, so that the hardware device
214*11d79c47SEmmanuel Vadot 	 * stays around after detachment.
215*11d79c47SEmmanuel Vadot 	 */
216*11d79c47SEmmanuel Vadot 	platform_device_unregister(pdev);
217*11d79c47SEmmanuel Vadot }
218*11d79c47SEmmanuel Vadot 
219*11d79c47SEmmanuel Vadot /**
220*11d79c47SEmmanuel Vadot  * devm_aperture_acquire_for_platform_device - Acquires ownership of an aperture
221*11d79c47SEmmanuel Vadot  *                                             on behalf of a platform device.
222*11d79c47SEmmanuel Vadot  * @pdev:	the platform device to own the aperture
223*11d79c47SEmmanuel Vadot  * @base:	the aperture's byte offset in physical memory
224*11d79c47SEmmanuel Vadot  * @size:	the aperture size in bytes
225*11d79c47SEmmanuel Vadot  *
226*11d79c47SEmmanuel Vadot  * Installs the given device as the new owner of the aperture. The function
227*11d79c47SEmmanuel Vadot  * expects the aperture to be provided by a platform device. If another
228*11d79c47SEmmanuel Vadot  * driver takes over ownership of the aperture, aperture helpers will then
229*11d79c47SEmmanuel Vadot  * unregister the platform device automatically. All acquired apertures are
230*11d79c47SEmmanuel Vadot  * released automatically when the underlying device goes away.
231*11d79c47SEmmanuel Vadot  *
232*11d79c47SEmmanuel Vadot  * The function fails if the aperture, or parts of it, is currently
233*11d79c47SEmmanuel Vadot  * owned by another device. To evict current owners, callers should use
234*11d79c47SEmmanuel Vadot  * remove_conflicting_devices() et al. before calling this function.
235*11d79c47SEmmanuel Vadot  *
236*11d79c47SEmmanuel Vadot  * Returns:
237*11d79c47SEmmanuel Vadot  * 0 on success, or a negative errno value otherwise.
238*11d79c47SEmmanuel Vadot  */
239*11d79c47SEmmanuel Vadot int devm_aperture_acquire_for_platform_device(struct platform_device *pdev,
240*11d79c47SEmmanuel Vadot 					      resource_size_t base,
241*11d79c47SEmmanuel Vadot 					      resource_size_t size)
242*11d79c47SEmmanuel Vadot {
243*11d79c47SEmmanuel Vadot 	return devm_aperture_acquire(&pdev->dev, base, size, aperture_detach_platform_device);
244*11d79c47SEmmanuel Vadot }
245*11d79c47SEmmanuel Vadot EXPORT_SYMBOL(devm_aperture_acquire_for_platform_device);
246*11d79c47SEmmanuel Vadot 
247*11d79c47SEmmanuel Vadot static void aperture_detach_devices(resource_size_t base, resource_size_t size)
248*11d79c47SEmmanuel Vadot {
249*11d79c47SEmmanuel Vadot 	resource_size_t end = base + size;
250*11d79c47SEmmanuel Vadot 	struct list_head *pos, *n;
251*11d79c47SEmmanuel Vadot 
252*11d79c47SEmmanuel Vadot 	mutex_lock(&apertures_lock);
253*11d79c47SEmmanuel Vadot 
254*11d79c47SEmmanuel Vadot 	list_for_each_safe(pos, n, &apertures) {
255*11d79c47SEmmanuel Vadot 		struct aperture_range *ap = container_of(pos, struct aperture_range, lh);
256*11d79c47SEmmanuel Vadot 		struct device *dev = ap->dev;
257*11d79c47SEmmanuel Vadot 
258*11d79c47SEmmanuel Vadot 		if (WARN_ON_ONCE(!dev))
259*11d79c47SEmmanuel Vadot 			continue;
260*11d79c47SEmmanuel Vadot 
261*11d79c47SEmmanuel Vadot 		if (!overlap(base, end, ap->base, ap->base + ap->size))
262*11d79c47SEmmanuel Vadot 			continue;
263*11d79c47SEmmanuel Vadot 
264*11d79c47SEmmanuel Vadot 		ap->dev = NULL; /* detach from device */
265*11d79c47SEmmanuel Vadot 		list_del(&ap->lh);
266*11d79c47SEmmanuel Vadot 
267*11d79c47SEmmanuel Vadot 		ap->detach(dev);
268*11d79c47SEmmanuel Vadot 	}
269*11d79c47SEmmanuel Vadot 
270*11d79c47SEmmanuel Vadot 	mutex_unlock(&apertures_lock);
271*11d79c47SEmmanuel Vadot }
272*11d79c47SEmmanuel Vadot 
273*11d79c47SEmmanuel Vadot /**
274*11d79c47SEmmanuel Vadot  * aperture_remove_conflicting_devices - remove devices in the given range
275*11d79c47SEmmanuel Vadot  * @base: the aperture's base address in physical memory
276*11d79c47SEmmanuel Vadot  * @size: aperture size in bytes
277*11d79c47SEmmanuel Vadot  * @primary: also kick vga16fb if present; only relevant for VGA devices
278*11d79c47SEmmanuel Vadot  * @name: a descriptive name of the requesting driver
279*11d79c47SEmmanuel Vadot  *
280*11d79c47SEmmanuel Vadot  * This function removes devices that own apertures within @base and @size.
281*11d79c47SEmmanuel Vadot  *
282*11d79c47SEmmanuel Vadot  * Returns:
283*11d79c47SEmmanuel Vadot  * 0 on success, or a negative errno code otherwise
284*11d79c47SEmmanuel Vadot  */
285*11d79c47SEmmanuel Vadot int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size,
286*11d79c47SEmmanuel Vadot 					bool primary, const char *name)
287*11d79c47SEmmanuel Vadot {
288*11d79c47SEmmanuel Vadot 	/*
289*11d79c47SEmmanuel Vadot 	 * If a driver asked to unregister a platform device registered by
290*11d79c47SEmmanuel Vadot 	 * sysfb, then can be assumed that this is a driver for a display
291*11d79c47SEmmanuel Vadot 	 * that is set up by the system firmware and has a generic driver.
292*11d79c47SEmmanuel Vadot 	 *
293*11d79c47SEmmanuel Vadot 	 * Drivers for devices that don't have a generic driver will never
294*11d79c47SEmmanuel Vadot 	 * ask for this, so let's assume that a real driver for the display
295*11d79c47SEmmanuel Vadot 	 * was already probed and prevent sysfb to register devices later.
296*11d79c47SEmmanuel Vadot 	 */
297*11d79c47SEmmanuel Vadot #ifdef __linux__
298*11d79c47SEmmanuel Vadot 	sysfb_disable();
299*11d79c47SEmmanuel Vadot #endif
300*11d79c47SEmmanuel Vadot 
301*11d79c47SEmmanuel Vadot 	aperture_detach_devices(base, size);
302*11d79c47SEmmanuel Vadot 
303*11d79c47SEmmanuel Vadot 	/*
304*11d79c47SEmmanuel Vadot 	 * If this is the primary adapter, there could be a VGA device
305*11d79c47SEmmanuel Vadot 	 * that consumes the VGA framebuffer I/O range. Remove this device
306*11d79c47SEmmanuel Vadot 	 * as well.
307*11d79c47SEmmanuel Vadot 	 */
308*11d79c47SEmmanuel Vadot 	if (primary)
309*11d79c47SEmmanuel Vadot 		aperture_detach_devices(VGA_FB_PHYS_BASE, VGA_FB_PHYS_SIZE);
310*11d79c47SEmmanuel Vadot 
311*11d79c47SEmmanuel Vadot 	return 0;
312*11d79c47SEmmanuel Vadot }
313*11d79c47SEmmanuel Vadot EXPORT_SYMBOL(aperture_remove_conflicting_devices);
314*11d79c47SEmmanuel Vadot 
315*11d79c47SEmmanuel Vadot /**
316*11d79c47SEmmanuel Vadot  * aperture_remove_conflicting_pci_devices - remove existing framebuffers for PCI devices
317*11d79c47SEmmanuel Vadot  * @pdev: PCI device
318*11d79c47SEmmanuel Vadot  * @name: a descriptive name of the requesting driver
319*11d79c47SEmmanuel Vadot  *
320*11d79c47SEmmanuel Vadot  * This function removes devices that own apertures within any of @pdev's
321*11d79c47SEmmanuel Vadot  * memory bars. The function assumes that PCI device with shadowed ROM
322*11d79c47SEmmanuel Vadot  * drives a primary display and therefore kicks out vga16fb as well.
323*11d79c47SEmmanuel Vadot  *
324*11d79c47SEmmanuel Vadot  * Returns:
325*11d79c47SEmmanuel Vadot  * 0 on success, or a negative errno code otherwise
326*11d79c47SEmmanuel Vadot  */
327*11d79c47SEmmanuel Vadot int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *name)
328*11d79c47SEmmanuel Vadot {
329*11d79c47SEmmanuel Vadot 	bool primary = false;
330*11d79c47SEmmanuel Vadot 	resource_size_t base, size;
331*11d79c47SEmmanuel Vadot 	int bar, ret;
332*11d79c47SEmmanuel Vadot 
333*11d79c47SEmmanuel Vadot #ifdef CONFIG_X86
334*11d79c47SEmmanuel Vadot #ifdef __linux__
335*11d79c47SEmmanuel Vadot 	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
336*11d79c47SEmmanuel Vadot #elif defined(__FreeBSD__)
337*11d79c47SEmmanuel Vadot 	primary = NULL;
338*11d79c47SEmmanuel Vadot #endif
339*11d79c47SEmmanuel Vadot #endif
340*11d79c47SEmmanuel Vadot 
341*11d79c47SEmmanuel Vadot 	for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) {
342*11d79c47SEmmanuel Vadot 		if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
343*11d79c47SEmmanuel Vadot 			continue;
344*11d79c47SEmmanuel Vadot 
345*11d79c47SEmmanuel Vadot 		base = pci_resource_start(pdev, bar);
346*11d79c47SEmmanuel Vadot 		size = pci_resource_len(pdev, bar);
347*11d79c47SEmmanuel Vadot 		ret = aperture_remove_conflicting_devices(base, size, primary, name);
348*11d79c47SEmmanuel Vadot 		if (ret)
349*11d79c47SEmmanuel Vadot 			return ret;
350*11d79c47SEmmanuel Vadot 	}
351*11d79c47SEmmanuel Vadot 
352*11d79c47SEmmanuel Vadot 	/*
353*11d79c47SEmmanuel Vadot 	 * WARNING: Apparently we must kick fbdev drivers before vgacon,
354*11d79c47SEmmanuel Vadot 	 * otherwise the vga fbdev driver falls over.
355*11d79c47SEmmanuel Vadot 	 */
356*11d79c47SEmmanuel Vadot #ifdef __linux__
357*11d79c47SEmmanuel Vadot 	ret = vga_remove_vgacon(pdev);
358*11d79c47SEmmanuel Vadot 	if (ret)
359*11d79c47SEmmanuel Vadot 		return ret;
360*11d79c47SEmmanuel Vadot #endif
361*11d79c47SEmmanuel Vadot 
362*11d79c47SEmmanuel Vadot 	return 0;
363*11d79c47SEmmanuel Vadot 
364*11d79c47SEmmanuel Vadot }
365*11d79c47SEmmanuel Vadot EXPORT_SYMBOL(aperture_remove_conflicting_pci_devices);
366