[PATCH] AMD64 On-CPU GART support + more

Jung-uk Kim jkim at niksun.com
Mon Jun 14 20:48:53 GMT 2004


Since the latest DRM is imported, I made my AMD64 on-CPU GART[1] 
working (patch attached).  This driver has some ugliness because of 
its nature: driver is for AGP bridge but directly touches north 
bridge registers (of multiple north bridges if you have multiple 
CPUs).  Ideally we can attach child driver here for each bridge but 
it is just a part of its functions so that I didn't want to create a 
full-blown driver.  The second ugliness comes from the agp_sis.c and 
agp_via.c.  They fall back to 'generic host to PCI bridge' if it is 
not supported but it finds a bridge.  I believe this has to be 
removed.  The kludge is 'AGP_AMD64_GART' in kernel configuration.  
This kludge can be removed when the 'fallback' match/probe is 
removed.  For now, 'AGP_AMD64_GART' is required to test this driver.  
If anyone is interested, please cleanup/fix them. :-(

It's tested with Via K8T800 (both FreeBSD/i386 and FreeBSD/amd64) but 
it should work with other bridges/tunnels.  XFree86 snapshot (after 
Mesa 6.1 import) + DRI snapshot worked fine with MGA 400 and Radeon 
RV280 in FreeBSD/i386.  In FreeBSD/amd64, MGA 400 works but Radeon 
RV280 doesn't work but I believe it's DRM/DRI's problem, i. e., 
Radeon SAREA handles.

Cheers,

Jung-uk Kim

[1] BIOS and Kernel Developer's Guide for AMD Athlon? 64 and AMD 
Opteron(tm) Processors (3.6.12-15)
http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26094.PDF

* PS: I think the current agp_via.c doesn't support K8T800 or other 
AGP v3 bridges correctly.  If anyone is interested, let me know. ;-)
-------------- next part --------------
--- src/sys/conf/files.amd64.orig	Mon May 24 08:08:56 2004
+++ src/sys/conf/files.amd64	Mon Jun 14 16:05:45 2004
@@ -133,6 +133,7 @@
 kern/link_elf_obj.c		standard
 pci/agp_ali.c			optional	agp
 pci/agp_amd.c			optional	agp
+pci/agp_amd64.c			optional	agp
 pci/agp_i810.c			optional	agp
 pci/agp_intel.c			optional	agp
 pci/agp_sis.c			optional	agp
--- src/sys/conf/files.i386.orig	Wed May 26 03:43:40 2004
+++ src/sys/conf/files.i386	Mon Jun 14 16:05:45 2004
@@ -411,6 +411,7 @@
 libkern/umoddi3.c		standard
 pci/agp_ali.c			optional	agp
 pci/agp_amd.c			optional	agp
+pci/agp_amd64.c			optional	agp
 pci/agp_i810.c			optional	agp
 pci/agp_intel.c			optional	agp
 pci/agp_nvidia.c		optional	agp
--- src/sys/conf/options.amd64.orig	Sat Mar 13 17:16:34 2004
+++ src/sys/conf/options.amd64	Mon Jun 14 16:05:45 2004
@@ -54,3 +54,6 @@
 IA32
 NO_MIXED_MODE
 DEV_ATPIC		opt_atpic.h
+
+# agp options
+AGP_AMD64_GART		opt_agp.h
--- src/sys/conf/options.i386.orig	Sun Mar 14 18:03:56 2004
+++ src/sys/conf/options.i386	Mon Jun 14 16:05:45 2004
@@ -161,3 +161,6 @@
 # Device options
 DEV_APIC		opt_apic.h
 DEV_NPX			opt_npx.h
+
+# agp options
+AGP_AMD64_GART		opt_agp.h
--- src/sys/modules/Makefile.orig	Mon May 17 10:22:40 2004
+++ src/sys/modules/Makefile	Mon Jun 14 16:06:00 2004
@@ -377,6 +377,8 @@
 .endif
 
 .if ${MACHINE_ARCH} == "amd64"
+_agp=		agp
+_drm=		drm
 #_ndis=		ndis
 .endif
 
