From 36af2dc80ce2824b027931856ea86324dd158e73 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 15 Dec 2001 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2001-12-15 --- boot/boot.h | 7 + boot/dosboot.c | 77 ----- mtx/fns.h | 19 ++ mtx/i8259.c | 199 +++++++++++ mtx/io.h | 39 ++- mtx/main.c | 3 + mtx/mem.h | 7 +- mtx/pci.c | 911 +++++++++++++++++++++++++++++++++++++++++++++++++ mtx/raven.c | 143 ++++++++ mtx/trap.c | 78 +---- pc/pci.c | 2 + 11 files changed, 1334 insertions(+), 151 deletions(-) delete mode 100644 boot/dosboot.c create mode 100644 mtx/i8259.c create mode 100644 mtx/pci.c create mode 100644 mtx/raven.c diff --git a/boot/boot.h b/boot/boot.h index b33956d259049f5e4b19ddcfc106e755e1ee30d3..f17024336247d26aed673238be0f10099244faf9 100644 --- a/boot/boot.h +++ b/boot/boot.h @@ -55,15 +55,22 @@ extern int parsefields(char*, char**, int, char*); extern void configil(Method*); extern int authil(void); extern int connectil(void); + extern void configtcp(Method*); extern int authtcp(void); extern int connecttcp(void); + extern void configlocal(Method*); extern int authlocal(void); extern int connectlocal(void); + extern void configsac(Method*); extern int authsac(void); extern int connectsac(void); +extern void configpaq(Method*); +extern int authpaq(void); +extern int connectpaq(void); + /* hack for passing authentication address */ extern char *authaddr; diff --git a/boot/dosboot.c b/boot/dosboot.c deleted file mode 100644 index 087bd055a46f123eb7bc6ddd78ab1b0296afdb14..0000000000000000000000000000000000000000 --- a/boot/dosboot.c +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include "../boot/boot.h" - -int printcol; - -static void dossrv(void); -static void swapproc(void); - -void -dosboot(void) -{ - int fd; - - open("#c/cons", OREAD); - open("#c/cons", OWRITE); - open("#c/cons", OWRITE); - - /* - * start to dos file system server - */ - dossrv(); - sleep(1000); - fd = open("#s/boot", ORDWR); - if(fd < 0) - fatal("open #s/boot"); - - /* - * pick a floppy and mount it as root - */ - if(bind("/", "/", MREPL) < 0) - fatal("bind /"); - if(mount(fd, -1, "/", MAFTER|MCREATE, "#f/fd0disk") < 0) - if(mount(fd, -1, "/", MAFTER|MCREATE, "#f/fd1disk") < 0) - if(mount(fd, -1, "/", MAFTER|MCREATE, "#S/sdC0/dos") < 0) - fatal("mount /"); - close(fd); - - settime(1, -1); - swapproc(); - - execl("/386/init", "init", "-mt", 0); - fatal("/386/init"); -} - -static void -dossrv(void) -{ - print("dossrv..."); - if(bind("#c", "/dev", MREPL) < 0) - fatal("bind #c"); - if(bind("#p", "/proc", MREPL) < 0) - fatal("bind #p"); - switch(fork()){ - case -1: - fatal("fork"); - case 0: - execl("/cfs", "cfs", "boot", 0); - fatal("can't exec cfs"); - default: - break; - } -} - -static void -swapproc(void) -{ - int fd; - - fd = open("#c/swap", OWRITE); - if(fd < 0){ - warning("opening #c/swap"); - return; - } - if(write(fd, "start", 5) <= 0) - warning("starting swap kproc"); -} diff --git a/mtx/fns.h b/mtx/fns.h index b95e134411d4313f4ee9d1ffe8aaa36cd2c61d8d..4f1aabb554845aba3813395719086618b3df6bbe 100644 --- a/mtx/fns.h +++ b/mtx/fns.h @@ -65,12 +65,30 @@ void links(void); void mathinit(void); void mmuinit(void); ulong* mmuwalk(ulong*, ulong, int); +void mpicenable(int); +void mpiceoi(void); +int mpicintack(void); void outb(int, int); void outsb(int, void*, int); void outs(int, ushort); void outss(int, void*, int); void outl(int, ulong); void outsl(int, void*, int); +int pciscan(int, Pcidev **); +ulong pcibarsize(Pcidev *, int); +int pcicfgr8(Pcidev*, int); +int pcicfgr16(Pcidev*, int); +int pcicfgr32(Pcidev*, int); +void pcicfgw8(Pcidev*, int, int); +void pcicfgw16(Pcidev*, int, int); +void pcicfgw32(Pcidev*, int, int); +void pciclrbme(Pcidev*); +void pcihinv(Pcidev*); +uchar pciipin(Pcidev *, uchar); +Pcidev* pcimatch(Pcidev*, int, int); +Pcidev* pcimatchtbdf(int); +void pcireset(void); +void pcisetbme(Pcidev*); int pcmspecial(char*, ISAConf*); void pcmspecialclose(int); #define procrestore(p) @@ -81,6 +99,7 @@ void procsetup(Proc*); void putdec(ulong); void putmsr(ulong); void putcasid(ulong); +void raveninit(void); void screeninit(void); void setpanic(void); int screenprint(char*, ...); /* debugging */ diff --git a/mtx/i8259.c b/mtx/i8259.c new file mode 100644 index 0000000000000000000000000000000000000000..562196b96fe5738eaa11a913ba7dbfdf716a879f --- /dev/null +++ b/mtx/i8259.c @@ -0,0 +1,199 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +/* + * 8259 interrupt controllers + */ +enum +{ + Int0ctl= 0x20, /* control port (ICW1, OCW2, OCW3) */ + Int0aux= 0x21, /* everything else (ICW2, ICW3, ICW4, OCW1) */ + Int1ctl= 0xA0, /* control port */ + Int1aux= 0xA1, /* everything else (ICW2, ICW3, ICW4, OCW1) */ + + Icw1= 0x10, /* select bit in ctl register */ + Ocw2= 0x00, + Ocw3= 0x08, + + EOI= 0x20, /* non-specific end of interrupt */ + + Elcr1= 0x4D0, /* Edge/Level Triggered Register */ + Elcr2= 0x4D1, +}; + +static Lock i8259lock; +static int i8259mask = 0xFFFF; /* disabled interrupts */ +int i8259elcr; /* mask of level-triggered interrupts */ + +void +i8259init(void) +{ + int x; + + ioalloc(Int0ctl, 2, 0, "i8259.0"); + ioalloc(Int1ctl, 2, 0, "i8259.1"); + ilock(&i8259lock); + + /* + * Set up the first 8259 interrupt processor. + * Make 8259 interrupts start at CPU vector VectorPIC. + * Set the 8259 as master with edge triggered + * input with fully nested interrupts. + */ + outb(Int0ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered, + ICW4 will be sent */ + outb(Int0aux, VectorPIC); /* ICW2 - interrupt vector offset */ + outb(Int0aux, 0x04); /* ICW3 - have slave on level 2 */ + outb(Int0aux, 0x01); /* ICW4 - 8086 mode, not buffered */ + + /* + * Set up the second 8259 interrupt processor. + * Make 8259 interrupts start at CPU vector VectorPIC+8. + * Set the 8259 as slave with edge triggered + * input with fully nested interrupts. + */ + outb(Int1ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered, + ICW4 will be sent */ + outb(Int1aux, VectorPIC+8); /* ICW2 - interrupt vector offset */ + outb(Int1aux, 0x02); /* ICW3 - I am a slave on level 2 */ + outb(Int1aux, 0x01); /* ICW4 - 8086 mode, not buffered */ + outb(Int1aux, (i8259mask>>8) & 0xFF); + + /* + * pass #2 8259 interrupts to #1 + */ + i8259mask &= ~0x04; + outb(Int0aux, i8259mask & 0xFF); + + /* + * Set Ocw3 to return the ISR when ctl read. + * After initialisation status read is set to IRR. + * Read IRR first to possibly deassert an outstanding + * interrupt. + */ + inb(Int0ctl); + outb(Int0ctl, Ocw3|0x03); + inb(Int1ctl); + outb(Int1ctl, Ocw3|0x03); + + /* + * Check for Edge/Level register. + * This check may not work for all chipsets. + * First try a non-intrusive test - the bits for + * IRQs 13, 8, 2, 1 and 0 must be edge (0). If + * that's OK try a R/W test. + */ + x = (inb(Elcr2)<<8)|inb(Elcr1); + if(!(x & 0x2107)){ + outb(Elcr1, 0); + if(inb(Elcr1) == 0){ + outb(Elcr1, 0x20); + if(inb(Elcr1) == 0x20) + i8259elcr = x; + outb(Elcr1, x & 0xFF); + print("ELCR: %4.4uX\n", i8259elcr); + } + } + iunlock(&i8259lock); +} + +int +i8259isr(int vno) +{ + int irq, isr; + + if(vno < VectorPIC || vno > VectorPIC+MaxIrqPIC) + return 0; + irq = vno-VectorPIC; + + /* + * tell the 8259 that we're done with the + * highest level interrupt (interrupts are still + * off at this point) + */ + ilock(&i8259lock); + isr = inb(Int0ctl); + outb(Int0ctl, EOI); + if(irq >= 8){ + isr |= inb(Int1ctl)<<8; + outb(Int1ctl, EOI); + } + iunlock(&i8259lock); + + return isr & (1<irq; + if(irq < 0 || irq > MaxIrqPIC){ + print("i8259enable: irq %d out of range\n", irq); + return -1; + } + irqbit = 1<>8) & 0xFF); + + if(i8259elcr & irqbit) + v->eoi = i8259isr; + else + v->isr = i8259isr; + iunlock(&i8259lock); + + return VectorPIC+irq; +} + +int +i8259vecno(int irq) +{ + return VectorPIC+irq; +} + +int +i8259disable(int irq) +{ + int irqbit; + + /* + * Given an IRQ, disable the corresponding interrupt + * in the 8259. + */ + if(irq < 0 || irq > MaxIrqPIC){ + print("i8259disable: irq %d out of range\n", irq); + return -1; + } + irqbit = 1<>8) & 0xFF); + } + iunlock(&i8259lock); + return 0; +} diff --git a/mtx/io.h b/mtx/io.h index 83bb404c04a5871b16f6db5338f733bfaa3f0b2f..80a216c4a734b7f9ba94ad25c8096fae685546b6 100644 --- a/mtx/io.h +++ b/mtx/io.h @@ -13,7 +13,7 @@ enum { IrqATA1 = 15, MaxIrqPIC = 15, - VectorPIC = 64, + VectorPIC = 32, MaxVectorPIC = VectorPIC+MaxIrqPIC, }; @@ -85,7 +85,6 @@ enum { /* type 0 and type 1 pre-defined header */ PciBAR0 = 0x10, /* base address */ PciBAR1 = 0x14, - PciROM = 0x30, PciINTL = 0x3C, /* interrupt line */ PciINTP = 0x3D, /* interrupt pin */ @@ -99,7 +98,7 @@ enum { /* type 0 pre-defined header */ PciCIS = 0x28, /* cardbus CIS pointer */ PciSVID = 0x2C, /* subsystem vendor ID */ PciSID = 0x2E, /* cardbus CIS pointer */ - PciEBAR0 = 0x30, /* xpansion ROM base address */ + PciEBAR0 = 0x30, /* expansion ROM base address */ PciMGNT = 0x3E, /* burst period length */ PciMLT = 0x3F, /* maximum latency between bursts */ }; @@ -124,6 +123,34 @@ enum { /* type 1 pre-defined header */ PciBCR = 0x3E, /* bridge control register */ }; +enum { /* type 2 pre-defined header */ + PciCBExCA = 0x10, + PciCBSPSR = 0x16, + PciCBPBN = 0x18, /* primary bus number */ + PciCBSBN = 0x19, /* secondary bus number */ + PciCBUBN = 0x1A, /* subordinate bus number */ + PciCBSLTR = 0x1B, /* secondary latency timer */ + PciCBMBR0 = 0x1C, + PciCBMLR0 = 0x20, + PciCBMBR1 = 0x24, + PciCBMLR1 = 0x28, + PciCBIBR0 = 0x2C, /* I/O base */ + PciCBILR0 = 0x30, /* I/O limit */ + PciCBIBR1 = 0x34, /* I/O base */ + PciCBILR1 = 0x38, /* I/O limit */ + PciCBSVID = 0x40, /* subsystem vendor ID */ + PciCBSID = 0x42, /* subsystem ID */ + PciCBLMBAR = 0x44, /* legacy mode base address */ +}; + +typedef struct Pcisiz Pcisiz; +struct Pcisiz +{ + Pcidev* dev; + int siz; + int bar; +}; + typedef struct Pcidev Pcidev; typedef struct Pcidev { int tbdf; /* type+bus+device+function */ @@ -153,7 +180,5 @@ typedef struct Pcidev { ulong pcr; }; -//#define PCIWINDOW 0x40000000 -//#define PCIWADDR(va) (PADDR(va)+PCIWINDOW) -//#define ISAWINDOW 0x00800000 -//#define ISAWADDR(va) (PADDR(va)+ISAWINDOW) +#define PCIWINDOW 0 +#define PCIWADDR(va) (PADDR(va)+PCIWINDOW) diff --git a/mtx/main.c b/mtx/main.c index e24203addcec23ec6554efb89cc7d41ea6f21347..f683a719585e6b6e3e54b58ce53c2d9f542348cf 100644 --- a/mtx/main.c +++ b/mtx/main.c @@ -21,9 +21,12 @@ main(void) print("\nPlan 9\n"); confinit(); xinit(); + raveninit(); trapinit(); printinit(); cpuidprint(); +pcihinv(nil); +firmware(); mmuinit(); procinit0(); initseg(); diff --git a/mtx/mem.h b/mtx/mem.h index dd36510a759e48375b947d6e0e9fefeeaff75dec..56ba1855bc4e89ee7996bf68d6fc8d2b4e5a5497 100644 --- a/mtx/mem.h +++ b/mtx/mem.h @@ -196,9 +196,12 @@ #define USTKSIZE (4*1024*1024) /* size of user stack */ #define UREGSIZE ((8+32)*4) -#define PCI1 0x40000000 -#define PCI0 0xfd000000 +#define PCIMEM0 0xf0000000 +#define PCISIZE0 0x0e000000 +#define PCIMEM1 0xc0000000 +#define PCISIZE1 0x30000000 #define IOMEM 0xfe000000 +#define IOSIZE 0x00800000 #define FALCON 0xfef80000 #define RAVEN 0xfeff0000 #define FLASHA 0xff000000 diff --git a/mtx/pci.c b/mtx/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..3a459875596645fd09ef09f871e79c7f5dad0b43 --- /dev/null +++ b/mtx/pci.c @@ -0,0 +1,911 @@ +/* + * PCI support code. + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#define DBG if(0) pcilog + +struct +{ + char output[16384]; + int ptr; +}PCICONS; + +int +pcilog(char *fmt, ...) +{ + int n; + va_list arg; + char buf[PRINTSIZE]; + + va_start(arg, fmt); + n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; + va_end(arg); + + memmove(PCICONS.output+PCICONS.ptr, buf, n); + PCICONS.ptr += n; + return n; +} + +enum +{ /* configuration mechanism #1 */ + PciADDR = 0xCF8, /* CONFIG_ADDRESS */ + PciDATA = 0xCFC, /* CONFIG_DATA */ + + /* configuration mechanism #2 */ + PciCSE = 0xCF8, /* configuration space enable */ + PciFORWARD = 0xCFA, /* which bus */ + + MaxFNO = 7, + MaxUBN = 255, +}; + +enum +{ /* command register */ + IOen = (1<<0), + MEMen = (1<<1), + MASen = (1<<2), + MemWrInv = (1<<4), + PErrEn = (1<<6), + SErrEn = (1<<8), +}; + +static Lock pcicfglock; +static QLock pcicfginitlock; +static int pcicfgmode = -1; +static int pcimaxbno = 7; +static int pcimaxdno; +static Pcidev* pciroot; +static Pcidev* pcilist; +static Pcidev* pcitail; + +static int pcicfgrw32(int, int, int, int); +static int pcicfgrw8(int, int, int, int); + +static char* bustypes[] = { + "CBUSI", + "CBUSII", + "EISA", + "FUTURE", + "INTERN", + "ISA", + "MBI", + "MBII", + "MCA", + "MPI", + "MPSA", + "NUBUS", + "PCI", + "PCMCIA", + "TC", + "VL", + "VME", + "XPRESS", +}; + +#pragma varargck type "T" int + +static int +tbdfconv(va_list* arg, Fconv* f) +{ + char *p; + int l, type, tbdf; + + p = malloc(READSTR); + if(p == nil){ + strconv("(tbdfconv)", f); + return sizeof(int); + } + + switch(f->chr){ + case 'T': + tbdf = va_arg(*arg, int); + type = BUSTYPE(tbdf); + if(type < nelem(bustypes)) + l = snprint(p, READSTR, bustypes[type]); + else + l = snprint(p, READSTR, "%d", type); + snprint(p+l, READSTR-l, ".%d.%d.%d", + BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf)); + break; + + default: + snprint(p, READSTR, "(tbdfconv)"); + break; + } + strconv(p, f); + free(p); + + return sizeof(int); +} + +ulong +pcibarsize(Pcidev *p, int rno) +{ + ulong v, size; + + v = pcicfgrw32(p->tbdf, rno, 0, 1); + pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0); + size = pcicfgrw32(p->tbdf, rno, 0, 1); + if(v & 1) + size |= 0xFFFF0000; + pcicfgrw32(p->tbdf, rno, v, 0); + + return -(size & ~0x0F); +} + +static int +pcisizcmp(void *a, void *b) +{ + Pcisiz *aa, *bb; + + aa = a; + bb = b; + return aa->siz - bb->siz; +} + +static ulong +pcimask(ulong v) +{ + ulong m; + + m = BI2BY*sizeof(v); + for(m = 1<<(m-1); m != 0; m >>= 1) { + if(m & v) + break; + } + + m--; + if((v & m) == 0) + return v; + + v |= m; + return v+1; +} + +static void +pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg) +{ + Pcidev *p; + int ntb, i, size, rno, hole; + ulong v, mema, ioa, sioa, smema, base, limit; + Pcisiz *table, *tptr, *mtb, *itb; + extern void qsort(void*, long, long, int (*)(void*, void*)); + + ioa = *pioa; + mema = *pmema; + + DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n", + wrreg, root->tbdf, mema, ioa); + + ntb = 0; + for(p = root; p != nil; p = p->link) + ntb++; + + ntb *= (PciCIS-PciBAR0)/4; + table = malloc(2*ntb*sizeof(Pcisiz)); + itb = table; + mtb = table+ntb; + + /* + * Build a table of sizes + */ + for(p = root; p != nil; p = p->link) { + if(p->ccrb == 0x06) { + if(p->ccru == 0x04 && p->bridge != nil) { + sioa = ioa; + smema = mema; + pcibusmap(p->bridge, &smema, &sioa, 0); + + hole = pcimask(smema-mema); + if(hole < (1<<20)) + hole = 1<<20; + p->mema.size = hole; + + hole = pcimask(sioa-ioa); + if(hole < (1<<12)) + hole = 1<<12; + + p->ioa.size = hole; + + itb->dev = p; + itb->bar = -1; + itb->siz = p->ioa.size; + itb++; + + mtb->dev = p; + mtb->bar = -1; + mtb->siz = p->mema.size; + mtb++; + } + if((pcicfgr8(p, PciHDT)&0x7f) != 0) + continue; + } + + for(i = 0; i <= 5; i++) { + rno = PciBAR0 + i*4; + v = pcicfgrw32(p->tbdf, rno, 0, 1); + size = pcibarsize(p, rno); + if(size == 0) + continue; + + if(v & 1) { + itb->dev = p; + itb->bar = i; + itb->siz = size; + itb++; + } + else { + mtb->dev = p; + mtb->bar = i; + mtb->siz = size; + mtb++; + } + + p->mem[i].size = size; + } + } + + /* + * Sort both tables IO smallest first, Memory largest + */ + qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp); + tptr = table+ntb; + qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp); + + /* + * Allocate IO address space on this bus + */ + for(tptr = table; tptr < itb; tptr++) { + hole = tptr->siz; + if(tptr->bar == -1) + hole = 1<<12; + ioa = (ioa+hole-1) & ~(hole-1); + + p = tptr->dev; + if(tptr->bar == -1) + p->ioa.bar = ioa; + else { + p->pcr |= IOen; + p->mem[tptr->bar].bar = ioa|1; + if(wrreg) + pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0); + } + + ioa += tptr->siz; + } + + /* + * Allocate Memory address space on this bus + */ + for(tptr = table+ntb; tptr < mtb; tptr++) { + hole = tptr->siz; + if(tptr->bar == -1) + hole = 1<<20; + mema = (mema+hole-1) & ~(hole-1); + + p = tptr->dev; + if(tptr->bar == -1) + p->mema.bar = mema; + else { + p->pcr |= MEMen; + p->mem[tptr->bar].bar = mema; + if(wrreg) + pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0); + } + mema += tptr->siz; + } + + *pmema = mema; + *pioa = ioa; + free(table); + + if(wrreg == 0) + return; + + /* + * Finally set all the bridge addresses & registers + */ + for(p = root; p != nil; p = p->link) { + if(p->bridge == nil) { + pcicfgrw8(p->tbdf, PciLTR, 64, 0); + + p->pcr |= MASen; + pcicfgrw32(p->tbdf, PciPCR, p->pcr, 0); + continue; + } + + base = p->ioa.bar; + limit = base+p->ioa.size-1; + v = pcicfgrw32(p->tbdf, PciBAR3, 0, 1); + v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8); + pcicfgrw32(p->tbdf, PciBAR3, v, 0); + v = (limit & 0xFFFF0000)|(base>>16); + pcicfgrw32(p->tbdf, 0x30, v, 0); + + base = p->mema.bar; + limit = base+p->mema.size-1; + v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16); + pcicfgrw32(p->tbdf, PciBAR4, v, 0); + + /* + * Disable memory prefetch + */ + pcicfgrw32(p->tbdf, PciBAR5, 0x0000FFFF, 0); + pcicfgrw8(p->tbdf, PciLTR, 64, 0); + + /* + * Enable the bridge + */ + v = 0xFFFF0000 | IOen | MEMen | MASen; + pcicfgrw32(p->tbdf, PciPCR, v, 0); + + sioa = p->ioa.bar; + smema = p->mema.bar; + pcibusmap(p->bridge, &smema, &sioa, 1); + } +} + +static int +pcilscan(int bno, Pcidev** list) +{ + Pcidev *p, *head, *tail; + int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn; + + maxubn = bno; + head = nil; + tail = nil; + for(dno = 0; dno <= pcimaxdno; dno++){ + maxfno = 0; + for(fno = 0; fno <= maxfno; fno++){ + /* + * For this possible device, form the + * bus+device+function triplet needed to address it + * and try to read the vendor and device ID. + * If successful, allocate a device struct and + * start to fill it in with some useful information + * from the device's configuration space. + */ + tbdf = MKBUS(BusPCI, bno, dno, fno); + l = pcicfgrw32(tbdf, PciVID, 0, 1); + if(l == 0xFFFFFFFF || l == 0) + continue; + p = malloc(sizeof(*p)); + p->tbdf = tbdf; + p->vid = l; + p->did = l>>16; + + if(pcilist != nil) + pcitail->list = p; + else + pcilist = p; + pcitail = p; + + p->rid = pcicfgr8(p, PciRID); + p->ccrp = pcicfgr8(p, PciCCRp); + p->ccru = pcicfgr8(p, PciCCRu); + p->ccrb = pcicfgr8(p, PciCCRb); + p->pcr = pcicfgr32(p, PciPCR); + + p->intl = pcicfgr8(p, PciINTL); + + /* + * If the device is a multi-function device adjust the + * loop count so all possible functions are checked. + */ + hdt = pcicfgr8(p, PciHDT); + if(hdt & 0x80) + maxfno = MaxFNO; + + /* + * If appropriate, read the base address registers + * and work out the sizes. + */ + switch(p->ccrb) { + case 0x01: /* mass storage controller */ + case 0x02: /* network controller */ + case 0x03: /* display controller */ + case 0x04: /* multimedia device */ + case 0x06: /* bridge device */ + case 0x07: /* simple comm. controllers */ + case 0x08: /* base system peripherals */ + case 0x09: /* input devices */ + case 0x0A: /* docking stations */ + case 0x0B: /* processors */ + case 0x0C: /* serial bus controllers */ + if((hdt & 0x7F) != 0) + break; + rno = PciBAR0 - 4; + for(i = 0; i < nelem(p->mem); i++) { + rno += 4; + p->mem[i].bar = pcicfgr32(p, rno); + p->mem[i].size = pcibarsize(p, rno); + } + break; + + case 0x00: + case 0x05: /* memory controller */ + default: + break; + } + + if(head != nil) + tail->link = p; + else + head = p; + tail = p; + } + } + + *list = head; + for(p = head; p != nil; p = p->link){ + /* + * Find PCI-PCI bridges and recursively descend the tree. + */ + if(p->ccrb != 0x06 || p->ccru != 0x04) + continue; + + /* + * If the secondary or subordinate bus number is not + * initialised try to do what the PCI BIOS should have + * done and fill in the numbers as the tree is descended. + * On the way down the subordinate bus number is set to + * the maximum as it's not known how many buses are behind + * this one; the final value is set on the way back up. + */ + sbn = pcicfgr8(p, PciSBN); + ubn = pcicfgr8(p, PciUBN); + + if(sbn == 0 || ubn == 0) { + sbn = maxubn+1; + /* + * Make sure memory, I/O and master enables are + * off, set the primary, secondary and subordinate + * bus numbers and clear the secondary status before + * attempting to scan the secondary bus. + * + * Initialisation of the bridge should be done here. + */ + pcicfgw32(p, PciPCR, 0xFFFF0000); + l = (MaxUBN<<16)|(sbn<<8)|bno; + pcicfgw32(p, PciPBN, l); + pcicfgw16(p, PciSPSR, 0xFFFF); + maxubn = pcilscan(sbn, &p->bridge); + l = (maxubn<<16)|(sbn<<8)|bno; + + pcicfgw32(p, PciPBN, l); + } + else { + maxubn = ubn; + pcilscan(sbn, &p->bridge); + } + } + + return maxubn; +} + +int +pciscan(int bno, Pcidev **list) +{ + int ubn; + + qlock(&pcicfginitlock); + ubn = pcilscan(bno, list); + qunlock(&pcicfginitlock); + return ubn; +} + +static void +pcicfginit(void) +{ + char *p; + int bno; + Pcidev **list; + ulong mema, ioa; + + qlock(&pcicfginitlock); + if(pcicfgmode != -1) + goto out; + + /* + * Try to determine which PCI configuration mode is implemented. + * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses + * a DWORD at 0xCF8 and another at 0xCFC and will pass through + * any non-DWORD accesses as normal I/O cycles. There shouldn't be + * a device behind these addresses so if Mode2 accesses fail try + * for Mode1 (which is preferred, Mode2 is deprecated). + */ + outb(PciCSE, 0); + if(inb(PciCSE) == 0){ + pcicfgmode = 2; + pcimaxdno = 15; + } + else { + outl(PciADDR, 0); + if(inl(PciADDR) == 0){ + pcicfgmode = 1; + pcimaxdno = 31; + } + } + + if(pcicfgmode < 0) + goto out; + + fmtinstall('T', tbdfconv); + + if(p = getconf("*pcimaxbno")) + pcimaxbno = strtoul(p, 0, 0); + if(p = getconf("*pcimaxdno")) + pcimaxdno = strtoul(p, 0, 0); + + list = &pciroot; + for(bno = 0; bno <= pcimaxbno; bno++) { + int sbno = bno; + bno = pcilscan(bno, list); + + while(*list) + list = &(*list)->link; + + if (sbno == 0) { + Pcidev *pci; + + /* + * If we have found a PCI-to-Cardbus bridge, make sure + * it has no valid mappings anymore. + */ + pci = pciroot; + while (pci) { + if (pci->ccrb == 6 && pci->ccru == 7) { + ushort bcr; + + /* reset the cardbus */ + bcr = pcicfgr16(pci, PciBCR); + pcicfgw16(pci, PciBCR, 0x40 | bcr); + delay(50); + } + pci = pci->link; + } + } + } + + if(pciroot == nil) + goto out; + + /* + * Work out how big the top bus is + */ + mema = 0; + ioa = 0; + pcibusmap(pciroot, &mema, &ioa, 0); + + DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n", + mema, pcimask(mema), ioa); + + /* + * Align the windows and map it + */ + ioa = 0x1000; + mema = 0; + + pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa); + + pcibusmap(pciroot, &mema, &ioa, 1); + DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa); + +out: + qunlock(&pcicfginitlock); +} + +static int +pcicfgrw8(int tbdf, int rno, int data, int read) +{ + int o, type, x; + + if(pcicfgmode == -1) + pcicfginit(); + + if(BUSBNO(tbdf)) + type = 0x01; + else + type = 0x00; + x = -1; + if(BUSDNO(tbdf) > pcimaxdno) + return x; + + lock(&pcicfglock); + switch(pcicfgmode){ + + case 1: + o = rno & 0x03; + rno &= ~0x03; + outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); + if(read) + x = inb(PciDATA+o); + else + outb(PciDATA+o, data); + outl(PciADDR, 0); + break; + + case 2: + outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); + outb(PciFORWARD, BUSBNO(tbdf)); + if(read) + x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno); + else + outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); + outb(PciCSE, 0); + break; + } + unlock(&pcicfglock); + + return x; +} + +int +pcicfgr8(Pcidev* pcidev, int rno) +{ + return pcicfgrw8(pcidev->tbdf, rno, 0, 1); +} + +void +pcicfgw8(Pcidev* pcidev, int rno, int data) +{ + pcicfgrw8(pcidev->tbdf, rno, data, 0); +} + +static int +pcicfgrw16(int tbdf, int rno, int data, int read) +{ + int o, type, x; + + if(pcicfgmode == -1) + pcicfginit(); + + if(BUSBNO(tbdf)) + type = 0x01; + else + type = 0x00; + x = -1; + if(BUSDNO(tbdf) > pcimaxdno) + return x; + + lock(&pcicfglock); + switch(pcicfgmode){ + + case 1: + o = rno & 0x02; + rno &= ~0x03; + outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); + if(read) + x = ins(PciDATA+o); + else + outs(PciDATA+o, data); + outl(PciADDR, 0); + break; + + case 2: + outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); + outb(PciFORWARD, BUSBNO(tbdf)); + if(read) + x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno); + else + outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); + outb(PciCSE, 0); + break; + } + unlock(&pcicfglock); + + return x; +} + +int +pcicfgr16(Pcidev* pcidev, int rno) +{ + return pcicfgrw16(pcidev->tbdf, rno, 0, 1); +} + +void +pcicfgw16(Pcidev* pcidev, int rno, int data) +{ + pcicfgrw16(pcidev->tbdf, rno, data, 0); +} + +static int +pcicfgrw32(int tbdf, int rno, int data, int read) +{ + int type, x; + + if(pcicfgmode == -1) + pcicfginit(); + + if(BUSBNO(tbdf)) + type = 0x01; + else + type = 0x00; + x = -1; + if(BUSDNO(tbdf) > pcimaxdno) + return x; + + lock(&pcicfglock); + switch(pcicfgmode){ + + case 1: + rno &= ~0x03; + outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); + if(read) + x = inl(PciDATA); + else + outl(PciDATA, data); + outl(PciADDR, 0); + break; + + case 2: + outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); + outb(PciFORWARD, BUSBNO(tbdf)); + if(read) + x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno); + else + outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); + outb(PciCSE, 0); + break; + } + unlock(&pcicfglock); + + return x; +} + +int +pcicfgr32(Pcidev* pcidev, int rno) +{ + return pcicfgrw32(pcidev->tbdf, rno, 0, 1); +} + +void +pcicfgw32(Pcidev* pcidev, int rno, int data) +{ + pcicfgrw32(pcidev->tbdf, rno, data, 0); +} + +Pcidev* +pcimatch(Pcidev* prev, int vid, int did) +{ + if(pcicfgmode == -1) + pcicfginit(); + + if(prev == nil) + prev = pcilist; + else + prev = prev->list; + + while(prev != nil){ + if((vid == 0 || prev->vid == vid) + && (did == 0 || prev->did == did)) + break; + prev = prev->list; + } + return prev; +} + +Pcidev* +pcimatchtbdf(int tbdf) +{ + Pcidev *pcidev; + + if(pcicfgmode == -1) + pcicfginit(); + + for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) { + if(pcidev->tbdf == tbdf) + break; + } + return pcidev; +} + +uchar +pciipin(Pcidev *pci, uchar pin) +{ + if (pci == nil) + pci = pcilist; + + while (pci) { + uchar intl; + + if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff) + return pci->intl; + + if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0) + return intl; + + pci = pci->list; + } + return 0; +} + +static void +pcilhinv(Pcidev* p) +{ + int i; + Pcidev *t; + + if(p == nil) { + putstrn(PCICONS.output, PCICONS.ptr); + p = pciroot; + print("bus dev type vid did intl memory\n"); + } + for(t = p; t != nil; t = t->link) { + print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d ", + BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf), + t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl); + + for(i = 0; i < nelem(p->mem); i++) { + if(t->mem[i].size == 0) + continue; + print("%d:%.8lux %d ", i, + t->mem[i].bar, t->mem[i].size); + } + if(t->ioa.bar || t->ioa.size) + print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size); + if(t->mema.bar || t->mema.size) + print("mema:%.8lux %d ", t->mema.bar, t->mema.size); + if(t->bridge) + print("->%d", BUSBNO(t->bridge->tbdf)); + print("\n"); + } + while(p != nil) { + if(p->bridge != nil) + pcilhinv(p->bridge); + p = p->link; + } +} + +void +pcihinv(Pcidev* p) +{ + if(pcicfgmode == -1) + pcicfginit(); + qlock(&pcicfginitlock); + pcilhinv(p); + qunlock(&pcicfginitlock); +} + +void +pcireset(void) +{ + Pcidev *p; + int pcr; + + if(pcicfgmode == -1) + pcicfginit(); + + for(p = pcilist; p != nil; p = p->list){ + pcr = pcicfgr16(p, PciPCR); + pcr &= ~0x0004; + pcicfgw16(p, PciPCR, pcr); + } +} + +void +pcisetbme(Pcidev* p) +{ + int pcr; + + pcr = pcicfgr16(p, PciPCR); + pcr |= MASen; + pcicfgw16(p, PciPCR, pcr); +} + +void +pciclrbme(Pcidev* p) +{ + int pcr; + + pcr = pcicfgr16(p, PciPCR); + pcr &= ~MASen; + pcicfgw16(p, PciPCR, pcr); +} diff --git a/mtx/raven.c b/mtx/raven.c new file mode 100644 index 0000000000000000000000000000000000000000..f5c9aaa0e2d5522e5a7100738c2818beb55a1a2c --- /dev/null +++ b/mtx/raven.c @@ -0,0 +1,143 @@ +/* + * ``Nevermore!'' + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +typedef struct Raven Raven; +struct Raven +{ + ushort vid; + ushort did; + uchar _pad4; + uchar rev; + uchar _pad6[2]; + ushort gcsr; + ushort feat; + uchar _padC[7]; + uchar padj; + uchar _pad14[12]; + ushort errtst; + ushort erren; + uchar _pad24[3]; + uchar errst; + ulong errad; + uchar _pad2C[2]; + ushort errat; + ulong piack; + uchar _pad34[12]; + + struct { + ushort start; + ushort end; + ushort off; + uchar _pad; + uchar attr; + } map[4]; + + struct { + ulong cntl; + uchar _pad[3]; + uchar stat; + } wdt[2]; + + ulong gpr[4]; +}; + +enum { + /* map[] attr bits */ + Iom = (1<<0), + Mem = (1<<1), + Wpen = (1<<4), + Wen = (1<<6), + Ren = (1<<7), +}; + +static Raven *raven = (Raven*)RAVEN; +static ulong mpic; + +static void +setmap(int i, ulong addr, ulong len, ulong busaddr, int attr) +{ + raven->map[i].start = addr>>16; + raven->map[i].end = (addr+len-1)>>16; + raven->map[i].off = (busaddr-addr)>>16; + raven->map[i].attr = attr; +} + +static ulong +swap32(ulong x) +{ + return (x>>24)|((x>>8)&0xff00)|((x<<8)&0xff0000)|(x<<24); +} + +static ulong +mpic32r(int rno) +{ + return swap32(*(ulong*)(mpic+rno)); +} + +static void +mpic32w(int rno, ulong x) +{ + *(ulong*)(mpic+rno) = swap32(x); + eieio(); +} + +void +raveninit(void) +{ + int i; + Pcidev *p; + + if(raven->vid != 0x1057 || raven->did !=0x4801) + panic("raven not found"); + + /* set up a sensible hardware memory/IO map */ + setmap(0, PCIMEM0, PCISIZE0, 0, Wen|Ren|Mem); + setmap(1, KZERO, IOSIZE, 0, Wen|Ren); /* keeps PPCbug happy */ + setmap(2, PCIMEM1, PCISIZE1, PCISIZE0, Wen|Ren|Mem); + setmap(3, IOMEM, IOSIZE, 0, Wen|Ren); /* I/O must be slot 3 for PCI cfg space */ + + p = pcimatch(nil, 0x1057, 0x4801); + if(p == nil) + panic("raven PCI regs not found"); + mpic = (p->mem[1].bar+PCIMEM0); + + /* ensure all interrupts are off, and routed to cpu 0 */ + for(i = 0; i < 16; i++) { + mpic32w(0x10000+0x20*i, (1<<31)); /* mask */ + mpic32w(0x10010+0x20*i, 1); /* route to cpu 0 */ + } + + mpic32w(0x20080, 1); /* cpu 0 task pri */ +// mpic32w(0x21080, 1); /* cpu 1 task pri */ + mpic32w(0x1020, (1<<29)); /* Mixed mode (8259 & Raven intrs both available) */ +} + +void +mpicenable(int vec) +{ + ulong x; + + x = (1<<22)|(15<<16)|vec; + if(vec == 0) + x |= (1<<23); + mpic32w(0x10000+0x20*vec, x); +} + +int +mpicintack(void) +{ + return mpic32r(0x200A0 + (m->machno<<12)); +} + +void +mpiceoi(void) +{ + mpic32w(0x200B0 + (m->machno<<12), 0); +} diff --git a/mtx/trap.c b/mtx/trap.c index b80a75aeeca342bd8d9ffd76ab21f2347e0fe795..76129dad3ccd502268779c9e7c8e9257ff95f02c 100644 --- a/mtx/trap.c +++ b/mtx/trap.c @@ -26,11 +26,13 @@ struct Handler struct { - Handler *ivec[128]; + Handler *ivec[MaxVectorPIC+1]; Handler h[Maxhandler]; int free; } halloc; +Lock veclock; + void faultpower(Ureg *ur, ulong addr, int read); void syscall(Ureg* ureg); void noted(Ureg*, ulong); @@ -198,11 +200,6 @@ spurious(Ureg *ur, void *a) panic("bad interrupt"); } -#define LEV(n) (((n)<<1)|1) -#define IRQ(n) (((n)<<1)|0) - -Lock veclock; - void sethvec(int v, void (*r)(void)) { @@ -242,92 +239,43 @@ trapinit(void) void intrenable(int v, void (*r)(Ureg*, void*), void *arg, int, char *name) { -#ifdef BLOG Handler *h; - IMM *io; if(halloc.free >= Maxhandler) panic("out of interrupt handlers"); - v -= VectorPIC; if(v < 0 || v >= nelem(halloc.ivec)) - panic("intrenable(%d)", v+VectorPIC); + panic("intrenable(%d)", v); ilock(&veclock); - if(v < VectorCPIC || (h = halloc.ivec[v]) == nil){ - h = &halloc.h[halloc.free++]; - h->next = halloc.ivec[v]; - halloc.ivec[v] = h; - } + h = &halloc.h[halloc.free++]; + h->next = halloc.ivec[v]; + halloc.ivec[v] = h; h->r = r; h->arg = arg; - /* - * enable corresponding interrupt in SIU/CPM - */ - eieio(); - io = m->iomem; - if(v >= VectorCPIC){ - v -= VectorCPIC; - io->cimr |= 1<<(v&0x1F); - } - else if(v >= VectorIRQ) - io->simask |= 1<<(31-IRQ(v&7)); - else - io->simask |= 1<<(31-LEV(v)); eieio(); iunlock(&veclock); -#endif } void intr(Ureg *ur) { -#ifdef BLOG int b, v; - IMM *io; Handler *h; - long t0; - - ur->cause &= ~0xff; - io = m->iomem; - b = io->sivec>>2; - v = b>>1; - if(b & 1) { - if(v == CPIClevel){ - io->civr = 1; - eieio(); - v = VectorCPIC+(io->civr>>11); - } - }else - v += VectorIRQ; - ur->cause |= v; - h = halloc.ivec[v]; - if(h == nil){ - print("unknown interrupt %d pc=0x%lux\n", v, ur->pc); - uartwait(); - return; - } - if(h->edge){ - io->sipend |= 1<<(31-b); - eieio(); + + v = mpicintack(); + if(v == 0) { /* 8259 */ } + /* * call the interrupt handlers */ - do { +/* do { h->nintr++; - t0 = getdec(); (*h->r)(ur, h->arg); - t0 -= getdec(); - h->ticks += t0; - if(h->maxtick < t0) - h->maxtick = t0; h = h->next; } while(h != nil); - if(v >= VectorCPIC) - io->cisr |= 1<<(v-VectorCPIC); - eieio(); -#endif +*/ } int diff --git a/pc/pci.c b/pc/pci.c index ad4edd44fd9ed959248f744a270b79f64ae47503..223ab4ddb4aaa7684c69ea7e6495a3e44a47acee 100644 --- a/pc/pci.c +++ b/pc/pci.c @@ -1155,6 +1155,8 @@ pcilhinv(Pcidev* p) void pcihinv(Pcidev* p) { + if(pcicfgmode == -1) + pcicfginit(); qlock(&pcicfginitlock); pcilhinv(p); qunlock(&pcicfginitlock);