From: Philip Homburg Date: Mon, 25 Feb 2008 12:07:19 +0000 (+0000) Subject: Driver for AMD's DEV. X-Git-Tag: v3.1.4~247 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/soc.html?a=commitdiff_plain;h=4474166403c088f2e9200111bf6da0fae20a48d8;p=minix.git Driver for AMD's DEV. --- diff --git a/drivers/amddev/Makefile b/drivers/amddev/Makefile new file mode 100644 index 000000000..85abf1d5a --- /dev/null +++ b/drivers/amddev/Makefile @@ -0,0 +1,33 @@ +# Makefile for AMD's DEV +DRIVER = amddev + +# programs, flags, etc. +CC = exec cc +CFLAGS = $(CPROFILE) +LDFLAGS = -i +#LIBS = -lsysutil -lsys -ltimers +LIBS = -lsysutil -lsys + +OBJ = amddev.o + +# build local binary +all build: $(DRIVER) +$(DRIVER): $(OBJ) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) + install -S 320k $(DRIVER) + +# install with other drivers +install: /usr/sbin/$(DRIVER) +/usr/sbin/$(DRIVER): $(DRIVER) + install -o root -cs $? $@ + +# clean up local files +clean: + rm -f *.o *.bak $(DRIVER) + +depend: + mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend + diff --git a/drivers/amddev/amddev.c b/drivers/amddev/amddev.c new file mode 100644 index 000000000..69fc430f2 --- /dev/null +++ b/drivers/amddev/amddev.c @@ -0,0 +1,516 @@ +/* +amddev.c + +Driver for the AMD Device Exclusion Vector (DEV) +*/ + +#define _SYSTEM +#define _MINIX + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Offsets from capability pointer */ +#define DEV_OP 4 /* Selects control/status register to access */ +#define DEV_OP_FUNC_SHIFT 8 /* Function part in OP reg. */ +#define DEV_DATA 8 /* Read/write to access reg. selected */ + +/* Functions */ +#define DEVF_BASE_LO 0 +#define DEVF_BASE_HI 1 +#define DEVF_MAP 2 +#define DEVF_CAP 3 +#define DEVF_CAP_MAPS_MASK 0x00ff0000 +#define DEVF_CAP_MAPS_SHIFT 16 +#define DEVF_CAP_DOMS_MASK 0x0000ff00 +#define DEVF_CAP_DOMS_SHIFT 8 +#define DEVF_CAP_REV_MASK 0x000000ff +#define DEVF_CAP_REV_SHIFT 0 +#define DEVF_CR 4 +#define DEVF_ERR_STATUS 5 +#define DEVF_ERR_ADDR_LO 6 +#define DEVF_ERR_ADDR_HI 7 + +static int dev_devind; +static u8_t dev_capptr; +static u8_t *table; + +static int init(void); +static int find_dev(int *devindp, u8_t *capaddrp); +static u32_t read_reg(int function, int index); +static void write_reg(int function, int index, u32_t value); +static void init_domain(int index); +static void init_map(int index); +static int do_add_phys(message *m); +static int do_del_phys(message *m); +static int do_add4pci(message *m); +static void add_range(u32_t busaddr, u32_t size); +static void del_range(u32_t busaddr, u32_t size); +static int do_pm_notify(message *m); +static void report_exceptions(void); + +int main(void) +{ + int r; + message m; + + printf("amddev: starting\n"); + + init(); + + for(;;) + { + report_exceptions(); + + r= receive(ANY, &m); + if (r != OK) + panic(__FILE__, "receive failed", r); + switch(m.m_type) + { + case PROC_EVENT: + do_pm_notify(&m); + continue; + + case IOMMU_ADD: + r= do_add4pci(&m); + m.m_type= r; + send(m.m_source, &m); + continue; + } + printf("amddev: got message from %d\n", m.m_source); + } +} + +static int init() +{ + int r, n_maps, n_domains, revision; + u16_t flags; + u32_t bits; + + r= find_dev(&dev_devind, &dev_capptr); + if (!r) + return r; + flags= pci_attr_r16(dev_devind, dev_capptr+CAP_SD_INFO); + printf("amddev`init: flags = 0x%x\n", flags); + + bits= read_reg(DEVF_CAP, 0); + n_maps= ((bits & DEVF_CAP_MAPS_MASK) >> DEVF_CAP_MAPS_SHIFT); + n_domains= ((bits & DEVF_CAP_DOMS_MASK) >> DEVF_CAP_DOMS_SHIFT); + revision= ((bits & DEVF_CAP_REV_MASK) >> DEVF_CAP_REV_SHIFT); + printf("amddev`init: DEVF_CAP = 0x%x (%d maps, %d domains, rev 0x%x)\n", + bits, n_maps, n_domains, revision); + + printf("status = 0x%x, addr-lo = 0x%x, addr-hi = 0x%x\n", + read_reg(DEVF_ERR_STATUS, 0), + read_reg(DEVF_ERR_ADDR_LO, 0), + read_reg(DEVF_ERR_ADDR_HI, 0)); + + init_domain(0); + init_map(0); +#if 0 + init_domain(1); +#endif + + write_reg(DEVF_CR, 0, 0x10 | 0x8 | 0x4 | 1); + + printf("after write: DEVF_CR: 0x%x\n", read_reg(DEVF_CR, 0)); +} + +static int find_dev(devindp, capaddrp) +int *devindp; +u8_t *capaddrp; +{ + int r, devind, first; + u8_t capptr, type, next, subtype; + u16_t vid, did, status; + + pci_init(); + + first= 1; + for(;;) + { + if (first) + { + first= 0; + r= pci_first_dev(&devind, &vid, &did); + if (!r) + { + printf("amddev`find_dev: no first dev\n"); + return; + } + } + else + { + r= pci_next_dev(&devind, &vid, &did); + if (!r) + { + printf("amddev`find_dev: no next dev\n"); + return; + } + } + + printf("amddev`find_dev: got devind %d, vid 0x%x, did 0x%x\n", + devind, vid, did); + + /* Check capabilities bit in the device status register */ + status= pci_attr_r16(devind, PCI_SR); + if (!(status & PSR_CAPPTR)) + continue; + + capptr= (pci_attr_r8(devind, PCI_CAPPTR) & PCI_CP_MASK); + while (capptr != 0) + { + type = pci_attr_r8(devind, capptr+CAP_TYPE); + next= (pci_attr_r8(devind, capptr+CAP_NEXT) & + PCI_CP_MASK); + if (type == CAP_T_SECURE_DEV) + { + printf( + "amddev`find_dev: found secure device\n"); + subtype= (pci_attr_r8(devind, capptr+ + CAP_SD_INFO) & CAP_SD_SUBTYPE_MASK); + if (subtype == CAP_T_SD_DEV) + { + printf("amddev`find_dev: AMD DEV\n"); + pci_reserve(devind); + *devindp= devind; + *capaddrp= capptr; + return 1; + } + } + capptr= next; + } + } + return 0; +} + +static u32_t read_reg(int function, int index) +{ + pci_attr_w32(dev_devind, dev_capptr + DEV_OP, ((function << + DEV_OP_FUNC_SHIFT) | index)); + return pci_attr_r32(dev_devind, dev_capptr + DEV_DATA); +} + +static void write_reg(int function, int index, u32_t value) +{ + pci_attr_w32(dev_devind, dev_capptr + DEV_OP, ((function << + DEV_OP_FUNC_SHIFT) | index)); + pci_attr_w32(dev_devind, dev_capptr + DEV_DATA, value); +} + +static void init_domain(int index) +{ + int r; + size_t o, size, memsize; + phys_bytes busaddr; + + size= 0x100000 / 8; + table= malloc(size + PAGE_SIZE); + if (table == NULL) + panic("AMDDEV","malloc failed", NO_NUM); + o= (unsigned)table & (PAGE_SIZE-1); + if (o) + table += PAGE_SIZE-o; + if (index == 0) + { + memset(table, 0, size); + memsize= 0x37000 / 8; + printf("memsize = 0x%x / 8\n", memsize*8); + memset(table, 0xff, memsize); + } + else + { + memset(table, 0xff, size); + memset(table, 0x00, size); + } + + r= sys_umap(SELF, D, (vir_bytes)table, size, &busaddr); + if (r != OK) + panic("AMDDEV","sys_umap failed", r); +printf("init_domain: busaddr = %p\n", busaddr); + + write_reg(DEVF_BASE_HI, index, 0); + write_reg(DEVF_BASE_LO, index, busaddr | 3); + + printf("after write: DEVF_BASE_LO: 0x%x\n", + read_reg(DEVF_BASE_LO, index)); +} + +static void init_map(int index) +{ + u32_t v, dom, busno, unit0, unit1; + + dom= 1; + busno= 7; + unit1= 9; + unit0= 9; + v= (dom << 26) | (dom << 20) | (busno << 12) | + (0 << 11) | (unit1 << 6) | + (0 << 5) | (unit0 << 0); + write_reg(DEVF_MAP, index, v); + + printf("after write: DEVF_MAP: 0x%x\n", read_reg(DEVF_MAP, index)); +} + +static int do_add(message *m) +{ + int r; + endpoint_t proc; + vir_bytes start; + size_t size; + phys_bytes busaddr; + + proc= m->m_source; + start= m->m2_l1; + size= m->m2_l2; + +#if 0 + printf("amddev`do_add: got request for 0x%x@0x%x from %d\n", + size, start, proc); +#endif + + if (start % PAGE_SIZE) + { + printf("amddev`do_add: bad start 0x%x from proc %d\n", + start, proc); + return EINVAL; + } + if (size % PAGE_SIZE) + { + printf("amddev`do_add: bad size 0x%x from proc %d\n", + size, proc); + return EINVAL; + } + r= sys_umap(proc, D, (vir_bytes)start, size, &busaddr); + if (r != OK) + { + printf("amddev`do_add: umap failed for 0x%x@0x%x, proc %d\n", + size, start, proc); + return r; + } + add_range(busaddr, size); + +} + +static int do_add_phys(message *m) +{ + int i, r; + phys_bytes start; + size_t size; + + start= m->m2_l1; + size= m->m2_l2; + +#if 0 + printf("amddev`do_add_phys: got request for 0x%x@0x%x\n", + size, start); +#endif + + if (start % PAGE_SIZE) + { + printf("amddev`do_add_phys: bad start 0x%x\n", start); + return EINVAL; + } + if (size % PAGE_SIZE) + { + printf("amddev`do_add_phys: bad size 0x%x\n", size); + return EINVAL; + } + add_range(start, size); + + write_reg(DEVF_CR, 0, 0x10); + for (i= 0; i<1000000; i++) + { + if (read_reg(DEVF_CR, 0) & 0x10) + continue; + return OK; + } + return EBUSY; +} + +static int do_del_phys(message *m) +{ + int r; + phys_bytes start; + size_t size; + + start= m->m2_l1; + size= m->m2_l2; + +#if 0 + printf("amddev`do_del_phys: got request for 0x%x@0x%x\n", + size, start); +#endif + + if (start % PAGE_SIZE) + { + printf("amddev`do_del_phys: bad start 0x%x\n", start); + return EINVAL; + } + if (size % PAGE_SIZE) + { + printf("amddev`do_del_phys: bad size 0x%x\n", size); + return EINVAL; + } + del_range(start, size); + + write_reg(DEVF_CR, 0, 0x10); + + return OK; +} + +static int do_add4pci(message *m) +{ + int r, pci_bus, pci_dev, pci_func; + endpoint_t proc; + vir_bytes start; + size_t size; + phys_bytes busaddr; + + proc= m->m_source; + start= m->m2_l1; + size= m->m2_l2; + pci_bus= m->m1_i1; + pci_dev= m->m1_i2; + pci_func= m->m1_i3; + + printf( +"amddev`do_add4pci: got request for 0x%x@0x%x from %d for pci dev %u.%u.%u\n", + size, start, proc, pci_bus, pci_dev, pci_func); + + if (start % PAGE_SIZE) + { + printf("amddev`do_add4pci: bad start 0x%x from proc %d\n", + start, proc); + return EINVAL; + } + if (size % PAGE_SIZE) + { + printf("amddev`do_add4pci: bad size 0x%x from proc %d\n", + size, proc); + return EINVAL; + } + + printf("amddev`do_add4pci: should check with PCI\n"); + + r= sys_umap(proc, D, (vir_bytes)start, size, &busaddr); + if (r != OK) + { + printf( + "amddev`do_add4pci: umap failed for 0x%x@0x%x, proc %d: %d\n", + size, start, proc, r); + return r; + } + + r= adddma(proc, busaddr, size); + if (r != 0) + { + r= -errno; + printf( + "amddev`do_add4pci: adddma failed for 0x%x@0x%x, proc %d: %d\n", + size, start, proc, r); + return r; + } + + add_range(busaddr, size); + + return OK; +} + + +static void add_range(u32_t busaddr, u32_t size) +{ + u32_t o, bit; + +#if 0 + printf("add_range: mapping 0x%x@0x%x\n", size, busaddr); +#endif + + for (o= 0; om_source != PM_PROC_NR) + { + printf("amddev`do_pm_notify: notify not from PM (from %d)\n", + m->m_source); + return; + } + + for (;;) + { + r= getdma(&proc_e, &base, &size); + if (r == -1) + { + if (errno != -EAGAIN) + { + printf( + "amddev`do_pm_notify: getdma failed: %d\n", + errno); + } + break; + } + + printf( + "amddev`do_pm_notify: deleting 0x%x@0x%x for proc %d\n", + size, base, proc_e); + del_range(base, size); + r= deldma(proc_e, base, size); + if (r == -1) + { + printf("amddev`do_pm_notify: deldma failed: %d\n", + errno); + break; + } + } +} + +static void report_exceptions(void) +{ + u32_t status; + + status= read_reg(DEVF_ERR_STATUS, 0); + if (!(status & 0x80000000)) + return; + printf("amddev: status = 0x%x, addr-lo = 0x%x, addr-hi = 0x%x\n", + status, read_reg(DEVF_ERR_ADDR_LO, 0), + read_reg(DEVF_ERR_ADDR_HI, 0)); + write_reg(DEVF_ERR_STATUS, 0, 0); +}