Test your agp(4) before blaming on DRM/DRI!
Jung-uk Kim
jkim at niksun.com
Tue May 18 09:45:18 PDT 2004
I was trying to make my Intel i815 and VIA K8T800 chipsets working
with agp(4) and I found that there were number of issues in the
driver. These issues were mainly from adding PCI IDs blindly without
verifying proper documentation. On top of that, some drivers do not
care whether the bridge is supported or not and just attach as
'generic' bridge, e. g., agp_sis.c and agp_via.c. This gives users
false hope and I believe this is wrong.
I found the following from DRI website:
http://dri.sourceforge.net/res/testgart.c
and SuSE Linux had little newer package:
http://www.suse.de/us/private/products/suse_linux/prof/packages_professional/testgart.html
I modified SuSE's to work with FreeBSD. Test your GART before blaming
on DRM/DRI! If aperture size is reported differently from BIOS
setting, that is not supported correctly, e. g., i815 - different
aperture size encoding and registers. If writeback test fails,
that's more serious problem, e. g., K8T800 - doesn't work at all for
me.
BTW, you have to unload your drm driver (or recompile kernel if you
compiled it in) before you test agp.
I hope this helps many confused users.
Cheers,
Jung-uk Kim
* PS: Is there anybody working on AMD64 on-CPU GART driver like this?
http://fxr.watson.org/fxr/source/drivers/char/agp/amd64-agp.c?v=linux-2.6.1
Documentation is here (Section 3.6.11-14):
http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26094.PDF
-------------- next part --------------
/*
* Test program for AGPGART module under Linux & FreeBSD
*
* Copyright (C) 1999 Jeff Hartmann, Precision Insight, Inc., Xi Graphics, Inc.
*
* FreeBSD porting by Jung-uk Kim <jkim at niksun.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/agpio.h>
#if defined (__i386__) || defined (__amd64__)
#include <sys/memrange.h>
#endif
#include <errno.h>
unsigned char *gart;
int gartfd;
#if defined (__i386__) || defined (__amd64__)
int mtrr;
u_int64_t gart_base;
u_int64_t gart_range;
#endif
int
usec(void)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
return (tv.tv_sec & 2047) * 1000000 + tv.tv_usec;
}
int
MemoryBenchmark(void *buffer, int dwords)
{
int i;
int start, end;
int mb;
int *base;
base = (int *)buffer;
start = usec();
for (i = 0; i < dwords; i += 8) {
base[i] =
base[i + 1] =
base[i + 2] =
base[i + 3] =
base[i + 4] =
base[i + 5] =
base[i + 6] =
base[i + 7] = 0x15151515; /* dmapad nops */
}
end = usec();
mb = ((float)dwords / 0x40000) * 1000000 / (end - start);
printf("start=%d, end=%d\n", start, end);
printf("MemoryBenchmark: %i mb/s\n", mb);
return mb;
}
int
insert_gart(int page, int size)
{
agp_allocate entry;
agp_bind bind;
entry.type = 0;
entry.pg_count = size;
#ifdef DEBUG
printf("Using AGPIOC_ALLOCATE\n");
#endif
if (ioctl(gartfd, AGPIOC_ALLOCATE, &entry) != 0) {
perror("ioctl(AGPIOC_ALLOCATE)");
exit(1);
}
bind.key = entry.key;
bind.pg_start = page;
#ifdef DEBUG
printf("Using AGPIOC_BIND\n");
#endif
if (ioctl(gartfd, AGPIOC_BIND, &bind)) {
perror("ioctl(AGPIOC_BIND)");
exit(1);
}
printf("entry.key : %u\n", entry.key);
return (entry.key);
}
int
unbind_gart(int key)
{
agp_unbind unbind;
unbind.key = key;
unbind.priority = 0;
#ifdef DEBUG
printf("Using AGPIOC_UNBIND\n");
#endif
if (ioctl(gartfd, AGPIOC_UNBIND, &unbind) != 0) {
perror("ioctl(AGPIOC_UNBIND)");
exit(1);
}
return (0);
}
int
bind_gart(int key, int page)
{
agp_bind bind;
bind.key = key;
bind.pg_start = page;
#ifdef DEBUG
printf("Using AGPIOC_BIND\n");
#endif
if (ioctl(gartfd, AGPIOC_BIND, &bind) != 0) {
perror("ioctl(AGPIOC_BIND)");
exit(1);
}
return (0);
}
int
remove_gart(int key)
{
#ifdef DEBUG
printf("Using AGPIOC_DEALLOCATE\n");
#endif
if (ioctl(gartfd, AGPIOC_DEALLOCATE, &key) != 0) {
perror("ioctl(AGPIOC_DEALLOCATE)");
exit(1);
}
return (0);
}
#if defined (__i386__) || defined (__amd64__)
void
openmtrr(void)
{
struct mem_range_op mop;
if ((mtrr = open("/dev/mem", O_WRONLY, 0)) == -1) {
perror("open(\"/dev/mem\")");
return;
}
mop.mo_arg[0] = 0;
if (ioctl(mtrr, MEMRANGE_GET, &mop) == -1) {
perror("ioctl(MEMRANGE_GET)");
mtrr = -1;
return;
}
}
void
closemtrr(void)
{
struct mem_range_desc sentry;
struct mem_range_op mop;
sentry.mr_base = gart_base;
sentry.mr_len = gart_range;
sentry.mr_owner[0] = '\0';
mop.mo_desc = &sentry;
mop.mo_arg[0] = MEMRANGE_SET_REMOVE;
mop.mo_arg[1] = 0;
if (ioctl(mtrr, MEMRANGE_SET, &mop) == -1) {
perror("ioctl(MEMRANGE_SET)");
exit(1);
}
close(mtrr);
}
void
CoverRangeWithMTRR(u_int64_t base, u_int64_t range, int type)
{
struct mem_range_desc sentry;
struct mem_range_op mop;
printf("MTRR: %llx/%llx\n",
(unsigned long long)base, (unsigned long long)range);
/* set it if we aren't just checking the number */
if (type != -1) {
sentry.mr_base = base;
sentry.mr_len = range;
sentry.mr_flags = type;
strcpy(sentry.mr_owner, "agpgart");
mop.mo_desc = &sentry;
mop.mo_arg[0] = MEMRANGE_SET_UPDATE;
mop.mo_arg[1] = 0;
if (ioctl(mtrr, MEMRANGE_SET, &mop) == -1) {
perror("ioctl(MEMRANGE_SET)");
exit(1);
}
}
}
#endif
int
init_agp(void)
{
agp_info info;
agp_setup setup;
#ifdef DEBUG
printf("Using AGPIOC_ACQUIRE\n");
#endif
if (ioctl(gartfd, AGPIOC_ACQUIRE, 0) != 0) {
perror("ioctl(AGPIOC_ACQUIRE)");
exit(1);
}
#ifdef DEBUG
printf("Using AGPIOC_INFO\n");
#endif
if (ioctl(gartfd, AGPIOC_INFO, &info) != 0) {
perror("ioctl(AGPIOC_INFO)");
exit(1);
}
printf("version: %u.%u\n", info.version.major, info.version.minor);
printf("bridge id: 0x%lx\n", (unsigned long)info.bridge_id);
printf("agp_mode: 0x%lx\n", (unsigned long)info.agp_mode);
printf("aper_base: 0x%lx\n", (unsigned long)info.aper_base);
printf("aper_size: %u\n", (unsigned int)info.aper_size);
printf("pg_total: %u\n", (unsigned int)info.pg_total);
printf("pg_system: %u\n", (unsigned int)info.pg_system);
printf("pg_used: %u\n", (unsigned int)info.pg_used);
#if defined (__i386__) || defined (__amd64__)
openmtrr();
if (mtrr != -1) {
gart_base = (u_int64_t)info.aper_base;
gart_range = (u_int64_t)info.aper_size << 20;
CoverRangeWithMTRR(gart_base, gart_range, MDF_WRITECOMBINE);
}
#endif
gart = mmap(NULL, (size_t)info.aper_size << 20,
PROT_READ | PROT_WRITE, MAP_SHARED, gartfd, 0);
if (gart == MAP_FAILED) {
perror("mmap()");
close(gartfd);
exit(1);
}
setup.agp_mode = info.agp_mode;
#ifdef DEBUG
printf("Using AGPIOC_SETUP\n");
#endif
if (ioctl(gartfd, AGPIOC_SETUP, &setup) != 0) {
perror("ioctl(AGPIOC_SETUP)");
exit(1);
}
return (0);
}
int xchangeDummy;
#if defined (__i386__) || defined (__amd64__)
void
FlushWriteCombining(void)
{
__asm__ volatile (
" push %%eax ; xchg %%eax, %0 ; pop %%eax"
: /* no outputs */ : "m" (xchangeDummy)
);
__asm__ volatile (
" push %%eax ; push %%ebx ; push %%ecx ; push %%edx ;"
" movl $0,%%eax ; cpuid ;"
" pop %%edx ; pop %%ecx ; pop %%ebx ; pop %%eax"
: /* no outputs */ : /* no inputs */
);
}
#endif
void
BenchMark(int key, int key2)
{
int i, worked = 1;
i = MemoryBenchmark(gart, (1024 * 1024 * 4) / 4) +
MemoryBenchmark(gart, (1024 * 1024 * 4) / 4) +
MemoryBenchmark(gart, (1024 * 1024 * 4) / 4);
printf("Average speed: %i mb/s\n", i / 3);
printf("Testing data integrity (1st pass): ");
fflush(stdout);
#if defined (__i386__) || defined (__amd64__)
FlushWriteCombining();
#endif
for (i = 0; i < 0x800000; i++) {
gart[i] = i % 256;
}
#if defined (__i386__) || defined (__amd64__)
FlushWriteCombining();
#endif
for (i = 0; i < 0x800000; i++) {
if (!(gart[i] == i % 256)) {
#ifdef DEBUG
printf("failed on %i, gart[i] = %i\n", i, gart[i]);
#endif
worked = 0;
}
}
if (!worked)
printf("failed on first pass!\n");
else
printf("passed on first pass.\n");
unbind_gart(key);
unbind_gart(key2);
bind_gart(key, 0);
bind_gart(key2, 1024);
worked = 1;
printf("Testing data integrity (2nd pass): ");
fflush(stdout);
for (i = 0; i < 0x800000; i++) {
if (!(gart[i] == i % 256)) {
#ifdef DEBUG
printf("failed on %i, gart[i] = %i\n", i, gart[i]);
#endif
worked = 0;
}
}
if (!worked)
printf("failed on second pass!\n");
else
printf("passed on second pass.\n");
}
int
main()
{
int key;
int key2;
#ifdef DEBUG
agp_info info;
#endif
gartfd = open("/dev/agpgart", O_RDWR);
if (gartfd == -1) {
perror("open(\"/dev/agpgart\")");
exit(1);
}
init_agp();
key = insert_gart(0, 1024);
key2 = insert_gart(1024, 1024);
#ifdef DEBUG
printf("Using AGPIOC_INFO\n");
if (ioctl(gartfd, AGPIOC_INFO, &info) != 0) {
perror("ioctl(AGPIOC_INFO)");
exit(1);
}
printf("version: %u.%u\n", info.version.major, info.version.minor);
printf("bridge id: 0x%lx\n", (unsigned long)info.bridge_id);
printf("agp_mode: 0x%lx\n", (unsigned long)info.agp_mode);
printf("aper_base: 0x%lx\n", (unsigned long)info.aper_base);
printf("aper_size: %u\n", (unsigned int)info.aper_size);
printf("pg_total: %u\n", (unsigned int)info.pg_total);
printf("pg_system: %u\n", (unsigned int)info.pg_system);
printf("pg_used: %u\n", (unsigned int)info.pg_used);
#endif
printf("Allocated 8 megs of GART memory\n");
BenchMark(key, key2);
remove_gart(key);
remove_gart(key2);
#ifdef DEBUG
printf("Using AGPIOC_RELEASE\n");
#endif
if (ioctl(gartfd, AGPIOC_RELEASE, 0) != 0) {
perror("ioctl(AGPIOC_RELEASE)");
exit(1);
}
close(gartfd);
#if defined (__i386__) || defined (__amd64__)
closemtrr();
#endif
return 0;
}
More information about the freebsd-x11
mailing list