openbsd_pci.c revision 49310723
1/*
2 * Copyright (c) 2008, 2011 Mark Kettenis
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16#ifdef HAVE_CONFIG_H
17#include "config.h"
18#endif
19
20#include <sys/param.h>
21#include <sys/ioctl.h>
22#include <sys/memrange.h>
23#include <sys/mman.h>
24#include <sys/pciio.h>
25
26#include <dev/pci/pcireg.h>
27#include <dev/pci/pcidevs.h>
28
29#include <errno.h>
30#include <fcntl.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
35
36#include "pciaccess.h"
37#include "pciaccess_private.h"
38
39/*
40 * This should allow for 16 domains, which should cover everything
41 * except perhaps the really big fridge-sized sparc64 server machines
42 * that are unlikely to have any graphics hardware in them.
43 */
44static int pcifd[16];
45static int ndomains;
46
47static int aperturefd = -1;
48
49static int
50pci_read(int domain, int bus, int dev, int func, uint32_t reg, uint32_t *val)
51{
52	struct pci_io io;
53	int err;
54
55	bzero(&io, sizeof(io));
56	io.pi_sel.pc_bus = bus;
57	io.pi_sel.pc_dev = dev;
58	io.pi_sel.pc_func = func;
59	io.pi_reg = reg;
60	io.pi_width = 4;
61
62	err = ioctl(pcifd[domain], PCIOCREAD, &io);
63	if (err)
64		return (err);
65
66	*val = io.pi_data;
67
68	return 0;
69}
70
71static int
72pci_write(int domain, int bus, int dev, int func, uint32_t reg, uint32_t val)
73{
74	struct pci_io io;
75
76	bzero(&io, sizeof(io));
77	io.pi_sel.pc_bus = bus;
78	io.pi_sel.pc_dev = dev;
79	io.pi_sel.pc_func = func;
80	io.pi_reg = reg;
81	io.pi_width = 4;
82	io.pi_data = val;
83
84	return ioctl(pcifd[domain], PCIOCWRITE, &io);
85}
86
87static int
88pci_readmask(int domain, int bus, int dev, int func, uint32_t reg,
89    uint32_t *val)
90{
91	struct pci_io io;
92	int err;
93
94	bzero(&io, sizeof(io));
95	io.pi_sel.pc_bus = bus;
96	io.pi_sel.pc_dev = dev;
97	io.pi_sel.pc_func = func;
98	io.pi_reg = reg;
99	io.pi_width = 4;
100
101	err = ioctl(pcifd[domain], PCIOCREADMASK, &io);
102	if (err)
103		return (err);
104
105	*val = io.pi_data;
106
107	return 0;
108}
109
110/**
111 * Read a VGA ROM
112 *
113 */
114static int
115pci_device_openbsd_read_rom(struct pci_device *device, void *buffer)
116{
117	struct pci_device_private *priv = (struct pci_device_private *)device;
118	unsigned char *bios;
119	pciaddr_t rom_base;
120	pciaddr_t rom_size;
121	u_int32_t csr, rom;
122	int pci_rom, domain, bus, dev, func;
123
124	domain = device->domain;
125	if (domain < 0 || domain >= ndomains)
126		return ENXIO;
127
128	bus = device->bus;
129	dev = device->dev;
130	func = device->func;
131
132	if (aperturefd == -1)
133		return ENOSYS;
134
135	if (priv->base.rom_size == 0) {
136#if defined(__alpha__) || defined(__amd64__) || defined(__i386__)
137		if ((device->device_class & 0x00ffff00) ==
138		    ((PCI_CLASS_DISPLAY << 16) |
139			(PCI_SUBCLASS_DISPLAY_VGA << 8))) {
140			rom_base = 0xc0000;
141			rom_size = 0x10000;
142			pci_rom = 0;
143		} else
144#endif
145			return ENOSYS;
146	} else {
147		rom_base = priv->rom_base;
148		rom_size = priv->base.rom_size;
149		pci_rom = 1;
150
151		pci_read(domain, bus, dev, func, PCI_COMMAND_STATUS_REG, &csr);
152		pci_write(domain, bus, dev, func, PCI_COMMAND_STATUS_REG,
153		    csr | PCI_COMMAND_MEM_ENABLE);
154		pci_read(domain, bus, dev, func, PCI_ROM_REG, &rom);
155		pci_write(domain, bus, dev, func, PCI_ROM_REG,
156		    rom | PCI_ROM_ENABLE);
157	}
158
159	bios = mmap(NULL, rom_size, PROT_READ, MAP_SHARED,
160	    aperturefd, (off_t)rom_base);
161	if (bios == MAP_FAILED)
162		return errno;
163
164	memcpy(buffer, bios, rom_size);
165	munmap(bios, rom_size);
166
167	if (pci_rom) {
168		/* Restore PCI config space */
169		pci_write(domain, bus, dev, func, PCI_ROM_REG, rom);
170		pci_write(domain, bus, dev, func, PCI_COMMAND_STATUS_REG, csr);
171	}
172	return 0;
173}
174
175static int
176pci_nfuncs(int domain, int bus, int dev)
177{
178	uint32_t hdr;
179
180	if (domain < 0 || domain >= ndomains)
181		return ENXIO;
182
183	if (pci_read(domain, bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
184		return -1;
185
186	return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
187}
188
189static int
190pci_device_openbsd_map_range(struct pci_device *dev,
191    struct pci_device_mapping *map)
192{
193	struct mem_range_desc mr;
194	struct mem_range_op mo;
195	int prot = PROT_READ;
196
197	if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
198		prot |= PROT_WRITE;
199
200	map->memory = mmap(NULL, map->size, prot, MAP_SHARED, aperturefd,
201	    map->base);
202	if (map->memory == MAP_FAILED)
203		return  errno;
204#if defined(__i386__) || defined(__amd64__)
205	/* No need to set an MTRR if it's the default mode. */
206	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
207	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
208		mr.mr_base = map->base;
209		mr.mr_len = map->size;
210		mr.mr_flags = 0;
211		if (map->flags & PCI_DEV_MAP_FLAG_CACHABLE)
212			mr.mr_flags |= MDF_WRITEBACK;
213		if (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)
214			mr.mr_flags |= MDF_WRITECOMBINE;
215		strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
216
217		mo.mo_desc = &mr;
218		mo.mo_arg[0] = MEMRANGE_SET_UPDATE;
219
220		if (ioctl(aperturefd, MEMRANGE_SET, &mo))
221			(void)fprintf(stderr, "mtrr set failed: %s\n",
222			    strerror(errno));
223	}
224#endif
225	return 0;
226}
227
228static int
229pci_device_openbsd_unmap_range(struct pci_device *dev,
230    struct pci_device_mapping *map)
231{
232#if defined(__i386__) || defined(__amd64__)
233	struct mem_range_desc mr;
234	struct mem_range_op mo;
235
236	if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) ||
237	    (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) {
238		mr.mr_base = map->base;
239		mr.mr_len = map->size;
240		mr.mr_flags = MDF_UNCACHEABLE;
241		strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner));
242
243		mo.mo_desc = &mr;
244		mo.mo_arg[0] = MEMRANGE_SET_REMOVE;
245
246		(void)ioctl(aperturefd, MEMRANGE_SET, &mo);
247	}
248#endif
249	return pci_device_generic_unmap_range(dev, map);
250}
251
252static int
253pci_device_openbsd_read(struct pci_device *dev, void *data,
254    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
255{
256	struct pci_io io;
257
258	io.pi_sel.pc_bus = dev->bus;
259	io.pi_sel.pc_dev = dev->dev;
260	io.pi_sel.pc_func = dev->func;
261
262	*bytes_read = 0;
263	while (size > 0) {
264		int toread = MIN(size, 4 - (offset & 0x3));
265
266		io.pi_reg = (offset & ~0x3);
267		io.pi_width = 4;
268
269		if (ioctl(pcifd[dev->domain], PCIOCREAD, &io) == -1)
270			return errno;
271
272		io.pi_data = htole32(io.pi_data);
273		io.pi_data >>= ((offset & 0x3) * 8);
274
275		memcpy(data, &io.pi_data, toread);
276
277		offset += toread;
278		data = (char *)data + toread;
279		size -= toread;
280		*bytes_read += toread;
281	}
282
283	return 0;
284}
285
286static int
287pci_device_openbsd_write(struct pci_device *dev, const void *data,
288    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
289{
290	struct pci_io io;
291
292	if ((offset % 4) != 0 || (size % 4) != 0)
293		return EINVAL;
294
295	io.pi_sel.pc_bus = dev->bus;
296	io.pi_sel.pc_dev = dev->dev;
297	io.pi_sel.pc_func = dev->func;
298
299	*bytes_written = 0;
300	while (size > 0) {
301		io.pi_reg = offset;
302		io.pi_width = 4;
303		memcpy(&io.pi_data, data, 4);
304
305		if (ioctl(pcifd[dev->domain], PCIOCWRITE, &io) == -1)
306			return errno;
307
308		offset += 4;
309		data = (char *)data + 4;
310		size -= 4;
311		*bytes_written += 4;
312	}
313
314	return 0;
315}
316
317static void
318pci_system_openbsd_destroy(void)
319{
320	int domain;
321
322	for (domain = 0; domain < ndomains; domain++)
323		close(pcifd[domain]);
324	ndomains = 0;
325}
326
327static int
328pci_device_openbsd_probe(struct pci_device *device)
329{
330	struct pci_device_private *priv = (struct pci_device_private *)device;
331	struct pci_mem_region *region;
332	uint64_t reg64, size64;
333	uint32_t bar, reg, size;
334	int domain, bus, dev, func, err;
335
336	domain = device->domain;
337	bus = device->bus;
338	dev = device->dev;
339	func = device->func;
340
341	err = pci_read(domain, bus, dev, func, PCI_BHLC_REG, &reg);
342	if (err)
343		return err;
344
345	priv->header_type = PCI_HDRTYPE_TYPE(reg);
346	if (priv->header_type != 0)
347		return 0;
348
349	region = device->regions;
350	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
351	     bar += sizeof(uint32_t), region++) {
352		err = pci_read(domain, bus, dev, func, bar, &reg);
353		if (err)
354			return err;
355
356		/* Probe the size of the region. */
357		err = pci_readmask(domain, bus, dev, func, bar, &size);
358		if (err)
359			return err;
360
361		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
362			region->is_IO = 1;
363			region->base_addr = PCI_MAPREG_IO_ADDR(reg);
364			region->size = PCI_MAPREG_IO_SIZE(size);
365		} else {
366			if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
367				region->is_prefetchable = 1;
368			switch(PCI_MAPREG_MEM_TYPE(reg)) {
369			case PCI_MAPREG_MEM_TYPE_32BIT:
370			case PCI_MAPREG_MEM_TYPE_32BIT_1M:
371				region->base_addr = PCI_MAPREG_MEM_ADDR(reg);
372				region->size = PCI_MAPREG_MEM_SIZE(size);
373				break;
374			case PCI_MAPREG_MEM_TYPE_64BIT:
375				region->is_64 = 1;
376
377				reg64 = reg;
378				size64 = size;
379
380				bar += sizeof(uint32_t);
381
382				err = pci_read(domain, bus, dev, func, bar, &reg);
383				if (err)
384					return err;
385				reg64 |= (uint64_t)reg << 32;
386
387				err = pci_readmask(domain, bus, dev, func, bar, &size);
388				if (err)
389					return err;
390				size64 |= (uint64_t)size << 32;
391
392				region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64);
393				region->size = PCI_MAPREG_MEM64_SIZE(size64);
394				region++;
395				break;
396			}
397		}
398	}
399
400	/* Probe expansion ROM if present */
401	err = pci_read(domain, bus, dev, func, PCI_ROM_REG, &reg);
402	if (err)
403		return err;
404	if (reg != 0) {
405		err = pci_write(domain, bus, dev, func, PCI_ROM_REG, ~PCI_ROM_ENABLE);
406		if (err)
407			return err;
408		pci_read(domain, bus, dev, func, PCI_ROM_REG, &size);
409		pci_write(domain, bus, dev, func, PCI_ROM_REG, reg);
410
411		if (PCI_ROM_ADDR(reg) != 0) {
412			priv->rom_base = PCI_ROM_ADDR(reg);
413			device->rom_size = PCI_ROM_SIZE(size);
414		}
415	}
416	return 0;
417}
418
419#if defined(__i386__) || defined(__amd64__)
420#include <machine/sysarch.h>
421#include <machine/pio.h>
422#endif
423
424static struct pci_io_handle *
425pci_device_openbsd_open_legacy_io(struct pci_io_handle *ret,
426    struct pci_device *dev, pciaddr_t base, pciaddr_t size)
427{
428#if defined(__i386__)
429	struct i386_iopl_args ia;
430
431	ia.iopl = 1;
432	if (sysarch(I386_IOPL, &ia))
433		return NULL;
434
435	ret->base = base;
436	ret->size = size;
437	ret->is_legacy = 1;
438	return ret;
439#elif defined(__amd64__)
440	struct amd64_iopl_args ia;
441
442	ia.iopl = 1;
443	if (sysarch(AMD64_IOPL, &ia))
444		return NULL;
445
446	ret->base = base;
447	ret->size = size;
448	ret->is_legacy = 1;
449	return ret;
450#elif defined(PCI_MAGIC_IO_RANGE)
451	ret->memory = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
452	    aperturefd, PCI_MAGIC_IO_RANGE + base);
453	if (ret->memory == MAP_FAILED)
454		return NULL;
455
456	ret->base = base;
457	ret->size = size;
458	ret->is_legacy = 1;
459	return ret;
460#else
461	return NULL;
462#endif
463}
464
465static uint32_t
466pci_device_openbsd_read32(struct pci_io_handle *handle, uint32_t reg)
467{
468#if defined(__i386__) || defined(__amd64__)
469	return inl(handle->base + reg);
470#else
471	return *(uint32_t *)((uintptr_t)handle->memory + reg);
472#endif
473}
474
475static uint16_t
476pci_device_openbsd_read16(struct pci_io_handle *handle, uint32_t reg)
477{
478#if defined(__i386__) || defined(__amd64__)
479	return inw(handle->base + reg);
480#else
481	return *(uint16_t *)((uintptr_t)handle->memory + reg);
482#endif
483}
484
485static uint8_t
486pci_device_openbsd_read8(struct pci_io_handle *handle, uint32_t reg)
487{
488#if defined(__i386__) || defined(__amd64__)
489	return inb(handle->base + reg);
490#else
491	return *(uint8_t *)((uintptr_t)handle->memory + reg);
492#endif
493}
494
495static void
496pci_device_openbsd_write32(struct pci_io_handle *handle, uint32_t reg,
497    uint32_t data)
498{
499#if defined(__i386__) || defined(__amd64__)
500	outl(handle->base + reg, data);
501#else
502	*(uint16_t *)((uintptr_t)handle->memory + reg) = data;
503#endif
504}
505
506static void
507pci_device_openbsd_write16(struct pci_io_handle *handle, uint32_t reg,
508    uint16_t data)
509{
510#if defined(__i386__) || defined(__amd64__)
511	outw(handle->base + reg, data);
512#else
513	*(uint8_t *)((uintptr_t)handle->memory + reg) = data;
514#endif
515}
516
517static void
518pci_device_openbsd_write8(struct pci_io_handle *handle, uint32_t reg,
519    uint8_t data)
520{
521#if defined(__i386__) || defined(__amd64__)
522	outb(handle->base + reg, data);
523#else
524	*(uint32_t *)((uintptr_t)handle->memory + reg) = data;
525#endif
526}
527
528static int
529pci_device_openbsd_map_legacy(struct pci_device *dev, pciaddr_t base,
530    pciaddr_t size, unsigned map_flags, void **addr)
531{
532	struct pci_device_mapping map;
533	int err;
534
535	map.base = base;
536	map.size = size;
537	map.flags = map_flags;
538	map.memory = NULL;
539	err = pci_device_openbsd_map_range(dev, &map);
540	*addr = map.memory;
541
542	return err;
543}
544
545static int
546pci_device_openbsd_unmap_legacy(struct pci_device *dev, void *addr,
547    pciaddr_t size)
548{
549	struct pci_device_mapping map;
550
551	map.memory = addr;
552	map.size = size;
553	map.flags = 0;
554	return pci_device_openbsd_unmap_range(dev, &map);
555}
556
557static const struct pci_system_methods openbsd_pci_methods = {
558	pci_system_openbsd_destroy,
559	NULL,
560	pci_device_openbsd_read_rom,
561	pci_device_openbsd_probe,
562	pci_device_openbsd_map_range,
563	pci_device_openbsd_unmap_range,
564	pci_device_openbsd_read,
565	pci_device_openbsd_write,
566	pci_fill_capabilities_generic,
567	NULL,
568	NULL,
569	NULL,
570	NULL,
571	pci_device_openbsd_open_legacy_io,
572	NULL,
573	pci_device_openbsd_read32,
574	pci_device_openbsd_read16,
575	pci_device_openbsd_read8,
576	pci_device_openbsd_write32,
577	pci_device_openbsd_write16,
578	pci_device_openbsd_write8,
579	pci_device_openbsd_map_legacy,
580	pci_device_openbsd_unmap_legacy
581};
582
583int
584pci_system_openbsd_create(void)
585{
586	struct pci_device_private *device;
587	int domain, bus, dev, func, ndevs, nfuncs;
588	char path[MAXPATHLEN];
589	uint32_t reg;
590
591	if (ndomains > 0)
592		return 0;
593
594	for (domain = 0; domain < sizeof(pcifd) / sizeof(pcifd[0]); domain++) {
595		snprintf(path, sizeof(path), "/dev/pci%d", domain);
596	        pcifd[domain] = open(path, O_RDWR | O_CLOEXEC);
597		if (pcifd[domain] == -1)
598			break;
599		ndomains++;
600	}
601
602	if (ndomains == 0)
603		return ENXIO;
604
605	pci_sys = calloc(1, sizeof(struct pci_system));
606	if (pci_sys == NULL) {
607		for (domain = 0; domain < ndomains; domain++)
608			close(pcifd[domain]);
609		ndomains = 0;
610		return ENOMEM;
611	}
612
613	pci_sys->methods = &openbsd_pci_methods;
614
615	ndevs = 0;
616	for (domain = 0; domain < ndomains; domain++) {
617		for (bus = 0; bus < 256; bus++) {
618			for (dev = 0; dev < 32; dev++) {
619				nfuncs = pci_nfuncs(domain, bus, dev);
620				for (func = 0; func < nfuncs; func++) {
621					if (pci_read(domain, bus, dev, func,
622					    PCI_ID_REG, &reg) != 0)
623						continue;
624					if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
625					    PCI_VENDOR(reg) == 0)
626						continue;
627
628					ndevs++;
629				}
630			}
631		}
632	}
633
634	pci_sys->num_devices = ndevs;
635	pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
636	if (pci_sys->devices == NULL) {
637		free(pci_sys);
638		pci_sys = NULL;
639		for (domain = 0; domain < ndomains; domain++)
640			close(pcifd[domain]);
641		ndomains = 0;
642		return ENOMEM;
643	}
644
645	device = pci_sys->devices;
646	for (domain = 0; domain < ndomains; domain++) {
647		for (bus = 0; bus < 256; bus++) {
648			for (dev = 0; dev < 32; dev++) {
649				nfuncs = pci_nfuncs(domain, bus, dev);
650				for (func = 0; func < nfuncs; func++) {
651					if (pci_read(domain, bus, dev, func,
652					    PCI_ID_REG, &reg) != 0)
653						continue;
654					if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
655					    PCI_VENDOR(reg) == 0)
656						continue;
657
658					device->base.domain = domain;
659					device->base.bus = bus;
660					device->base.dev = dev;
661					device->base.func = func;
662					device->base.vendor_id = PCI_VENDOR(reg);
663					device->base.device_id = PCI_PRODUCT(reg);
664
665					if (pci_read(domain, bus, dev, func,
666					    PCI_CLASS_REG, &reg) != 0)
667						continue;
668
669					device->base.device_class =
670					    PCI_INTERFACE(reg) |
671					    PCI_CLASS(reg) << 16 |
672					    PCI_SUBCLASS(reg) << 8;
673					device->base.revision = PCI_REVISION(reg);
674
675					if (pci_read(domain, bus, dev, func,
676					    PCI_SUBVEND_0, &reg) != 0)
677						continue;
678
679					device->base.subvendor_id = PCI_VENDOR(reg);
680					device->base.subdevice_id = PCI_PRODUCT(reg);
681
682					device->base.vgaarb_rsrc =
683					    VGA_ARB_RSRC_LEGACY_IO |
684					    VGA_ARB_RSRC_LEGACY_MEM;
685
686					device++;
687				}
688			}
689		}
690	}
691
692	return 0;
693}
694
695void
696pci_system_openbsd_init_dev_mem(int fd)
697{
698	aperturefd = fd;
699}
700
701int
702pci_device_vgaarb_init(void)
703{
704	struct pci_device *dev = pci_sys->vga_target;
705	struct pci_device_iterator *iter;
706	struct pci_id_match vga_match = {
707		PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
708		(PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8),
709		0x00ffff00
710	};
711	struct pci_vga pv;
712	int err;
713
714	pv.pv_sel.pc_bus = 0;
715	pv.pv_sel.pc_dev = 0;
716	pv.pv_sel.pc_func = 0;
717	err = ioctl(pcifd[0], PCIOCGETVGA, &pv);
718	if (err)
719		return err;
720
721	pci_sys->vga_target = pci_device_find_by_slot(0, pv.pv_sel.pc_bus,
722	    pv.pv_sel.pc_dev, pv.pv_sel.pc_func);
723
724	/* Count the number of VGA devices in domain 0. */
725	iter = pci_id_match_iterator_create(&vga_match);
726	if (iter == NULL)
727		return -1;
728	pci_sys->vga_count = 0;
729	while ((dev = pci_device_next(iter)) != NULL) {
730		if (dev->domain == 0)
731			pci_sys->vga_count++;
732	}
733	pci_iterator_destroy(iter);
734
735	return 0;
736}
737
738void
739pci_device_vgaarb_fini(void)
740{
741	struct pci_device *dev;
742	struct pci_vga pv;
743
744	if (pci_sys == NULL)
745		return;
746	dev = pci_sys->vga_target;
747	if (dev == NULL)
748		return;
749
750	pv.pv_sel.pc_bus = dev->bus;
751	pv.pv_sel.pc_dev = dev->dev;
752	pv.pv_sel.pc_func = dev->func;
753	pv.pv_lock = PCI_VGA_UNLOCK;
754	ioctl(pcifd[dev->domain], PCIOCSETVGA, &pv);
755}
756
757int
758pci_device_vgaarb_set_target(struct pci_device *dev)
759{
760	pci_sys->vga_target = dev;
761	return (0);
762}
763
764int
765pci_device_vgaarb_lock(void)
766{
767	struct pci_device *dev = pci_sys->vga_target;
768	struct pci_vga pv;
769
770	if (dev == NULL)
771		return -1;
772
773#if 0
774	if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
775		return 0;
776#else
777	if (pci_sys->vga_count == 1)
778		return 0;
779#endif
780
781	pv.pv_sel.pc_bus = dev->bus;
782	pv.pv_sel.pc_dev = dev->dev;
783	pv.pv_sel.pc_func = dev->func;
784	pv.pv_lock = PCI_VGA_LOCK;
785	return ioctl(pcifd[dev->domain], PCIOCSETVGA, &pv);
786}
787
788int
789pci_device_vgaarb_unlock(void)
790{
791	struct pci_device *dev = pci_sys->vga_target;
792	struct pci_vga pv;
793
794	if (dev == NULL)
795		return -1;
796
797#if 0
798	if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
799		return 0;
800#else
801	if (pci_sys->vga_count == 1)
802		return 0;
803#endif
804
805	pv.pv_sel.pc_bus = dev->bus;
806	pv.pv_sel.pc_dev = dev->dev;
807	pv.pv_sel.pc_func = dev->func;
808	pv.pv_lock = PCI_VGA_UNLOCK;
809	return ioctl(pcifd[dev->domain], PCIOCSETVGA, &pv);
810}
811
812int
813pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count,
814    int *rsrc_decodes)
815{
816	*vga_count = pci_sys->vga_count;
817
818	if (dev)
819		*rsrc_decodes = dev->vgaarb_rsrc;
820
821	return 0;
822}
823
824int
825pci_device_vgaarb_decodes(int rsrc_decodes)
826{
827	struct pci_device *dev = pci_sys->vga_target;
828
829	if (dev == NULL)
830		return -1;
831
832	dev->vgaarb_rsrc = rsrc_decodes;
833	return 0;
834}
835