agp_amd64.c revision 144809
1189251Ssam/*-
2189251Ssam * Copyright (c) 2004 Jung-uk Kim
3189251Ssam * All rights reserved.
4189251Ssam *
5252726Srpaulo * Redistribution and use in source and binary forms, with or without
6252726Srpaulo * modification, are permitted provided that the following conditions
7189251Ssam * are met:
8189251Ssam * 1. Redistributions of source code must retain the above copyright
9189251Ssam *    notice, this list of conditions and the following disclaimer.
10189251Ssam * 2. Redistributions in binary form must reproduce the above copyright
11189251Ssam *    notice, this list of conditions and the following disclaimer in the
12189251Ssam *    documentation and/or other materials provided with the distribution.
13189251Ssam *
14189251Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15189251Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16189251Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17189251Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18189251Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19189251Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20189251Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21189251Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22189251Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23189251Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24189251Ssam * SUCH DAMAGE.
25189251Ssam */
26189251Ssam
27189251Ssam#include <sys/cdefs.h>
28189251Ssam__FBSDID("$FreeBSD: head/sys/dev/agp/agp_amd64.c 144809 2005-04-08 18:04:39Z obrien $");
29189251Ssam
30189251Ssam#include "opt_bus.h"
31189251Ssam
32189251Ssam#include <sys/param.h>
33189251Ssam#include <sys/systm.h>
34189251Ssam#include <sys/malloc.h>
35189251Ssam#include <sys/kernel.h>
36189251Ssam#include <sys/module.h>
37189251Ssam#include <sys/bus.h>
38252726Srpaulo#include <sys/lock.h>
39252726Srpaulo#include <sys/mutex.h>
40252726Srpaulo#include <sys/proc.h>
41189251Ssam
42189251Ssam#include <dev/pci/pcivar.h>
43189251Ssam#include <dev/pci/pcireg.h>
44189251Ssam#include <pci/agppriv.h>
45189251Ssam#include <pci/agpreg.h>
46189251Ssam
47189251Ssam#include <vm/vm.h>
48189251Ssam#include <vm/vm_object.h>
49189251Ssam#include <vm/pmap.h>
50189251Ssam#include <machine/bus.h>
51189251Ssam#include <machine/resource.h>
52189251Ssam#include <sys/rman.h>
53189251Ssam
54189251Ssam/* XXX */
55189251Ssamextern void pci_cfgregwrite(int, int, int, int, uint32_t, int);
56189251Ssamextern uint32_t pci_cfgregread(int, int, int, int, int);
57189251Ssam
58189251SsamMALLOC_DECLARE(M_AGP);
59189251Ssam
60189251Ssam#define	AMD64_MAX_MCTRL		8
61189251Ssam
62189251Ssamstruct agp_amd64_softc {
63189251Ssam	struct agp_softc	agp;
64189251Ssam	uint32_t	initial_aperture; /* aperture size at startup */
65189251Ssam	struct agp_gatt	*gatt;
66189251Ssam	int		mctrl[AMD64_MAX_MCTRL];
67189251Ssam	int		n_mctrl;
68189251Ssam};
69189251Ssam
70189251Ssamstatic const char*
71189251Ssamagp_amd64_match(device_t dev)
72189251Ssam{
73189251Ssam	if (pci_get_class(dev) != PCIC_BRIDGE
74189251Ssam	    || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
75189251Ssam		return NULL;
76189251Ssam
77189251Ssam	if (agp_find_caps(dev) == 0)
78189251Ssam		return NULL;
79189251Ssam
80189251Ssam	switch (pci_get_devid(dev)) {
81189251Ssam	case 0x74541022:
82189251Ssam		return ("AMD 8151 AGP graphics tunnel");
83189251Ssam	case 0x07551039:
84189251Ssam		return ("SiS 755 host to AGP bridge");
85214734Srpaulo	case 0x00d110de:
86214734Srpaulo		return ("NVIDIA nForce3 AGP Controller");
87214734Srpaulo	case 0x00e110de:
88214734Srpaulo		return ("NVIDIA nForce3-250 AGP Controller");
89214734Srpaulo	case 0x02041106:
90214734Srpaulo		return ("VIA 8380 host to PCI bridge");
91214734Srpaulo	case 0x02821106:
92214734Srpaulo		return ("VIA K8T800Pro host to PCI bridge");
93214734Srpaulo	case 0x31881106:
94189251Ssam		return ("VIA 8385 host to PCI bridge");
95189251Ssam	};
96189251Ssam
97189251Ssam	return NULL;
98189251Ssam}
99189251Ssam
100189251Ssamstatic int
101189251Ssamagp_amd64_probe(device_t dev)
102189251Ssam{
103189251Ssam	const char *desc;
104189251Ssam
105189251Ssam	if (resource_disabled("agp", device_get_unit(dev)))
106189251Ssam		return ENXIO;
107189251Ssam	if ((desc = agp_amd64_match(dev))) {
108189251Ssam		device_verbose(dev);
109189251Ssam		device_set_desc(dev, desc);
110189251Ssam		return BUS_PROBE_DEFAULT;
111189251Ssam	}
112189251Ssam
113189251Ssam	return ENXIO;
114189251Ssam}
115189251Ssam
116189251Ssamstatic int
117189251Ssamagp_amd64_attach(device_t dev)
118189251Ssam{
119189251Ssam	struct agp_amd64_softc *sc = device_get_softc(dev);
120189251Ssam	struct agp_gatt *gatt;
121189251Ssam	int i, n, error;
122189251Ssam
123189251Ssam	for (i = 0, n = 0; i < PCI_SLOTMAX && n < AMD64_MAX_MCTRL; i++)
124189251Ssam		if (pci_cfgregread(0, i, 3, 0, 4) == 0x11031022) {
125189251Ssam			sc->mctrl[n] = i;
126189251Ssam			n++;
127189251Ssam		}
128189251Ssam
129189251Ssam	if (n == 0)
130189251Ssam		return ENXIO;
131189251Ssam
132189251Ssam	sc->n_mctrl = n;
133189251Ssam
134189251Ssam	if (bootverbose)
135189251Ssam		printf("AMD64: %d Misc. Control unit(s) found.\n", sc->n_mctrl);
136189251Ssam
137189251Ssam	if ((error = agp_generic_attach(dev)))
138189251Ssam		return error;
139189251Ssam
140189251Ssam	sc->initial_aperture = AGP_GET_APERTURE(dev);
141189251Ssam
142189251Ssam	for (;;) {
143189251Ssam		gatt = agp_alloc_gatt(dev);
144189251Ssam		if (gatt)
145189251Ssam			break;
146189251Ssam
147189251Ssam		/*
148189251Ssam		 * Probably contigmalloc failure. Try reducing the
149189251Ssam		 * aperture so that the gatt size reduces.
150189251Ssam		 */
151189251Ssam		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
152189251Ssam			agp_generic_detach(dev);
153189251Ssam			return ENOMEM;
154189251Ssam		}
155189251Ssam	}
156189251Ssam	sc->gatt = gatt;
157189251Ssam
158189251Ssam	/* Install the gatt and enable aperture. */
159189251Ssam	for (i = 0; i < sc->n_mctrl; i++) {
160189251Ssam		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_ATTBASE,
161189251Ssam		    (uint32_t)(gatt->ag_physical >> 8) & AGP_AMD64_ATTBASE_MASK,
162189251Ssam		    4);
163189251Ssam		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL,
164189251Ssam		    (pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL, 4) |
165189251Ssam		    AGP_AMD64_APCTRL_GARTEN) &
166189251Ssam		    ~(AGP_AMD64_APCTRL_DISGARTCPU | AGP_AMD64_APCTRL_DISGARTIO),
167189251Ssam		    4);
168189251Ssam	}
169189251Ssam
170189251Ssam	agp_flush_cache();
171189251Ssam
172189251Ssam	return 0;
173189251Ssam}
174189251Ssam
175189251Ssamstatic int
176189251Ssamagp_amd64_detach(device_t dev)
177189251Ssam{
178189251Ssam	struct agp_amd64_softc *sc = device_get_softc(dev);
179189251Ssam	int i, error;
180189251Ssam
181189251Ssam	if ((error = agp_generic_detach(dev)))
182189251Ssam		return error;
183189251Ssam
184189251Ssam	for (i = 0; i < sc->n_mctrl; i++)
185189251Ssam		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL,
186189251Ssam		    pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL, 4) &
187189251Ssam		    ~AGP_AMD64_APCTRL_GARTEN, 4);
188189251Ssam
189189251Ssam	AGP_SET_APERTURE(dev, sc->initial_aperture);
190189251Ssam	agp_free_gatt(sc->gatt);
191189251Ssam
192189251Ssam	return 0;
193189251Ssam}
194189251Ssam
195189251Ssamstatic uint32_t agp_amd64_table[] = {
196189251Ssam	0x02000000,	/*   32 MB */
197189251Ssam	0x04000000,	/*   64 MB */
198189251Ssam	0x08000000,	/*  128 MB */
199189251Ssam	0x10000000,	/*  256 MB */
200189251Ssam	0x20000000,	/*  512 MB */
201189251Ssam	0x40000000,	/* 1024 MB */
202189251Ssam	0x80000000,	/* 2048 MB */
203189251Ssam};
204189251Ssam
205189251Ssam#define AGP_AMD64_TABLE_SIZE \
206189251Ssam	(sizeof(agp_amd64_table) / sizeof(agp_amd64_table[0]))
207189251Ssam
208189251Ssamstatic uint32_t
209189251Ssamagp_amd64_get_aperture(device_t dev)
210189251Ssam{
211189251Ssam	struct agp_amd64_softc *sc = device_get_softc(dev);
212189251Ssam	uint32_t i;
213189251Ssam
214189251Ssam	i = (pci_cfgregread(0, sc->mctrl[0], 3, AGP_AMD64_APCTRL, 4) &
215189251Ssam		AGP_AMD64_APCTRL_SIZE_MASK) >> 1;
216189251Ssam
217189251Ssam	if (i >= AGP_AMD64_TABLE_SIZE)
218189251Ssam		return 0;
219189251Ssam
220189251Ssam	return (agp_amd64_table[i]);
221189251Ssam}
222189251Ssam
223189251Ssamstatic int
224189251Ssamagp_amd64_set_aperture(device_t dev, uint32_t aperture)
225189251Ssam{
226189251Ssam	struct agp_amd64_softc *sc = device_get_softc(dev);
227189251Ssam	uint32_t i;
228189251Ssam	int j;
229189251Ssam
230189251Ssam	for (i = 0; i < AGP_AMD64_TABLE_SIZE; i++)
231189251Ssam		if (agp_amd64_table[i] == aperture)
232189251Ssam			break;
233189251Ssam	if (i == AGP_AMD64_TABLE_SIZE)
234189251Ssam		return EINVAL;
235189251Ssam
236189251Ssam	for (j = 0; j < sc->n_mctrl; j++)
237189251Ssam		pci_cfgregwrite(0, sc->mctrl[j], 3, AGP_AMD64_APCTRL,
238189251Ssam		    (pci_cfgregread(0, sc->mctrl[j], 3, AGP_AMD64_APCTRL, 4) &
239189251Ssam		    ~(AGP_AMD64_APCTRL_SIZE_MASK)) | (i << 1), 4);
240189251Ssam
241189251Ssam	return 0;
242189251Ssam}
243189251Ssam
244189251Ssamstatic int
245189251Ssamagp_amd64_bind_page(device_t dev, int offset, vm_offset_t physical)
246189251Ssam{
247189251Ssam	struct agp_amd64_softc *sc = device_get_softc(dev);
248189251Ssam
249189251Ssam	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
250189251Ssam		return EINVAL;
251189251Ssam
252189251Ssam	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
253189251Ssam	return 0;
254189251Ssam}
255189251Ssam
256189251Ssamstatic int
257189251Ssamagp_amd64_unbind_page(device_t dev, int offset)
258189251Ssam{
259189251Ssam	struct agp_amd64_softc *sc = device_get_softc(dev);
260189251Ssam
261189251Ssam	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
262189251Ssam		return EINVAL;
263189251Ssam
264189251Ssam	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
265189251Ssam	return 0;
266189251Ssam}
267189251Ssam
268189251Ssamstatic void
269189251Ssamagp_amd64_flush_tlb(device_t dev)
270189251Ssam{
271189251Ssam	struct agp_amd64_softc *sc = device_get_softc(dev);
272189251Ssam	int i;
273189251Ssam
274189251Ssam	for (i = 0; i < sc->n_mctrl; i++)
275189251Ssam		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_CACHECTRL,
276189251Ssam		    pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_CACHECTRL, 4) |
277189251Ssam		    AGP_AMD64_CACHECTRL_INVGART, 4);
278189251Ssam}
279189251Ssam
280189251Ssamstatic device_method_t agp_amd64_methods[] = {
281189251Ssam	/* Device interface */
282189251Ssam	DEVMETHOD(device_probe,		agp_amd64_probe),
283189251Ssam	DEVMETHOD(device_attach,	agp_amd64_attach),
284189251Ssam	DEVMETHOD(device_detach,	agp_amd64_detach),
285189251Ssam	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
286189251Ssam	DEVMETHOD(device_suspend,	bus_generic_suspend),
287189251Ssam	DEVMETHOD(device_resume,	bus_generic_resume),
288189251Ssam
289189251Ssam	/* AGP interface */
290189251Ssam	DEVMETHOD(agp_get_aperture,	agp_amd64_get_aperture),
291189251Ssam	DEVMETHOD(agp_set_aperture,	agp_amd64_set_aperture),
292189251Ssam	DEVMETHOD(agp_bind_page,	agp_amd64_bind_page),
293189251Ssam	DEVMETHOD(agp_unbind_page,	agp_amd64_unbind_page),
294189251Ssam	DEVMETHOD(agp_flush_tlb,	agp_amd64_flush_tlb),
295189251Ssam	DEVMETHOD(agp_enable,		agp_generic_enable),
296189251Ssam	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
297189251Ssam	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
298189251Ssam	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
299189251Ssam	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
300189251Ssam
301189251Ssam	{ 0, 0 }
302189251Ssam};
303189251Ssam
304189251Ssamstatic driver_t agp_amd64_driver = {
305189251Ssam	"agp",
306189251Ssam	agp_amd64_methods,
307189251Ssam	sizeof(struct agp_amd64_softc),
308189251Ssam};
309189251Ssam
310189251Ssamstatic devclass_t agp_devclass;
311189251Ssam
312189251SsamDRIVER_MODULE(agp_amd64, pci, agp_amd64_driver, agp_devclass, 0, 0);
313189251SsamMODULE_DEPEND(agp_amd64, agp, 1, 1, 1);
314189251SsamMODULE_DEPEND(agp_amd64, pci, 1, 1, 1);
315189251Ssam