Hi, I'm playing around with my G400 using mmio access. Can someone tell me what I'm doing wrong? Writing to the registers doesn't produce a seg fault (so it seems that it would be mapped correctly), but reading back from them afterwards gives me either strange values or zero.
(Ignore the WARPREG* reading, that was only a test to see if they really were W/O.) Poking a value into any of the other registers has no effect on what is read back later. Some of them are explicitly marked as R/W, but I can't tell from the databook whether or not the value I write in that register should be "latched" and available for subsequent reads, or if some altogether different value is typically made available for reading from that reg. Any PCI posting should be flushed out by the read, and I made sure that access to MMIO space is enabled by hitting a register in the pci config space. Curiously, making changes to PCI config space seems to be fine, even while I am banging my head on the mmio. (If I disable MMIO access there, then any reads from MMIO space obviously return 0xffffffff.) I tried using msync, munmap, etc, and none of that seems to have an effect. I'm slowly beginning to suspect that R/W doesn't mean what I think it means with respect to MMIO registers. -- Ryan Underwood, <[EMAIL PROTECTED]>
#include <stdlib.h> #include <stdio.h> #include <assert.h> #include <sys/mman.h> #include <pci/pci.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define MGA_VENDOR 0x102b #define G400_DEVICE 0x0525 #include "warp_hw.h" #define MGAREG(x) *(volatile u32 *)(MGABASE1+x) #define MGA_LEN 0x4000 void init_warp_regs(volatile void *MGABASE1) { int i; /* memset(MGABASE1+WARPREG(0), 0, 64*4); */ fprintf(stderr, "Seeding WARP regs...\n"); for (i = 0; i < 64; i++) { MGAREG(WARPREG(i)) = i+1; fprintf(stderr, "[%d]:\t%8lx ", i, i+1); if (!((i+1)%4)) fprintf(stderr, "\n"); } // fprintf(stderr, "Setting WMISC (0x%08p) to 3...\n", MGABASE1+WMISC); // MGAREG(WMISC) &= 3; // fprintf(stderr, "WMISC (0x%08p) is %d\n", MGABASE1+WMISC, MGAREG(WMISC)); fprintf(stderr, "Setting WIADDRNB (%08p) to 0x30000...\n", MGABASE1+WIADDRNB); MGAREG(WIADDRNB) = 0x30000; fprintf(stderr, "WIADDRNB (%08p) is %d\n", MGABASE1+WIADDRNB, MGAREG(WIADDRNB)); fprintf(stderr, "Setting C2CTL (%08p:%08lx) \n", MGABASE1+C2CTL, MGAREG(C2CTL)); MGAREG(C2CTL) &= C2CTL_C2EN; fprintf(stderr, "C2CTL (%08p) is %d\n", MGABASE1+C2CTL, MGAREG(C2CTL)); } void dump_warp(volatile void *MGABASE1) { int i; fprintf(stderr, "Display WARP0 regs:\n"); for (i = 0; i < 64; i++) { fprintf(stderr, "[%d]:\t%8lx ", i, MGAREG(WARPREG(i))); if (!((i+1)%4)) fprintf(stderr, "\n"); } fprintf(stderr, "WARP0 Interrupt %s\n", (MGAREG(IEN) & WIEN)? "enabled":"disabled"); fprintf(stderr, "WARP0 Cache-miss Interrupt %s\n", (MGAREG(IEN) & WCIEN)? "enabled":"disabled"); fprintf(stderr, "WARP1 Interrupt %s\n", (MGAREG(IEN) & WIEN1)? "enabled":"disabled"); fprintf(stderr, "WARP1 Cache-miss Interrupt %s\n", (MGAREG(IEN) & WCIEN1)? "enabled":"disabled"); fprintf(stderr, "Drawing engine status: %s\n", (MGAREG(STATUS) & DWGENGSTS)? "busy": "idle"); fprintf(stderr, "WARP0 status: %s\n", (MGAREG(STATUS) & WBUSY)? "not idle": "idle"); fprintf(stderr, "WARP1 status: %s\n", (MGAREG(STATUS) & WBUSY1)? "not idle": "idle"); fprintf(stderr, "WARP BFIFO Path: %s\n", (MGAREG(STATUS) & WARPBFPATH)? "WARP1": "WARP0"); fprintf(stderr, "WARPFIFO Input Path: %s\n", (MGAREG(STATUS) & WFIPATH)? "WARPFIFO1": "WARPFIFO0"); fprintf(stderr, "WARPFIFO Output Path: %s\n", (MGAREG(STATUS) & WFOPATH)? "WARPFIFO1": "WARPFIFO0"); fprintf(stderr, "WARP microcode address: 0x%lx\n", MGAREG(WCODEADDR) & 0xffffff00); fprintf(stderr, "WARP microcode caching %s\n", (MGAREG(WMISC) & (1 << 0))? "enabled":"disabled"); fprintf(stderr, "WARP microcode load strategy: "); if (MGAREG(WMISC) & (1 << 0)) { if (MGAREG(WMISC) & (1 << 1)) { fprintf(stderr, "bus mastering\n"); } else { fprintf(stderr, "interrupt\n"); } } else { fprintf(stderr, "direct load\n"); } } int main(int argc, char**argv) { volatile void *MGABASE1; struct pci_access *all_devices; struct pci_dev cfg; struct pci_dev *cur; int fd, i; u32 mgabase_addr = 0; u32 ret; assert(!getuid()); iopl(3); /* Scan PCI buses for G400 */ all_devices = pci_alloc(); all_devices->numeric_ids = 1; pci_init(all_devices); pci_scan_bus(all_devices); cur = all_devices->devices; for (i = 0; ; i++) { if (cur[i].vendor_id == MGA_VENDOR && cur[i].device_id == G400_DEVICE) { printf("found MGA: irq %d\n", cur[i].irq); memcpy(&cfg, &cur[i], sizeof(struct pci_dev)); mgabase_addr = pci_read_long(&cur[i], 0x14) & PCI_ADDR_MEM_MASK; break; } if (cur[i].next == NULL) break; } if (mgabase_addr == 0) { fprintf(stderr, "MGABASE1 not found\n"); exit(EXIT_FAILURE); } fprintf(stderr,"MGABASE1: 0x%lx\n", mgabase_addr); fprintf(stderr,"MGABASE2: 0x%lx\n", pci_read_long(&cfg, 0x10)); fprintf(stderr,"DEVID: 0x%lx\n", (ret = pci_read_long(&cfg, 0x00))); fprintf(stderr,"DEVCTRL: 0x%lx\n", (ret = pci_read_long(&cfg, 0x04))); if (!(ret & DEVCTRL_MEMSPACE)) { fprintf(stderr,"Enabling MMIO access\n"); pci_write_long(&cfg, 0x04, ret|DEVCTRL_MEMSPACE); fprintf(stderr,"DEVCTRL: 0x%lx\n", (ret = pci_read_long(&cfg, 0x04))); } fprintf(stderr,"OPTION: 0x%lx\n", (ret = pci_read_long(&cfg, 0x40))); fprintf(stderr,"OPTION2: 0x%lx\n", (ret = pci_read_long(&cfg, 0x50))); fprintf(stderr,"OPTION3: 0x%lx\n", (ret = pci_read_long(&cfg, 0x54))); fprintf(stderr,"PM_CSR: 0x%lx\n", (ret = pci_read_long(&cfg, 0xe0))); fprintf(stderr,"PM_IDENT: 0x%lx\n", (ret = pci_read_long(&cfg, 0xdc))); fprintf(stderr,"ROMBASE: 0x%lx\n", (ret = pci_read_long(&cfg, 0x30))); fprintf(stderr,"SUBSYSID: 0x%lx\n", (ret = pci_read_long(&cfg, 0x2c))); pci_cleanup(all_devices); fd = open("/dev/mem", O_RDWR); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } MGABASE1 = mmap(NULL, MGA_LEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t)mgabase_addr); if (MGABASE1 == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } fprintf(stderr, "mmap successful: 0x%lx\n", MGABASE1); { char *buf; asprintf(&buf, "cat /proc/%d/maps", getpid()); system(buf); free(buf); } init_warp_regs(MGABASE1); dump_warp(MGABASE1); if (munmap((void*)MGABASE1, MGA_LEN) == -1) { perror("munmap"); } close(fd); }
signature.asc
Description: Digital signature