Driver for AMD's DEV.
This commit is contained in:
parent
a51dbad054
commit
4474166403
2 changed files with 549 additions and 0 deletions
33
drivers/amddev/Makefile
Normal file
33
drivers/amddev/Makefile
Normal file
|
@ -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
|
||||
|
516
drivers/amddev/amddev.c
Normal file
516
drivers/amddev/amddev.c
Normal file
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue