xref: /openbsd-src/sys/dev/pci/mmuagp.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*-
2  * Copyright (c) 2004, 2005 Jung-uk Kim <jkim@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/malloc.h>
32 #include <sys/kernel.h>
33 #include <sys/proc.h>
34 #include <sys/conf.h>
35 #include <sys/device.h>
36 #include <sys/agpio.h>
37 
38 #include <uvm/uvm_extern.h>
39 
40 #include <dev/pci/pcivar.h>
41 #include <dev/pci/pcireg.h>
42 #include <dev/pci/agpvar.h>
43 #include <dev/pci/agpreg.h>
44 
45 #include <dev/pci/pcidevs.h>
46 
47 #include <machine/bus.h>
48 
49 /*
50  * AMD64 GART registers
51  */
52 #define	AGP_AMD64_APCTRL		0x90
53 #define	AGP_AMD64_APBASE		0x94
54 #define	AGP_AMD64_ATTBASE		0x98
55 #define	AGP_AMD64_CACHECTRL		0x9c
56 #define	AGP_AMD64_APCTRL_GARTEN		0x00000001
57 #define	AGP_AMD64_APCTRL_SIZE_MASK	0x0000000e
58 #define	AGP_AMD64_APCTRL_DISGARTCPU	0x00000010
59 #define	AGP_AMD64_APCTRL_DISGARTIO	0x00000020
60 #define	AGP_AMD64_APCTRL_DISWLKPRB	0x00000040
61 #define	AGP_AMD64_APBASE_MASK		0x00007fff
62 #define	AGP_AMD64_ATTBASE_MASK		0xfffffff0
63 #define	AGP_AMD64_CACHECTRL_INVGART	0x00000001
64 #define	AGP_AMD64_CACHECTRL_PTEERR	0x00000002
65 
66 /*
67  * NVIDIA nForce3 registers
68  */
69 #define AGP_AMD64_NVIDIA_0_APBASE	0x10
70 #define AGP_AMD64_NVIDIA_1_APBASE1	0x50
71 #define AGP_AMD64_NVIDIA_1_APLIMIT1	0x54
72 #define AGP_AMD64_NVIDIA_1_APSIZE	0xa8
73 #define AGP_AMD64_NVIDIA_1_APBASE2	0xd8
74 #define AGP_AMD64_NVIDIA_1_APLIMIT2	0xdc
75 
76 /*
77  * ULi M1689 registers
78  */
79 #define AGP_AMD64_ULI_APBASE		0x10
80 #define AGP_AMD64_ULI_HTT_FEATURE	0x50
81 #define AGP_AMD64_ULI_ENU_SCR		0x54
82 
83 
84 #define	AMD64_MAX_MCTRL		8
85 
86 /* XXX nForce3 requires secondary AGP bridge at 0:11:0. */
87 #define AGP_AMD64_NVIDIA_PCITAG(pc)	pci_make_tag(pc, 0, 11, 0)
88 /* XXX Some VIA bridge requires secondary AGP bridge at 0:1:0. */
89 #define AGP_AMD64_VIA_PCITAG(pc)	pci_make_tag(pc, 0, 1, 0)
90 
91 
92 int	mmuagp_probe(struct device *, void *, void *);
93 void	mmuagp_attach(struct device *, struct device *, void *);
94 bus_size_t mmuagp_get_aperture(void *);
95 int	mmuagp_set_aperture(void *, bus_size_t);
96 void	mmuagp_bind_page(void *, bus_addr_t, paddr_t, int);
97 void	mmuagp_unbind_page(void *, bus_addr_t);
98 void	mmuagp_flush_tlb(void *);
99 
100 void	mmuagp_apbase_fixup(void *);
101 
102 void	mmuagp_uli_init(void *);
103 int	mmuagp_uli_set_aperture(void *, bus_size_t);
104 
105 int	mmuagp_nvidia_match(const struct pci_attach_args *, uint16_t);
106 void	mmuagp_nvidia_init(void *);
107 int	mmuagp_nvidia_set_aperture(void *, bus_size_t);
108 
109 int	mmuagp_via_match(const struct pci_attach_args *);
110 void	mmuagp_via_init(void *);
111 int	mmuagp_via_set_aperture(void *, bus_size_t);
112 
113 struct mmuagp_softc {
114 	struct device		 dev;
115 	struct agp_softc	*agpdev;
116 	struct agp_gatt		*gatt;
117 	bus_addr_t		 msc_apaddr;
118 	bus_size_t		 msc_apsize;
119 	uint32_t		 apbase;
120 	pcitag_t		 ctrl_tag;	/* use NVIDIA and VIA */
121 	pcitag_t		 mctrl_tag[AMD64_MAX_MCTRL];
122 	pci_chipset_tag_t	 msc_pc;
123 	pcitag_t		 msc_tag;
124 	int			 n_mctrl;
125 };
126 
127 struct cfattach mmuagp_ca = {
128         sizeof(struct mmuagp_softc), mmuagp_probe, mmuagp_attach
129 };
130 
131 struct cfdriver mmuagp_cd = {
132 	NULL, "mmuagp", DV_DULL
133 };
134 
135 const struct agp_methods mmuagp_methods = {
136 	mmuagp_bind_page,
137 	mmuagp_unbind_page,
138 	mmuagp_flush_tlb,
139 };
140 
141 int
142 mmuagp_probe(struct device *parent, void *match, void *aux)
143 {
144 	struct agp_attach_args	*aa = aux;
145 	struct pci_attach_args	*pa = aa->aa_pa;
146 
147 	/* Must be a pchb, don't attach to iommu-style agp devs */
148 	if (agpbus_probe(aa) == 0)
149 		return (0);
150 
151 	switch (PCI_VENDOR(pa->pa_id)) {
152 	case PCI_VENDOR_ALI:
153 		switch (PCI_PRODUCT(pa->pa_id)) {
154 		case PCI_PRODUCT_ALI_M1689:
155 			return (1);
156 		}
157 		break;
158 	case PCI_VENDOR_AMD:
159 		switch (PCI_PRODUCT(pa->pa_id)) {
160 		case PCI_PRODUCT_AMD_8151_SC:
161 			return (1);
162 		}
163 		break;
164 	case PCI_VENDOR_NVIDIA:
165 		switch (PCI_PRODUCT(pa->pa_id)) {
166 		case PCI_PRODUCT_NVIDIA_NFORCE3_PCHB:
167 			return (mmuagp_nvidia_match(pa,
168 			    PCI_PRODUCT_NVIDIA_NFORCE3_PPB2));
169 			/* NOTREACHED */
170 		case PCI_PRODUCT_NVIDIA_NFORCE3_250_PCHB:
171 			return (mmuagp_nvidia_match(pa,
172 			    PCI_PRODUCT_NVIDIA_NFORCE3_250_AGP));
173 			/* NOTREACHED */
174 		}
175 		break;
176 	case PCI_VENDOR_SIS:
177 		switch (PCI_PRODUCT(pa->pa_id)) {
178 		case PCI_PRODUCT_SIS_755:
179 		case PCI_PRODUCT_SIS_760:
180 			return (1);
181 		}
182 		break;
183 	case PCI_VENDOR_VIATECH:
184 		switch (PCI_PRODUCT(pa->pa_id)) {
185 		case PCI_PRODUCT_VIATECH_K8M800_0:
186 		case PCI_PRODUCT_VIATECH_K8T890_0:
187 		case PCI_PRODUCT_VIATECH_K8HTB_0:
188 		case PCI_PRODUCT_VIATECH_K8HTB:
189 			return (1);
190 		}
191 		break;
192 	}
193 
194 	return (0);
195 }
196 
197 int
198 mmuagp_nvidia_match(const struct pci_attach_args *pa, uint16_t devid)
199 {
200 	pcitag_t	tag;
201 	pcireg_t	reg;
202 
203 	tag = AGP_AMD64_NVIDIA_PCITAG(pa->pa_pc);
204 
205 	reg = pci_conf_read(pa->pa_pc, tag, PCI_CLASS_REG);
206 	if (PCI_CLASS(reg) != PCI_CLASS_BRIDGE ||
207 	    PCI_SUBCLASS(reg) != PCI_SUBCLASS_BRIDGE_PCI)
208 		return 0;
209 
210 	reg = pci_conf_read(pa->pa_pc, tag, PCI_ID_REG);
211 	if (PCI_VENDOR(reg) != PCI_VENDOR_NVIDIA || PCI_PRODUCT(reg) != devid)
212 		return 0;
213 
214 	return 1;
215 }
216 
217 int
218 mmuagp_via_match(const struct pci_attach_args *pa)
219 {
220 	pcitag_t tag;
221 	pcireg_t reg;
222 
223 	tag = AGP_AMD64_VIA_PCITAG(pa->pa_pc);
224 
225 	reg = pci_conf_read(pa->pa_pc, tag, PCI_CLASS_REG);
226 	if (PCI_CLASS(reg) != PCI_CLASS_BRIDGE ||
227 	    PCI_SUBCLASS(reg) != PCI_SUBCLASS_BRIDGE_PCI)
228 		return 0;
229 
230 	reg = pci_conf_read(pa->pa_pc, tag, PCI_ID_REG);
231 	if (PCI_VENDOR(reg) != PCI_VENDOR_VIATECH ||
232 	    PCI_PRODUCT(reg) != PCI_PRODUCT_VIATECH_K8HTB_AGP)
233 		return 0;
234 
235 	return 1;
236 }
237 
238 void
239 mmuagp_attach(struct device *parent, struct device *self, void *aux)
240 {
241 	struct mmuagp_softc	*msc = (struct mmuagp_softc *)self ;
242 	struct agp_attach_args	*aa = aux;
243 	struct pci_attach_args	*pa = aa->aa_pa;
244 	struct agp_gatt		*gatt;
245 	int			 (*set_aperture)(void *, bus_size_t) = NULL;
246 	pcireg_t		 id, attbase, apctrl;
247 	pcitag_t		 tag;
248 	int			 maxdevs, i, n;
249 
250 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE,
251 	    PCI_MAPREG_TYPE_MEM, &msc->msc_apaddr, NULL, NULL) != 0) {
252 		printf(": can't get aperture info\n");
253 		return;
254 	}
255 
256 	msc->msc_pc = pa->pa_pc;
257 	msc->msc_tag = pa->pa_tag;
258 
259 	maxdevs = pci_bus_maxdevs(pa->pa_pc, 0);
260 	for (i = 0, n = 0; i < maxdevs && n < AMD64_MAX_MCTRL; i++) {
261 		tag = pci_make_tag(pa->pa_pc, 0, i, 3);
262 		id = pci_conf_read(pa->pa_pc, tag, PCI_ID_REG);
263 		if (PCI_VENDOR(id) == PCI_VENDOR_AMD &&
264 		    PCI_PRODUCT(id) ==  PCI_PRODUCT_AMD_AMD64_0F_MISC) {
265 			msc->mctrl_tag[n] = tag;
266 			n++;
267 		}
268 	}
269 	if (n == 0) {
270 		printf(": no Miscellaneous Control units found\n");
271 		return;
272 	}
273 	msc->n_mctrl = n;
274 
275 	printf(": %d Miscellaneous Control unit(s) found", msc->n_mctrl);
276 
277 	msc->msc_apsize = mmuagp_get_aperture(msc);
278 
279 	for (;;) {
280 		gatt = agp_alloc_gatt(pa->pa_dmat, msc->msc_apsize);
281 		if (gatt != NULL)
282 			break;
283 
284 		/*
285 		 * Probably failed to alloc contigious memory. Try reducing the
286 		 * aperture so that the gatt size reduces.
287 		 */
288 		msc->msc_apsize /= 2;
289 		if (mmuagp_set_aperture(msc, msc->msc_apsize)) {
290 			printf(" can't set aperture size\n");
291 			return;
292 		}
293 	}
294 	msc->gatt = gatt;
295 
296 	switch (PCI_VENDOR(pa->pa_id)) {
297 	case PCI_VENDOR_ALI:
298 		mmuagp_uli_init(msc);
299 		set_aperture = mmuagp_uli_set_aperture;
300 		break;
301 
302 	case PCI_VENDOR_NVIDIA:
303 		msc->ctrl_tag = AGP_AMD64_NVIDIA_PCITAG(pa->pa_pc);
304 		mmuagp_nvidia_init(msc);
305 		set_aperture = mmuagp_nvidia_set_aperture;
306 		break;
307 
308 	case PCI_VENDOR_VIATECH:
309 		/* do we have to set the extra bridge too? */
310 		if (mmuagp_via_match(pa)) {
311 			msc->ctrl_tag = AGP_AMD64_VIA_PCITAG(pa->pa_pc);
312 			mmuagp_via_init(msc);
313 			set_aperture = mmuagp_via_set_aperture;
314 		}
315 		break;
316 	}
317 
318 	if (set_aperture != NULL) {
319 		if ((*set_aperture)(msc, msc->msc_apsize)) {
320 			printf(", failed aperture set\n");
321 			return;
322 		}
323 	}
324 
325 	/* Install the gatt and enable aperture. */
326 	attbase = (uint32_t)(gatt->ag_physical >> 8) & AGP_AMD64_ATTBASE_MASK;
327 	for (i = 0; i < msc->n_mctrl; i++) {
328 		pci_conf_write(pa->pa_pc, msc->mctrl_tag[i], AGP_AMD64_ATTBASE,
329 		    attbase);
330 		apctrl = pci_conf_read(pa->pa_pc, msc->mctrl_tag[i],
331 		    AGP_AMD64_APCTRL);
332 		apctrl |= AGP_AMD64_APCTRL_GARTEN;
333 		apctrl &=
334 		    ~(AGP_AMD64_APCTRL_DISGARTCPU | AGP_AMD64_APCTRL_DISGARTIO);
335 		pci_conf_write(pa->pa_pc, msc->mctrl_tag[i], AGP_AMD64_APCTRL,
336 		    apctrl);
337 	}
338 
339 	agp_flush_cache();
340 
341 	msc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &mmuagp_methods,
342 	    msc->msc_apaddr, msc->msc_apsize, &msc->dev);
343 	return;
344 }
345 
346 
347 static bus_size_t mmuagp_table[] = {
348 	0x02000000,	/*   32 MB */
349 	0x04000000,	/*   64 MB */
350 	0x08000000,	/*  128 MB */
351 	0x10000000,	/*  256 MB */
352 	0x20000000,	/*  512 MB */
353 	0x40000000,	/* 1024 MB */
354 	0x80000000,	/* 2048 MB */
355 };
356 
357 #define AGP_AMD64_TABLE_SIZE \
358 	(sizeof(mmuagp_table) / sizeof(mmuagp_table[0]))
359 
360 bus_size_t
361 mmuagp_get_aperture(void *sc)
362 {
363 	struct mmuagp_softc *msc = sc;
364 	uint32_t i;
365 
366 	i = (pci_conf_read(msc->msc_pc, msc->mctrl_tag[0], AGP_AMD64_APCTRL) &
367 		AGP_AMD64_APCTRL_SIZE_MASK) >> 1;
368 
369 	if (i >= AGP_AMD64_TABLE_SIZE)
370 		return 0;
371 
372 	return mmuagp_table[i];
373 }
374 
375 int
376 mmuagp_set_aperture(void *sc, bus_size_t aperture)
377 {
378 	struct mmuagp_softc	*msc = sc;
379 	uint32_t		 i;
380 	pcireg_t		 apctrl;
381 	int			 j;
382 
383 	for (i = 0; i < AGP_AMD64_TABLE_SIZE; i++)
384 		if (mmuagp_table[i] == aperture)
385 			break;
386 	if (i >= AGP_AMD64_TABLE_SIZE)
387 		return (EINVAL);
388 
389 	for (j = 0; j < msc->n_mctrl; j++) {
390 		apctrl = pci_conf_read(msc->msc_pc, msc->mctrl_tag[0],
391 		    AGP_AMD64_APCTRL);
392 		pci_conf_write(msc->msc_pc, msc->mctrl_tag[0], AGP_AMD64_APCTRL,
393 		    (apctrl & ~(AGP_AMD64_APCTRL_SIZE_MASK)) | (i << 1));
394 	}
395 
396 	return (0);
397 }
398 
399 void
400 mmuagp_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags)
401 {
402 	struct mmuagp_softc	*msc = sc;
403 
404 	msc->gatt->ag_virtual[(offset - msc->msc_apaddr) >> AGP_PAGE_SHIFT] =
405 	    (physical & 0xfffff000) | ((physical >> 28) & 0x00000ff0) | 3;
406 }
407 
408 void
409 mmuagp_unbind_page(void *sc, bus_addr_t offset)
410 {
411 	struct mmuagp_softc *msc = sc;
412 
413 	msc->gatt->ag_virtual[(offset - msc->msc_apaddr) >> AGP_PAGE_SHIFT] = 0;
414 }
415 
416 void
417 mmuagp_flush_tlb(void *sc)
418 {
419 	struct mmuagp_softc	*msc = sc;
420 	pcireg_t		 cachectrl;
421 	int			 i;
422 
423 	for (i = 0; i < msc->n_mctrl; i++) {
424 		cachectrl = pci_conf_read(msc->msc_pc, msc->mctrl_tag[i],
425 		    AGP_AMD64_CACHECTRL);
426 		pci_conf_write(msc->msc_pc, msc->mctrl_tag[i],
427 		    AGP_AMD64_CACHECTRL,
428 		    cachectrl | AGP_AMD64_CACHECTRL_INVGART);
429 	}
430 }
431 
432 void
433 mmuagp_apbase_fixup(void *sc)
434 {
435 	struct mmuagp_softc	*msc = sc;
436 	uint32_t		 apbase;
437 	int			 i;
438 
439 	apbase = pci_conf_read(msc->msc_pc, msc->msc_tag, AGP_APBASE);
440 	msc->apbase = PCI_MAPREG_MEM_ADDR(apbase);
441 	apbase = (msc->apbase >> 25) & AGP_AMD64_APBASE_MASK;
442 	for (i = 0; i < msc->n_mctrl; i++)
443 		pci_conf_write(msc->msc_pc, msc->mctrl_tag[i], AGP_AMD64_APBASE,
444 		    apbase);
445 }
446 
447 void
448 mmuagp_uli_init(void *sc)
449 {
450 	struct mmuagp_softc *msc = sc;
451 	pcireg_t apbase;
452 
453 	mmuagp_apbase_fixup(msc);
454 	apbase = pci_conf_read(msc->msc_pc, msc->msc_tag,
455 	    AGP_AMD64_ULI_APBASE);
456 	pci_conf_write(msc->msc_pc, msc->msc_tag, AGP_AMD64_ULI_APBASE,
457 	    (apbase & 0x0000000f) | msc->apbase);
458 	pci_conf_write(msc->msc_pc, msc->msc_tag, AGP_AMD64_ULI_HTT_FEATURE,
459 	    msc->apbase);
460 }
461 
462 int
463 mmuagp_uli_set_aperture(void *sc, bus_size_t aperture)
464 {
465 	struct mmuagp_softc	*msc = sc;
466 
467 	switch (aperture) {
468 	case 0x02000000:	/*  32 MB */
469 	case 0x04000000:	/*  64 MB */
470 	case 0x08000000:	/* 128 MB */
471 	case 0x10000000:	/* 256 MB */
472 		break;
473 	default:
474 		return EINVAL;
475 	}
476 
477 	pci_conf_write(msc->msc_pc, msc->msc_tag, AGP_AMD64_ULI_ENU_SCR,
478 	    msc->apbase + aperture - 1);
479 
480 	return 0;
481 }
482 
483 void
484 mmuagp_nvidia_init(void *sc)
485 {
486 	struct mmuagp_softc	*msc = sc;
487 	pcireg_t		 apbase;
488 
489 	mmuagp_apbase_fixup(msc);
490 	apbase = pci_conf_read(msc->msc_pc, msc->msc_tag,
491 	    AGP_AMD64_NVIDIA_0_APBASE);
492 	pci_conf_write(msc->msc_pc, msc->msc_tag, AGP_AMD64_NVIDIA_0_APBASE,
493 	    (apbase & 0x0000000f) | msc->apbase);
494 	pci_conf_write(msc->msc_pc, msc->ctrl_tag, AGP_AMD64_NVIDIA_1_APBASE1,
495 	    msc->apbase);
496 	pci_conf_write(msc->msc_pc, msc->ctrl_tag, AGP_AMD64_NVIDIA_1_APBASE2,
497 	    msc->apbase);
498 }
499 
500 int
501 mmuagp_nvidia_set_aperture(void *sc, bus_size_t aperture)
502 {
503 	struct mmuagp_softc	*msc = sc;
504 	bus_size_t		 apsize;
505 
506 	switch (aperture) {
507 	case 0x02000000:	/*  32 MB */
508 		apsize = 0x0f;
509 		break;
510 	case 0x04000000:	/*  64 MB */
511 		apsize = 0x0e;
512 		break;
513 	case 0x08000000:	/* 128 MB */
514 		apsize = 0x0c;
515 		break;
516 	case 0x10000000:	/* 256 MB */
517 		apsize = 0x08;
518 		break;
519 	case 0x20000000:	/* 512 MB */
520 		apsize = 0x00;
521 		break;
522 	default:
523 		return (EINVAL);
524 	}
525 
526 	pci_conf_write(msc->msc_pc, msc->ctrl_tag, AGP_AMD64_NVIDIA_1_APSIZE,
527 	    (pci_conf_read(msc->msc_pc, msc->ctrl_tag,
528 	    AGP_AMD64_NVIDIA_1_APSIZE) & 0xfffffff0) | apsize);
529 	pci_conf_write(msc->msc_pc, msc->ctrl_tag, AGP_AMD64_NVIDIA_1_APLIMIT1,
530 	    msc->apbase + aperture - 1);
531 	pci_conf_write(msc->msc_pc, msc->ctrl_tag, AGP_AMD64_NVIDIA_1_APLIMIT2,
532 	    msc->apbase + aperture - 1);
533 
534 	return (0);
535 }
536 
537 void
538 mmuagp_via_init(void *sc)
539 {
540 	struct mmuagp_softc	*msc = sc;
541 
542 	mmuagp_apbase_fixup(sc);
543 	pci_conf_write(msc->msc_pc, msc->ctrl_tag, AGP3_VIA_ATTBASE,
544 	    msc->gatt->ag_physical);
545 	pci_conf_write(msc->msc_pc, msc->ctrl_tag, AGP3_VIA_GARTCTRL,
546 	    pci_conf_read(msc->msc_pc, msc->ctrl_tag, AGP3_VIA_ATTBASE) |
547 	        0x180);
548 }
549 
550 int
551 mmuagp_via_set_aperture(void *sc, bus_size_t aperture)
552 {
553 	struct mmuagp_softc	*msc = sc;
554 	bus_size_t		 apsize;
555 
556 	apsize = ((aperture - 1) >> 20) ^ 0xff;
557 	if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
558 		return (EINVAL);
559 	pci_conf_write(msc->msc_pc, msc->ctrl_tag, AGP3_VIA_APSIZE,
560 	    (pci_conf_read(msc->msc_pc, msc->ctrl_tag, AGP3_VIA_APSIZE) &
561 	        ~0xff) | apsize);
562 
563 	return 0;
564 }
565