/* * 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 */ #include #include #include #include #include #include #include #include #include #include #if defined (__i386__) || defined (__amd64__) #include #endif #include 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; }