--- src/sys/modules/agp/Makefile.orig	Sat Aug 23 14:00:31 2003
+++ src/sys/modules/agp/Makefile	Mon Jun 14 16:05:45 2004
@@ -6,10 +6,13 @@
 SRCS=	agp.c agp_if.c
 .if ${MACHINE_ARCH} == "i386"
 SRCS+=	agp_i810.c agp_intel.c agp_via.c agp_sis.c agp_ali.c agp_amd.c \
-	agp_nvidia.c
+	agp_amd64.c agp_nvidia.c opt_agp.h
 .endif
 .if  ${MACHINE_ARCH} == "alpha"
 SRCS+=	agp_amd.c
+.endif
+.if  ${MACHINE_ARCH} == "amd64"
+SRCS+=	agp_amd64.c opt_agp.h
 .endif
 SRCS+=	device_if.h bus_if.h agp_if.h pci_if.h
 SRCS+=	opt_bdg.h opt_bus.h
--- src/sys/pci/agp.c.orig	Sun May 30 16:00:40 2004
+++ src/sys/pci/agp.c	Mon Jun 14 16:05:45 2004
@@ -87,7 +87,7 @@
 void
 agp_flush_cache()
 {
-#ifdef __i386__
+#if defined(__i386__) || defined(__amd64__)
 	wbinvd();
 #endif
 #ifdef __alpha__
--- src/sys/pci/agp_amd64.c.orig	Mon Jun  7 23:42:04 2004
+++ src/sys/pci/agp_amd64.c	Mon Jun 14 16:05:45 2004
@@ -0,0 +1,315 @@
+/*-
+ * Copyright (c) 2004 Jung-uk Kim
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_bus.h"
+#include "opt_agp.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <pci/agppriv.h>
+#include <pci/agpreg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/pmap.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+/* XXX */
+extern void pci_cfgregwrite(int, int, int, int, uint32_t, int);
+extern uint32_t pci_cfgregread(int, int, int, int, int);
+
+MALLOC_DECLARE(M_AGP);
+
+#define AMD64_MAX_MCTRL		8
+
+struct agp_amd64_softc {
+	struct agp_softc agp;
+	uint32_t	initial_aperture; /* aperture size at startup */
+	struct agp_gatt *gatt;
+	int		mctrl[AMD64_MAX_MCTRL];
+	int		n_mctrl;
+};
+
+static const char*
+agp_amd64_match(device_t dev)
+{
+	if (pci_get_class(dev) != PCIC_BRIDGE
+	    || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
+		return NULL;
+
+	if (agp_find_caps(dev) == 0)
+		return NULL;
+
+#ifdef AGP_AMD64_GART
+	switch (pci_get_devid(dev)) {
+	case 0x74541022:
+		return ("AMD 8151 AGP graphics tunnel");
+	case 0x10221039:
+		return ("SiS 755 host to AGP bridge");
+	case 0x02041106:
+		return ("VIA 8380 host to PCI bridge");
+	case 0x31881106:
+		return ("VIA 8385 host to PCI bridge");
+	};
+#endif
+
+	return NULL;
+}
+
+static int
+agp_amd64_probe(device_t dev)
+{
+	const char *desc;
+
+	if (resource_disabled("agp", device_get_unit(dev)))
+		return (ENXIO);
+	desc = agp_amd64_match(dev);
+	if (desc) {
+		device_verbose(dev);
+		device_set_desc(dev, desc);
+		return 0;
+	}
+
+	return ENXIO;
+}
+
+static int
+agp_amd64_attach(device_t dev)
+{
+	struct agp_amd64_softc *sc = device_get_softc(dev);
+	struct agp_gatt *gatt;
+	int i, n, error;
+
+	for (i = 0, n = 0; i < PCI_SLOTMAX && n < AMD64_MAX_MCTRL; i++)
+		if (pci_cfgregread(0, i, 3, 0, 4) == 0x11031022) {
+			sc->mctrl[n] = i;
+			n++;
+		}
+
+	if (n == 0)
+		return ENXIO;
+
+	sc->n_mctrl = n;
+
+	if (bootverbose)
+		printf("AMD64: %d Misc. Control unit(s) found.\n",
+			sc->n_mctrl);
+
+	error = agp_generic_attach(dev);
+	if (error)
+		return error;
+
+	sc->initial_aperture = AGP_GET_APERTURE(dev);
+
+	for (;;) {
+		gatt = agp_alloc_gatt(dev);
+		if (gatt)
+			break;
+
+		/*
+		 * Probably contigmalloc failure. Try reducing the
+		 * aperture so that the gatt size reduces.
+		 */
+		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
+			agp_generic_detach(dev);
+			return ENOMEM;
+		}
+	}
+	sc->gatt = gatt;
+
+	/* Install the gatt and enable aperture. */
+	for (i = 0; i < sc->n_mctrl; i++) {
+		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_ATTBASE,
+		    (uint32_t)(gatt->ag_physical >> 8) & AGP_AMD64_ATTBASE_MASK,
+		    4);
+		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL,
+		    (pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL, 4) |
+		    AGP_AMD64_APCTRL_GARTEN) &
+		    ~(AGP_AMD64_APCTRL_DISGARTCPU | AGP_AMD64_APCTRL_DISGARTIO),
+		    4);
+	}
+
+	agp_flush_cache();
+
+	return 0;
+}
+
+static int
+agp_amd64_detach(device_t dev)
+{
+	struct agp_amd64_softc *sc = device_get_softc(dev);
+	int i, error;
+
+	error = agp_generic_detach(dev);
+	if (error)
+		return error;
+
+	for (i = 0; i < sc->n_mctrl; i++)
+		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL,
+		    pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL, 4) &
+		    ~AGP_AMD64_APCTRL_GARTEN, 4);
+
+	AGP_SET_APERTURE(dev, sc->initial_aperture);
+	agp_free_gatt(sc->gatt);
+
+	return 0;
+}
+
+static uint32_t agp_amd64_table[] = {
+	0x02000000,	/*   32 MB */
+	0x04000000,	/*   64 MB */
+	0x08000000,	/*  128 MB */
+	0x10000000,	/*  256 MB */
+	0x20000000,	/*  512 MB */
+	0x40000000,	/* 1024 MB */
+	0x80000000,	/* 2048 MB */
+};
+
+#define AGP_AMD64_TABLE_SIZE \
+	(sizeof(agp_amd64_table) / sizeof(agp_amd64_table[0]))
+
+static uint32_t
+agp_amd64_get_aperture(device_t dev)
+{
+	struct agp_amd64_softc *sc = device_get_softc(dev);
+	uint32_t i;
+
+	i = (pci_cfgregread(0, sc->mctrl[0], 3, AGP_AMD64_APCTRL, 4) &
+		AGP_AMD64_APCTRL_SIZE_MASK) >> 1;
+
+	if (i >= AGP_AMD64_TABLE_SIZE)
+		return 0;
+
+	return (agp_amd64_table[i]);
+}
+
+static int
+agp_amd64_set_aperture(device_t dev, uint32_t aperture)
+{
+	struct agp_amd64_softc *sc = device_get_softc(dev);
+	uint32_t i;
+	int j;
+
+	for (i = 0; i < AGP_AMD64_TABLE_SIZE; i++)
+		if (agp_amd64_table[i] == aperture)
+			break;
+	if (i == AGP_AMD64_TABLE_SIZE)
+		return EINVAL;
+
+	for (j = 0; j < sc->n_mctrl; j++)
+		pci_cfgregwrite(0, sc->mctrl[j], 3, AGP_AMD64_APCTRL,
+		    (pci_cfgregread(0, sc->mctrl[j], 3, AGP_AMD64_APCTRL, 4) &
+		    ~(AGP_AMD64_APCTRL_SIZE_MASK)) | (i << 1), 4);
+
+	return 0;
+}
+
+static int
+agp_amd64_bind_page(device_t dev, int offset, vm_offset_t physical)
+{
+	struct agp_amd64_softc *sc = device_get_softc(dev);
+
+	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+		return EINVAL;
+
+	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
+	return 0;
+}
+
+static int
+agp_amd64_unbind_page(device_t dev, int offset)
+{
+	struct agp_amd64_softc *sc = device_get_softc(dev);
+
+	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
+		return EINVAL;
+
+	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
+	return 0;
+}
+
+static void
+agp_amd64_flush_tlb(device_t dev)
+{
+	struct agp_amd64_softc *sc = device_get_softc(dev);
+	int i;
+
+	for (i = 0; i < sc->n_mctrl; i++)
+		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_CACHECTRL,
+		    pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_CACHECTRL, 4) |
+		    AGP_AMD64_CACHECTRL_INVGART, 4);
+}
+
+static device_method_t agp_amd64_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		agp_amd64_probe),
+	DEVMETHOD(device_attach,	agp_amd64_attach),
+	DEVMETHOD(device_detach,	agp_amd64_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+	DEVMETHOD(device_suspend,	bus_generic_suspend),
+	DEVMETHOD(device_resume,	bus_generic_resume),
+
+	/* AGP interface */
+	DEVMETHOD(agp_get_aperture,	agp_amd64_get_aperture),
+	DEVMETHOD(agp_set_aperture,	agp_amd64_set_aperture),
+	DEVMETHOD(agp_bind_page,	agp_amd64_bind_page),
+	DEVMETHOD(agp_unbind_page,	agp_amd64_unbind_page),
+	DEVMETHOD(agp_flush_tlb,	agp_amd64_flush_tlb),
+	DEVMETHOD(agp_enable,		agp_generic_enable),
+	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
+	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
+	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
+	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
+
+	{ 0, 0 }
+};
+
+static driver_t agp_amd64_driver = {
+	"agp",
+	agp_amd64_methods,
+	sizeof(struct agp_amd64_softc),
+};
+
+static devclass_t agp_devclass;
+
+DRIVER_MODULE(agp_amd64, pci, agp_amd64_driver, agp_devclass, 0, 0);
+MODULE_DEPEND(agp_amd64, agp, 1, 1, 1);
+MODULE_DEPEND(agp_amd64, pci, 1, 1, 1);
--- src/sys/pci/agp_sis.c.orig	Sun May 30 16:00:40 2004
+++ src/sys/pci/agp_sis.c	Mon Jun 14 16:05:45 2004
@@ -28,6 +28,7 @@
 __FBSDID("$FreeBSD: src/sys/pci/agp_sis.c,v 1.13 2004/05/30 20:00:40 phk Exp $");
 
 #include "opt_bus.h"
