Module Name:    xsrc
Committed By:   macallan
Date:           Thu Jul  9 19:27:08 UTC 2009

Modified Files:
        xsrc/external/mit/libpciaccess/dist/src: netbsd_pci.c

Log Message:
teack libpciaccess how to discover and map PCI devices on machines with
more than one host bridge. While there get rid of some local (re)defines
if PCI-related constants.
With this Xorg should be able to use any PCI graphics device, no matter
if it's console or not.
TODO:
- cleanup
- deal with IO spaces
- fix Xorg -configure


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 xsrc/external/mit/libpciaccess/dist/src/netbsd_pci.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: xsrc/external/mit/libpciaccess/dist/src/netbsd_pci.c
diff -u xsrc/external/mit/libpciaccess/dist/src/netbsd_pci.c:1.3 xsrc/external/mit/libpciaccess/dist/src/netbsd_pci.c:1.4
--- xsrc/external/mit/libpciaccess/dist/src/netbsd_pci.c:1.3	Fri Jul  3 21:03:50 2009
+++ xsrc/external/mit/libpciaccess/dist/src/netbsd_pci.c	Thu Jul  9 19:27:08 2009
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2008 Juan Romero Pardines
  * Copyright (c) 2008 Mark Kettenis
+ * Copyright (c) 2009 Michael Lorenz
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -43,22 +44,50 @@
 #include "pciaccess.h"
 #include "pciaccess_private.h"
 
-#define PCIR_COMMAND    0x04
-#define PCIM_CMD_PORTEN         0x0001
-#define PCIM_CMD_MEMEN          0x0002
-#define PCIR_BIOS	0x30
-#define PCIM_BIOS_ENABLE	0x01
-#define PCIM_BIOS_ADDR_MASK	0xfffff800
-
-static int pcifd;
+typedef struct _pcibus {
+	int fd;		/* /dev/pci* */
+	int num;	/* bus number */
+	int maxdevs;	/* maximum number of devices */
+} PciBus;
+
+static PciBus buses[32];	/* indexed by pci_device.domain */
+static int nbuses = 0;		/* number of buses found */
+
+/*
+ * NetBSD's userland has a /dev/pci* entry for each bus but userland has no way
+ * to tell if a bus is a subordinate of another one or if it's on a different
+ * host bridge. On some architectures ( macppc for example ) all root buses have
+ * bus number 0 but on sparc64 for example the two roots in an Ultra60 have
+ * different bus numbers - one is 0 and the other 128.
+ * With each /dev/pci* we can map everything on the same root and we can also
+ * see all devices on the same root, trying to do that causes problems though:
+ * - since we can't tell which /dev/pci* is a subordinate we would find some
+ *   devices more than once
+ * - we would have to guess subordinate bus numbers which is a waste of time
+ *   since we can ask each /dev/pci* for its bus number so we can scan only the
+ *   buses we know exist, not all 256 which may exist in each domain.
+ * - some bus_space_mmap() methods may limit mappings to address ranges which
+ *   belong to known devices on that bus only.
+ * Each host bridge may or may not have its own IO range, to avoid guesswork
+ * here each /dev/pci* will let userland map its appropriate IO range at
+ * PCI_MAGIC_IO_RANGE if defined in <machine/param.h>
+ * With all this we should be able to use any PCI graphics device on any PCI
+ * bus on any architecture as long as Xorg has a driver, without allowing
+ * arbitrary mappings via /dev/mem and without userland having to know or care
+ * about translating bus addresses to physical addresses or the other way 
+ * around.
+ */
 
 static int
-pci_read(int bus, int dev, int func, uint32_t reg, uint32_t *val)
+pci_read(int domain, int bus, int dev, int func, uint32_t reg, uint32_t *val)
 {
 	uint32_t rval;
 
-	if (pcibus_conf_read(pcifd, (unsigned int)bus, (unsigned int)dev,
-	    (unsigned int)func, reg, &rval) == -1)
+	if ((domain < 0) || (domain > nbuses))
+		return -1;
+
+	if (pcibus_conf_read(buses[domain].fd, (unsigned int)bus,
+	    (unsigned int)dev, (unsigned int)func, reg, &rval) == -1)
 		return (-1);
 
 	*val = rval;
@@ -67,18 +96,25 @@
 }
 
 static int
