14f5e7dd7Smrg/*
2cad31331Smrg * Copyright (c) 2008, 2011 Mark Kettenis
34f5e7dd7Smrg *
44f5e7dd7Smrg * Permission to use, copy, modify, and distribute this software for any
54f5e7dd7Smrg * purpose with or without fee is hereby granted, provided that the above
64f5e7dd7Smrg * copyright notice and this permission notice appear in all copies.
74f5e7dd7Smrg *
84f5e7dd7Smrg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
94f5e7dd7Smrg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
104f5e7dd7Smrg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
114f5e7dd7Smrg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
124f5e7dd7Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
134f5e7dd7Smrg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
144f5e7dd7Smrg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
154f5e7dd7Smrg */
1649310723Smrg#ifdef HAVE_CONFIG_H
1749310723Smrg#include "config.h"
1849310723Smrg#endif
194f5e7dd7Smrg
204f5e7dd7Smrg#include <sys/param.h>
214f5e7dd7Smrg#include <sys/ioctl.h>
224f5e7dd7Smrg#include <sys/memrange.h>
234f5e7dd7Smrg#include <sys/mman.h>
244f5e7dd7Smrg#include <sys/pciio.h>
254f5e7dd7Smrg
264f5e7dd7Smrg#include <dev/pci/pcireg.h>
274f5e7dd7Smrg#include <dev/pci/pcidevs.h>
284f5e7dd7Smrg
294f5e7dd7Smrg#include <errno.h>
304f5e7dd7Smrg#include <fcntl.h>
314f5e7dd7Smrg#include <stdio.h>
324f5e7dd7Smrg#include <stdlib.h>
334f5e7dd7Smrg#include <string.h>
344f5e7dd7Smrg#include <unistd.h>
354f5e7dd7Smrg
364f5e7dd7Smrg#include "pciaccess.h"
374f5e7dd7Smrg#include "pciaccess_private.h"
384f5e7dd7Smrg
394f5e7dd7Smrg/*
404f5e7dd7Smrg * This should allow for 16 domains, which should cover everything
414f5e7dd7Smrg * except perhaps the really big fridge-sized sparc64 server machines
424f5e7dd7Smrg * that are unlikely to have any graphics hardware in them.
434f5e7dd7Smrg */
444f5e7dd7Smrgstatic int pcifd[16];
454f5e7dd7Smrgstatic int ndomains;
464f5e7dd7Smrg
474f5e7dd7Smrgstatic int aperturefd = -1;
484f5e7dd7Smrg
494f5e7dd7Smrgstatic int
504f5e7dd7Smrgpci_read(int domain, int bus, int dev, int func, uint32_t reg, uint32_t *val)
514f5e7dd7Smrg{
524f5e7dd7Smrg	struct pci_io io;
534f5e7dd7Smrg	int err;
544f5e7dd7Smrg
554f5e7dd7Smrg	bzero(&io, sizeof(io));
564f5e7dd7Smrg	io.pi_sel.pc_bus = bus;
574f5e7dd7Smrg	io.pi_sel.pc_dev = dev;
584f5e7dd7Smrg	io.pi_sel.pc_func = func;
594f5e7dd7Smrg	io.pi_reg = reg;
604f5e7dd7Smrg	io.pi_width = 4;
614f5e7dd7Smrg
624f5e7dd7Smrg	err = ioctl(pcifd[domain], PCIOCREAD, &io);
634f5e7dd7Smrg	if (err)
644f5e7dd7Smrg		return (err);
654f5e7dd7Smrg
664f5e7dd7Smrg	*val = io.pi_data;
674f5e7dd7Smrg
684f5e7dd7Smrg	return 0;
694f5e7dd7Smrg}
704f5e7dd7Smrg
714f5e7dd7Smrgstatic int
724f5e7dd7Smrgpci_write(int domain, int bus, int dev, int func, uint32_t reg, uint32_t val)
734f5e7dd7Smrg{
744f5e7dd7Smrg	struct pci_io io;
754f5e7dd7Smrg
764f5e7dd7Smrg	bzero(&io, sizeof(io));
774f5e7dd7Smrg	io.pi_sel.pc_bus = bus;
784f5e7dd7Smrg	io.pi_sel.pc_dev = dev;
794f5e7dd7Smrg	io.pi_sel.pc_func = func;
804f5e7dd7Smrg	io.pi_reg = reg;
814f5e7dd7Smrg	io.pi_width = 4;
824f5e7dd7Smrg	io.pi_data = val;
834f5e7dd7Smrg
844f5e7dd7Smrg	return ioctl(pcifd[domain], PCIOCWRITE, &io);
854f5e7dd7Smrg}
864f5e7dd7Smrg
876a94483fSmrgstatic int
886a94483fSmrgpci_readmask(int domain, int bus, int dev, int func, uint32_t reg,
896a94483fSmrg    uint32_t *val)
906a94483fSmrg{
916a94483fSmrg	struct pci_io io;
926a94483fSmrg	int err;
936a94483fSmrg
946a94483fSmrg	bzero(&io, sizeof(io));
956a94483fSmrg	io.pi_sel.pc_bus = bus;
966a94483fSmrg	io.pi_sel.pc_dev = dev;
976a94483fSmrg	io.pi_sel.pc_func = func;
986a94483fSmrg	io.pi_reg = reg;
996a94483fSmrg	io.pi_width = 4;
1006a94483fSmrg
1016a94483fSmrg	err = ioctl(pcifd[domain], PCIOCREADMASK, &io);
1026a94483fSmrg	if (err)
1036a94483fSmrg		return (err);
1046a94483fSmrg
1056a94483fSmrg	*val = io.pi_data;
1066a94483fSmrg
1076a94483fSmrg	return 0;
1086a94483fSmrg}
1096a94483fSmrg
1104f5e7dd7Smrg/**
1114f5e7dd7Smrg * Read a VGA ROM
1124f5e7dd7Smrg *
1134f5e7dd7Smrg */
1144f5e7dd7Smrgstatic int
1154f5e7dd7Smrgpci_device_openbsd_read_rom(struct pci_device *device, void *buffer)
1164f5e7dd7Smrg{
1174f5e7dd7Smrg	struct pci_device_private *priv = (struct pci_device_private *)device;
1184f5e7dd7Smrg	unsigned char *bios;
1194f5e7dd7Smrg	pciaddr_t rom_base;
1204f5e7dd7Smrg	pciaddr_t rom_size;
1214f5e7dd7Smrg	u_int32_t csr, rom;
1224f5e7dd7Smrg	int pci_rom, domain, bus, dev, func;
1234f5e7dd7Smrg
1244f5e7dd7Smrg	domain = device->domain;
1254f5e7dd7Smrg	if (domain < 0 || domain >= ndomains)
1264f5e7dd7Smrg		return ENXIO;
1274f5e7dd7Smrg
1284f5e7dd7Smrg	bus = device->bus;
1294f5e7dd7Smrg	dev = device->dev;
1304f5e7dd7Smrg	func = device->func;
1314f5e7dd7Smrg
1324f5e7dd7Smrg	if (aperturefd == -1)
1334f5e7dd7Smrg		return ENOSYS;
1344f5e7dd7Smrg
1354f5e7dd7Smrg	if (priv->base.rom_size == 0) {
1364f5e7dd7Smrg#if defined(__alpha__) || defined(__amd64__) || defined(__i386__)
1374f5e7dd7Smrg		if ((device->device_class & 0x00ffff00) ==
1384f5e7dd7Smrg		    ((PCI_CLASS_DISPLAY << 16) |
1394f5e7dd7Smrg			(PCI_SUBCLASS_DISPLAY_VGA << 8))) {
1404f5e7dd7Smrg			rom_base = 0xc0000;
1414f5e7dd7Smrg			rom_size = 0x10000;
1424f5e7dd7Smrg			pci_rom = 0;
1434f5e7dd7Smrg		} else
1444f5e7dd7Smrg#endif
1454f5e7dd7Smrg			return ENOSYS;
1464f5e7dd7Smrg	} else {
1474f5e7dd7Smrg		rom_base = priv->rom_base;
1484f5e7dd7Smrg		rom_size = priv->base.rom_size;
1494f5e7dd7Smrg		pci_rom = 1;
1504f5e7dd7Smrg
1514f5e7dd7Smrg		pci_read(domain, bus, dev, func, PCI_COMMAND_STATUS_REG, &csr);
1524f5e7dd7Smrg		pci_write(domain, bus, dev, func, PCI_COMMAND_STATUS_REG,
1534f5e7dd7Smrg		    csr | PCI_COMMAND_MEM_ENABLE);
1544f5e7dd7Smrg		pci_read(domain, bus, dev, func, PCI_ROM_REG, &rom);
1554f5e7dd7Smrg		pci_write(domain, bus, dev, func, PCI_ROM_REG,
1564f5e7dd7Smrg		    rom | PCI_ROM_ENABLE);
1574f5e7dd7Smrg	}
1584f5e7dd7Smrg
1594f5e7dd7Smrg	bios = mmap(NULL, rom_size, PROT_READ, MAP_SHARED,
1604f5e7dd7Smrg	    aperturefd, (off_t)rom_base);
1614f5e7dd7Smrg	if (bios == MAP_FAILED)
1624f5e7dd7Smrg		return errno;
1634f5e7dd7Smrg
1644f5e7dd7Smrg	memcpy(buffer, bios, rom_size);
1654f5e7dd7Smrg	munmap(bios, rom_size);
1664f5e7dd7Smrg
1674f5e7dd7Smrg	if (pci_rom) {
1684f5e7dd7Smrg		/* Restore PCI config space */
1694f5e7dd7Smrg		pci_write(domain, bus, dev, func, PCI_ROM_REG, rom);
1704f5e7dd7Smrg		pci_write(domain, bus, dev, func, PCI_COMMAND_STATUS_REG, csr);
1714f5e7dd7Smrg	}
1724f5e7dd7Smrg	return 0;
1734f5e7dd7Smrg}
1744f5e7dd7Smrg
1754f5e7dd7Smrgstatic int
1764f5e7dd7Smrgpci_nfuncs(int domain, int bus, int dev)
1774f5e7dd7Smrg{
1784f5e7dd7Smrg	uint32_t hdr;
1794f5e7dd7Smrg
1804f5e7dd7Smrg	if (domain < 0 || domain >= ndomains)
1814f5e7dd7Smrg		return ENXIO;
1824f5e7dd7Smrg
1834f5e7dd7Smrg	if (pci_read(domain, bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
1844f5e7dd7Smrg		return -1;
1854f5e7dd7Smrg
1864f5e7dd7Smrg	return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
1874f5e7dd7Smrg}
1884f5e7dd7Smrg
1894f5e7dd7Smrgstatic int
1904f5e7dd7Smrgpci_device_openbsd_map_range(struct pci_device *dev,
1914f5e7dd7Smrg    struct pci_device_mapping *map)
1924f5e7dd7Smrg{
1934f5e7dd7Smrg	struct mem_range_desc mr;
1944f5e7dd7Smrg	struct mem_range_op mo;
1954f5e7dd7Smrg	int prot = PROT_READ;
1964f5e7dd7Smrg
1974f5e7dd7Smrg	if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
1984f5e7dd7Smrg		prot |= PROT_WRITE;
1994f5e7dd7Smrg
2004f5e7dd7Smrg	map->memory = mmap(NULL, map->size, prot, MAP_SHARED, aperturefd,
2014f5e7dd7Smrg	    map->base);
2024f5e7dd7Smrg	if (map->memory == MAP_FAILED)
2034f5e7dd7Smrg		return  errno;
2044f5e7dd7Smrg#if defined(__i386__) || defined(__amd64__)
2054f5e7dd7Smrg	/* No need to set an MTRR if it's the default mode. */
2064f5e7dd7Smrg	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
2074f5e7dd7Smrg	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
2084f5e7dd7Smrg		mr.mr_base = map->base;
2094f5e7dd7Smrg		mr.mr_len = map->size;
2104f5e7dd7Smrg		mr.mr_flags = 0;
2114f5e7dd7Smrg		if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE)
2124f5e7dd7Smrg			mr.mr_flags |= MDF_WRITEBACK;
2134f5e7dd7Smrg		if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)
2144f5e7dd7Smrg			mr.mr_flags |= MDF_WRITECOMBINE;
2154f5e7dd7Smrg		strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
2164f5e7dd7Smrg
2174f5e7dd7Smrg		mo.mo_desc = &mr;
2184f5e7dd7Smrg		mo.mo_arg[0] = MEMRANGE_SET_UPDATE;
2194f5e7dd7Smrg
2204f5e7dd7Smrg		if (ioctl(aperturefd, MEMRANGE_SET, &mo))
2214f5e7dd7Smrg			(void)fprintf(stderr, "mtrr set failed: %s\n",
2224f5e7dd7Smrg			    strerror(errno));
2234f5e7dd7Smrg	}
2244f5e7dd7Smrg#endif
2254f5e7dd7Smrg	return 0;
2264f5e7dd7Smrg}
2274f5e7dd7Smrg
2284f5e7dd7Smrgstatic int
2294f5e7dd7Smrgpci_device_openbsd_unmap_range(struct pci_device *dev,
2304f5e7dd7Smrg    struct pci_device_mapping *map)
2314f5e7dd7Smrg{
2324f5e7dd7Smrg#if defined(__i386__) || defined(__amd64__)
2334f5e7dd7Smrg	struct mem_range_desc mr;
2344f5e7dd7Smrg	struct mem_range_op mo;
2354f5e7dd7Smrg
2364f5e7dd7Smrg	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
2374f5e7dd7Smrg	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
2384f5e7dd7Smrg		mr.mr_base = map->base;
2394f5e7dd7Smrg		mr.mr_len = map->size;
2404f5e7dd7Smrg		mr.mr_flags = MDF_UNCACHEABLE;
2414f5e7dd7Smrg		strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
2424f5e7dd7Smrg
2434f5e7dd7Smrg		mo.mo_desc = &mr;
2444f5e7dd7Smrg		mo.mo_arg[0] = MEMRANGE_SET_REMOVE;
2454f5e7dd7Smrg
2464f5e7dd7Smrg		(void)ioctl(aperturefd, MEMRANGE_SET, &mo);
2474f5e7dd7Smrg	}
2484f5e7dd7Smrg#endif
2494f5e7dd7Smrg	return pci_device_generic_unmap_range(dev, map);
2504f5e7dd7Smrg}
2514f5e7dd7Smrg
2524f5e7dd7Smrgstatic int
2534f5e7dd7Smrgpci_device_openbsd_read(struct pci_device *dev, void *data,
2544f5e7dd7Smrg    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
2554f5e7dd7Smrg{
2564f5e7dd7Smrg	struct pci_io io;
2574f5e7dd7Smrg
2584f5e7dd7Smrg	io.pi_sel.pc_bus = dev->bus;
2594f5e7dd7Smrg	io.pi_sel.pc_dev = dev->dev;
2604f5e7dd7Smrg	io.pi_sel.pc_func = dev->func;
2614f5e7dd7Smrg
2624f5e7dd7Smrg	*bytes_read = 0;
2634f5e7dd7Smrg	while (size > 0) {
2644f5e7dd7Smrg		int toread = MIN(size, 4 - (offset & 0x3));
2654f5e7dd7Smrg
2664f5e7dd7Smrg		io.pi_reg = (offset & ~0x3);
2674f5e7dd7Smrg		io.pi_width = 4;
2684f5e7dd7Smrg
2694f5e7dd7Smrg		if (ioctl(pcifd[dev->domain], PCIOCREAD, &io) == -1)
2704f5e7dd7Smrg			return errno;
2714f5e7dd7Smrg
2724f5e7dd7Smrg		io.pi_data = htole32(io.pi_data);
2734f5e7dd7Smrg		io.pi_data >>= ((offset & 0x3) * 8);
2744f5e7dd7Smrg
2754f5e7dd7Smrg		memcpy(data, &io.pi_data, toread);
2764f5e7dd7Smrg
2774f5e7dd7Smrg		offset += toread;
2784f5e7dd7Smrg		data = (char *)data + toread;
2794f5e7dd7Smrg		size -= toread;
2804f5e7dd7Smrg		*bytes_read += toread;
2814f5e7dd7Smrg	}
2824f5e7dd7Smrg
2834f5e7dd7Smrg	return 0;
2844f5e7dd7Smrg}
2854f5e7dd7Smrg
2864f5e7dd7Smrgstatic int
2874f5e7dd7Smrgpci_device_openbsd_write(struct pci_device *dev, const void *data,
2884f5e7dd7Smrg    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
2894f5e7dd7Smrg{
2904f5e7dd7Smrg	struct pci_io io;
2914f5e7dd7Smrg
2924f5e7dd7Smrg	if ((offset % 4) != 0 || (size % 4) != 0)
2934f5e7dd7Smrg		return EINVAL;
2944f5e7dd7Smrg
2954f5e7dd7Smrg	io.pi_sel.pc_bus = dev->bus;
2964f5e7dd7Smrg	io.pi_sel.pc_dev = dev->dev;
2974f5e7dd7Smrg	io.pi_sel.pc_func = dev->func;
2984f5e7dd7Smrg
2994f5e7dd7Smrg	*bytes_written = 0;
3004f5e7dd7Smrg	while (size > 0) {
3014f5e7dd7Smrg		io.pi_reg = offset;
3024f5e7dd7Smrg		io.pi_width = 4;
3034f5e7dd7Smrg		memcpy(&io.pi_data, data, 4);
3044f5e7dd7Smrg
3054f5e7dd7Smrg		if (ioctl(pcifd[dev->domain], PCIOCWRITE, &io) == -1)
3064f5e7dd7Smrg			return errno;
3074f5e7dd7Smrg
3084f5e7dd7Smrg		offset += 4;
3094f5e7dd7Smrg		data = (char *)data + 4;
3104f5e7dd7Smrg		size -= 4;
3114f5e7dd7Smrg		*bytes_written += 4;
3124f5e7dd7Smrg	}
3134f5e7dd7Smrg
3144f5e7dd7Smrg	return 0;
3154f5e7dd7Smrg}
3164f5e7dd7Smrg
3174f5e7dd7Smrgstatic void
3184f5e7dd7Smrgpci_system_openbsd_destroy(void)
3194f5e7dd7Smrg{
3204f5e7dd7Smrg	int domain;
3214f5e7dd7Smrg
3224f5e7dd7Smrg	for (domain = 0; domain < ndomains; domain++)
3234f5e7dd7Smrg		close(pcifd[domain]);
3244f5e7dd7Smrg	ndomains = 0;
3254f5e7dd7Smrg}
3264f5e7dd7Smrg
3274f5e7dd7Smrgstatic int
3284f5e7dd7Smrgpci_device_openbsd_probe(struct pci_device *device)
3294f5e7dd7Smrg{
3304f5e7dd7Smrg	struct pci_device_private *priv = (struct pci_device_private *)device;
3314f5e7dd7Smrg	struct pci_mem_region *region;
3324f5e7dd7Smrg	uint64_t reg64, size64;
3334f5e7dd7Smrg	uint32_t bar, reg, size;
3344f5e7dd7Smrg	int domain, bus, dev, func, err;
3354f5e7dd7Smrg
3364f5e7dd7Smrg	domain = device->domain;
3374f5e7dd7Smrg	bus = device->bus;
3384f5e7dd7Smrg	dev = device->dev;
3394f5e7dd7Smrg	func = device->func;
3404f5e7dd7Smrg
3414f5e7dd7Smrg	err = pci_read(domain, bus, dev, func, PCI_BHLC_REG, &reg);
3424f5e7dd7Smrg	if (err)
3434f5e7dd7Smrg		return err;
3444f5e7dd7Smrg
3454f5e7dd7Smrg	priv->header_type = PCI_HDRTYPE_TYPE(reg);
3464f5e7dd7Smrg	if (priv->header_type != 0)
3474f5e7dd7Smrg		return 0;
3484f5e7dd7Smrg
3494f5e7dd7Smrg	region = device->regions;
3504f5e7dd7Smrg	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
3514f5e7dd7Smrg	     bar += sizeof(uint32_t), region++) {
3524f5e7dd7Smrg		err = pci_read(domain, bus, dev, func, bar, &reg);
3534f5e7dd7Smrg		if (err)
3544f5e7dd7Smrg			return err;
3554f5e7dd7Smrg
3564f5e7dd7Smrg		/* Probe the size of the region. */
3576a94483fSmrg		err = pci_readmask(domain, bus, dev, func, bar, &size);
3584f5e7dd7Smrg		if (err)
3594f5e7dd7Smrg			return err;
3604f5e7dd7Smrg
3614f5e7dd7Smrg		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
3624f5e7dd7Smrg			region->is_IO = 1;
3634f5e7dd7Smrg			region->base_addr = PCI_MAPREG_IO_ADDR(reg);
3644f5e7dd7Smrg			region->size = PCI_MAPREG_IO_SIZE(size);
3654f5e7dd7Smrg		} else {
3664f5e7dd7Smrg			if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
3674f5e7dd7Smrg				region->is_prefetchable = 1;
3684f5e7dd7Smrg			switch(PCI_MAPREG_MEM_TYPE(reg)) {
3694f5e7dd7Smrg			case PCI_MAPREG_MEM_TYPE_32BIT:
3704f5e7dd7Smrg			case PCI_MAPREG_MEM_TYPE_32BIT_1M:
3714f5e7dd7Smrg				region->base_addr = PCI_MAPREG_MEM_ADDR(reg);
3724f5e7dd7Smrg				region->size = PCI_MAPREG_MEM_SIZE(size);
3734f5e7dd7Smrg				break;
3744f5e7dd7Smrg			case PCI_MAPREG_MEM_TYPE_64BIT:
3754f5e7dd7Smrg				region->is_64 = 1;
3764f5e7dd7Smrg
3774f5e7dd7Smrg				reg64 = reg;
3784f5e7dd7Smrg				size64 = size;
3794f5e7dd7Smrg
3804f5e7dd7Smrg				bar += sizeof(uint32_t);
3814f5e7dd7Smrg
3824f5e7dd7Smrg				err = pci_read(domain, bus, dev, func, bar, &reg);
3834f5e7dd7Smrg				if (err)
3844f5e7dd7Smrg					return err;
3854f5e7dd7Smrg				reg64 |= (uint64_t)reg << 32;
3864f5e7dd7Smrg
3876a94483fSmrg				err = pci_readmask(domain, bus, dev, func, bar, &size);
3884f5e7dd7Smrg				if (err)
3894f5e7dd7Smrg					return err;
3904f5e7dd7Smrg				size64 |= (uint64_t)size << 32;
3914f5e7dd7Smrg
3924f5e7dd7Smrg				region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64);
3934f5e7dd7Smrg				region->size = PCI_MAPREG_MEM64_SIZE(size64);
3944f5e7dd7Smrg				region++;
3954f5e7dd7Smrg				break;
3964f5e7dd7Smrg			}
3974f5e7dd7Smrg		}
3984f5e7dd7Smrg	}
3994f5e7dd7Smrg
4004f5e7dd7Smrg	/* Probe expansion ROM if present */
4014f5e7dd7Smrg	err = pci_read(domain, bus, dev, func, PCI_ROM_REG, &reg);
4024f5e7dd7Smrg	if (err)
4034f5e7dd7Smrg		return err;
4044f5e7dd7Smrg	if (reg != 0) {
4054f5e7dd7Smrg		err = pci_write(domain, bus, dev, func, PCI_ROM_REG, ~PCI_ROM_ENABLE);
4064f5e7dd7Smrg		if (err)
4074f5e7dd7Smrg			return err;
4084f5e7dd7Smrg		pci_read(domain, bus, dev, func, PCI_ROM_REG, &size);
4094f5e7dd7Smrg		pci_write(domain, bus, dev, func, PCI_ROM_REG, reg);
4104f5e7dd7Smrg
4114f5e7dd7Smrg		if (PCI_ROM_ADDR(reg) != 0) {
4124f5e7dd7Smrg			priv->rom_base = PCI_ROM_ADDR(reg);
4134f5e7dd7Smrg			device->rom_size = PCI_ROM_SIZE(size);
4144f5e7dd7Smrg		}
4154f5e7dd7Smrg	}
4164f5e7dd7Smrg	return 0;
4174f5e7dd7Smrg}
4184f5e7dd7Smrg
419cad31331Smrg#if defined(__i386__) || defined(__amd64__)
420cad31331Smrg#include <machine/sysarch.h>
421cad31331Smrg#include <machine/pio.h>
422cad31331Smrg#endif
423cad31331Smrg
424cad31331Smrgstatic struct pci_io_handle *
425cad31331Smrgpci_device_openbsd_open_legacy_io(struct pci_io_handle *ret,
426cad31331Smrg    struct pci_device *dev, pciaddr_t base, pciaddr_t size)
427cad31331Smrg{
428cad31331Smrg#if defined(__i386__)
429cad31331Smrg	struct i386_iopl_args ia;
430cad31331Smrg
431cad31331Smrg	ia.iopl = 1;
432cad31331Smrg	if (sysarch(I386_IOPL, &ia))
433cad31331Smrg		return NULL;
434cad31331Smrg
435cad31331Smrg	ret->base = base;
436cad31331Smrg	ret->size = size;
4376a94483fSmrg	ret->is_legacy = 1;
438cad31331Smrg	return ret;
439cad31331Smrg#elif defined(__amd64__)
440cad31331Smrg	struct amd64_iopl_args ia;
441cad31331Smrg
442cad31331Smrg	ia.iopl = 1;
443cad31331Smrg	if (sysarch(AMD64_IOPL, &ia))
444cad31331Smrg		return NULL;
445cad31331Smrg
446cad31331Smrg	ret->base = base;
447cad31331Smrg	ret->size = size;
4486a94483fSmrg	ret->is_legacy = 1;
449cad31331Smrg	return ret;
450cad31331Smrg#elif defined(PCI_MAGIC_IO_RANGE)
451cad31331Smrg	ret->memory = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
452cad31331Smrg	    aperturefd, PCI_MAGIC_IO_RANGE + base);
453cad31331Smrg	if (ret->memory == MAP_FAILED)
454cad31331Smrg		return NULL;
455cad31331Smrg
456cad31331Smrg	ret->base = base;
457cad31331Smrg	ret->size = size;
4586a94483fSmrg	ret->is_legacy = 1;
459cad31331Smrg	return ret;
460cad31331Smrg#else
461cad31331Smrg	return NULL;
462cad31331Smrg#endif
463cad31331Smrg}
464cad31331Smrg
465cad31331Smrgstatic uint32_t
466cad31331Smrgpci_device_openbsd_read32(struct pci_io_handle *handle, uint32_t reg)
467cad31331Smrg{
468cad31331Smrg#if defined(__i386__) || defined(__amd64__)
469cad31331Smrg	return inl(handle->base + reg);
470cad31331Smrg#else
471cad31331Smrg	return *(uint32_t *)((uintptr_t)handle->memory + reg);
472cad31331Smrg#endif
473cad31331Smrg}
474cad31331Smrg
475cad31331Smrgstatic uint16_t
476cad31331Smrgpci_device_openbsd_read16(struct pci_io_handle *handle, uint32_t reg)
477cad31331Smrg{
478cad31331Smrg#if defined(__i386__) || defined(__amd64__)
479cad31331Smrg	return inw(handle->base + reg);
480cad31331Smrg#else
481cad31331Smrg	return *(uint16_t *)((uintptr_t)handle->memory + reg);
482cad31331Smrg#endif
483cad31331Smrg}
484cad31331Smrg
485cad31331Smrgstatic uint8_t
486cad31331Smrgpci_device_openbsd_read8(struct pci_io_handle *handle, uint32_t reg)
487cad31331Smrg{
488cad31331Smrg#if defined(__i386__) || defined(__amd64__)
489cad31331Smrg	return inb(handle->base + reg);
490cad31331Smrg#else
491cad31331Smrg	return *(uint8_t *)((uintptr_t)handle->memory + reg);
492cad31331Smrg#endif
493cad31331Smrg}
494cad31331Smrg
495cad31331Smrgstatic void
496cad31331Smrgpci_device_openbsd_write32(struct pci_io_handle *handle, uint32_t reg,
497cad31331Smrg    uint32_t data)
498cad31331Smrg{
499cad31331Smrg#if defined(__i386__) || defined(__amd64__)
500cad31331Smrg	outl(handle->base + reg, data);
501cad31331Smrg#else
502cad31331Smrg	*(uint16_t *)((uintptr_t)handle->memory + reg) = data;
503cad31331Smrg#endif
504cad31331Smrg}
505cad31331Smrg
506cad31331Smrgstatic void
507cad31331Smrgpci_device_openbsd_write16(struct pci_io_handle *handle, uint32_t reg,
508cad31331Smrg    uint16_t data)
509cad31331Smrg{
510cad31331Smrg#if defined(__i386__) || defined(__amd64__)
511cad31331Smrg	outw(handle->base + reg, data);
512cad31331Smrg#else
513cad31331Smrg	*(uint8_t *)((uintptr_t)handle->memory + reg) = data;
514cad31331Smrg#endif
515cad31331Smrg}
516cad31331Smrg
517cad31331Smrgstatic void
518cad31331Smrgpci_device_openbsd_write8(struct pci_io_handle *handle, uint32_t reg,
519cad31331Smrg    uint8_t data)
520cad31331Smrg{
521cad31331Smrg#if defined(__i386__) || defined(__amd64__)
522cad31331Smrg	outb(handle->base + reg, data);
523cad31331Smrg#else
524cad31331Smrg	*(uint32_t *)((uintptr_t)handle->memory + reg) = data;
525cad31331Smrg#endif
526cad31331Smrg}
527cad31331Smrg
528cad31331Smrgstatic int
529cad31331Smrgpci_device_openbsd_map_legacy(struct pci_device *dev, pciaddr_t base,
530cad31331Smrg    pciaddr_t size, unsigned map_flags, void **addr)
531cad31331Smrg{
532cad31331Smrg	struct pci_device_mapping map;
533cad31331Smrg	int err;
534cad31331Smrg
535cad31331Smrg	map.base = base;
536cad31331Smrg	map.size = size;
537cad31331Smrg	map.flags = map_flags;
538cad31331Smrg	map.memory = NULL;
539cad31331Smrg	err = pci_device_openbsd_map_range(dev, &map);
540cad31331Smrg	*addr = map.memory;
541cad31331Smrg
542cad31331Smrg	return err;
543cad31331Smrg}
544cad31331Smrg
545cad31331Smrgstatic int
546cad31331Smrgpci_device_openbsd_unmap_legacy(struct pci_device *dev, void *addr,
547cad31331Smrg    pciaddr_t size)
548cad31331Smrg{
549cad31331Smrg	struct pci_device_mapping map;
550cad31331Smrg
551cad31331Smrg	map.memory = addr;
552cad31331Smrg	map.size = size;
553cad31331Smrg	map.flags = 0;
554cad31331Smrg	return pci_device_openbsd_unmap_range(dev, &map);
555cad31331Smrg}
556cad31331Smrg
5574f5e7dd7Smrgstatic const struct pci_system_methods openbsd_pci_methods = {
5584f5e7dd7Smrg	pci_system_openbsd_destroy,
5594f5e7dd7Smrg	NULL,
5604f5e7dd7Smrg	pci_device_openbsd_read_rom,
5614f5e7dd7Smrg	pci_device_openbsd_probe,
5624f5e7dd7Smrg	pci_device_openbsd_map_range,
5634f5e7dd7Smrg	pci_device_openbsd_unmap_range,
5644f5e7dd7Smrg	pci_device_openbsd_read,
5654f5e7dd7Smrg	pci_device_openbsd_write,
566cad31331Smrg	pci_fill_capabilities_generic,
567cad31331Smrg	NULL,
568cad31331Smrg	NULL,
569cad31331Smrg	NULL,
570cad31331Smrg	NULL,
571cad31331Smrg	pci_device_openbsd_open_legacy_io,
572cad31331Smrg	NULL,
573cad31331Smrg	pci_device_openbsd_read32,
574cad31331Smrg	pci_device_openbsd_read16,
575cad31331Smrg	pci_device_openbsd_read8,
576cad31331Smrg	pci_device_openbsd_write32,
577cad31331Smrg	pci_device_openbsd_write16,
578cad31331Smrg	pci_device_openbsd_write8,
579cad31331Smrg	pci_device_openbsd_map_legacy,
580cad31331Smrg	pci_device_openbsd_unmap_legacy
5814f5e7dd7Smrg};
5824f5e7dd7Smrg
5834f5e7dd7Smrgint
5844f5e7dd7Smrgpci_system_openbsd_create(void)
5854f5e7dd7Smrg{
5864f5e7dd7Smrg	struct pci_device_private *device;
5874f5e7dd7Smrg	int domain, bus, dev, func, ndevs, nfuncs;
5884f5e7dd7Smrg	char path[MAXPATHLEN];
5894f5e7dd7Smrg	uint32_t reg;
5904f5e7dd7Smrg
5914f5e7dd7Smrg	if (ndomains > 0)
5924f5e7dd7Smrg		return 0;
5934f5e7dd7Smrg
5944f5e7dd7Smrg	for (domain = 0; domain < sizeof(pcifd) / sizeof(pcifd[0]); domain++) {
5954f5e7dd7Smrg		snprintf(path, sizeof(path), "/dev/pci%d", domain);
596cad31331Smrg	        pcifd[domain] = open(path, O_RDWR | O_CLOEXEC);
5974f5e7dd7Smrg		if (pcifd[domain] == -1)
5984f5e7dd7Smrg			break;
5994f5e7dd7Smrg		ndomains++;
6004f5e7dd7Smrg	}
6014f5e7dd7Smrg
6024f5e7dd7Smrg	if (ndomains == 0)
6034f5e7dd7Smrg		return ENXIO;
6044f5e7dd7Smrg
6054f5e7dd7Smrg	pci_sys = calloc(1, sizeof(struct pci_system));
6064f5e7dd7Smrg	if (pci_sys == NULL) {
6074f5e7dd7Smrg		for (domain = 0; domain < ndomains; domain++)
6084f5e7dd7Smrg			close(pcifd[domain]);
6094f5e7dd7Smrg		ndomains = 0;
6104f5e7dd7Smrg		return ENOMEM;
6114f5e7dd7Smrg	}
6124f5e7dd7Smrg
6134f5e7dd7Smrg	pci_sys->methods = &openbsd_pci_methods;
6144f5e7dd7Smrg
6154f5e7dd7Smrg	ndevs = 0;
6164f5e7dd7Smrg	for (domain = 0; domain < ndomains; domain++) {
6174f5e7dd7Smrg		for (bus = 0; bus < 256; bus++) {
6184f5e7dd7Smrg			for (dev = 0; dev < 32; dev++) {
6194f5e7dd7Smrg				nfuncs = pci_nfuncs(domain, bus, dev);
6204f5e7dd7Smrg				for (func = 0; func < nfuncs; func++) {
6214f5e7dd7Smrg					if (pci_read(domain, bus, dev, func,
6224f5e7dd7Smrg					    PCI_ID_REG, &reg) != 0)
6234f5e7dd7Smrg						continue;
6244f5e7dd7Smrg					if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
6254f5e7dd7Smrg					    PCI_VENDOR(reg) == 0)
6264f5e7dd7Smrg						continue;
6274f5e7dd7Smrg
6284f5e7dd7Smrg					ndevs++;
6294f5e7dd7Smrg				}
6304f5e7dd7Smrg			}
6314f5e7dd7Smrg		}
6324f5e7dd7Smrg	}
6334f5e7dd7Smrg
6344f5e7dd7Smrg	pci_sys->num_devices = ndevs;
6354f5e7dd7Smrg	pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
6364f5e7dd7Smrg	if (pci_sys->devices == NULL) {
6374f5e7dd7Smrg		free(pci_sys);
6384f5e7dd7Smrg		pci_sys = NULL;
6394f5e7dd7Smrg		for (domain = 0; domain < ndomains; domain++)
6404f5e7dd7Smrg			close(pcifd[domain]);
6414f5e7dd7Smrg		ndomains = 0;
6424f5e7dd7Smrg		return ENOMEM;
6434f5e7dd7Smrg	}
6444f5e7dd7Smrg
6454f5e7dd7Smrg	device = pci_sys->devices;
6464f5e7dd7Smrg	for (domain = 0; domain < ndomains; domain++) {
6474f5e7dd7Smrg		for (bus = 0; bus < 256; bus++) {
6484f5e7dd7Smrg			for (dev = 0; dev < 32; dev++) {
6494f5e7dd7Smrg				nfuncs = pci_nfuncs(domain, bus, dev);
6504f5e7dd7Smrg				for (func = 0; func < nfuncs; func++) {
6514f5e7dd7Smrg					if (pci_read(domain, bus, dev, func,
6524f5e7dd7Smrg					    PCI_ID_REG, &reg) != 0)
6534f5e7dd7Smrg						continue;
6544f5e7dd7Smrg					if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
6554f5e7dd7Smrg					    PCI_VENDOR(reg) == 0)
6564f5e7dd7Smrg						continue;
6574f5e7dd7Smrg
6584f5e7dd7Smrg					device->base.domain = domain;
65966337f63Smrg					if (domain > 0xffff)
66066337f63Smrg					    device->base.domain_16 = 0xffff;
66166337f63Smrg					else
66266337f63Smrg					    device->base.domain_16 = domain & 0xffff;
6634f5e7dd7Smrg					device->base.bus = bus;
6644f5e7dd7Smrg					device->base.dev = dev;
6654f5e7dd7Smrg					device->base.func = func;
6664f5e7dd7Smrg					device->base.vendor_id = PCI_VENDOR(reg);
6674f5e7dd7Smrg					device->base.device_id = PCI_PRODUCT(reg);
6684f5e7dd7Smrg
6694f5e7dd7Smrg					if (pci_read(domain, bus, dev, func,
6704f5e7dd7Smrg					    PCI_CLASS_REG, &reg) != 0)
6714f5e7dd7Smrg						continue;
6724f5e7dd7Smrg
6734f5e7dd7Smrg					device->base.device_class =
6744f5e7dd7Smrg					    PCI_INTERFACE(reg) |
6754f5e7dd7Smrg					    PCI_CLASS(reg) << 16 |
6764f5e7dd7Smrg					    PCI_SUBCLASS(reg) << 8;
6774f5e7dd7Smrg					device->base.revision = PCI_REVISION(reg);
6784f5e7dd7Smrg
6794f5e7dd7Smrg					if (pci_read(domain, bus, dev, func,
6804f5e7dd7Smrg					    PCI_SUBVEND_0, &reg) != 0)
6814f5e7dd7Smrg						continue;
6824f5e7dd7Smrg
6834f5e7dd7Smrg					device->base.subvendor_id = PCI_VENDOR(reg);
6844f5e7dd7Smrg					device->base.subdevice_id = PCI_PRODUCT(reg);
6854f5e7dd7Smrg
686cad31331Smrg					device->base.vgaarb_rsrc =
687cad31331Smrg					    VGA_ARB_RSRC_LEGACY_IO |
688cad31331Smrg					    VGA_ARB_RSRC_LEGACY_MEM;
689cad31331Smrg
6904f5e7dd7Smrg					device++;
6914f5e7dd7Smrg				}
6924f5e7dd7Smrg			}
6934f5e7dd7Smrg		}
6944f5e7dd7Smrg	}
6954f5e7dd7Smrg
6964f5e7dd7Smrg	return 0;
6974f5e7dd7Smrg}
6984f5e7dd7Smrg
6994f5e7dd7Smrgvoid
7004f5e7dd7Smrgpci_system_openbsd_init_dev_mem(int fd)
7014f5e7dd7Smrg{
7024f5e7dd7Smrg	aperturefd = fd;
7034f5e7dd7Smrg}
704cad31331Smrg
705cad31331Smrgint
706cad31331Smrgpci_device_vgaarb_init(void)
707cad31331Smrg{
708cad31331Smrg	struct pci_device *dev = pci_sys->vga_target;
709cad31331Smrg	struct pci_device_iterator *iter;
710cad31331Smrg	struct pci_id_match vga_match = {
711cad31331Smrg		PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
712cad31331Smrg		(PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8),
713cad31331Smrg		0x00ffff00
714cad31331Smrg	};
715cad31331Smrg	struct pci_vga pv;
716cad31331Smrg	int err;
717cad31331Smrg
718cad31331Smrg	pv.pv_sel.pc_bus = 0;
719cad31331Smrg	pv.pv_sel.pc_dev = 0;
720cad31331Smrg	pv.pv_sel.pc_func = 0;
721cad31331Smrg	err = ioctl(pcifd[0], PCIOCGETVGA, &pv);
722cad31331Smrg	if (err)
723cad31331Smrg		return err;
724cad31331Smrg
725cad31331Smrg	pci_sys->vga_target = pci_device_find_by_slot(0, pv.pv_sel.pc_bus,
726cad31331Smrg	    pv.pv_sel.pc_dev, pv.pv_sel.pc_func);
727cad31331Smrg
728cad31331Smrg	/* Count the number of VGA devices in domain 0. */
729cad31331Smrg	iter = pci_id_match_iterator_create(&vga_match);
730cad31331Smrg	if (iter == NULL)
731cad31331Smrg		return -1;
732cad31331Smrg	pci_sys->vga_count = 0;
733cad31331Smrg	while ((dev = pci_device_next(iter)) != NULL) {
734cad31331Smrg		if (dev->domain == 0)
735cad31331Smrg			pci_sys->vga_count++;
736cad31331Smrg	}
737cad31331Smrg	pci_iterator_destroy(iter);
738cad31331Smrg
739cad31331Smrg	return 0;
740cad31331Smrg}
741cad31331Smrg
742cad31331Smrgvoid
743cad31331Smrgpci_device_vgaarb_fini(void)
744cad31331Smrg{
745cad31331Smrg	struct pci_device *dev;
746cad31331Smrg	struct pci_vga pv;
747cad31331Smrg
748cad31331Smrg	if (pci_sys == NULL)
749cad31331Smrg		return;
750cad31331Smrg	dev = pci_sys->vga_target;
751cad31331Smrg	if (dev == NULL)
752cad31331Smrg		return;
753cad31331Smrg
754cad31331Smrg	pv.pv_sel.pc_bus = dev->bus;
755cad31331Smrg	pv.pv_sel.pc_dev = dev->dev;
756cad31331Smrg	pv.pv_sel.pc_func = dev->func;
757cad31331Smrg	pv.pv_lock = PCI_VGA_UNLOCK;
758cad31331Smrg	ioctl(pcifd[dev->domain], PCIOCSETVGA, &pv);
759cad31331Smrg}
760cad31331Smrg
761cad31331Smrgint
762cad31331Smrgpci_device_vgaarb_set_target(struct pci_device *dev)
763cad31331Smrg{
764cad31331Smrg	pci_sys->vga_target = dev;
765cad31331Smrg	return (0);
766cad31331Smrg}
767cad31331Smrg
768cad31331Smrgint
769cad31331Smrgpci_device_vgaarb_lock(void)
770cad31331Smrg{
771cad31331Smrg	struct pci_device *dev = pci_sys->vga_target;
772cad31331Smrg	struct pci_vga pv;
773cad31331Smrg
774cad31331Smrg	if (dev == NULL)
775cad31331Smrg		return -1;
776cad31331Smrg
777cad31331Smrg#if 0
778cad31331Smrg	if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
779cad31331Smrg		return 0;
780cad31331Smrg#else
781cad31331Smrg	if (pci_sys->vga_count == 1)
782cad31331Smrg		return 0;
783cad31331Smrg#endif
784cad31331Smrg
785cad31331Smrg	pv.pv_sel.pc_bus = dev->bus;
786cad31331Smrg	pv.pv_sel.pc_dev = dev->dev;
787cad31331Smrg	pv.pv_sel.pc_func = dev->func;
788cad31331Smrg	pv.pv_lock = PCI_VGA_LOCK;
789cad31331Smrg	return ioctl(pcifd[dev->domain], PCIOCSETVGA, &pv);
790cad31331Smrg}
791cad31331Smrg
792cad31331Smrgint
793cad31331Smrgpci_device_vgaarb_unlock(void)
794cad31331Smrg{
795cad31331Smrg	struct pci_device *dev = pci_sys->vga_target;
796cad31331Smrg	struct pci_vga pv;
797cad31331Smrg
798cad31331Smrg	if (dev == NULL)
799cad31331Smrg		return -1;
800cad31331Smrg
801cad31331Smrg#if 0
802cad31331Smrg	if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
803cad31331Smrg		return 0;
804cad31331Smrg#else
805cad31331Smrg	if (pci_sys->vga_count == 1)
806cad31331Smrg		return 0;
807cad31331Smrg#endif
808cad31331Smrg
809cad31331Smrg	pv.pv_sel.pc_bus = dev->bus;
810cad31331Smrg	pv.pv_sel.pc_dev = dev->dev;
811cad31331Smrg	pv.pv_sel.pc_func = dev->func;
812cad31331Smrg	pv.pv_lock = PCI_VGA_UNLOCK;
813cad31331Smrg	return ioctl(pcifd[dev->domain], PCIOCSETVGA, &pv);
814cad31331Smrg}
815cad31331Smrg
816cad31331Smrgint
817cad31331Smrgpci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count,
818cad31331Smrg    int *rsrc_decodes)
819cad31331Smrg{
820cad31331Smrg	*vga_count = pci_sys->vga_count;
821cad31331Smrg
822cad31331Smrg	if (dev)
823cad31331Smrg		*rsrc_decodes = dev->vgaarb_rsrc;
824cad31331Smrg
825cad31331Smrg	return 0;
826cad31331Smrg}
827cad31331Smrg
828cad31331Smrgint
829cad31331Smrgpci_device_vgaarb_decodes(int rsrc_decodes)
830cad31331Smrg{
831cad31331Smrg	struct pci_device *dev = pci_sys->vga_target;
832cad31331Smrg
833cad31331Smrg	if (dev == NULL)
834cad31331Smrg		return -1;
835cad31331Smrg
836cad31331Smrg	dev->vgaarb_rsrc = rsrc_decodes;
837cad31331Smrg	return 0;
838cad31331Smrg}
839