+#include "opt_agp.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -105,6 +106,10 @@
 		return ("SiS 746 host to AGP bridge");
 	case 0x07601039:
 		return ("SiS 760 host to AGP bridge");
+#ifdef AGP_AMD64_GART
+	case 0x10221039:
+		return NULL;
+#endif
 	};
 
 	if (pci_get_vendor(dev) == 0x1039)
--- src/sys/pci/agp_via.c.orig	Mon Jun 14 16:09:52 2004
+++ src/sys/pci/agp_via.c	Mon Jun 14 16:09:07 2004
@@ -88,7 +88,11 @@
 	case 0x06911106:
 		return ("VIA 82C691 (Apollo Pro) host to PCI bridge");
 	case 0x31881106:
+#ifdef AGP_AMD64_GART
+		return NULL;
+#else
 		return ("VIA 8385 host to PCI bridge");
+#endif
 	};
 
 	if (pci_get_vendor(dev) == 0x1106)
--- src/sys/pci/agpreg.h.orig	Thu May 13 16:05:42 2004
+++ src/sys/pci/agpreg.h	Mon Jun 14 16:05:45 2004
@@ -244,4 +244,21 @@
 #define	AGP_NVIDIA_3_APBASE		0x50
 #define	AGP_NVIDIA_3_APLIMIT		0x54
 
+/*
+ * AMD64 GART registers
+ */
+#define AGP_AMD64_APCTRL		0x90
+#define AGP_AMD64_APBASE		0x94
+#define AGP_AMD64_ATTBASE		0x98
+#define AGP_AMD64_CACHECTRL		0x9c
+#define AGP_AMD64_APCTRL_GARTEN		0x00000001
+#define AGP_AMD64_APCTRL_SIZE_MASK	0x0000000e
+#define AGP_AMD64_APCTRL_DISGARTCPU	0x00000010
+#define AGP_AMD64_APCTRL_DISGARTIO	0x00000020
+#define AGP_AMD64_APCTRL_DISWLKPRB	0x00000040
+#define AGP_AMD64_APBASE_MASK		0x00007fff
+#define AGP_AMD64_ATTBASE_MASK		0xfffffff0
+#define AGP_AMD64_CACHECTRL_INVGART	0x00000001
+#define AGP_AMD64_CACHECTRL_PTEERR	0x00000002
+
 #endif /* !_PCI_AGPREG_H_ */


More information about the freebsd-amd64 mailing list