[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, ®);
> + 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, ®);
> + 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, ®);
> + 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,
> + ®) != 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,
> + ®) != 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,
> + ®) != 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,
> + ®) != 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