[PATCH] OpenBSD support for libpciaccess

Eric Anholt eric at anholt.net
Wed Mar 12 13:20:38 PDT 2008


On Tue, 2008-03-11 at 22:30 +0100, Mark Kettenis wrote:
> Here are the OpenBSD-specific bits for libpciaccess.  As discussed
> earlier on this list, there is a bit of a problem with xserver and
> libpciaccess both needing to open /dev/xf86, which can only be opened
> once.  I implemented pci_system_init_dev_mem() like Ian suggested.
> This requires some minor changes to the BSD-specific os-support code.
> Since pci_system_init_dev_mem() is a no-op on FreeBSD this should be
> no problem.  Here are the xserver bits (the libpciaccess bits folow
> below).
> 
> 
> diff --git a/hw/xfree86/os-support/bsd/i386_video.c b/hw/xfree86/os-support/bsd/i386_video.c
> index 0dcff66..7e4a4d2 100644
> --- a/hw/xfree86/os-support/bsd/i386_video.c
> +++ b/hw/xfree86/os-support/bsd/i386_video.c
> @@ -212,6 +212,9 @@ xf86OSInitVidMem(VidMemInfoPtr pVidMem)
>  	pVidMem->mapMem = mapVidMem;
>  	pVidMem->unmapMem = unmapVidMem;
>  
> +	if (useDevMem)
> +		pci_system_init_dev_mem(devMemFd);
> +

The changeset looks great, though I'd like to slip this hunk under
#ifdef __OpenBSD__ or a version check so that non-OpenBSD doesn't have
to catch up to libpciaccess from git to build.

