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