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