-pci_write(int bus, int dev, int func, uint32_t reg, uint32_t val)
+pci_write(int domain, int bus, int dev, int func, uint32_t reg, uint32_t val)
 {
-	return pcibus_conf_write(pcifd, (unsigned int)bus, (unsigned int)dev,
-	    (unsigned int)func, reg, val);
+
+	if ((domain < 0) || (domain > nbuses))
+		return -1;
+
+	return pcibus_conf_write(buses[domain].fd, (unsigned int)bus,
+	    (unsigned int)dev, (unsigned int)func, reg, val);
 }
 
 static int
-pci_nfuncs(int bus, int dev)
+pci_nfuncs(int domain, int bus, int dev)
 {
 	uint32_t hdr;
 
-	if (pci_read(bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
+	if ((domain < 0) || (domain > nbuses))
+		return -1;
+
+	if (pci_read(domain, bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
 		return -1;
 
 	return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
@@ -93,18 +129,14 @@
 	struct mtrr m;
 	int n = 1;
 #endif
-	int prot, fd, ret = 0;
+	int prot, ret = 0;
 
 	prot = PROT_READ;
 
 	if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
 		prot |= PROT_WRITE;
-
-	fd = open("/dev/mem", O_RDWR);
-	if (fd == -1)
-		return errno;
-	map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd,
-	    (off_t)map->base);
+	map->memory = mmap(NULL, map->size, prot, MAP_SHARED,
+	    buses[dev->domain].fd, (off_t)map->base);
 	if (map->memory == MAP_FAILED)
 		return errno;
 
@@ -128,8 +160,6 @@
 	}
 #endif
 
-	close(fd);
-
 	return ret;
 }
 
@@ -168,9 +198,9 @@
 
 		reg = (u_int)(offset & ~0x3);
 
-		if ((pcibus_conf_read(pcifd, (unsigned int)dev->bus,
-		    (unsigned int)dev->dev, (unsigned int)dev->func,
-		    reg, &rval)) == -1)
+		if ((pcibus_conf_read(buses[dev->domain].fd,
+		    (unsigned int)dev->bus, (unsigned int)dev->dev,
+		    (unsigned int)dev->func, reg, &rval)) == -1)
 			return errno;
 
 		rval = htole32(rval);
@@ -201,9 +231,9 @@
 		reg = (u_int)offset;
 		memcpy(&val, data, 4);
 
-		if ((pcibus_conf_write(pcifd, (unsigned int)dev->bus,
-		    (unsigned int)dev->dev, (unsigned int)dev->func,
-		   reg, val)) == -1)
+		if ((pcibus_conf_write(buses[dev->domain].fd,
+		    (unsigned int)dev->bus, (unsigned int)dev->dev,
+		    (unsigned int)dev->func, reg, val)) == -1)
 			return errno;
 
 		offset += 4;
@@ -218,7 +248,11 @@
 static void
 pci_system_netbsd_destroy(void)
 {
-	close(pcifd);
+	int i;
+
+	for (i = 0; i < nbuses; i++) {
+		close(buses[i].fd);
+	}
 	free(pci_sys);
 	pci_sys = NULL;
 }
@@ -231,13 +265,14 @@
 	struct pci_mem_region *region;
 	uint64_t reg64, size64;
 	uint32_t bar, reg, size;
-	int bus, dev, func, err;
+	int bus, dev, func, err, domain;
 
+	domain = device->domain;
 	bus = device->bus;
 	dev = device->dev;
 	func = device->func;
 
-	err = pci_read(bus, dev, func, PCI_BHLC_REG, &reg);
+	err = pci_read(domain, bus, dev, func, PCI_BHLC_REG, &reg);
 	if (err)
 		return err;
 
@@ -248,16 +283,16 @@
 	region = device->regions;
 	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
 	     bar += sizeof(uint32_t), region++) {
-		err = pci_read(bus, dev, func, bar, &reg);
+		err = pci_read(domain, bus, dev, func, bar, &reg);
 		if (err)
 			return err;
 
 		/* Probe the size of the region. */
-		err = pci_write(bus, dev, func, bar, (unsigned int)~0);
+		err = pci_write(domain, bus, dev, func, bar, (unsigned int)~0);
 		if (err)
 			return err;
-		pci_read(bus, dev, func, bar, &size);
-		pci_write(bus, dev, func, bar, reg);
+		pci_read(domain, bus, dev, func, bar, &size);
+		pci_write(domain, bus, dev, func, bar, reg);
 
 		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
 			region->is_IO = 1;
@@ -280,17 +315,17 @@
 
 				bar += sizeof(uint32_t);
 
-				err = pci_read(bus, dev, func, bar, &reg);
+				err = pci_read(domain, bus, dev, func, bar, &reg);
 				if (err)
 					return err;
 				reg64 |= (uint64_t)reg << 32;
 
-				err = pci_write(bus, dev, func, bar,
+				err = pci_write(domain, bus, dev, func, bar,
 				    (unsigned int)~0);
 				if (err)
 					return err;
-				pci_read(bus, dev, func, bar, &size);
-				pci_write(bus, dev, func, bar,
+				pci_read(domain, bus, dev, func, bar, &size);
+				pci_write(domain, bus, dev, func, bar,
 				    (unsigned int)(reg64 >> 32));
 				size64 |= (uint64_t)size << 32;
 
@@ -339,24 +374,26 @@
 	rom_base = priv->rom_base;
 	rom_size = dev->rom_size;
 	pci_rom = 1;
-	if ((pcibus_conf_read(pcifd, (unsigned int)dev->bus,
+	if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus,
 	    (unsigned int)dev->dev, (unsigned int)dev->func,
-	    PCIR_COMMAND, &command_val)) == -1)
+	    PCI_COMMAND_STATUS_REG, &command_val)) == -1)
 	    return errno;
-	if ((command_val & PCIM_CMD_MEMEN) == 0) {
-	    if ((pcibus_conf_write(pcifd, (unsigned int)dev->bus,
-		(unsigned int)dev->dev, (unsigned int)dev->func,
-		PCIR_COMMAND, command_val | PCIM_CMD_MEMEN)) == -1)
+	if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) {
+	    if ((pcibus_conf_write(buses[dev->domain].fd,
+	        (unsigned int)dev->bus, (unsigned int)dev->dev,
+		(unsigned int)dev->func, PCI_COMMAND_STATUS_REG,
+		command_val | PCI_COMMAND_MEM_ENABLE)) == -1)
 		return errno;
 	}
-	if ((pcibus_conf_read(pcifd, (unsigned int)dev->bus,
+	if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus,
 	    (unsigned int)dev->dev, (unsigned int)dev->func,
-	    PCIR_BIOS, &bios_val)) == -1)
+	    PCI_MAPREG_ROM, &bios_val)) == -1)
 	    return errno;
