vga_pci.c revision 205018
1284345Ssjg/*-
2284345Ssjg * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
3284345Ssjg * All rights reserved.
4284345Ssjg *
5284345Ssjg * Redistribution and use in source and binary forms, with or without
6284345Ssjg * modification, are permitted provided that the following conditions
7284345Ssjg * are met:
8284345Ssjg * 1. Redistributions of source code must retain the above copyright
9284345Ssjg *    notice, this list of conditions and the following disclaimer.
10284345Ssjg * 2. Redistributions in binary form must reproduce the above copyright
11284345Ssjg *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/dev/pci/vga_pci.c 205018 2010-03-11 15:25:47Z jhb $");
32
33/*
34 * Simple driver for PCI VGA display devices.  Drivers such as agp(4) and
35 * drm(4) should attach as children of this device.
36 *
37 * XXX: The vgapci name is a hack until we somehow merge the isa vga driver
38 * in or rename it.
39 */
40
41#include <sys/param.h>
42#include <sys/bus.h>
43#include <sys/kernel.h>
44#include <sys/module.h>
45#include <sys/rman.h>
46#include <sys/sysctl.h>
47#include <sys/systm.h>
48
49#include <dev/pci/pcireg.h>
50#include <dev/pci/pcivar.h>
51
52struct vga_resource {
53	struct resource	*vr_res;
54	int	vr_refs;
55};
56
57struct vga_pci_softc {
58	device_t	vga_msi_child;	/* Child driver using MSI. */
59	struct vga_resource vga_res[PCIR_MAX_BAR_0 + 1];
60};
61
62SYSCTL_DECL(_hw_pci);
63
64int vga_pci_default_unit = -1;
65TUNABLE_INT("hw.pci.default_vgapci_unit", &vga_pci_default_unit);
66SYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN,
67    &vga_pci_default_unit, -1, "Default VGA-compatible display");
68
69static int
70vga_pci_probe(device_t dev)
71{
72	device_t bdev;
73	int unit;
74	uint16_t bctl;
75
76	switch (pci_get_class(dev)) {
77	case PCIC_DISPLAY:
78		break;
79	case PCIC_OLD:
80		if (pci_get_subclass(dev) != PCIS_OLD_VGA)
81			return (ENXIO);
82		break;
83	default:
84		return (ENXIO);
85	}
86
87	/* Probe default display. */
88	unit = device_get_unit(dev);
89	bdev = device_get_parent(device_get_parent(dev));
90	bctl = pci_read_config(bdev, PCIR_BRIDGECTL_1, 2);
91	if (vga_pci_default_unit < 0 && (bctl & PCIB_BCR_VGA_ENABLE) != 0)
92		vga_pci_default_unit = unit;
93	if (vga_pci_default_unit == unit)
94		device_set_flags(dev, 1);
95
96	device_set_desc(dev, "VGA-compatible display");
97	return (BUS_PROBE_GENERIC);
98}
99
100static int
101vga_pci_attach(device_t dev)
102{
103
104	bus_generic_probe(dev);
105
106	/* Always create a drm child for now to make it easier on drm. */
107	device_add_child(dev, "drm", -1);
108	bus_generic_attach(dev);
109	return (0);
110}
111
112static int
113vga_pci_suspend(device_t dev)
114{
115
116	return (bus_generic_suspend(dev));
117}
118
119static int
120vga_pci_resume(device_t dev)
121{
122
123	return (bus_generic_resume(dev));
124}
125
126/* Bus interface. */
127
128static int
129vga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
130{
131
132	return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result));
133}
134
135static int
136vga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
137{
138
139	return (EINVAL);
140}
141
142static int
143vga_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
144    int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
145    void **cookiep)
146{
147	return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
148	    filter, intr, arg, cookiep));
149}
150
151static int
152vga_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
153    void *cookie)
154{
155	return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
156}
157
158static struct resource *
159vga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
160    u_long start, u_long end, u_long count, u_int flags)
161{
162	struct vga_pci_softc *sc;
163	int bar;
164
165	switch (type) {
166	case SYS_RES_MEMORY:
167	case SYS_RES_IOPORT:
168		/*
169		 * For BARs, we cache the resource so that we only allocate it
170		 * from the PCI bus once.
171		 */
172		bar = PCI_RID2BAR(*rid);
173		if (bar < 0 || bar > PCIR_MAX_BAR_0)
174			return (NULL);
175		sc = device_get_softc(dev);
176		if (sc->vga_res[bar].vr_res == NULL)
177			sc->vga_res[bar].vr_res = bus_alloc_resource(dev, type,
178			    rid, start, end, count, flags);
179		if (sc->vga_res[bar].vr_res != NULL)
180			sc->vga_res[bar].vr_refs++;
181		return (sc->vga_res[bar].vr_res);
182	}
183	return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
184}
185
186static int
187vga_pci_release_resource(device_t dev, device_t child, int type, int rid,
188    struct resource *r)
189{
190	struct vga_pci_softc *sc;
191	int bar, error;
192
193	switch (type) {
194	case SYS_RES_MEMORY:
195	case SYS_RES_IOPORT:
196		/*
197		 * For BARs, we release the resource from the PCI bus
198		 * when the last child reference goes away.
199		 */
200		bar = PCI_RID2BAR(rid);
201		if (bar < 0 || bar > PCIR_MAX_BAR_0)
202			return (EINVAL);
203		sc = device_get_softc(dev);
204		if (sc->vga_res[bar].vr_res == NULL)
205			return (EINVAL);
206		KASSERT(sc->vga_res[bar].vr_res == r,
207		    ("vga_pci resource mismatch"));
208		if (sc->vga_res[bar].vr_refs > 1) {
209			sc->vga_res[bar].vr_refs--;
210			return (0);
211		}
212		KASSERT(sc->vga_res[bar].vr_refs > 0,
213		    ("vga_pci resource reference count underflow"));
214		error = bus_release_resource(dev, type, rid, r);
215		if (error == 0) {
216			sc->vga_res[bar].vr_res = NULL;
217			sc->vga_res[bar].vr_refs = 0;
218		}
219		return (error);
220	}
221
222	return (bus_release_resource(dev, type, rid, r));
223}
224
225/* PCI interface. */
226
227static uint32_t
228vga_pci_read_config(device_t dev, device_t child, int reg, int width)
229{
230
231	return (pci_read_config(dev, reg, width));
232}
233
234static void
235vga_pci_write_config(device_t dev, device_t child, int reg,
236    uint32_t val, int width)
237{
238
239	pci_write_config(dev, reg, val, width);
240}
241
242static int
243vga_pci_enable_busmaster(device_t dev, device_t child)
244{
245
246	device_printf(dev, "child %s requested pci_enable_busmaster\n",
247	    device_get_nameunit(child));
248	return (pci_enable_busmaster(dev));
249}
250
251static int
252vga_pci_disable_busmaster(device_t dev, device_t child)
253{
254
255	device_printf(dev, "child %s requested pci_disable_busmaster\n",
256	    device_get_nameunit(child));
257	return (pci_disable_busmaster(dev));
258}
259
260static int
261vga_pci_enable_io(device_t dev, device_t child, int space)
262{
263
264	device_printf(dev, "child %s requested pci_enable_io\n",
265	    device_get_nameunit(child));
266	return (pci_enable_io(dev, space));
267}
268
269static int
270vga_pci_disable_io(device_t dev, device_t child, int space)
271{
272
273	device_printf(dev, "child %s requested pci_disable_io\n",
274	    device_get_nameunit(child));
275	return (pci_disable_io(dev, space));
276}
277
278static int
279vga_pci_get_vpd_ident(device_t dev, device_t child, const char **identptr)
280{
281
282	return (pci_get_vpd_ident(dev, identptr));
283}
284
285static int
286vga_pci_get_vpd_readonly(device_t dev, device_t child, const char *kw,
287    const char **vptr)
288{
289
290	return (pci_get_vpd_readonly(dev, kw, vptr));
291}
292
293static int
294vga_pci_set_powerstate(device_t dev, device_t child, int state)
295{
296
297	device_printf(dev, "child %s requested pci_set_powerstate\n",
298	    device_get_nameunit(child));
299	return (pci_set_powerstate(dev, state));
300}
301
302static int
303vga_pci_get_powerstate(device_t dev, device_t child)
304{
305
306	device_printf(dev, "child %s requested pci_get_powerstate\n",
307	    device_get_nameunit(child));
308	return (pci_get_powerstate(dev));
309}
310
311static int
312vga_pci_assign_interrupt(device_t dev, device_t child)
313{
314
315	device_printf(dev, "child %s requested pci_assign_interrupt\n",
316	    device_get_nameunit(child));
317	return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
318}
319
320static int
321vga_pci_find_extcap(device_t dev, device_t child, int capability,
322    int *capreg)
323{
324
325	return (pci_find_extcap(dev, capability, capreg));
326}
327
328static int
329vga_pci_alloc_msi(device_t dev, device_t child, int *count)
330{
331	struct vga_pci_softc *sc;
332	int error;
333
334	sc = device_get_softc(dev);
335	if (sc->vga_msi_child != NULL)
336		return (EBUSY);
337	error = pci_alloc_msi(dev, count);
338	if (error == 0)
339		sc->vga_msi_child = child;
340	return (error);
341}
342
343static int
344vga_pci_alloc_msix(device_t dev, device_t child, int *count)
345{
346	struct vga_pci_softc *sc;
347	int error;
348
349	sc = device_get_softc(dev);
350	if (sc->vga_msi_child != NULL)
351		return (EBUSY);
352	error = pci_alloc_msix(dev, count);
353	if (error == 0)
354		sc->vga_msi_child = child;
355	return (error);
356}
357
358static int
359vga_pci_remap_msix(device_t dev, device_t child, int count,
360    const u_int *vectors)
361{
362	struct vga_pci_softc *sc;
363
364	sc = device_get_softc(dev);
365	if (sc->vga_msi_child != child)
366		return (ENXIO);
367	return (pci_remap_msix(dev, count, vectors));
368}
369
370static int
371vga_pci_release_msi(device_t dev, device_t child)
372{
373	struct vga_pci_softc *sc;
374	int error;
375
376	sc = device_get_softc(dev);
377	if (sc->vga_msi_child != child)
378		return (ENXIO);
379	error = pci_release_msi(dev);
380	if (error == 0)
381		sc->vga_msi_child = NULL;
382	return (error);
383}
384
385static int
386vga_pci_msi_count(device_t dev, device_t child)
387{
388
389	return (pci_msi_count(dev));
390}
391
392static int
393vga_pci_msix_count(device_t dev, device_t child)
394{
395
396	return (pci_msix_count(dev));
397}
398
399static device_method_t vga_pci_methods[] = {
400	/* Device interface */
401	DEVMETHOD(device_probe,		vga_pci_probe),
402	DEVMETHOD(device_attach,	vga_pci_attach),
403	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
404	DEVMETHOD(device_suspend,	vga_pci_suspend),
405	DEVMETHOD(device_resume,	vga_pci_resume),
406
407	/* Bus interface */
408	DEVMETHOD(bus_read_ivar,	vga_pci_read_ivar),
409	DEVMETHOD(bus_write_ivar,	vga_pci_write_ivar),
410	DEVMETHOD(bus_setup_intr,	vga_pci_setup_intr),
411	DEVMETHOD(bus_teardown_intr,	vga_pci_teardown_intr),
412	DEVMETHOD(bus_alloc_resource,	vga_pci_alloc_resource),
413	DEVMETHOD(bus_release_resource,	vga_pci_release_resource),
414	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
415	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
416
417	/* PCI interface */
418	DEVMETHOD(pci_read_config,	vga_pci_read_config),
419	DEVMETHOD(pci_write_config,	vga_pci_write_config),
420	DEVMETHOD(pci_enable_busmaster,	vga_pci_enable_busmaster),
421	DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster),
422	DEVMETHOD(pci_enable_io,	vga_pci_enable_io),
423	DEVMETHOD(pci_disable_io,	vga_pci_disable_io),
424	DEVMETHOD(pci_get_vpd_ident,	vga_pci_get_vpd_ident),
425	DEVMETHOD(pci_get_vpd_readonly,	vga_pci_get_vpd_readonly),
426	DEVMETHOD(pci_get_powerstate,	vga_pci_get_powerstate),
427	DEVMETHOD(pci_set_powerstate,	vga_pci_set_powerstate),
428	DEVMETHOD(pci_assign_interrupt,	vga_pci_assign_interrupt),
429	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
430	DEVMETHOD(pci_alloc_msi,	vga_pci_alloc_msi),
431	DEVMETHOD(pci_alloc_msix,	vga_pci_alloc_msix),
432	DEVMETHOD(pci_remap_msix,	vga_pci_remap_msix),
433	DEVMETHOD(pci_release_msi,	vga_pci_release_msi),
434	DEVMETHOD(pci_msi_count,	vga_pci_msi_count),
435	DEVMETHOD(pci_msix_count,	vga_pci_msix_count),
436
437	{ 0, 0 }
438};
439
440static driver_t vga_pci_driver = {
441	"vgapci",
442	vga_pci_methods,
443	sizeof(struct vga_pci_softc),
444};
445
446static devclass_t vga_devclass;
447
448DRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0);
449