vga_pci.c revision 279494
14Srgrimes/*-
24Srgrimes * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
3295Sjtc * All rights reserved.
44Srgrimes *
5295Sjtc * Redistribution and use in source and binary forms, with or without
6295Sjtc * modification, are permitted provided that the following conditions
750471Speter * are met:
84Srgrimes * 1. Redistributions of source code must retain the above copyright
9468Sjtc *    notice, this list of conditions and the following disclaimer.
1062926Sse * 2. Redistributions in binary form must reproduce the above copyright
1192979Swollman *    notice, this list of conditions and the following disclaimer in the
1292979Swollman *    documentation and/or other materials provided with the distribution.
1392979Swollman *
1492979Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1592979Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1692979Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1792979Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
184Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
194Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
204Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2162926Sse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2292979Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2331Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2492979Swollman * SUCH DAMAGE.
2592979Swollman */
2692979Swollman
2792979Swollman#include <sys/cdefs.h>
2892979Swollman__FBSDID("$FreeBSD: head/sys/dev/pci/vga_pci.c 279494 2015-03-01 20:54:29Z dumbbell $");
2992979Swollman
304Srgrimes/*
3112378Sjoerg * Simple driver for PCI VGA display devices.  Drivers such as agp(4) and
324Srgrimes * drm(4) should attach as children of this device.
3331Salm *
344Srgrimes * XXX: The vgapci name is a hack until we somehow merge the isa vga driver
354Srgrimes * in or rename it.
364Srgrimes */
374Srgrimes
3892979Swollman#include <sys/param.h>
394Srgrimes#include <sys/bus.h>
4031Salm#include <sys/kernel.h>
414Srgrimes#include <sys/module.h>
424Srgrimes#include <sys/rman.h>
434Srgrimes#include <sys/sysctl.h>
4492979Swollman#include <sys/systm.h>
4592979Swollman
4692979Swollman#if defined(__amd64__) || defined(__i386__)
4792979Swollman#include <vm/vm.h>
4890109Simp#include <vm/pmap.h>
4990109Simp#endif
5090109Simp
5192979Swollman#include <dev/pci/pcireg.h>
5290109Simp#include <dev/pci/pcivar.h>
5390109Simp
5490109Simp#include <compat/x86bios/x86bios.h> /* To re-POST the card. */
5590109Simp
5690109Simpstruct vga_resource {
5790109Simp	struct resource	*vr_res;
5890109Simp	int	vr_refs;
5990109Simp};
6090109Simp
6190109Simpstruct vga_pci_softc {
6290109Simp	device_t	vga_msi_child;	/* Child driver using MSI. */
6390109Simp	struct vga_resource vga_bars[PCIR_MAX_BAR_0 + 1];
6490109Simp	struct vga_resource vga_bios;
6590109Simp};
6690109Simp
6792979SwollmanSYSCTL_DECL(_hw_pci);
6890109Simp
6990109Simpstatic struct vga_resource *lookup_res(struct vga_pci_softc *sc, int rid);
7090109Simpstatic struct resource *vga_pci_alloc_resource(device_t dev, device_t child,
7190109Simp    int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
7277244Skrisstatic int	vga_pci_release_resource(device_t dev, device_t child, int type,
734Srgrimes    int rid, struct resource *r);
744Srgrimes
754Srgrimesint vga_pci_default_unit = -1;
764SrgrimesSYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN,
774Srgrimes    &vga_pci_default_unit, -1, "Default VGA-compatible display");
784Srgrimes
794Srgrimesint
804Srgrimesvga_pci_is_boot_display(device_t dev)
814Srgrimes{
824Srgrimes	int unit;
834Srgrimes	device_t pcib;
844Srgrimes	uint16_t config;
854Srgrimes
864Srgrimes	/* Check that the given device is a video card */
874Srgrimes	if ((pci_get_class(dev) != PCIC_DISPLAY &&
884Srgrimes	    (pci_get_class(dev) != PCIC_OLD ||
894Srgrimes	     pci_get_subclass(dev) != PCIS_OLD_VGA)))
904Srgrimes		return (0);
914Srgrimes
924Srgrimes	unit = device_get_unit(dev);
934Srgrimes
944Srgrimes	if (vga_pci_default_unit >= 0) {
954Srgrimes		/*
964Srgrimes		 * The boot display device was determined by a previous
974Srgrimes		 * call to this function, or the user forced it using
984Srgrimes		 * the hw.pci.default_vgapci_unit tunable.
994Srgrimes		 */
1004Srgrimes		return (vga_pci_default_unit == unit);
1014Srgrimes	}
1024Srgrimes
1034Srgrimes	/*
1044Srgrimes	 * The primary video card used as a boot display must have the
1054Srgrimes	 * "I/O" and "Memory Address Space Decoding" bits set in its
1064Srgrimes	 * Command register.
1074Srgrimes	 *
1084Srgrimes	 * Furthermore, if the card is attached to a bridge, instead of
1094Srgrimes	 * the root PCI bus, the bridge must have the "VGA Enable" bit
1104Srgrimes	 * set in its Control register.
1114Srgrimes	 */
1124Srgrimes
1134Srgrimes	pcib = device_get_parent(device_get_parent(dev));
1144Srgrimes	if (device_get_devclass(device_get_parent(pcib)) ==
1154Srgrimes	    devclass_find("pci")) {
1164Srgrimes		/*
11792979Swollman		 * The parent bridge is a PCI-to-PCI bridge: check the
1184Srgrimes		 * value of the "VGA Enable" bit.
1194Srgrimes		 */
1204Srgrimes		config = pci_read_config(pcib, PCIR_BRIDGECTL_1, 2);
1214Srgrimes		if ((config & PCIB_BCR_VGA_ENABLE) == 0)
1224Srgrimes			return (0);
12392979Swollman	}
1244Srgrimes
1254Srgrimes	config = pci_read_config(dev, PCIR_COMMAND, 2);
1264Srgrimes	if ((config & (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN)) == 0)
1274Srgrimes		return (0);
1284Srgrimes
1294Srgrimes	/* This video card is the boot display: record its unit number. */
1304Srgrimes	vga_pci_default_unit = unit;
1314Srgrimes	device_set_flags(dev, 1);
13290109Simp
1334Srgrimes	return (1);
1344Srgrimes}
13592979Swollman
1364Srgrimesvoid *
1374Srgrimesvga_pci_map_bios(device_t dev, size_t *size)
1384Srgrimes{
13992979Swollman	int rid;
1404Srgrimes	struct resource *res;
1414Srgrimes
14292979Swollman#if defined(__amd64__) || defined(__i386__)
14392979Swollman	if (vga_pci_is_boot_display(dev)) {
14492979Swollman		/*
14592979Swollman		 * On x86, the System BIOS copy the default display
14692979Swollman		 * device's Video BIOS at a fixed location in system
14792979Swollman		 * memory (0xC0000, 128 kBytes long) at boot time.
14892979Swollman		 *
14992979Swollman		 * We use this copy for the default boot device, because
15092979Swollman		 * the original ROM may not be valid after boot.
15192979Swollman		 */
15292979Swollman
15392979Swollman		*size = VGA_PCI_BIOS_SHADOW_SIZE;
15492979Swollman		return (pmap_mapbios(VGA_PCI_BIOS_SHADOW_ADDR, *size));
15592979Swollman	}
15692979Swollman#endif
15792979Swollman
1589909Sjoerg	rid = PCIR_BIOS;
15992979Swollman	res = vga_pci_alloc_resource(dev, NULL, SYS_RES_MEMORY, &rid, 0ul,
16092979Swollman	    ~0ul, 1, RF_ACTIVE);
16192979Swollman	if (res == NULL) {
16212378Sjoerg		return (NULL);
1639909Sjoerg	}
1644Srgrimes
1654Srgrimes	*size = rman_get_size(res);
1664Srgrimes	return (rman_get_virtual(res));
1674Srgrimes}
1684Srgrimes
16990109Simpvoid
1704Srgrimesvga_pci_unmap_bios(device_t dev, void *bios)
17112378Sjoerg{
1724Srgrimes	struct vga_resource *vr;
1734Srgrimes
1744Srgrimes	if (bios == NULL) {
1754Srgrimes		return;
17692979Swollman	}
17790109Simp
1784Srgrimes#if defined(__amd64__) || defined(__i386__)
17992979Swollman	if (vga_pci_is_boot_display(dev)) {
1804Srgrimes		/* We mapped the BIOS shadow copy located at 0xC0000. */
1814Srgrimes		pmap_unmapdev((vm_offset_t)bios, VGA_PCI_BIOS_SHADOW_SIZE);
1824Srgrimes
1834Srgrimes		return;
18412378Sjoerg	}
18512378Sjoerg#endif
1864Srgrimes
18712378Sjoerg	/*
18863755Sse	 * Look up the PCIR_BIOS resource in our softc.  It should match
18992979Swollman	 * the address we returned previously.
19092979Swollman	 */
19192979Swollman	vr = lookup_res(device_get_softc(dev), PCIR_BIOS);
19292979Swollman	KASSERT(vr->vr_res != NULL, ("vga_pci_unmap_bios: bios not mapped"));
1934Srgrimes	KASSERT(rman_get_virtual(vr->vr_res) == bios,
19412378Sjoerg	    ("vga_pci_unmap_bios: mismatch"));
1954Srgrimes	vga_pci_release_resource(dev, NULL, SYS_RES_MEMORY, PCIR_BIOS,
1964Srgrimes	    vr->vr_res);
1974Srgrimes}
1984Srgrimes
1994Srgrimesint
20090109Simpvga_pci_repost(device_t dev)
2014Srgrimes{
2024Srgrimes#if defined(__amd64__) || (defined(__i386__) && !defined(PC98))
2034Srgrimes	x86regs_t regs;
20412378Sjoerg
2054Srgrimes	if (!vga_pci_is_boot_display(dev))
2064Srgrimes		return (EINVAL);
20792979Swollman
20892979Swollman	if (x86bios_get_orm(VGA_PCI_BIOS_SHADOW_ADDR) == NULL)
20992979Swollman		return (ENOTSUP);
21092979Swollman
21192979Swollman	x86bios_init_regs(&regs);
21292979Swollman
21392979Swollman	regs.R_AH = pci_get_bus(dev);
21492979Swollman	regs.R_AL = (pci_get_slot(dev) << 3) | (pci_get_function(dev) & 0x07);
21592979Swollman	regs.R_DL = 0x80;
2164Srgrimes
21792979Swollman	device_printf(dev, "REPOSTing\n");
2184Srgrimes	x86bios_call(&regs, X86BIOS_PHYSTOSEG(VGA_PCI_BIOS_SHADOW_ADDR + 3),
2194Srgrimes	    X86BIOS_PHYSTOOFF(VGA_PCI_BIOS_SHADOW_ADDR + 3));
2204Srgrimes
2214Srgrimes	x86bios_get_intr(0x10);
2224Srgrimes
2234Srgrimes	return (0);
22490109Simp#else
2254Srgrimes	return (ENOTSUP);
22612378Sjoerg#endif
2274Srgrimes}
2284Srgrimes
2294Srgrimesstatic int
2304Srgrimesvga_pci_probe(device_t dev)
2314Srgrimes{
23290109Simp
2334Srgrimes	switch (pci_get_class(dev)) {
2344Srgrimes	case PCIC_DISPLAY:
2354Srgrimes		break;
2364Srgrimes	case PCIC_OLD:
2374Srgrimes		if (pci_get_subclass(dev) != PCIS_OLD_VGA)
2384Srgrimes			return (ENXIO);
2394Srgrimes		break;
2404Srgrimes	default:
2414Srgrimes		return (ENXIO);
2424Srgrimes	}
2434Srgrimes
2444Srgrimes	/* Probe default display. */
2454Srgrimes	vga_pci_is_boot_display(dev);
2464Srgrimes
2474Srgrimes	device_set_desc(dev, "VGA-compatible display");
2484Srgrimes	return (BUS_PROBE_GENERIC);
2494Srgrimes}
2504Srgrimes
2514Srgrimesstatic int
2524Srgrimesvga_pci_attach(device_t dev)
2534Srgrimes{
2544Srgrimes
2554Srgrimes	bus_generic_probe(dev);
2564Srgrimes
25790109Simp	/* Always create a drm child for now to make it easier on drm. */
2584Srgrimes	device_add_child(dev, "drm", -1);
2594Srgrimes	device_add_child(dev, "drmn", -1);
2604Srgrimes	bus_generic_attach(dev);
2614Srgrimes
262181Sconklin	if (vga_pci_is_boot_display(dev))
2634Srgrimes		device_printf(dev, "Boot video device\n");
2644Srgrimes
2654Srgrimes	return (0);
2664Srgrimes}
26712378Sjoerg
26892979Swollmanstatic int
2694Srgrimesvga_pci_suspend(device_t dev)
27092979Swollman{
27192979Swollman
272468Sjtc	return (bus_generic_suspend(dev));
27392979Swollman}
27492979Swollman
27592979Swollmanstatic int
27692979Swollmanvga_pci_resume(device_t dev)
27792979Swollman{
27892979Swollman
279468Sjtc	return (bus_generic_resume(dev));
28092979Swollman}
2814Srgrimes
28292979Swollman/* Bus interface. */
2834Srgrimes
2844Srgrimesstatic int
28592979Swollmanvga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
2864Srgrimes{
28792979Swollman
2884Srgrimes	return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result));
28992979Swollman}
2904Srgrimes
2914Srgrimesstatic int
2924Srgrimesvga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
29390109Simp{
2944Srgrimes
29592979Swollman	return (EINVAL);
2964Srgrimes}
2974Srgrimes
2984Srgrimesstatic int
2994Srgrimesvga_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
30090109Simp    int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
3014Srgrimes    void **cookiep)
3024Srgrimes{
3034Srgrimes	return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
3044Srgrimes	    filter, intr, arg, cookiep));
3054Srgrimes}
3064Srgrimes
3074Srgrimesstatic int
3084Srgrimesvga_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
3094Srgrimes    void *cookie)
3104Srgrimes{
3114Srgrimes	return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
31290109Simp}
3134Srgrimes
3144Srgrimesstatic struct vga_resource *
3154Srgrimeslookup_res(struct vga_pci_softc *sc, int rid)
3164Srgrimes{
31792979Swollman	int bar;
3184Srgrimes
3194Srgrimes	if (rid == PCIR_BIOS)
3204Srgrimes		return (&sc->vga_bios);
3214Srgrimes	bar = PCI_RID2BAR(rid);
3224Srgrimes	if (bar >= 0 && bar <= PCIR_MAX_BAR_0)
3234Srgrimes		return (&sc->vga_bars[bar]);
3244Srgrimes	return (NULL);
32590109Simp}
3264Srgrimes
3274Srgrimesstatic struct resource *
3284Srgrimesvga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
3294Srgrimes    u_long start, u_long end, u_long count, u_int flags)
3304Srgrimes{
3314Srgrimes	struct vga_resource *vr;
33292979Swollman
3334Srgrimes	switch (type) {
33412378Sjoerg	case SYS_RES_MEMORY:
33512378Sjoerg	case SYS_RES_IOPORT:
33692979Swollman		/*
3374Srgrimes		 * For BARs, we cache the resource so that we only allocate it
3384Srgrimes		 * from the PCI bus once.
3394Srgrimes		 */
3404Srgrimes		vr = lookup_res(device_get_softc(dev), *rid);
3414Srgrimes		if (vr == NULL)
3424Srgrimes			return (NULL);
3434Srgrimes		if (vr->vr_res == NULL)
3444Srgrimes			vr->vr_res = bus_alloc_resource(dev, type, rid, start,
34590109Simp			    end, count, flags);
3464Srgrimes		if (vr->vr_res != NULL)
3474Srgrimes			vr->vr_refs++;
3484Srgrimes		return (vr->vr_res);
3494Srgrimes	}
3504Srgrimes	return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
3514Srgrimes}
35292979Swollman
3534Srgrimesstatic int
35412378Sjoergvga_pci_release_resource(device_t dev, device_t child, int type, int rid,
35512378Sjoerg    struct resource *r)
35692979Swollman{
3574Srgrimes	struct vga_resource *vr;
3584Srgrimes	int error;
3594Srgrimes
3604Srgrimes	switch (type) {
3614Srgrimes	case SYS_RES_MEMORY:
3624Srgrimes	case SYS_RES_IOPORT:
3634Srgrimes		/*
3644Srgrimes		 * For BARs, we release the resource from the PCI bus
36590109Simp		 * when the last child reference goes away.
3664Srgrimes		 */
3674Srgrimes		vr = lookup_res(device_get_softc(dev), rid);
3684Srgrimes		if (vr == NULL)
3694Srgrimes			return (EINVAL);
3704Srgrimes		if (vr->vr_res == NULL)
3714Srgrimes			return (EINVAL);
37292979Swollman		KASSERT(vr->vr_res == r, ("vga_pci resource mismatch"));
3734Srgrimes		if (vr->vr_refs > 1) {
37412378Sjoerg			vr->vr_refs--;
37512378Sjoerg			return (0);
37692979Swollman		}
3774Srgrimes		KASSERT(vr->vr_refs > 0,
3784Srgrimes		    ("vga_pci resource reference count underflow"));
3794Srgrimes		error = bus_release_resource(dev, type, rid, r);
3804Srgrimes		if (error == 0) {
3814Srgrimes			vr->vr_res = NULL;
3824Srgrimes			vr->vr_refs = 0;
3834Srgrimes		}
3844Srgrimes		return (error);
38590109Simp	}
3864Srgrimes
3874Srgrimes	return (bus_release_resource(dev, type, rid, r));
3884Srgrimes}
3894Srgrimes
3904Srgrimes/* PCI interface. */
3914Srgrimes
39292979Swollmanstatic uint32_t
3934Srgrimesvga_pci_read_config(device_t dev, device_t child, int reg, int width)
39412378Sjoerg{
39512378Sjoerg
39692979Swollman	return (pci_read_config(dev, reg, width));
3974Srgrimes}
3984Srgrimes
3994Srgrimesstatic void
4004Srgrimesvga_pci_write_config(device_t dev, device_t child, int reg,
4014Srgrimes    uint32_t val, int width)
4024Srgrimes{
4034Srgrimes
4044Srgrimes	pci_write_config(dev, reg, val, width);
40590109Simp}
4064Srgrimes
4074Srgrimesstatic int
4084Srgrimesvga_pci_enable_busmaster(device_t dev, device_t child)
4094Srgrimes{
4104Srgrimes
4114Srgrimes	return (pci_enable_busmaster(dev));
41292979Swollman}
4134Srgrimes
41412378Sjoergstatic int
41512378Sjoergvga_pci_disable_busmaster(device_t dev, device_t child)
41692979Swollman{
4174Srgrimes
4184Srgrimes	return (pci_disable_busmaster(dev));
4194Srgrimes}
4204Srgrimes
4214Srgrimesstatic int
4224Srgrimesvga_pci_enable_io(device_t dev, device_t child, int space)
4234Srgrimes{
4244Srgrimes
42590109Simp	device_printf(dev, "child %s requested pci_enable_io\n",
4264Srgrimes	    device_get_nameunit(child));
4274Srgrimes	return (pci_enable_io(dev, space));
4284Srgrimes}
4294Srgrimes
4304Srgrimesstatic int
4314Srgrimesvga_pci_disable_io(device_t dev, device_t child, int space)
43292979Swollman{
4334Srgrimes
43412378Sjoerg	device_printf(dev, "child %s requested pci_disable_io\n",
43512378Sjoerg	    device_get_nameunit(child));
43692979Swollman	return (pci_disable_io(dev, space));
4374Srgrimes}
4384Srgrimes
4394Srgrimesstatic int
4404Srgrimesvga_pci_get_vpd_ident(device_t dev, device_t child, const char **identptr)
4414Srgrimes{
4424Srgrimes
4434Srgrimes	return (pci_get_vpd_ident(dev, identptr));
44463755Sse}
44592979Swollman
44663755Ssestatic int
44763755Ssevga_pci_get_vpd_readonly(device_t dev, device_t child, const char *kw,
44863755Sse    const char **vptr)
44963755Sse{
45063755Sse
45163755Sse	return (pci_get_vpd_readonly(dev, kw, vptr));
45263755Sse}
45363755Sse
45463755Ssestatic int
45563755Ssevga_pci_set_powerstate(device_t dev, device_t child, int state)
45663755Sse{
4574Srgrimes
45890109Simp	device_printf(dev, "child %s requested pci_set_powerstate\n",
4594Srgrimes	    device_get_nameunit(child));
4604Srgrimes	return (pci_set_powerstate(dev, state));
4614Srgrimes}
4624Srgrimes
46392979Swollmanstatic int
4644Srgrimesvga_pci_get_powerstate(device_t dev, device_t child)
4654Srgrimes{
46692979Swollman
46763755Sse	device_printf(dev, "child %s requested pci_get_powerstate\n",
46892979Swollman	    device_get_nameunit(child));
46963755Sse	return (pci_get_powerstate(dev));
4704Srgrimes}
4714Srgrimes
4724Srgrimesstatic int
4734Srgrimesvga_pci_assign_interrupt(device_t dev, device_t child)
47463755Sse{
47563755Sse
47692979Swollman	device_printf(dev, "child %s requested pci_assign_interrupt\n",
47763755Sse	    device_get_nameunit(child));
47892979Swollman	return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
47992979Swollman}
48063755Sse
48163755Ssestatic int
48263755Ssevga_pci_find_cap(device_t dev, device_t child, int capability,
48363755Sse    int *capreg)
48463755Sse{
48592979Swollman
48663755Sse	return (pci_find_cap(dev, capability, capreg));
48763755Sse}
48863755Sse
4894Srgrimesstatic int
49090109Simpvga_pci_find_extcap(device_t dev, device_t child, int capability,
4914Srgrimes    int *capreg)
4924Srgrimes{
4934Srgrimes
4944Srgrimes	return (pci_find_extcap(dev, capability, capreg));
49592979Swollman}
4964Srgrimes
4974Srgrimesstatic int
49892979Swollmanvga_pci_find_htcap(device_t dev, device_t child, int capability,
49963755Sse    int *capreg)
50092979Swollman{
50163755Sse
5024Srgrimes	return (pci_find_htcap(dev, capability, capreg));
5034Srgrimes}
5044Srgrimes
5054Srgrimesstatic int
50663755Ssevga_pci_alloc_msi(device_t dev, device_t child, int *count)
50763755Sse{
50892979Swollman	struct vga_pci_softc *sc;
50963755Sse	int error;
51063755Sse
51163755Sse	sc = device_get_softc(dev);
51263755Sse	if (sc->vga_msi_child != NULL)
51363755Sse		return (EBUSY);
51463755Sse	error = pci_alloc_msi(dev, count);
51563755Sse	if (error == 0)
51663755Sse		sc->vga_msi_child = child;
51763755Sse	return (error);
51863755Sse}
5194Srgrimes
52090109Simpstatic int
5214Srgrimesvga_pci_alloc_msix(device_t dev, device_t child, int *count)
5224Srgrimes{
5234Srgrimes	struct vga_pci_softc *sc;
5244Srgrimes	int error;
52592979Swollman
5264Srgrimes	sc = device_get_softc(dev);
5274Srgrimes	if (sc->vga_msi_child != NULL)
52892979Swollman		return (EBUSY);
52963755Sse	error = pci_alloc_msix(dev, count);
53092979Swollman	if (error == 0)
53163755Sse		sc->vga_msi_child = child;
5324Srgrimes	return (error);
5334Srgrimes}
5344Srgrimes
5354Srgrimesstatic int
53663755Ssevga_pci_remap_msix(device_t dev, device_t child, int count,
53763755Sse    const u_int *vectors)
53892979Swollman{
53963755Sse	struct vga_pci_softc *sc;
54063755Sse
54192979Swollman	sc = device_get_softc(dev);
54292979Swollman	if (sc->vga_msi_child != child)
54363755Sse		return (ENXIO);
54463755Sse	return (pci_remap_msix(dev, count, vectors));
54563755Sse}
54663755Sse
54763755Ssestatic int
5484Srgrimesvga_pci_release_msi(device_t dev, device_t child)
54990109Simp{
5504Srgrimes	struct vga_pci_softc *sc;
5514Srgrimes	int error;
5524Srgrimes
5534Srgrimes	sc = device_get_softc(dev);
55492979Swollman	if (sc->vga_msi_child != child)
5554Srgrimes		return (ENXIO);
5564Srgrimes	error = pci_release_msi(dev);
5574Srgrimes	if (error == 0)
55892979Swollman		sc->vga_msi_child = NULL;
5594Srgrimes	return (error);
5604Srgrimes}
56192979Swollman
56277244Skrisstatic int
56392979Swollmanvga_pci_msi_count(device_t dev, device_t child)
56463755Sse{
5654Srgrimes
5664Srgrimes	return (pci_msi_count(dev));
5674Srgrimes}
5684Srgrimes
5694Srgrimesstatic int
5704Srgrimesvga_pci_msix_count(device_t dev, device_t child)
57190109Simp{
5724Srgrimes
5734Srgrimes	return (pci_msix_count(dev));
5744Srgrimes}
5754Srgrimes
57692979Swollmanstatic bus_dma_tag_t
5774Srgrimesvga_pci_get_dma_tag(device_t bus, device_t child)
5784Srgrimes{
5794Srgrimes
58092979Swollman	return (bus_get_dma_tag(bus));
5814Srgrimes}
5824Srgrimes
58392979Swollmanstatic device_method_t vga_pci_methods[] = {
58463755Sse	/* Device interface */
5854Srgrimes	DEVMETHOD(device_probe,		vga_pci_probe),
5864Srgrimes	DEVMETHOD(device_attach,	vga_pci_attach),
5874Srgrimes	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
5884Srgrimes	DEVMETHOD(device_suspend,	vga_pci_suspend),
5894Srgrimes	DEVMETHOD(device_resume,	vga_pci_resume),
5904Srgrimes
59190109Simp	/* Bus interface */
5924Srgrimes	DEVMETHOD(bus_read_ivar,	vga_pci_read_ivar),
59331Salm	DEVMETHOD(bus_write_ivar,	vga_pci_write_ivar),
594468Sjtc	DEVMETHOD(bus_setup_intr,	vga_pci_setup_intr),
59531Salm	DEVMETHOD(bus_teardown_intr,	vga_pci_teardown_intr),
59631Salm	DEVMETHOD(bus_alloc_resource,	vga_pci_alloc_resource),
597181Sconklin	DEVMETHOD(bus_release_resource,	vga_pci_release_resource),
5984Srgrimes	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
599181Sconklin	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
600181Sconklin	DEVMETHOD(bus_get_dma_tag,	vga_pci_get_dma_tag),
601181Sconklin
602181Sconklin	/* PCI interface */
60331Salm	DEVMETHOD(pci_read_config,	vga_pci_read_config),
604539Sjtc	DEVMETHOD(pci_write_config,	vga_pci_write_config),
60531Salm	DEVMETHOD(pci_enable_busmaster,	vga_pci_enable_busmaster),
60692979Swollman	DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster),
6074Srgrimes	DEVMETHOD(pci_enable_io,	vga_pci_enable_io),
6084Srgrimes	DEVMETHOD(pci_disable_io,	vga_pci_disable_io),
60931Salm	DEVMETHOD(pci_get_vpd_ident,	vga_pci_get_vpd_ident),
610539Sjtc	DEVMETHOD(pci_get_vpd_readonly,	vga_pci_get_vpd_readonly),
61177244Skris	DEVMETHOD(pci_get_powerstate,	vga_pci_get_powerstate),
61231Salm	DEVMETHOD(pci_set_powerstate,	vga_pci_set_powerstate),
613295Sjtc	DEVMETHOD(pci_assign_interrupt,	vga_pci_assign_interrupt),
61431Salm	DEVMETHOD(pci_find_cap,		vga_pci_find_cap),
61531Salm	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
6164Srgrimes	DEVMETHOD(pci_find_htcap,	vga_pci_find_htcap),
61792979Swollman	DEVMETHOD(pci_alloc_msi,	vga_pci_alloc_msi),
6184Srgrimes	DEVMETHOD(pci_alloc_msix,	vga_pci_alloc_msix),
6194Srgrimes	DEVMETHOD(pci_remap_msix,	vga_pci_remap_msix),
620295Sjtc	DEVMETHOD(pci_release_msi,	vga_pci_release_msi),
62192979Swollman	DEVMETHOD(pci_msi_count,	vga_pci_msi_count),
622295Sjtc	DEVMETHOD(pci_msix_count,	vga_pci_msix_count),
623295Sjtc
624295Sjtc	{ 0, 0 }
6254Srgrimes};
6264Srgrimes
62731Salmstatic driver_t vga_pci_driver = {
62831Salm	"vgapci",
62931Salm	vga_pci_methods,
63031Salm	sizeof(struct vga_pci_softc),
63131Salm};
63231Salm
6334Srgrimesstatic devclass_t vga_devclass;
634
635DRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0);
636MODULE_DEPEND(vgapci, x86bios, 1, 1, 1);
637