1153577Sjhb/*-
2153577Sjhb * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
3153577Sjhb * All rights reserved.
4153577Sjhb *
5153577Sjhb * Redistribution and use in source and binary forms, with or without
6153577Sjhb * modification, are permitted provided that the following conditions
7153577Sjhb * are met:
8153577Sjhb * 1. Redistributions of source code must retain the above copyright
9153577Sjhb *    notice, this list of conditions and the following disclaimer.
10153577Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11153577Sjhb *    notice, this list of conditions and the following disclaimer in the
12153577Sjhb *    documentation and/or other materials provided with the distribution.
13153577Sjhb *
14153577Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15153577Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16153577Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17153577Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18153577Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19153577Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20153577Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21153577Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22153577Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23153577Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24153577Sjhb * SUCH DAMAGE.
25153577Sjhb */
26153577Sjhb
27153577Sjhb#include <sys/cdefs.h>
28153577Sjhb__FBSDID("$FreeBSD: releng/10.2/sys/dev/pci/vga_pci.c 284503 2015-06-17 07:41:53Z hselasky $");
29153577Sjhb
30153577Sjhb/*
31153577Sjhb * Simple driver for PCI VGA display devices.  Drivers such as agp(4) and
32153577Sjhb * drm(4) should attach as children of this device.
33153577Sjhb *
34153577Sjhb * XXX: The vgapci name is a hack until we somehow merge the isa vga driver
35153577Sjhb * in or rename it.
36153577Sjhb */
37153577Sjhb
38153577Sjhb#include <sys/param.h>
39153577Sjhb#include <sys/bus.h>
40153577Sjhb#include <sys/kernel.h>
41153577Sjhb#include <sys/module.h>
42189373Sjhb#include <sys/rman.h>
43198251Sjkim#include <sys/sysctl.h>
44189373Sjhb#include <sys/systm.h>
45153577Sjhb
46254882Sdumbbell#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
47254882Sdumbbell#include <vm/vm.h>
48254882Sdumbbell#include <vm/pmap.h>
49254882Sdumbbell#endif
50254882Sdumbbell
51153577Sjhb#include <dev/pci/pcireg.h>
52153577Sjhb#include <dev/pci/pcivar.h>
53153577Sjhb
54189373Sjhbstruct vga_resource {
55189373Sjhb	struct resource	*vr_res;
56189373Sjhb	int	vr_refs;
57189373Sjhb};
58189373Sjhb
59183095Sjhbstruct vga_pci_softc {
60183095Sjhb	device_t	vga_msi_child;	/* Child driver using MSI. */
61249315Sjhb	struct vga_resource vga_bars[PCIR_MAX_BAR_0 + 1];
62249315Sjhb	struct vga_resource vga_bios;
63183095Sjhb};
64183095Sjhb
65198251SjkimSYSCTL_DECL(_hw_pci);
66198251Sjkim
67255571Sdumbbellstatic struct vga_resource *lookup_res(struct vga_pci_softc *sc, int rid);
68255571Sdumbbellstatic struct resource *vga_pci_alloc_resource(device_t dev, device_t child,
69255571Sdumbbell    int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
70255571Sdumbbellstatic int	vga_pci_release_resource(device_t dev, device_t child, int type,
71255571Sdumbbell    int rid, struct resource *r);
72255571Sdumbbell
73198251Sjkimint vga_pci_default_unit = -1;
74198251SjkimTUNABLE_INT("hw.pci.default_vgapci_unit", &vga_pci_default_unit);
75198964SjkimSYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN,
76198251Sjkim    &vga_pci_default_unit, -1, "Default VGA-compatible display");
77198251Sjkim
78254882Sdumbbellint
79254882Sdumbbellvga_pci_is_boot_display(device_t dev)
80254882Sdumbbell{
81259741Sdumbbell	int unit;
82259741Sdumbbell	device_t pcib;
83259741Sdumbbell	uint16_t config;
84254882Sdumbbell
85259741Sdumbbell	/* Check that the given device is a video card */
86259741Sdumbbell	if ((pci_get_class(dev) != PCIC_DISPLAY &&
87259741Sdumbbell	    (pci_get_class(dev) != PCIC_OLD ||
88259741Sdumbbell	     pci_get_subclass(dev) != PCIS_OLD_VGA)))
89259741Sdumbbell		return (0);
90259741Sdumbbell
91259741Sdumbbell	unit = device_get_unit(dev);
92259741Sdumbbell
93259741Sdumbbell	if (vga_pci_default_unit >= 0) {
94259741Sdumbbell		/*
95259741Sdumbbell		 * The boot display device was determined by a previous
96259741Sdumbbell		 * call to this function, or the user forced it using
97259741Sdumbbell		 * the hw.pci.default_vgapci_unit tunable.
98259741Sdumbbell		 */
99259741Sdumbbell		return (vga_pci_default_unit == unit);
100259741Sdumbbell	}
101259741Sdumbbell
102254882Sdumbbell	/*
103259741Sdumbbell	 * The primary video card used as a boot display must have the
104259741Sdumbbell	 * "I/O" and "Memory Address Space Decoding" bits set in its
105259741Sdumbbell	 * Command register.
106259741Sdumbbell	 *
107259741Sdumbbell	 * Furthermore, if the card is attached to a bridge, instead of
108259741Sdumbbell	 * the root PCI bus, the bridge must have the "VGA Enable" bit
109259741Sdumbbell	 * set in its Control register.
110254882Sdumbbell	 */
111259741Sdumbbell
112259741Sdumbbell	pcib = device_get_parent(device_get_parent(dev));
113259741Sdumbbell	if (device_get_devclass(device_get_parent(pcib)) ==
114259741Sdumbbell	    devclass_find("pci")) {
115259741Sdumbbell		/*
116259741Sdumbbell		 * The parent bridge is a PCI-to-PCI bridge: check the
117259741Sdumbbell		 * value of the "VGA Enable" bit.
118259741Sdumbbell		 */
119259741Sdumbbell		config = pci_read_config(pcib, PCIR_BRIDGECTL_1, 2);
120259741Sdumbbell		if ((config & PCIB_BCR_VGA_ENABLE) == 0)
121259741Sdumbbell			return (0);
122259741Sdumbbell	}
123259741Sdumbbell
124259741Sdumbbell	config = pci_read_config(dev, PCIR_COMMAND, 2);
125259741Sdumbbell	if ((config & (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN)) == 0)
126259741Sdumbbell		return (0);
127259741Sdumbbell
128284503Shselasky	/*
129284503Shselasky	 * Disable interrupts until a chipset driver is loaded for
130284503Shselasky	 * this PCI device. Else unhandled display adapter interrupts
131284503Shselasky	 * might freeze the CPU.
132284503Shselasky	 */
133284503Shselasky	pci_write_config(dev, PCIR_COMMAND, config | PCIM_CMD_INTxDIS, 2);
134284503Shselasky
135259741Sdumbbell	/* This video card is the boot display: record its unit number. */
136259741Sdumbbell	vga_pci_default_unit = unit;
137259741Sdumbbell	device_set_flags(dev, 1);
138259741Sdumbbell
139259741Sdumbbell	return (1);
140254882Sdumbbell}
141254882Sdumbbell
142254882Sdumbbellvoid *
143254882Sdumbbellvga_pci_map_bios(device_t dev, size_t *size)
144254882Sdumbbell{
145254882Sdumbbell	int rid;
146254882Sdumbbell	struct resource *res;
147254882Sdumbbell
148254882Sdumbbell#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
149254882Sdumbbell	if (vga_pci_is_boot_display(dev)) {
150254882Sdumbbell		/*
151254882Sdumbbell		 * On x86, the System BIOS copy the default display
152254882Sdumbbell		 * device's Video BIOS at a fixed location in system
153254882Sdumbbell		 * memory (0xC0000, 128 kBytes long) at boot time.
154254882Sdumbbell		 *
155254882Sdumbbell		 * We use this copy for the default boot device, because
156254882Sdumbbell		 * the original ROM may not be valid after boot.
157254882Sdumbbell		 */
158254882Sdumbbell
159254882Sdumbbell		*size = VGA_PCI_BIOS_SHADOW_SIZE;
160254882Sdumbbell		return (pmap_mapbios(VGA_PCI_BIOS_SHADOW_ADDR, *size));
161254882Sdumbbell	}
162254882Sdumbbell#endif
163254882Sdumbbell
164254882Sdumbbell	rid = PCIR_BIOS;
165255571Sdumbbell	res = vga_pci_alloc_resource(dev, NULL, SYS_RES_MEMORY, &rid, 0ul,
166255571Sdumbbell	    ~0ul, 1, RF_ACTIVE);
167254882Sdumbbell	if (res == NULL) {
168254882Sdumbbell		return (NULL);
169254882Sdumbbell	}
170254882Sdumbbell
171254882Sdumbbell	*size = rman_get_size(res);
172254882Sdumbbell	return (rman_get_virtual(res));
173254882Sdumbbell}
174254882Sdumbbell
175254882Sdumbbellvoid
176254882Sdumbbellvga_pci_unmap_bios(device_t dev, void *bios)
177254882Sdumbbell{
178255571Sdumbbell	struct vga_resource *vr;
179254882Sdumbbell
180254882Sdumbbell	if (bios == NULL) {
181254882Sdumbbell		return;
182254882Sdumbbell	}
183254882Sdumbbell
184254882Sdumbbell#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
185254882Sdumbbell	if (vga_pci_is_boot_display(dev)) {
186254882Sdumbbell		/* We mapped the BIOS shadow copy located at 0xC0000. */
187254882Sdumbbell		pmap_unmapdev((vm_offset_t)bios, VGA_PCI_BIOS_SHADOW_SIZE);
188254882Sdumbbell
189254882Sdumbbell		return;
190254882Sdumbbell	}
191254882Sdumbbell#endif
192254882Sdumbbell
193254882Sdumbbell	/*
194255571Sdumbbell	 * Look up the PCIR_BIOS resource in our softc.  It should match
195255571Sdumbbell	 * the address we returned previously.
196254882Sdumbbell	 */
197255571Sdumbbell	vr = lookup_res(device_get_softc(dev), PCIR_BIOS);
198255571Sdumbbell	KASSERT(vr->vr_res != NULL, ("vga_pci_unmap_bios: bios not mapped"));
199255571Sdumbbell	KASSERT(rman_get_virtual(vr->vr_res) == bios,
200255571Sdumbbell	    ("vga_pci_unmap_bios: mismatch"));
201255571Sdumbbell	vga_pci_release_resource(dev, NULL, SYS_RES_MEMORY, PCIR_BIOS,
202255571Sdumbbell	    vr->vr_res);
203254882Sdumbbell}
204254882Sdumbbell
205153577Sjhbstatic int
206153577Sjhbvga_pci_probe(device_t dev)
207153577Sjhb{
208153577Sjhb
209153577Sjhb	switch (pci_get_class(dev)) {
210153577Sjhb	case PCIC_DISPLAY:
211153577Sjhb		break;
212153577Sjhb	case PCIC_OLD:
213153577Sjhb		if (pci_get_subclass(dev) != PCIS_OLD_VGA)
214153577Sjhb			return (ENXIO);
215153577Sjhb		break;
216153577Sjhb	default:
217153577Sjhb		return (ENXIO);
218153577Sjhb	}
219198251Sjkim
220198251Sjkim	/* Probe default display. */
221259741Sdumbbell	vga_pci_is_boot_display(dev);
222198251Sjkim
223153577Sjhb	device_set_desc(dev, "VGA-compatible display");
224153646Sjhb	return (BUS_PROBE_GENERIC);
225153577Sjhb}
226153577Sjhb
227153577Sjhbstatic int
228153577Sjhbvga_pci_attach(device_t dev)
229153577Sjhb{
230153577Sjhb
231153577Sjhb	bus_generic_probe(dev);
232153577Sjhb
233153577Sjhb	/* Always create a drm child for now to make it easier on drm. */
234153577Sjhb	device_add_child(dev, "drm", -1);
235235846Skib	device_add_child(dev, "drmn", -1);
236153577Sjhb	bus_generic_attach(dev);
237259741Sdumbbell
238259741Sdumbbell	if (vga_pci_is_boot_display(dev))
239259741Sdumbbell		device_printf(dev, "Boot video device\n");
240259741Sdumbbell
241153577Sjhb	return (0);
242153577Sjhb}
243153577Sjhb
244153577Sjhbstatic int
245153577Sjhbvga_pci_suspend(device_t dev)
246153577Sjhb{
247153577Sjhb
248199002Sjkim	return (bus_generic_suspend(dev));
249153577Sjhb}
250153577Sjhb
251153577Sjhbstatic int
252153577Sjhbvga_pci_resume(device_t dev)
253153577Sjhb{
254153577Sjhb
255153577Sjhb	return (bus_generic_resume(dev));
256153577Sjhb}
257153577Sjhb
258153577Sjhb/* Bus interface. */
259153577Sjhb
260153577Sjhbstatic int
261153577Sjhbvga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
262153577Sjhb{
263153577Sjhb
264153577Sjhb	return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result));
265153577Sjhb}
266153577Sjhb
267153577Sjhbstatic int
268153577Sjhbvga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
269153577Sjhb{
270153577Sjhb
271153577Sjhb	return (EINVAL);
272153577Sjhb}
273153577Sjhb
274183194Srnolandstatic int
275183194Srnolandvga_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
276183194Srnoland    int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
277183194Srnoland    void **cookiep)
278183194Srnoland{
279183194Srnoland	return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
280183194Srnoland	    filter, intr, arg, cookiep));
281183194Srnoland}
282183194Srnoland
283183194Srnolandstatic int
284183194Srnolandvga_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
285183194Srnoland    void *cookie)
286183194Srnoland{
287183194Srnoland	return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
288183194Srnoland}
289183194Srnoland
290249315Sjhbstatic struct vga_resource *
291249315Sjhblookup_res(struct vga_pci_softc *sc, int rid)
292249315Sjhb{
293249315Sjhb	int bar;
294249315Sjhb
295249315Sjhb	if (rid == PCIR_BIOS)
296249315Sjhb		return (&sc->vga_bios);
297249315Sjhb	bar = PCI_RID2BAR(rid);
298249315Sjhb	if (bar >= 0 && bar <= PCIR_MAX_BAR_0)
299249315Sjhb		return (&sc->vga_bars[bar]);
300249315Sjhb	return (NULL);
301249315Sjhb}
302249315Sjhb
303153577Sjhbstatic struct resource *
304153577Sjhbvga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
305153577Sjhb    u_long start, u_long end, u_long count, u_int flags)
306153577Sjhb{
307249315Sjhb	struct vga_resource *vr;
308153577Sjhb
309189373Sjhb	switch (type) {
310189373Sjhb	case SYS_RES_MEMORY:
311189373Sjhb	case SYS_RES_IOPORT:
312189373Sjhb		/*
313189373Sjhb		 * For BARs, we cache the resource so that we only allocate it
314189373Sjhb		 * from the PCI bus once.
315189373Sjhb		 */
316249315Sjhb		vr = lookup_res(device_get_softc(dev), *rid);
317249315Sjhb		if (vr == NULL)
318189373Sjhb			return (NULL);
319249315Sjhb		if (vr->vr_res == NULL)
320249315Sjhb			vr->vr_res = bus_alloc_resource(dev, type, rid, start,
321249315Sjhb			    end, count, flags);
322249315Sjhb		if (vr->vr_res != NULL)
323249315Sjhb			vr->vr_refs++;
324249315Sjhb		return (vr->vr_res);
325189373Sjhb	}
326153577Sjhb	return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
327153577Sjhb}
328153577Sjhb
329153577Sjhbstatic int
330153577Sjhbvga_pci_release_resource(device_t dev, device_t child, int type, int rid,
331153577Sjhb    struct resource *r)
332153577Sjhb{
333249315Sjhb	struct vga_resource *vr;
334249315Sjhb	int error;
335153577Sjhb
336189373Sjhb	switch (type) {
337189373Sjhb	case SYS_RES_MEMORY:
338189373Sjhb	case SYS_RES_IOPORT:
339189373Sjhb		/*
340189373Sjhb		 * For BARs, we release the resource from the PCI bus
341189373Sjhb		 * when the last child reference goes away.
342189373Sjhb		 */
343249315Sjhb		vr = lookup_res(device_get_softc(dev), rid);
344249315Sjhb		if (vr == NULL)
345189373Sjhb			return (EINVAL);
346249315Sjhb		if (vr->vr_res == NULL)
347189373Sjhb			return (EINVAL);
348249315Sjhb		KASSERT(vr->vr_res == r, ("vga_pci resource mismatch"));
349249315Sjhb		if (vr->vr_refs > 1) {
350249315Sjhb			vr->vr_refs--;
351189373Sjhb			return (0);
352189373Sjhb		}
353249315Sjhb		KASSERT(vr->vr_refs > 0,
354189373Sjhb		    ("vga_pci resource reference count underflow"));
355189373Sjhb		error = bus_release_resource(dev, type, rid, r);
356189373Sjhb		if (error == 0) {
357249315Sjhb			vr->vr_res = NULL;
358249315Sjhb			vr->vr_refs = 0;
359189373Sjhb		}
360189373Sjhb		return (error);
361189373Sjhb	}
362189373Sjhb
363153577Sjhb	return (bus_release_resource(dev, type, rid, r));
364153577Sjhb}
365153577Sjhb
366153577Sjhb/* PCI interface. */
367153577Sjhb
368153577Sjhbstatic uint32_t
369153577Sjhbvga_pci_read_config(device_t dev, device_t child, int reg, int width)
370153577Sjhb{
371153577Sjhb
372153577Sjhb	return (pci_read_config(dev, reg, width));
373153577Sjhb}
374153577Sjhb
375153577Sjhbstatic void
376205018Sjhbvga_pci_write_config(device_t dev, device_t child, int reg,
377153577Sjhb    uint32_t val, int width)
378153577Sjhb{
379153577Sjhb
380153577Sjhb	pci_write_config(dev, reg, val, width);
381153577Sjhb}
382153577Sjhb
383153577Sjhbstatic int
384153577Sjhbvga_pci_enable_busmaster(device_t dev, device_t child)
385153577Sjhb{
386153577Sjhb
387153577Sjhb	return (pci_enable_busmaster(dev));
388153577Sjhb}
389153577Sjhb
390153577Sjhbstatic int
391153577Sjhbvga_pci_disable_busmaster(device_t dev, device_t child)
392153577Sjhb{
393153577Sjhb
394153577Sjhb	return (pci_disable_busmaster(dev));
395153577Sjhb}
396153577Sjhb
397153577Sjhbstatic int
398153577Sjhbvga_pci_enable_io(device_t dev, device_t child, int space)
399153577Sjhb{
400153577Sjhb
401153577Sjhb	device_printf(dev, "child %s requested pci_enable_io\n",
402153577Sjhb	    device_get_nameunit(child));
403153577Sjhb	return (pci_enable_io(dev, space));
404153577Sjhb}
405153577Sjhb
406153577Sjhbstatic int
407153577Sjhbvga_pci_disable_io(device_t dev, device_t child, int space)
408153577Sjhb{
409153577Sjhb
410153577Sjhb	device_printf(dev, "child %s requested pci_disable_io\n",
411153577Sjhb	    device_get_nameunit(child));
412153577Sjhb	return (pci_disable_io(dev, space));
413153577Sjhb}
414153577Sjhb
415153577Sjhbstatic int
416183095Sjhbvga_pci_get_vpd_ident(device_t dev, device_t child, const char **identptr)
417183095Sjhb{
418183095Sjhb
419183095Sjhb	return (pci_get_vpd_ident(dev, identptr));
420183095Sjhb}
421183095Sjhb
422183095Sjhbstatic int
423183095Sjhbvga_pci_get_vpd_readonly(device_t dev, device_t child, const char *kw,
424183095Sjhb    const char **vptr)
425183095Sjhb{
426183095Sjhb
427183095Sjhb	return (pci_get_vpd_readonly(dev, kw, vptr));
428183095Sjhb}
429183095Sjhb
430183095Sjhbstatic int
431153577Sjhbvga_pci_set_powerstate(device_t dev, device_t child, int state)
432153577Sjhb{
433153577Sjhb
434153577Sjhb	device_printf(dev, "child %s requested pci_set_powerstate\n",
435153577Sjhb	    device_get_nameunit(child));
436153577Sjhb	return (pci_set_powerstate(dev, state));
437153577Sjhb}
438153577Sjhb
439153577Sjhbstatic int
440153577Sjhbvga_pci_get_powerstate(device_t dev, device_t child)
441153577Sjhb{
442153577Sjhb
443153577Sjhb	device_printf(dev, "child %s requested pci_get_powerstate\n",
444153577Sjhb	    device_get_nameunit(child));
445153577Sjhb	return (pci_get_powerstate(dev));
446153577Sjhb}
447153577Sjhb
448153577Sjhbstatic int
449153577Sjhbvga_pci_assign_interrupt(device_t dev, device_t child)
450153577Sjhb{
451153577Sjhb
452153577Sjhb	device_printf(dev, "child %s requested pci_assign_interrupt\n",
453153577Sjhb	    device_get_nameunit(child));
454153577Sjhb	return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
455153577Sjhb}
456153577Sjhb
457153577Sjhbstatic int
458232472Sjhbvga_pci_find_cap(device_t dev, device_t child, int capability,
459232472Sjhb    int *capreg)
460232472Sjhb{
461232472Sjhb
462232472Sjhb	return (pci_find_cap(dev, capability, capreg));
463232472Sjhb}
464232472Sjhb
465232472Sjhbstatic int
466153577Sjhbvga_pci_find_extcap(device_t dev, device_t child, int capability,
467153577Sjhb    int *capreg)
468153577Sjhb{
469153577Sjhb
470153577Sjhb	return (pci_find_extcap(dev, capability, capreg));
471153577Sjhb}
472153577Sjhb
473183095Sjhbstatic int
474232472Sjhbvga_pci_find_htcap(device_t dev, device_t child, int capability,
475232472Sjhb    int *capreg)
476232472Sjhb{
477232472Sjhb
478232472Sjhb	return (pci_find_htcap(dev, capability, capreg));
479232472Sjhb}
480232472Sjhb
481232472Sjhbstatic int
482183095Sjhbvga_pci_alloc_msi(device_t dev, device_t child, int *count)
483183095Sjhb{
484183095Sjhb	struct vga_pci_softc *sc;
485183095Sjhb	int error;
486183095Sjhb
487183095Sjhb	sc = device_get_softc(dev);
488183095Sjhb	if (sc->vga_msi_child != NULL)
489183095Sjhb		return (EBUSY);
490183095Sjhb	error = pci_alloc_msi(dev, count);
491183095Sjhb	if (error == 0)
492183095Sjhb		sc->vga_msi_child = child;
493183095Sjhb	return (error);
494183095Sjhb}
495183095Sjhb
496183095Sjhbstatic int
497183095Sjhbvga_pci_alloc_msix(device_t dev, device_t child, int *count)
498183095Sjhb{
499183095Sjhb	struct vga_pci_softc *sc;
500183095Sjhb	int error;
501183095Sjhb
502183095Sjhb	sc = device_get_softc(dev);
503183095Sjhb	if (sc->vga_msi_child != NULL)
504183095Sjhb		return (EBUSY);
505183095Sjhb	error = pci_alloc_msix(dev, count);
506183095Sjhb	if (error == 0)
507183095Sjhb		sc->vga_msi_child = child;
508183095Sjhb	return (error);
509183095Sjhb}
510183095Sjhb
511183095Sjhbstatic int
512183095Sjhbvga_pci_remap_msix(device_t dev, device_t child, int count,
513183095Sjhb    const u_int *vectors)
514183095Sjhb{
515183095Sjhb	struct vga_pci_softc *sc;
516183095Sjhb
517183095Sjhb	sc = device_get_softc(dev);
518183095Sjhb	if (sc->vga_msi_child != child)
519183095Sjhb		return (ENXIO);
520183095Sjhb	return (pci_remap_msix(dev, count, vectors));
521183095Sjhb}
522183095Sjhb
523183095Sjhbstatic int
524183095Sjhbvga_pci_release_msi(device_t dev, device_t child)
525183095Sjhb{
526183095Sjhb	struct vga_pci_softc *sc;
527183095Sjhb	int error;
528183095Sjhb
529183095Sjhb	sc = device_get_softc(dev);
530183095Sjhb	if (sc->vga_msi_child != child)
531183095Sjhb		return (ENXIO);
532183095Sjhb	error = pci_release_msi(dev);
533183095Sjhb	if (error == 0)
534183095Sjhb		sc->vga_msi_child = NULL;
535183095Sjhb	return (error);
536183095Sjhb}
537183095Sjhb
538183095Sjhbstatic int
539183095Sjhbvga_pci_msi_count(device_t dev, device_t child)
540183095Sjhb{
541183095Sjhb
542183095Sjhb	return (pci_msi_count(dev));
543183095Sjhb}
544183095Sjhb
545183095Sjhbstatic int
546183095Sjhbvga_pci_msix_count(device_t dev, device_t child)
547183095Sjhb{
548183095Sjhb
549183095Sjhb	return (pci_msix_count(dev));
550183095Sjhb}
551183095Sjhb
552249476Skibstatic bus_dma_tag_t
553249476Skibvga_pci_get_dma_tag(device_t bus, device_t child)
554249476Skib{
555249476Skib
556249476Skib	return (bus_get_dma_tag(bus));
557249476Skib}
558249476Skib
559153577Sjhbstatic device_method_t vga_pci_methods[] = {
560153577Sjhb	/* Device interface */
561153577Sjhb	DEVMETHOD(device_probe,		vga_pci_probe),
562153577Sjhb	DEVMETHOD(device_attach,	vga_pci_attach),
563153577Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
564153577Sjhb	DEVMETHOD(device_suspend,	vga_pci_suspend),
565153577Sjhb	DEVMETHOD(device_resume,	vga_pci_resume),
566153577Sjhb
567153577Sjhb	/* Bus interface */
568153577Sjhb	DEVMETHOD(bus_read_ivar,	vga_pci_read_ivar),
569153577Sjhb	DEVMETHOD(bus_write_ivar,	vga_pci_write_ivar),
570183194Srnoland	DEVMETHOD(bus_setup_intr,	vga_pci_setup_intr),
571183194Srnoland	DEVMETHOD(bus_teardown_intr,	vga_pci_teardown_intr),
572153577Sjhb	DEVMETHOD(bus_alloc_resource,	vga_pci_alloc_resource),
573153577Sjhb	DEVMETHOD(bus_release_resource,	vga_pci_release_resource),
574153577Sjhb	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
575153577Sjhb	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
576249476Skib	DEVMETHOD(bus_get_dma_tag,	vga_pci_get_dma_tag),
577153577Sjhb
578153577Sjhb	/* PCI interface */
579153577Sjhb	DEVMETHOD(pci_read_config,	vga_pci_read_config),
580153577Sjhb	DEVMETHOD(pci_write_config,	vga_pci_write_config),
581153577Sjhb	DEVMETHOD(pci_enable_busmaster,	vga_pci_enable_busmaster),
582153577Sjhb	DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster),
583153577Sjhb	DEVMETHOD(pci_enable_io,	vga_pci_enable_io),
584153577Sjhb	DEVMETHOD(pci_disable_io,	vga_pci_disable_io),
585183095Sjhb	DEVMETHOD(pci_get_vpd_ident,	vga_pci_get_vpd_ident),
586183095Sjhb	DEVMETHOD(pci_get_vpd_readonly,	vga_pci_get_vpd_readonly),
587153577Sjhb	DEVMETHOD(pci_get_powerstate,	vga_pci_get_powerstate),
588153577Sjhb	DEVMETHOD(pci_set_powerstate,	vga_pci_set_powerstate),
589153577Sjhb	DEVMETHOD(pci_assign_interrupt,	vga_pci_assign_interrupt),
590232472Sjhb	DEVMETHOD(pci_find_cap,		vga_pci_find_cap),
591153577Sjhb	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
592232472Sjhb	DEVMETHOD(pci_find_htcap,	vga_pci_find_htcap),
593183095Sjhb	DEVMETHOD(pci_alloc_msi,	vga_pci_alloc_msi),
594183095Sjhb	DEVMETHOD(pci_alloc_msix,	vga_pci_alloc_msix),
595183095Sjhb	DEVMETHOD(pci_remap_msix,	vga_pci_remap_msix),
596183095Sjhb	DEVMETHOD(pci_release_msi,	vga_pci_release_msi),
597183095Sjhb	DEVMETHOD(pci_msi_count,	vga_pci_msi_count),
598183095Sjhb	DEVMETHOD(pci_msix_count,	vga_pci_msix_count),
599153577Sjhb
600153577Sjhb	{ 0, 0 }
601153577Sjhb};
602153577Sjhb
603153577Sjhbstatic driver_t vga_pci_driver = {
604153577Sjhb	"vgapci",
605153577Sjhb	vga_pci_methods,
606183095Sjhb	sizeof(struct vga_pci_softc),
607153577Sjhb};
608153577Sjhb
609153577Sjhbstatic devclass_t vga_devclass;
610153577Sjhb
611153577SjhbDRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0);
612