-	if ((bios_val & PCIM_BIOS_ENABLE) == 0) {
-	    if ((pcibus_conf_write(pcifd, (unsigned int)dev->bus,
+	if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) {
+	    if ((pcibus_conf_write(buses[dev->domain].fd,
+	        (unsigned int)dev->bus,
 		(unsigned int)dev->dev, (unsigned int)dev->func,
-		PCIR_BIOS, bios_val | PCIM_BIOS_ENABLE)) == -1)
+		PCI_MAPREG_ROM, bios_val | PCI_MAPREG_ROM_ENABLE)) == -1)
 		return errno;
 	}
     }
@@ -380,16 +417,18 @@
     close(memfd);
 
     if (pci_rom) {
-	if ((command_val & PCIM_CMD_MEMEN) == 0) {
-	    if ((pcibus_conf_write(pcifd, (unsigned int)dev->bus,
+	if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) {
+	    if ((pcibus_conf_write(buses[dev->domain].fd,
+	        (unsigned int)dev->bus,
 		(unsigned int)dev->dev, (unsigned int)dev->func,
-		PCIR_COMMAND, command_val)) == -1)
+		PCI_COMMAND_STATUS_REG, command_val)) == -1)
 		return errno;
 	}
-	if ((bios_val & PCIM_BIOS_ENABLE) == 0) {
-	    if ((pcibus_conf_write(pcifd, (unsigned int)dev->bus,
+	if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) {
+	    if ((pcibus_conf_write(buses[dev->domain].fd,
+	        (unsigned int)dev->bus,
 		(unsigned int)dev->dev, (unsigned int)dev->func,
-		PCIR_BIOS, bios_val)) == -1)
+		PCI_MAPREG_ROM, bios_val)) == -1)
 		return errno;
 	}
     }
