Date: Tue, 18 May 2004 12:44:28 -0400 From: Jung-uk Kim <jkim@niksun.com> To: freebsd-current@freebsd.org, freebsd-x11@freebsd.org Subject: Test your agp(4) before blaming on DRM/DRI! Message-ID: <200405181244.28716.jkim@niksun.com>
next in thread | raw e-mail | index | archive | help
--Boundary-00=_s1jqACQmfCTEW1t Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline 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 --Boundary-00=_s1jqACQmfCTEW1t Content-Type: text/plain; charset="us-ascii"; name="testgart.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="testgart.c" /* * 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@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; } --Boundary-00=_s1jqACQmfCTEW1t--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200405181244.28716.jkim>