]> Zhao Yanbai Git Server - minix.git/commitdiff
Driver for AMD's DEV.
authorPhilip Homburg <philip@cs.vu.nl>
Mon, 25 Feb 2008 12:07:19 +0000 (12:07 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Mon, 25 Feb 2008 12:07:19 +0000 (12:07 +0000)
drivers/amddev/Makefile [new file with mode: 0644]
drivers/amddev/amddev.c [new file with mode: 0644]

diff --git a/drivers/amddev/Makefile b/drivers/amddev/Makefile
new file mode 100644 (file)
index 0000000..85abf1d
--- /dev/null
@@ -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 (file)
index 0000000..69fc430
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+amddev.c
+
+Driver for the AMD Device Exclusion Vector (DEV)
+*/
+
+#define _SYSTEM
+#define _MINIX
+
+#include <minix/config.h>
+#include <minix/type.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/vm.h>
+#include <minix/com.h>
+#include <minix/const.h>
+#include <minix/ipc.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <ibm/pci.h>
+
+/* 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; o<size; o += PAGE_SIZE)
+       {
+               bit= (busaddr+o)/PAGE_SIZE;
+               table[bit/8] &= ~(1 << (bit % 8));
+       }
+}
+
+static void del_range(u32_t busaddr, u32_t size)
+{
+       u32_t o, bit;
+
+#if 0
+       printf("del_range: mapping 0x%x@0x%x\n", size, busaddr);
+#endif
+
+       for (o= 0; o<size; o += PAGE_SIZE)
+       {
+               bit= (busaddr+o)/PAGE_SIZE;
+               table[bit/8] |= (1 << (bit % 8));
+       }
+}
+
+static int do_pm_notify(message *m)
+{
+       int r;
+       endpoint_t proc_e;
+       phys_bytes base, size;
+
+       if (m->m_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);
+}