@@ -413,27 +452,30 @@
 pci_system_netbsd_create(void)
 {
 	struct pci_device_private *device;
-	int bus, dev, func, ndevs, nfuncs;
+	int bus, dev, func, ndevs, nfuncs, domain, pcifd;
 	uint32_t reg;
-
-	pcifd = open("/dev/pci0", O_RDWR);
-	if (pcifd == -1)
-		return ENXIO;
+	char devname[32];
+	struct pciio_businfo businfo;
 
 	pci_sys = calloc(1, sizeof(struct pci_system));
-	if (pci_sys == NULL) {
-		close(pcifd);
-		return ENOMEM;
-	}
 
 	pci_sys->methods = &netbsd_pci_methods;
 
 	ndevs = 0;
-	for (bus = 0; bus < 256; bus++) {
-		for (dev = 0; dev < 32; dev++) {
-			nfuncs = pci_nfuncs(bus, dev);
+	nbuses = 0;
+	snprintf(devname, 32, "/dev/pci%d", nbuses);
+	pcifd = open(devname, O_RDWR);
+	while (pcifd > 0) {
+		ioctl(pcifd, PCI_IOC_BUSINFO, &businfo);
+		buses[nbuses].fd = pcifd;
+		buses[nbuses].num = bus = businfo.busno;
+		buses[nbuses].maxdevs = businfo.maxdevs;
+		domain = nbuses;
+		nbuses++;
+		for (dev = 0; dev < businfo.maxdevs; dev++) {
+			nfuncs = pci_nfuncs(domain, bus, dev);
 			for (func = 0; func < nfuncs; func++) {
-				if (pci_read(bus, dev, func, PCI_ID_REG,
+				if (pci_read(domain, bus, dev, func, PCI_ID_REG,
 				    &reg) != 0)
 					continue;
 				if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
@@ -443,37 +485,43 @@
 				ndevs++;
 			}
 		}
+		snprintf(devname, 32, "/dev/pci%d", nbuses);
+		pcifd = open(devname, O_RDWR);
 	}
 
 	pci_sys->num_devices = ndevs;
 	pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
 	if (pci_sys->devices == NULL) {
+		int i;
+
+		for (i = 0; i < nbuses; i++)
+			close(buses[i].fd);
 		free(pci_sys);
-		close(pcifd);
 		return ENOMEM;
 	}
 
 	device = pci_sys->devices;
-	for (bus = 0; bus < 256; bus++) {
-		for (dev = 0; dev < 32; dev++) {
-			nfuncs = pci_nfuncs(bus, dev);
+	for (domain = 0; domain < nbuses; domain++) {
+		bus = buses[domain].num;
+		for (dev = 0; dev < buses[domain].maxdevs; dev++) {
+			nfuncs = pci_nfuncs(domain, bus, dev);
 			for (func = 0; func < nfuncs; func++) {
-				if (pci_read(bus, dev, func, PCI_ID_REG,
-				    &reg) != 0)
+				if (pci_read(domain, bus, dev, func,
+				    PCI_ID_REG, &reg) != 0)
 					continue;
 				if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
 				    PCI_VENDOR(reg) == 0)
 					continue;
 
-				device->base.domain = 0;
+				device->base.domain = domain;
 				device->base.bus = bus;
 				device->base.dev = dev;
 				device->base.func = func;
 				device->base.vendor_id = PCI_VENDOR(reg);
 				device->base.device_id = PCI_PRODUCT(reg);
 
-				if (pci_read(bus, dev, func, PCI_CLASS_REG,
-				    &reg) != 0)
+				if (pci_read(domain, bus, dev, func,
+				    PCI_CLASS_REG, &reg) != 0)
 					continue;
 
 				device->base.device_class =
@@ -481,8 +529,8 @@
 				    PCI_SUBCLASS(reg) << 8;
 				device->base.revision = PCI_REVISION(reg);
 
-				if (pci_read(bus, dev, func, PCI_SUBSYS_ID_REG,
-				    &reg) != 0)
+				if (pci_read(domain, bus, dev, func,
+				    PCI_SUBSYS_ID_REG, &reg) != 0)
 					continue;
 
 				device->base.subvendor_id = PCI_VENDOR(reg);

Reply via email to