>  #ifdef HAS_MTRR_SUPPORT
>  	if (useDevMem) {
>  		if (cleanMTRR()) {
> diff --git a/hw/xfree86/os-support/bus/bsd_pci.c b/hw/xfree86/os-support/bus/bsd_pci.c
> index bceb108..57ad09b 100644
> --- a/hw/xfree86/os-support/bus/bsd_pci.c
> +++ b/hw/xfree86/os-support/bus/bsd_pci.c
> @@ -81,4 +81,6 @@ bsdPciInit(void)
>  {
>      pciNumBuses = 1;
>      pciBusInfo[0] = &bsd_pci;
> +
> +    xf86InitVidMem();
>  }
> diff --git a/hw/xfree86/utils/ioport/Makefile.am b/hw/xfree86/utils/ioport/Makefile.am
> index c1f9453..12f8613 100644
> --- a/hw/xfree86/utils/ioport/Makefile.am
> +++ b/hw/xfree86/utils/ioport/Makefile.am
> @@ -37,7 +37,7 @@ ioport_CFLAGS = $(DIX_CFLAGS) $(XORG_CFLAGS)
>  ioport_LDADD = \
>  	../../os-support/libxorgos.la \
>  	../../dummylib/libdummy-nonserver.a \
> -	${UTILS_SYS_LIBS}
> +	${UTILS_SYS_LIBS} ${PCIACCESS_LIBS}
>  
> 
>  ioport_SOURCES =	\
> 
> 
> 
> Here are the libpciaccess bits.  OpenBSD needs <sys/types.h to be
> included before <sys/mman.h>.  This should be no problem on any
> POSIX-like system.  Also, the endian-ness conversion macros on OpenBSD
> are different than on FreeBSD.
> 
> 
> diff --git a/configure.ac b/configure.ac
> index 8f4e55d..6163577 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -77,6 +77,9 @@ case $host_os in
>  	*linux*)
>  		linux=yes
>  		;;
> +	*openbsd*)
> +		openbsd=yes
> +		;;
>  	*solaris*)
>  		solaris=yes
>  		PCIACCESS_LIBS="$PCIACCESS_LIBS -ldevinfo"
> @@ -85,6 +88,7 @@ esac
>  
>  AM_CONDITIONAL(LINUX, [test "x$linux" = xyes])
>  AM_CONDITIONAL(FREEBSD, [test "x$freebsd" = xyes])
> +AM_CONDITIONAL(OPENBSD, [test "x$openbsd" = xyes])
>  AM_CONDITIONAL(SOLARIS, [test "x$solaris" = xyes])
>  
>  AC_CHECK_FILE([/usr/include/asm/mtrr.h],
> diff --git a/include/pciaccess.h b/include/pciaccess.h
> index dcc0122..3138877 100644
> --- a/include/pciaccess.h
> +++ b/include/pciaccess.h
> @@ -81,6 +81,8 @@ int pci_device_get_bridge_buses(struct pci_device *dev, int *primary_bus,
>  
>  int pci_system_init(void);
>  
> +void pci_system_init_dev_mem(int fd);
> +
>  void pci_system_cleanup(void);
>  
>  struct pci_device_iterator *pci_slot_match_iterator_create(
> diff --git a/src/Makefile.am b/src/Makefile.am
> index f370920..f60ccbd 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -33,6 +33,10 @@ if FREEBSD
>  OS_SUPPORT = freebsd_pci.c
>  endif
>  
> +if OPENBSD
> +OS_SUPPORT = openbsd_pci.c
> +endif
> +
>  if SOLARIS
>  OS_SUPPORT = solx_devfs.c pci_tools.h
>  endif
> diff --git a/src/common_init.c b/src/common_init.c
> index 1092faf..7429518 100644
> --- a/src/common_init.c
> +++ b/src/common_init.c
> @@ -56,13 +56,22 @@ pci_system_init( void )
>      err = pci_system_linux_sysfs_create();
>  #elif defined(__FreeBSD__)
>      err = pci_system_freebsd_create();
> +#elif defined(__OpenBSD__)
> +    err = pci_system_openbsd_create();
>  #elif defined(__sun)
> -	err = pci_system_solx_devfs_create();
> +    err = pci_system_solx_devfs_create();
>  #endif
>  
>      return err;
>  }
>  
> +void
> +pci_system_init_dev_mem(int fd)
> +{
> +#ifdef __OpenBSD__
> +    pci_system_openbsd_init_dev_mem(fd);
> +#endif
> +}
>  
>  /**
>   * Shutdown all access to the PCI subsystem.
> diff --git a/src/common_interface.c b/src/common_interface.c
> index 7fae277..d7e4b62 100644
> --- a/src/common_interface.c
> +++ b/src/common_interface.c
> @@ -61,11 +61,17 @@
>  
>  #include <sys/endian.h>
>  
> -#define LETOH_16(x)	le16toh(x)
>  #define HTOLE_16(x)	htole16(x)
> -#define LETOH_32(x)	le32toh(x)
>  #define HTOLE_32(x)	htole32(x)
>  
> +#ifdef __FreeBSD__
> +#define LETOH_16(x)	le16toh(x)
> +#define LETOH_32(x)	le32toh(x)
> +#else
> +#define LETOH_16(x)	letoh16(x)
> +#define LETOH_32(x)	letoh32(x)
> +#endif
> +
>  #endif /* others */
>  
>  /**
> diff --git a/src/common_map.c b/src/common_map.c
> index ac1c668..8757151 100644
> --- a/src/common_map.c
> +++ b/src/common_map.c
> @@ -22,6 +22,7 @@
>   * DEALINGS IN THE SOFTWARE.
>   */
>  
> +#include <sys/types.h>
>  #include <sys/mman.h>
>  #include <errno.h>
>  
> diff --git a/src/openbsd_pci.c b/src/openbsd_pci.c
> new file mode 100644
> index 0000000..5c06b47
> --- /dev/null
> +++ b/src/openbsd_pci.c
> @@ -0,0 +1,406 @@
> +/*
> + * Copyright (c) 2008 Mark Kettenis
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/ioctl.h>
> +#include <sys/memrange.h>
> +#include <sys/mman.h>
> +#include <sys/pciio.h>
> +
> +#include <dev/pci/pcireg.h>
> +#include <dev/pci/pcidevs.h>
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include "pciaccess.h"
> +#include "pciaccess_private.h"
> +
> +static int pcifd;
> +static int aperturefd = -1;
> +
> +static int
> +pci_read(int bus, int dev, int func, uint32_t reg, uint32_t *val)
> +{
> +	struct pci_io io;
> +	int err;
> +
> +	bzero(&io, sizeof(io));
> +	io.pi_sel.pc_bus = bus;
> +	io.pi_sel.pc_dev = dev;
> +	io.pi_sel.pc_func = func;
> +	io.pi_reg = reg;
> +	io.pi_width = 4;
> +
> +	err = ioctl(pcifd, PCIOCREAD, &io);
> +	if (err)
> +		return (err);
> +
> +	*val = io.pi_data;
> +
> +	return (0);
> +}
> +
> +static int
> +pci_write(int bus, int dev, int func, uint32_t reg, uint32_t val)
> +{
> +	struct pci_io io;
> +
> +	bzero(&io, sizeof(io));
> +	io.pi_sel.pc_bus = bus;
> +	io.pi_sel.pc_dev = dev;
> +	io.pi_sel.pc_func = func;
> +	io.pi_reg = reg;
> +	io.pi_width = 4;
> +	io.pi_data = val;
> +
> +	return ioctl(pcifd, PCIOCWRITE, &io);
> +}
> +
> +static int
> +pci_nfuncs(int bus, int dev)
> +{
> +	uint32_t hdr;
> +
> +	if (pci_read(bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
> +		return -1;
> +
> +	return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
> +}
> +
> +static int
> +pci_device_openbsd_map_range(struct pci_device *dev,
> +    struct pci_device_mapping *map)
> +{
> +	struct mem_range_desc mr;
> +	struct mem_range_op mo;
> +	int prot = PROT_READ;
> +
> +	if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
> +		prot |= PROT_WRITE;
> +
> +	map->memory = mmap(NULL, map->size, prot, MAP_SHARED, aperturefd,
> +	    map->base);
> +	if (map->memory == MAP_FAILED)
> +		return  errno;
> +
> +	/* No need to set an MTRR if it's the default mode. */
> +	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
> +	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
> +		mr.mr_base = map->base;
> +		mr.mr_len = map->size;
> +		mr.mr_flags = 0;
> +		if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE)
> +			mr.mr_flags |= MDF_WRITEBACK;
> +		if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)
> +			mr.mr_flags |= MDF_WRITECOMBINE;
> +		strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
> +
> +		mo.mo_desc = &mr;
> +		mo.mo_arg[0] = MEMRANGE_SET_UPDATE;
> +
> +		if (ioctl(aperturefd, MEMRANGE_SET, &mo))
> +			return errno;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +pci_device_openbsd_unmap_range(struct pci_device *dev,
> +    struct pci_device_mapping *map)
> +{
> +	struct mem_range_desc mr;
> +	struct mem_range_op mo;
> +
> +	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
> +	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
> +		mr.mr_base = map->base;
> +		mr.mr_len = map->size;
> +		mr.mr_flags = MDF_UNCACHEABLE;
> +		strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
> +
> +		mo.mo_desc = &mr;
> +		mo.mo_arg[0] = MEMRANGE_SET_REMOVE;
> +
> +		(void)ioctl(aperturefd, MEMRANGE_SET, &mo);
> +	}
> +
> +	return pci_device_generic_unmap_range(dev, map);
> +}
> +
> +static int
> +pci_device_openbsd_read(struct pci_device *dev, void *data,
> +    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
> +{
> +	struct pci_io io;
> +
> +	io.pi_sel.pc_bus = dev->bus;
> +	io.pi_sel.pc_dev = dev->dev;
> +	io.pi_sel.pc_func = dev->func;
> +
> +	*bytes_read = 0;
> +	while (size > 0) {
> +		int toread = MIN(size, 4 - (offset & 0x3));
> +
> +		io.pi_reg = (offset & ~0x3);
> +		io.pi_width = 4;
> +
> +		if (ioctl(pcifd, PCIOCREAD, &io) == -1)
> +			return errno;
> +
> +		io.pi_data = htole32(io.pi_data);
> +		io.pi_data >>= ((offset & 0x3) * 8);
> +
> +		memcpy(data, &io.pi_data, toread);
> +
> +		offset += toread;
> +		data = (char *)data + toread;
> +		size -= toread;
> +		*bytes_read += toread;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +pci_device_openbsd_write(struct pci_device *dev, const void *data,
> +    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
> +{
> +	struct pci_io io;
> +
> +	if ((offset % 4) == 0 || (size % 4) == 0)
> +		return EINVAL;
> +
> +	io.pi_sel.pc_bus = dev->bus;
> +	io.pi_sel.pc_dev = dev->dev;
> +	io.pi_sel.pc_func = dev->func;
> +
> +	*bytes_written = 0;
> +	while (size > 0) {
> +		io.pi_reg = offset;
> +		io.pi_width = 4;
> +		memcpy(&io.pi_data, data, 4);
> +
> +		if (ioctl(pcifd, PCIOCWRITE, &io) == -1) 
> +			return errno;
> +
> +		offset += 4;
> +		data = (char *)data + 4;
> +		size -= 4;
> +		*bytes_written += 4;
> +	}
> +
> +	return 0;
> +}
> +
> +static void
> +pci_system_openbsd_destroy(void)
> +{
> +	close(aperturefd);
> +	close(pcifd);
> +	free(pci_sys);
> +	pci_sys = NULL;
> +}
> +
> +static int
> +pci_device_openbsd_probe(struct pci_device *device)
> +{
> +	struct pci_device_private *priv = (struct pci_device_private *)device;
> +	struct pci_mem_region *region;
> +	uint64_t reg64, size64;
> +	uint32_t bar, reg, size;
> +	int bus, dev, func, err;
> +
> +	bus = device->bus;
> +	dev = device->dev;
> +	func = device->func;
> +
> +	err = pci_read(bus, dev, func, PCI_BHLC_REG, &reg);
> +	if (err)
> +		return err;
> +
> +	priv->header_type = PCI_HDRTYPE_TYPE(reg);
> +	if (priv->header_type != 0)
> +		return 0;
> +
> +	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);
> +		if (err)
> +			return err;
> +
> +		/* Probe the size of the region. */
> +		err = pci_write(bus, dev, func, bar, ~0);
> +		if (err)
> +			return err;
> +		pci_read(bus, dev, func, bar, &size);
> +		pci_write(bus, dev, func, bar, reg);
> +
> +		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
> +			region->is_IO = 1;
> +			region->base_addr = PCI_MAPREG_IO_ADDR(reg);
> +			region->size = PCI_MAPREG_IO_SIZE(size);
> +		} else {
> +			if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
> +				region->is_prefetchable = 1;
> +			switch(PCI_MAPREG_MEM_TYPE(reg)) {
> +			case PCI_MAPREG_MEM_TYPE_32BIT:
> +			case PCI_MAPREG_MEM_TYPE_32BIT_1M:
> +				region->base_addr = PCI_MAPREG_MEM_ADDR(reg);
> +				region->size = PCI_MAPREG_MEM_SIZE(size);
> +				break;
> +			case PCI_MAPREG_MEM_TYPE_64BIT:
> +				region->is_64 = 1;
> +
> +				reg64 = reg;
> +				size64 = size;
> +
> +				bar += sizeof(uint32_t);
> +
> +				err = pci_read(bus, dev, func, bar, &reg);
> +				if (err)
> +					return err;
> +				reg64 |= (uint64_t)reg << 32;
> +
> +				err = pci_write(bus, dev, func, bar, ~0);
> +				if (err)
> +					return err;
> +				pci_read(bus, dev, func, bar, &size);
> +				pci_write(bus, dev, func, bar, reg64 >> 32);
> +				size64 |= (uint64_t)size << 32;
> +
> +				region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64);
> +				region->size = PCI_MAPREG_MEM64_SIZE(size64);
> +				region++;
> +				break;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct pci_system_methods openbsd_pci_methods = {
> +	pci_system_openbsd_destroy,
> +	NULL,
> +	NULL,
> +	pci_device_openbsd_probe,
> +	pci_device_openbsd_map_range,
> +	pci_device_openbsd_unmap_range,
> +	pci_device_openbsd_read,
> +	pci_device_openbsd_write,
> +	pci_fill_capabilities_generic
> +};
> +
> +int
> +pci_system_openbsd_create(void)
> +{
> +	struct pci_device_private *device;
> +	int bus, dev, func, ndevs, nfuncs;
> +	uint32_t reg;
> +
> +	pcifd = open("/dev/pci", O_RDWR);
> +	if (pcifd == -1)
> +		return ENXIO;
> +
> +	pci_sys = calloc(1, sizeof(struct pci_system));
> +	if (pci_sys == NULL) {
> +		close(aperturefd);
> +		close(pcifd);
> +		return ENOMEM;
> +	}
> +
> +	pci_sys->methods = &openbsd_pci_methods;
> +
> +	ndevs = 0;
> +	for (bus = 0; bus < 256; bus++) {
> +		for (dev = 0; dev < 32; dev++) {
> +			nfuncs = pci_nfuncs(bus, dev);
> +			for (func = 0; func < nfuncs; func++) {
> +				if (pci_read(bus, dev, func, PCI_ID_REG,
> +				    &reg) != 0)
> +					continue;
> +				if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
> +				    PCI_VENDOR(reg) == 0)
> +					continue;
> +
> +				ndevs++;
> +			}
> +		}
> +	}
> +
> +	pci_sys->num_devices = ndevs;
> +	pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
> +	if (pci_sys->devices == NULL) {
> +		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 (func = 0; func < nfuncs; func++) {
> +				if (pci_read(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.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)
> +					continue;
> +
> +				device->base.device_class =
> +				    PCI_INTERFACE(reg) | PCI_CLASS(reg) << 16 |
> +				    PCI_SUBCLASS(reg) << 8;
> +				device->base.revision = PCI_REVISION(reg);
> +
> +				if (pci_read(bus, dev, func, PCI_SUBVEND_0,
> +				    &reg) != 0)
> +					continue;
> +
> +				device->base.subvendor_id = PCI_VENDOR(reg);
> +				device->base.subdevice_id = PCI_PRODUCT(reg);
> +
> +				device++;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +void
> +pci_system_openbsd_init_dev_mem(int fd)
> +{
> +	aperturefd = fd;
> +}
> diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h
> index c8a483e..94b12bd 100644
> --- a/src/pciaccess_private.h
> +++ b/src/pciaccess_private.h
> @@ -135,3 +135,5 @@ extern struct pci_system * pci_sys;
>  
>  extern int pci_system_linux_sysfs_create( void );
>  extern int pci_system_freebsd_create( void );
> +extern int pci_system_openbsd_create( void );
> +extern void pci_system_openbsd_init_dev_mem( int );
> _______________________________________________
> xorg mailing list
> xorg at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/xorg
-- 
Eric Anholt                             anholt at FreeBSD.org
eric at anholt.net                         eric.anholt at intel.com

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: This is a digitally signed message part
URL: <http://lists.x.org/archives/xorg/attachments/20080312/eeca6054/attachment.pgp>


More information about the xorg mailing list