Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit deb2d2ec authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Jesse Barnes
Browse files

PCI/GPU: implement VGA arbitration on Linux



Background:
Graphic devices are accessed through ranges in I/O or memory space. While most
modern devices allow relocation of such ranges, some "Legacy" VGA devices
implemented on PCI will typically have the same "hard-decoded" addresses as
they did on ISA. For more details see "PCI Bus Binding to IEEE Std 1275-1994
Standard for Boot (Initialization Configuration) Firmware Revision 2.1"
Section 7, Legacy Devices.

The Resource Access Control (RAC) module inside the X server currently does
the task of arbitration when more than one legacy device co-exists on the same
machine. But the problem happens when these devices are trying to be accessed
by different userspace clients (e.g. two server in parallel). Their address
assignments conflict. Therefore an arbitration scheme _outside_ of the X
server is needed to control the sharing of these resources. This document
introduces the operation of the VGA arbiter implemented for Linux kernel.

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarTiago Vignatti <tiago.vignatti@nokia.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 500559a9
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
obj-y			+= drm/
obj-y			+= drm/ vga/
+10 −0
Original line number Original line Diff line number Diff line
config VGA_ARB
	bool "VGA Arbitration" if EMBEDDED
	default y
	depends on PCI
	help
	  Some "legacy" VGA devices implemented on PCI typically have the same
	  hard-decoded addresses as they did on ISA. When multiple PCI devices
	  are accessed at same time they need some kind of coordination. Please
	  see Documentation/vgaarbiter.txt for more details. Select this to
	  enable VGA arbiter.
+1 −0
Original line number Original line Diff line number Diff line
obj-$(CONFIG_VGA_ARB)  += vgaarb.o
+1206 −0

File added.

Preview size limit exceeded, changes collapsed.

+44 −0
Original line number Original line Diff line number Diff line
@@ -2520,6 +2520,50 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
	return 0;
	return 0;
}
}


/**
 * pci_set_vga_state - set VGA decode state on device and parents if requested
 * @dev the PCI device
 * @decode - true = enable decoding, false = disable decoding
 * @command_bits PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
 * @change_bridge - traverse ancestors and change bridges
 */
int pci_set_vga_state(struct pci_dev *dev, bool decode,
		      unsigned int command_bits, bool change_bridge)
{
	struct pci_bus *bus;
	struct pci_dev *bridge;
	u16 cmd;

	WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));

	pci_read_config_word(dev, PCI_COMMAND, &cmd);
	if (decode == true)
		cmd |= command_bits;
	else
		cmd &= ~command_bits;
	pci_write_config_word(dev, PCI_COMMAND, cmd);

	if (change_bridge == false)
		return 0;

	bus = dev->bus;
	while (bus) {
		bridge = bus->self;
		if (bridge) {
			pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
					     &cmd);
			if (decode == true)
				cmd |= PCI_BRIDGE_CTL_VGA;
			else
				cmd &= ~PCI_BRIDGE_CTL_VGA;
			pci_write_config_word(bridge, PCI_BRIDGE_CONTROL,
					      cmd);
		}
		bus = bus->parent;
	}
	return 0;
}

#define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE
#define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE
static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0};
static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0};
spinlock_t resource_alignment_lock = SPIN_LOCK_UNLOCKED;
spinlock_t resource_alignment_lock = SPIN_LOCK_UNLOCKED;
Loading