agp_ali.c revision 122513
1254721Semaste/*-
2254721Semaste * Copyright (c) 2000 Doug Rabson
3254721Semaste * All rights reserved.
4254721Semaste *
5254721Semaste * Redistribution and use in source and binary forms, with or without
6254721Semaste * modification, are permitted provided that the following conditions
7254721Semaste * are met:
8254721Semaste * 1. Redistributions of source code must retain the above copyright
9254721Semaste *    notice, this list of conditions and the following disclaimer.
10254721Semaste * 2. Redistributions in binary form must reproduce the above copyright
11254721Semaste *    notice, this list of conditions and the following disclaimer in the
12254721Semaste *    documentation and/or other materials provided with the distribution.
13296417Sdim *
14296417Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15254721Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16254721Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17254721Semaste * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18258054Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19258054Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20276479Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21258054Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22258054Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23258054Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24258054Semaste * SUCH DAMAGE.
25258054Semaste */
26258054Semaste
27296417Sdim#include <sys/cdefs.h>
28296417Sdim__FBSDID("$FreeBSD: head/sys/dev/agp/agp_ali.c 122513 2003-11-11 21:49:18Z anholt $");
29296417Sdim
30254721Semaste#include "opt_bus.h"
31254721Semaste
32254721Semaste#include <sys/param.h>
33254721Semaste#include <sys/systm.h>
34254721Semaste#include <sys/malloc.h>
35254721Semaste#include <sys/kernel.h>
36254721Semaste#include <sys/bus.h>
37254721Semaste#include <sys/lock.h>
38254721Semaste#include <sys/lockmgr.h>
39254721Semaste#include <sys/mutex.h>
40254721Semaste#include <sys/proc.h>
41254721Semaste
42254721Semaste#include <dev/pci/pcivar.h>
43254721Semaste#include <dev/pci/pcireg.h>
44254721Semaste#include <pci/agppriv.h>
45254721Semaste#include <pci/agpreg.h>
46296417Sdim
47296417Sdim#include <vm/vm.h>
48296417Sdim#include <vm/vm_object.h>
49296417Sdim#include <vm/pmap.h>
50296417Sdim
51296417Sdimstruct agp_ali_softc {
52296417Sdim	struct agp_softc agp;
53254721Semaste	u_int32_t	initial_aperture; /* aperture size at startup */
54258054Semaste	struct agp_gatt *gatt;
55254721Semaste};
56258054Semaste
57258054Semastestatic const char*
58258054Semasteagp_ali_match(device_t dev)
59254721Semaste{
60296417Sdim	if (pci_get_class(dev) != PCIC_BRIDGE
61254721Semaste	    || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
62254721Semaste		return NULL;
63254721Semaste
64254721Semaste	if (agp_find_caps(dev) == 0)
65254721Semaste		return NULL;
66254721Semaste
67254721Semaste	switch (pci_get_devid(dev)) {
68254721Semaste	case 0x154110b9:
69254721Semaste		return ("Ali M1541 host to AGP bridge");
70254721Semaste	};
71254721Semaste
72254721Semaste	if (pci_get_vendor(dev) == 0x10b9)
73254721Semaste		return ("Ali Generic host to PCI bridge");
74254721Semaste
75296417Sdim	return NULL;
76254721Semaste}
77276479Sdim
78276479Sdimstatic int
79254721Semasteagp_ali_probe(device_t dev)
80254721Semaste{
81254721Semaste	const char *desc;
82254721Semaste
83254721Semaste	desc = agp_ali_match(dev);
84254721Semaste	if (desc) {
85254721Semaste		device_verbose(dev);
86254721Semaste		device_set_desc(dev, desc);
87254721Semaste		return 0;
88254721Semaste	}
89254721Semaste
90254721Semaste	return ENXIO;
91254721Semaste}
92254721Semaste
93254721Semastestatic int
94254721Semasteagp_ali_attach(device_t dev)
95254721Semaste{
96254721Semaste	struct agp_ali_softc *sc = device_get_softc(dev);
97254721Semaste	struct agp_gatt *gatt;
98254721Semaste	int error;
99254721Semaste
100254721Semaste	error = agp_generic_attach(dev);
101254721Semaste	if (error)
102254721Semaste		return error;
103254721Semaste
104254721Semaste	sc->initial_aperture = AGP_GET_APERTURE(dev);
105254721Semaste	if (sc->initial_aperture == 0) {
106254721Semaste		device_printf(dev, "bad initial aperture size, disabling\n");
107254721Semaste		return ENXIO;
108254721Semaste	}
109254721Semaste
110254721Semaste	for (;;) {
111254721Semaste		gatt = agp_alloc_gatt(dev);
112254721Semaste		if (gatt)
113254721Semaste			break;
114254721Semaste
115254721Semaste		/*
116254721Semaste		 * Probably contigmalloc failure. Try reducing the
117254721Semaste		 * aperture so that the gatt size reduces.
118254721Semaste		 */
119254721Semaste		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
120254721Semaste			agp_generic_detach(dev);
121296417Sdim			return ENOMEM;
122296417Sdim		}
123254721Semaste	}
124254721Semaste	sc->gatt = gatt;
125254721Semaste
126254721Semaste	/* Install the gatt. */
127254721Semaste	pci_write_config(dev, AGP_ALI_ATTBASE,
128254721Semaste			 (gatt->ag_physical
129254721Semaste			  | (pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff)),
130254721Semaste			 4);
131254721Semaste
132254721Semaste	/* Enable the TLB. */
133296417Sdim	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
134254721Semaste
135254721Semaste	return 0;
136254721Semaste}
137254721Semaste
138254721Semastestatic int
139254721Semasteagp_ali_detach(device_t dev)
140296417Sdim{
141254721Semaste	struct agp_ali_softc *sc = device_get_softc(dev);
142254721Semaste	int error;
143254721Semaste
144254721Semaste	error = agp_generic_detach(dev);
145254721Semaste	if (error)
146296417Sdim		return error;
147254721Semaste
148254721Semaste	/* Disable the TLB.. */
149276479Sdim	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
150254721Semaste
151254721Semaste	/* Put the aperture back the way it started. */
152254721Semaste	AGP_SET_APERTURE(dev, sc->initial_aperture);
153254721Semaste	pci_write_config(dev, AGP_ALI_ATTBASE,
154254721Semaste			 pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff,
155254721Semaste			 4);
156254721Semaste
157254721Semaste	agp_free_gatt(sc->gatt);
158254721Semaste	return 0;
159254721Semaste}
160254721Semaste
161254721Semaste#define M 1024*1024
162254721Semaste
163254721Semastestatic u_int32_t agp_ali_table[] = {
164254721Semaste	0,			/* 0 - invalid */
165288943Sdim	1,			/* 1 - invalid */
166254721Semaste	2,			/* 2 - invalid */
167254721Semaste	4*M,			/* 3 - invalid */
168254721Semaste	8*M,			/* 4 - invalid */
169254721Semaste	0,			/* 5 - invalid */
170254721Semaste	16*M,			/* 6 - invalid */
171254721Semaste	32*M,			/* 7 - invalid */
172296417Sdim	64*M,			/* 8 - invalid */
173254721Semaste	128*M,			/* 9 - invalid */
174254721Semaste	256*M,			/* 10 - invalid */
175254721Semaste};
176254721Semaste#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
177254721Semaste
178254721Semastestatic u_int32_t
179254721Semasteagp_ali_get_aperture(device_t dev)
180254721Semaste{
181254721Semaste	/*
182254721Semaste	 * The aperture size is derived from the low bits of attbase.
183254721Semaste	 * I'm not sure this is correct..
184254721Semaste	 */
185254721Semaste	int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff;
186254721Semaste	if (i >= agp_ali_table_size)
187254721Semaste		return 0;
188254721Semaste	return agp_ali_table[i];
189254721Semaste}
190254721Semaste
191254721Semastestatic int
192254721Semasteagp_ali_set_aperture(device_t dev, u_int32_t aperture)
193254721Semaste{
194254721Semaste	int i;
195254721Semaste
196254721Semaste	for (i = 0; i < agp_ali_table_size; i++)
197254721Semaste		if (agp_ali_table[i] == aperture)
198254721Semaste			break;
199296417Sdim	if (i == agp_ali_table_size)
200296417Sdim		return EINVAL;
201254721Semaste
202254721Semaste	pci_write_config(dev, AGP_ALI_ATTBASE,
203276479Sdim			 ((pci_read_config(dev, AGP_ALI_ATTBASE, 4) & ~0xff)
204276479Sdim			  | i), 4);
205276479Sdim	return 0;
206276479Sdim}
207296417Sdim
208296417Sdimstatic int
209276479Sdimagp_ali_bind_page(device_t dev, int offset, vm_offset_t physical)
210276479Sdim{
211254721Semaste	struct agp_ali_softc *sc = device_get_softc(dev);
212254721Semaste
213254721Semaste	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
214254721Semaste		return EINVAL;
215296417Sdim
216254721Semaste	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
217254721Semaste	return 0;
218254721Semaste}
219254721Semaste
220254721Semastestatic int
221254721Semasteagp_ali_unbind_page(device_t dev, int offset)
222254721Semaste{
223254721Semaste	struct agp_ali_softc *sc = device_get_softc(dev);
224254721Semaste
225254721Semaste	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
226254721Semaste		return EINVAL;
227254721Semaste
228254721Semaste	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
229254721Semaste	return 0;
230254721Semaste}
231254721Semaste
232254721Semastestatic void
233254721Semasteagp_ali_flush_tlb(device_t dev)
234254721Semaste{
235254721Semaste	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
236254721Semaste	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
237254721Semaste}
238254721Semaste
239254721Semastestatic device_method_t agp_ali_methods[] = {
240254721Semaste	/* Device interface */
241254721Semaste	DEVMETHOD(device_probe,		agp_ali_probe),
242254721Semaste	DEVMETHOD(device_attach,	agp_ali_attach),
243254721Semaste	DEVMETHOD(device_detach,	agp_ali_detach),
244254721Semaste	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
245254721Semaste	DEVMETHOD(device_suspend,	bus_generic_suspend),
246254721Semaste	DEVMETHOD(device_resume,	bus_generic_resume),
247254721Semaste
248254721Semaste	/* AGP interface */
249254721Semaste	DEVMETHOD(agp_get_aperture,	agp_ali_get_aperture),
250254721Semaste	DEVMETHOD(agp_set_aperture,	agp_ali_set_aperture),
251254721Semaste	DEVMETHOD(agp_bind_page,	agp_ali_bind_page),
252254721Semaste	DEVMETHOD(agp_unbind_page,	agp_ali_unbind_page),
253254721Semaste	DEVMETHOD(agp_flush_tlb,	agp_ali_flush_tlb),
254254721Semaste	DEVMETHOD(agp_enable,		agp_generic_enable),
255254721Semaste	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
256254721Semaste	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
257254721Semaste	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
258254721Semaste	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
259254721Semaste
260254721Semaste	{ 0, 0 }
261254721Semaste};
262254721Semaste
263254721Semastestatic driver_t agp_ali_driver = {
264254721Semaste	"agp",
265254721Semaste	agp_ali_methods,
266254721Semaste	sizeof(struct agp_ali_softc),
267254721Semaste};
268254721Semaste
269254721Semastestatic devclass_t agp_devclass;
270254721Semaste
271254721SemasteDRIVER_MODULE(agp_ali, pci, agp_ali_driver, agp_devclass, 0, 0);
272254721SemasteMODULE_DEPEND(agp_ali, agp, 1, 1, 1);
273254721SemasteMODULE_DEPEND(agp_ali, pci, 1, 1, 1);
274254721Semaste