M carrera/fns.h => carrera/fns.h +1 -1
@@ 72,7 72,7 @@ void wrcompare(ulong);
void serialinit(void);
void ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
-void ns16552setup(ulong, ulong, char*);
+void ns16552setup(ulong, ulong, char*, int);
void ns16552intr(int);
void etherintr(void);
void iomapinit(void);
M carrera/ns16552.h => carrera/ns16552.h +1 -1
@@ 13,7 13,7 @@ ns16552install(void)
return;
already = 1;
- ns16552setup(Uart1, UartFREQ, "eia0");
+ ns16552setup(Uart1, UartFREQ, "eia0", Ns550);
}
#define RD(r) (*(uchar*)((Uart1+r)^7))
M ip/esp.c => ip/esp.c +1 -0
@@ 484,6 484,7 @@ convlookup(Proto *esp, ulong spi)
if(ecb->incoming && ecb->spi == spi)
return c;
}
+ return nil;
}
static char *
A mpc/_inb.s => mpc/_inb.s +110 -0
@@ 0,0 1,110 @@
+#include "mem.h"
+
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+TEXT inb(SB), $0
+ OR $ISAMEM, R3
+ MOVBZ (R3), R3
+ RETURN
+
+TEXT insb(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $1, R4
+insb1:
+ MOVBZ (R3), R7
+ MOVBU R7, 1(R4)
+ BDNZ insb1
+ RETURN
+
+TEXT outb(SB), $0
+ MOVW v+4(FP), R4
+ OR $ISAMEM, R3
+ MOVB R4, (R3)
+ RETURN
+
+TEXT outsb(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $1, R4
+outsb1:
+ MOVBZU 1(R4), R7
+ MOVB R7, (R3)
+ BDNZ outsb1
+ RETURN
+
+TEXT ins(SB), $0
+ OR $ISAMEM, R3
+ EIEIO
+ MOVHBR (R3), R3
+ RETURN
+
+TEXT inss(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $2, R4
+inss1:
+ MOVHZ (R3), R7
+ MOVHU R7, 2(R4)
+ BDNZ inss1
+ RETURN
+
+TEXT outs(SB), $0
+ MOVW v+4(FP), R4
+ OR $ISAMEM, R3
+ MOVHBR R4, (R3)
+ RETURN
+
+TEXT outss(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $2, R4
+outss1:
+ MOVHZU 2(R4), R7
+ MOVH R7, (R3)
+ BDNZ outss1
+ RETURN
+
+TEXT inl(SB), $0
+ OR $ISAMEM, R3
+ MOVWBR (R3), R3
+ RETURN
+
+TEXT insl(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $4, R4
+insl1:
+ MOVW (R3), R7
+ MOVWU R7, 4(R4)
+ BDNZ insl1
+ RETURN
+
+TEXT outl(SB), $0
+ MOVW v+4(FP), R4
+ OR $ISAMEM, R3
+ MOVWBR R4, (R3)
+ RETURN
+
+TEXT outsl(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $4, R4
+outsl1:
+ MOVWU 4(R4), R7
+ MOVW R7, (R3)
+ BDNZ outsl1
+ RETURN
M mpc/clock.c => mpc/clock.c +17 -10
@@ 112,26 112,33 @@ clockintr(Ureg *ur)
m->iomem->swsr = 0xaa39;
m->ticks++;
+ if(m->proc)
+ m->proc->pc = ur->pc;
+
+ accounttime();
+ if(kproftimer != nil)
+ kproftimer(ur->pc);
- if(up)
- up->pc = ur->pc;
checkalarms();
if(m->machno == 0) {
- if(kproftick != nil)
- (*kproftick)(ur->pc);
lock(&clock0lock);
for(lp = clock0link; lp; lp = lp->link)
lp->clock();
unlock(&clock0lock);
}
- if(up && up->state == Running){
-// if(up->type == Interp && tready())
-// ur->cr |= 1<<(31-31);
- if(nrdy > 0)
- sched();
- }
+ if(up == 0 || up->state != Running)
+ return;
+
+// user profiling clock
+// if(ur->status & KUSER) {
+// (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1);
+// segclock(ur->pc);
+// }
+
+ if(anyready())
+ sched();
}
void
M mpc/devether.c => mpc/devether.c +34 -39
@@ 12,8 12,6 @@
static Ether *etherxx[MaxEther];
-void ethermediumlink(void);
-
Chan*
etherattach(char* spec)
{
@@ 37,19 35,6 @@ etherattach(char* spec)
return chan;
}
-static void
-etherdetach(void)
-{
- Ether **ether;
-
- ether = etherxx;
- while(*ether){
- if((*ether)->detach)
- (*ether)->detach(*ether);
- ether++;
- }
-}
-
static int
etherwalk(Chan* chan, char* name)
{
@@ 76,18 61,14 @@ ethercreate(Chan*, char*, int, ulong)
static void
etherclose(Chan* chan)
{
- Ether *ether;
-
- ether = etherxx[chan->dev];
- netifclose(ether, chan);
- if(ether->closed)
- ether->closed(ether);
+ netifclose(etherxx[chan->dev], chan);
}
static long
-etherread(Chan* chan, void* buf, long n, vlong offset)
+etherread(Chan* chan, void* buf, long n, vlong off)
{
Ether *ether;
+ ulong offset = off;
ether = etherxx[chan->dev];
if((chan->qid.path & CHDIR) == 0 && ether->ifstat){
@@ 153,7 134,7 @@ etheriq(Ether* ether, Block* bp, int freebp)
{
Etherpkt *pkt;
ushort type;
- int len;
+ int len, multi, forme;
Netfile **ep, *f, **fp, *fx;
Block *xbp;
@@ 165,8 146,9 @@ etheriq(Ether* ether, Block* bp, int freebp)
fx = 0;
ep = ðer->f[Ntypes];
+ multi = pkt->d[0] & 1;
/* check for valid multcast addresses */
- if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
+ if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
if(freebp){
freeb(bp);
@@ 176,6 158,9 @@ etheriq(Ether* ether, Block* bp, int freebp)
}
}
+ // is it for me?
+ forme = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
+
/*
* Multiplex the packet to all the connections which want it.
* If the packet is not to be used subsequently (freebp != 0),
@@ 183,7 168,7 @@ etheriq(Ether* ether, Block* bp, int freebp)
* saving a copy of the data (usual case hopefully).
*/
for(fp = ether->f; fp < ep; fp++){
- if((f = *fp) && (f->type == type || f->type < 0)){
+ if((f = *fp) && (f->type == type || f->type < 0) && (forme || multi || f->prom)){
if(f->type > -2){
if(freebp && fx == 0)
fx = f;
@@ 201,7 186,8 @@ etheriq(Ether* ether, Block* bp, int freebp)
}
if(fx){
- qpass(fx->in, bp);
+ if(qpass(fx->in, bp) < 0)
+ ether->soverflows++;
return 0;
}
if(freebp){
@@ 215,7 201,7 @@ etheriq(Ether* ether, Block* bp, int freebp)
static int
etheroq(Ether* ether, Block* bp)
{
- int len, loopback, s;
+ int len, loopback, s, mine;
Etherpkt *pkt;
ether->outpackets++;
@@ 226,10 212,14 @@ etheroq(Ether* ether, Block* bp)
* in promiscuous mode.
* If it's a loopback packet indicate to etheriq that the data isn't
* needed and return, etheriq will pass-on or free the block.
+ * To enable bridging to work, only packets that were originated
+ * by this interface are fed back.
*/
pkt = (Etherpkt*)bp->rp;
len = BLEN(bp);
loopback = (memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0);
+ mine = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
+ if(mine)
if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
s = splhi();
etheriq(ether, bp, loopback);
@@ 256,8 246,8 @@ etherwrite(Chan* chan, void* buf, long n, vlong)
if(n > ETHERMAXTU)
error(Etoobig);
-// if(n < ETHERMINTU)
-// error(Etoosmall);
+ if(n < ETHERMINTU)
+ error(Etoosmall);
bp = allocb(n);
if(waserror()){
@@ 279,7 269,6 @@ etherbwrite(Chan* chan, Block* bp, ulong)
long n;
n = BLEN(bp);
-
ether = etherxx[chan->dev];
if(NETTYPE(chan->qid.path) != Ndataqid){
n = netifwrite(ether, chan, bp->rp, n);
@@ 291,6 280,10 @@ etherbwrite(Chan* chan, Block* bp, ulong)
freeb(bp);
error(Ebadarg);
}
+ if(n < ETHERMINTU){
+ freeb(bp);
+ error(Etoosmall);
+ }
return etheroq(ether, bp);
}
@@ 304,7 297,7 @@ void
addethercard(char* t, int (*r)(Ether*))
{
static int ncard;
-print("addethercard\n");
+
if(ncard == MaxEther)
panic("too many ether cards");
cards[ncard].type = t;
@@ 342,8 335,6 @@ etherreset(void)
int i, n, ctlrno;
char name[NAMELEN], buf[128];
-print("etherreset\n");
- //ethermediumlink();
for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
if(ether == 0)
ether = malloc(sizeof(Ether));
@@ 353,9 344,7 @@ print("etherreset\n");
ether->mbps = 10;
if(isaconfig("ether", ctlrno, ether) == 0)
continue;
-print("after isaconfig %d\n", n);
for(n = 0; cards[n].type; n++){
-print("card %d\n", n);
if(cistrcmp(cards[n].type, ether->type))
continue;
for(i = 0; i < ether->nopt; i++){
@@ 367,9 356,16 @@ print("card %d\n", n);
if(cards[n].reset(ether))
break;
+ /*
+ * IRQ2 doesn't really exist, it's used to gang the interrupt
+ * controllers together. A device set to IRQ2 will appear on
+ * the second interrupt controller as IRQ9.
+ */
+ if(ether->irq == 2)
+ ether->irq = 9;
intrenable(ether->irq, ether->interrupt, ether, ether->tbdf);
- i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
+ i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
if(ether->mem)
i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
@@ 388,9 384,9 @@ print("card %d\n", n);
ether->oq = qopen(256*1024, 1, 0, 0);
}
else{
- netifinit(ether, name, Ntypes, 32*1024);
+ netifinit(ether, name, Ntypes, 65*1024);
if(ether->oq == 0)
- ether->oq = qopen(64*1024, 1, 0, 0);
+ ether->oq = qopen(65*1024, 1, 0, 0);
}
if(ether->oq == 0)
panic("etherreset %s", name);
@@ 434,7 430,6 @@ Dev etherdevtab = {
etherreset,
devinit,
etherattach,
- /*etherdetach,*/
devclone,
etherwalk,
etherstat,
A mpc/devpcmcia.c => mpc/devpcmcia.c +1118 -0
@@ 0,0 1,1118 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+/*
+ * MPC8xx PCMCIA driver
+ *
+ */
+
+typedef struct PCMmap PCMmap;
+typedef struct Slot Slot;
+typedef struct Conftab Conftab;
+
+enum
+{
+ Maxctlr= 1,
+
+ /* pipr */
+ Cvs1= 1<<15, // voltage sense 1
+ Cvs2= 1<<14, // voltage sense 2
+ Cwp= 1<<13, // write protect
+ Ccd2= 1<<12, // card detect 2
+ Ccd1= 1<<11, // card detect 1
+ Cbvd2= 1<<10, // battery voltage 2
+ Cbvd1= 1<<9, // battery voltage 1
+ Crdy= 1<<8, // ready
+
+ /* pscr */
+ Cvs1_c= 1<<15, // voltage sense 1 changed
+ Cvs2_c= 1<<14, // voltage sense 2 changed
+ Cwp_c= 1<<13, // write protect changed
+ Ccd2_c= 1<<12, // card detect 2 changed
+ Ccd1_c= 1<<11, // card detect 1 changed
+ Cbvd2_c= 1<<10, // battery voltage 2 changed
+ Cbvd1_c= 1<<9, // battery voltage 1 changed
+ Crdy_l= 1<<7, // ready is low
+ Crdy_h= 1<<6, // ready is hi
+ Crdy_r= 1<<5, // ready raising edge
+ Crdy_f= 1<<4, // ready falling edge
+
+ /* pgcrx */
+ Creset = IBIT(25), // card reset
+ Coe = IBIT(24), // output enable
+
+ /* porN */
+ Rport8= 0<<6,
+ Rport16= 1<<6,
+ Rmem= 0<<3, /* common memory space */
+ Rattrib= 2<<3, /* attribute space */
+ Rio= 3<<3,
+ Rdma= 4<<3, /* normal DMA */
+ Rdmalx= 5<<3, /* DMA, last transaction */
+ RA22_23= 6<<3, /* ``drive A22 and A23 signals on CE2 and CE1'' */
+ RslotB= 1<<2, /* select slot B (always, on MPC823) */
+ Rwp= 1<<1, /* write protect */
+ Rvalid= 1<<0, /* region valid */
+
+ /*
+ * configuration registers - they start at an offset in attribute
+ * memory found in the CIS.
+ */
+ Rconfig= 0,
+ Clevel= (1<<6), /* level sensitive interrupt line */
+
+ Maxctab= 8, /* maximum configuration table entries */
+ Nmap= 4, // map entries per slot
+ Mshift= 12,
+ Mgran= (1<<Mshift), /* granularity of maps */
+ Mmask= ~(Mgran-1), /* mask for address bits important to the chip */
+};
+
+/* configuration table entry */
+struct Conftab
+{
+ int index;
+ ushort irqs; /* legal irqs */
+ uchar irqtype;
+ uchar bit16; /* true for 16 bit access */
+ struct {
+ ulong start;
+ ulong len;
+ } io[16];
+ int nio;
+ uchar vpp1;
+ uchar vpp2;
+ uchar memwait;
+ ulong maxwait;
+ ulong readywait;
+ ulong otherwait;
+};
+
+/*
+ * Map between ISA memory space and PCMCIA card memory space.
+ */
+struct PCMmap {
+ ulong ca; /* card address */
+ ulong cea; /* card end address */
+ ulong isa; /* ISA address */
+ int len; /* length of the ISA area */
+ int attr; /* attribute memory */
+ int ref;
+};
+
+/* a card slot */
+struct Slot
+{
+ Lock;
+ int ref;
+
+ long memlen; /* memory length */
+ uchar base; /* index register base */
+ uchar slotno; /* slot number */
+
+ /* status */
+ uchar special; /* in use for a special device */
+ uchar already; /* already inited */
+ uchar occupied;
+ uchar voltage;
+ uchar battery;
+ uchar wrprot;
+ uchar powered;
+ uchar configed;
+ uchar enabled;
+ uchar busy;
+
+ /* cis info */
+ char verstr[512]; /* version string */
+ uchar cpresent; /* config registers present */
+ ulong caddr; /* relative address of config registers */
+ int nctab; /* number of config table entries */
+ Conftab ctab[Maxctab];
+ Conftab *def; /* default conftab */
+
+ /* for walking through cis */
+ int cispos; /* current position scanning cis */
+ uchar *cisbase;
+
+ /* memory maps */
+ Lock mlock; /* lock down the maps */
+ int time;
+ PCMmap mmap[Nmap]; /* maps, last is always for the kernel */
+};
+
+enum
+{
+ Qdir,
+ Qmem,
+ Qattr,
+ Qctl,
+};
+
+#define SLOTNO(c) ((c->qid.path>>8)&0xff)
+#define TYPE(c) (c->qid.path&0xff)
+#define QID(s,t) (((s)<<8)|(t))
+
+static void pcmciaintr(Ureg *, void *);
+static void increfp(Slot *pp);
+static void decrefp(Slot *pp);
+static PCMmap* pcmmap(Slot*, ulong, int, int);
+static void pcmunmap(Slot*, PCMmap*);
+
+static Slot *slot;
+static nslot;
+
+static int
+pcmgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
+{
+ int slotno;
+ Qid qid;
+ long len;
+ Slot *pp;
+ char name[NAMELEN];
+
+ USED(tab, ntab);
+ if(i>=3*nslot)
+ return -1;
+ slotno = i/3;
+ pp = slot + slotno;
+ len = 0;
+ switch(i%3){
+ case 0:
+ qid.path = QID(slotno, Qmem);
+ sprint(name, "pcm%dmem", slotno);
+ len = pp->memlen;
+ break;
+ case 1:
+ qid.path = QID(slotno, Qattr);
+ sprint(name, "pcm%dattr", slotno);
+ len = pp->memlen;
+ break;
+ case 2:
+ qid.path = QID(slotno, Qctl);
+ sprint(name, "pcm%dctl", slotno);
+ break;
+ }
+ qid.vers = 0;
+ devdir(c, qid, name, len, eve, 0660, dp);
+ return 1;
+}
+
+/*
+ * set up for slot cards
+ */
+static void
+pcmciareset(void)
+{
+ static int already;
+ int i;
+ IMM *io;
+ Slot *pp;
+
+ if(already)
+ return;
+ already = 1;
+
+ nslot = 2;
+ slot = xalloc(nslot * sizeof(Slot));
+
+ io = m->iomem;
+
+ for(i=0; i<8; i++){
+ io->pcmr[i].option = 0;
+ io->pcmr[i].base = 0;
+ }
+
+ for(i=0; i<2; i++)
+ io->pgcr[i] = (1<<(31-PCMCIAlevel)) | (1<<(23-PCMCIAlevel));
+
+ for(i = 0; i < nslot; i++){
+ pp = slot + i;
+ pp->slotno = i;
+ pp->memlen = 512*1024;
+ }
+
+ /* 512K - slow - attr */
+ io->pcmr[0].base = ISAMEM + 512*1024;
+ io->pcmr[0].option = (0x1a<<27) | (8<<16) | (6<<12) | (24<<7)
+ | Rport16 | Rattrib | Rvalid;
+ // 64K io
+ io->pcmr[1].base = ISAMEM+0x300;
+ io->pcmr[1].option = (0x6<<27) | (2<<16) | (4<<12) | (8<<7)
+ | Rport16 | Rio | Rvalid;
+
+// intrenable(VectorPIC+PCMCIAlevel, pcmciaintr, 0, BUSUNKNOWN);
+ io->pscr = 0xFEF0FEF0; /* reset status */
+ io->per = 0x00800000; /* enable interrupts */
+
+ print("pcmcia reset\n");
+}
+
+static Chan*
+pcmciaattach(char *spec)
+{
+ return devattach('y', spec);
+}
+
+static int
+pcmciawalk(Chan *c, char *name)
+{
+ return devwalk(c, name, 0, 0, pcmgen);
+}
+
+static void
+pcmciastat(Chan *c, char *db)
+{
+ devstat(c, db, 0, 0, pcmgen);
+}
+
+static Chan*
+pcmciaopen(Chan *c, int omode)
+{
+ if(c->qid.path == CHDIR){
+ if(omode != OREAD)
+ error(Eperm);
+ } else
+ increfp(slot + SLOTNO(c));
+ c->mode = openmode(omode);
+ c->flag |= COPEN;
+ c->offset = 0;
+ return c;
+}
+
+static void
+pcmciaclose(Chan *c)
+{
+ if(c->flag & COPEN)
+ if(c->qid.path != CHDIR)
+ decrefp(slot+SLOTNO(c));
+}
+
+/* a memmove using only bytes */
+static void
+memmoveb(uchar *to, uchar *from, int n)
+{
+ while(n-- > 0)
+ *to++ = *from++;
+}
+
+static long
+pcmread(int slotno, int attr, void *a, long n, vlong offset)
+{
+ int i, len;
+ PCMmap *m;
+ ulong ka;
+ uchar *ac;
+ Slot *pp;
+
+ pp = slot + slotno;
+ if(pp->memlen < offset)
+ return 0;
+ if(pp->memlen < offset + n)
+ n = pp->memlen - offset;
+
+ m = 0;
+ if(waserror()){
+ if(m)
+ pcmunmap(pp, m);
+ nexterror();
+ }
+
+ ac = a;
+ for(len = n; len > 0; len -= i){
+ m = pcmmap(pp, offset, 0, attr);
+ if(m == 0)
+ error("can't map PCMCIA card");
+ if(offset + len > m->cea)
+ i = m->cea - offset;
+ else
+ i = len;
+ ka = KZERO|(m->isa + offset - m->ca);
+ memmoveb(ac, (void*)ka, i);
+ pcmunmap(pp, m);
+ offset += i;
+ ac += i;
+ }
+ poperror();
+ return n;
+}
+
+static long
+pcmciaread(Chan *c, void *a, long n, vlong offset)
+{
+ char *cp, *buf;
+ ulong p;
+ Slot *pp;
+
+ p = TYPE(c);
+ switch(p){
+ case Qdir:
+ return devdirread(c, a, n, 0, 0, pcmgen);
+ case Qmem:
+ case Qattr:
+ return pcmread(SLOTNO(c), p==Qattr, a, n, offset);
+ case Qctl:
+ buf = malloc(2048);
+ if(buf == nil)
+ error(Enomem);
+ if(waserror()){
+ free(buf);
+ nexterror();
+ }
+ cp = buf;
+ pp = slot + SLOTNO(c);
+ if(pp->occupied)
+ cp += sprint(cp, "occupied\n");
+ if(pp->enabled)
+ cp += sprint(cp, "enabled\n");
+ if(pp->powered)
+ cp += sprint(cp, "powered\n");
+ if(pp->configed)
+ cp += sprint(cp, "configed\n");
+ if(pp->wrprot)
+ cp += sprint(cp, "write protected\n");
+ if(pp->busy)
+ cp += sprint(cp, "busy\n");
+ cp += sprint(cp, "battery lvl %d\n", pp->battery);
+ cp += sprint(cp, "voltage select %d\n", pp->voltage);
+ cp += sprint(cp, "pipr %ux\n", m->iomem->pipr);
+ cp += sprint(cp, "pcsr %ux\n", m->iomem->pscr);
+ *cp = 0;
+ n = readstr(offset, a, n, buf);
+ poperror();
+ free(buf);
+ break;
+ default:
+ n=0;
+ break;
+ }
+ return n;
+}
+
+static long
+pcmwrite(int dev, int attr, void *a, long n, vlong offset)
+{
+ int i, len;
+ PCMmap *m;
+ ulong ka;
+ uchar *ac;
+ Slot *pp;
+
+ pp = slot + dev;
+ if(pp->memlen < offset)
+ return 0;
+ if(pp->memlen < offset + n)
+ n = pp->memlen - offset;
+
+#ifdef xxx
+ m = 0;
+ if(waserror()){
+ if(m)
+ pcmunmap(pp->slotno, m);
+ nexterror();
+ }
+
+ ac = a;
+ for(len = n; len > 0; len -= i){
+ m = pcmmap(pp, offset, 0, attr);
+ if(m == 0)
+ error("can't map PCMCIA card");
+ if(offset + len > m->cea)
+ i = m->cea - offset;
+ else
+ i = len;
+ ka = KZERO|(m->isa + offset - m->ca);
+ memmoveb((void*)ka, ac, i);
+ pcmunmap(pp->slotno, m);
+ offset += i;
+ ac += i;
+ }
+
+ poperror();
+#endif
+
+ return n;
+}
+
+static long
+pcmciawrite(Chan *c, void *a, long n, vlong offset)
+{
+ ulong p;
+ Slot *pp;
+ char buf[32];
+
+ p = TYPE(c);
+ switch(p){
+ case Qctl:
+ if(n >= sizeof(buf))
+ n = sizeof(buf) - 1;
+ strncpy(buf, a, n);
+ buf[n] = 0;
+ pp = slot + SLOTNO(c);
+ if(!pp->occupied)
+ error(Eio);
+
+ break;
+ case Qmem:
+ case Qattr:
+ pp = slot + SLOTNO(c);
+ if(pp->occupied == 0 || pp->enabled == 0)
+ error(Eio);
+ n = pcmwrite(pp->slotno, p == Qattr, a, n, offset);
+ if(n < 0)
+ error(Eio);
+ break;
+ default:
+ error(Ebadusefd);
+ }
+ return n;
+}
+
+Dev pcmciadevtab = {
+ 'y',
+ "pcmcia",
+
+ pcmciareset,
+ devinit,
+ pcmciaattach,
+ devclone,
+ pcmciawalk,
+ pcmciastat,
+ pcmciaopen,
+ devcreate,
+ pcmciaclose,
+ pcmciaread,
+ devbread,
+ pcmciawrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
+
+static void
+pcmciaintr(Ureg *, void *)
+{
+ print("pcmciaintr\n");
+}
+
+/*
+ * get a map for pc card region, return corrected len
+ */
+static PCMmap*
+pcmmap(Slot *pp, ulong offset, int len, int attr)
+{
+ PCMmap *m;
+ ulong e;
+
+ if(attr == 0)
+ panic("pcmmap");
+
+ /* convert offset to granularity */
+ if(len <= 0)
+ len = 1;
+ e = ROUND(offset+len, Mgran);
+ offset &= Mmask;
+ len = e - offset;
+
+ m = pp->mmap;
+
+ m->ca = 0;
+ m->cea = 512*1024;
+ m->isa = ISAMEM + 512*1024;
+ m->len = 512*1024;
+ m->attr = attr;
+ m->ref = 1;
+
+ return m;
+}
+
+static void
+pcmunmap(Slot *pp, PCMmap *m)
+{
+}
+
+static int
+pcmio(int slotno, ISAConf *isa)
+{
+ uchar we, x, *p;
+ Slot *pp;
+ Conftab *ct, *et, *t;
+ PCMmap *m;
+ int i, index, irq;
+ char *cp;
+
+ isa->irq = VectorPIC+PCMCIAlevel;
+ irq = isa->irq;
+
+ if(slotno > nslot)
+ return -1;
+ pp = slot + slotno;
+
+ if(!pp->occupied)
+ return -1;
+
+ et = &pp->ctab[pp->nctab];
+
+ ct = 0;
+ for(i = 0; i < isa->nopt; i++){
+ if(strncmp(isa->opt[i], "index=", 6))
+ continue;
+ index = strtol(&isa->opt[i][6], &cp, 0);
+ if(cp == &isa->opt[i][6] || index >= pp->nctab)
+ return -1;
+ ct = &pp->ctab[index];
+ }
+
+ if(ct == 0){
+
+ /* assume default is right */
+ if(pp->def)
+ ct = pp->def;
+ else
+ ct = pp->ctab;
+
+ /* try for best match */
+ if(ct->nio == 0
+ || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
+ for(t = pp->ctab; t < et; t++)
+ if(t->nio
+ && t->io[0].start == isa->port
+ && ((1<<irq) & t->irqs)){
+ ct = t;
+ break;
+ }
+ }
+ if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
+ for(t = pp->ctab; t < et; t++)
+ if(t->nio && ((1<<irq) & t->irqs)){
+ ct = t;
+ break;
+ }
+ }
+ if(ct->nio == 0){
+ for(t = pp->ctab; t < et; t++)
+ if(t->nio){
+ ct = t;
+ break;
+ }
+ }
+ }
+
+ if(ct == et || ct->nio == 0)
+ return -1;
+
+ /* enable io port map 0 */
+ if(isa->port == 0)
+ isa->port = ct->io[0].start;
+ if(isa->port == 0 && ct->io[0].start == 0)
+ return -1;
+
+ if(pp->cpresent & (1<<Rconfig)){
+ /* Reset adapter */
+ m = pcmmap(pp, pp->caddr + Rconfig, 1, 1);
+ p = KADDR(m->isa + pp->caddr + Rconfig - m->ca);
+
+ /* set configuration and interrupt type */
+ x = 1;
+ x |= ct->index<<1;
+ if((ct->irqtype & 0x20) && ((ct->irqtype & 0x40)==0 || isa->irq>7)) {
+ x |= Clevel;
+ }
+ *p = x;
+ delay(5);
+ pcmunmap(pp, m);
+ }
+ return 0;
+}
+
+/*
+ * look for a card whose version contains 'idstr'
+ */
+int
+pcmspecial(char *idstr, ISAConf *isa)
+{
+ Slot *pp;
+ extern char *strstr(char*, char*);
+
+ for(pp = slot; pp < slot+nslot; pp++){
+ if(pp->special)
+ continue; /* already taken */
+ increfp(pp);
+
+ if(pp->occupied)
+ if(strstr(pp->verstr, idstr))
+ if(isa == 0 || pcmio(pp->slotno, isa) == 0){
+ pp->special = 1;
+ return pp->slotno;
+ }
+
+ decrefp(pp);
+ }
+ return -1;
+}
+
+void
+pcmspecialclose(int slotno)
+{
+ Slot *pp;
+
+ if(slotno >= nslot)
+ panic("pcmspecialclose");
+ pp = slot + slotno;
+ pp->special = 0;
+ decrefp(pp);
+}
+
+static void
+slotinfo(Slot *pp)
+{
+ ulong pipr;
+
+ pipr = m->iomem->pipr;
+ if(pp->slotno == 0)
+ pipr >>= 16;
+ pp->occupied = (pipr&(Ccd1|Ccd2))==0;
+ pp->battery = (pipr & (Cbvd1|Cbvd2)) != 0;
+ pp->voltage = ((pipr & Cvs1) != 0) | (((pipr & Cvs2) != 0)<<1);
+ pp->wrprot = (pipr&Cwp)==0;
+ pp->busy = (pipr&Crdy)==0;
+ pp->powered = 1; // assume power is always on for the momment
+}
+
+/*
+ * read and crack the card information structure enough to set
+ * important parameters like power
+ */
+static void tcfig(Slot*, int);
+static void tentry(Slot*, int);
+static void tvers1(Slot*, int);
+
+static void (*parse[256])(Slot*, int) =
+{
+[0x15] tvers1,
+[0x1A] tcfig,
+[0x1B] tentry,
+};
+
+static int
+readc(Slot *pp, uchar *x)
+{
+ if(pp->cispos >= Mgran)
+ return 0;
+ *x = pp->cisbase[2*pp->cispos];
+ pp->cispos++;
+ return 1;
+}
+
+static void
+cisread(Slot *pp)
+{
+ uchar link;
+ uchar type;
+ int this, i;
+ PCMmap *m;
+
+ memset(pp->ctab, 0, sizeof(pp->ctab));
+ pp->caddr = 0;
+ pp->cpresent = 0;
+ pp->configed = 0;
+ pp->nctab = 0;
+
+ m = pcmmap(pp, 0, 0, 1);
+ if(m == 0)
+ return;
+ pp->cisbase = KADDR(m->isa);
+ pp->cispos = 0;
+
+ /* loop through all the tuples */
+ for(i = 0; i < 1000; i++){
+ this = pp->cispos;
+ if(readc(pp, &type) != 1)
+ break;
+ if(type == 0xFF)
+ break;
+ if(readc(pp, &link) != 1)
+ break;
+ if(parse[type])
+ (*parse[type])(pp, type);
+ if(link == 0xff)
+ break;
+ pp->cispos = this + (2+link);
+ }
+ pcmunmap(pp, m);
+}
+
+static ulong
+getlong(Slot *pp, int size)
+{
+ uchar c;
+ int i;
+ ulong x;
+
+ x = 0;
+ for(i = 0; i < size; i++){
+ if(readc(pp, &c) != 1)
+ break;
+ x |= c<<(i*8);
+ }
+ return x;
+}
+
+static void
+tcfig(Slot *pp, int )
+{
+ uchar size, rasize, rmsize;
+ uchar last;
+
+ if(readc(pp, &size) != 1)
+ return;
+ rasize = (size&0x3) + 1;
+ rmsize = ((size>>2)&0xf) + 1;
+ if(readc(pp, &last) != 1)
+ return;
+ pp->caddr = getlong(pp, rasize);
+ pp->cpresent = getlong(pp, rmsize);
+}
+
+/*
+ * enable the slot card
+ */
+static void
+slotena(Slot *pp)
+{
+ IMM *io;
+ int shift;
+
+ if(pp->enabled)
+ return;
+ shift = (pp->slotno == 0)?16:0;
+
+ io = m->iomem;
+// io->pgcr[pp->slotno] |= Coe;
+ io->pgcr[pp->slotno] &= ~Coe; // active low
+ delay(300);
+ io->pgcr[pp->slotno] |= Creset;
+ delay(100);
+ io->pgcr[pp->slotno] &= ~Creset;
+ delay(500);
+#ifdef XXX
+ eieio();
+ delay(300);
+ io->pgcrb |= Cbreset; /* TO DO: active high? active low? */
+ eieio();
+ delay(100);
+ io->pgcrb &= ~Cbreset;
+ eieio();
+ delay(500);
+#endif
+ /* get configuration */
+ slotinfo(pp);
+ if(pp->occupied){
+ cisread(pp);
+ pp->enabled = 1;
+ }
+}
+
+/*
+ * disable the slot card
+ */
+static void
+slotdis(Slot *pp)
+{
+ pp->enabled = 0;
+}
+
+static void
+increfp(Slot *pp)
+{
+ lock(pp);
+ if(pp->ref++ == 0)
+ slotena(pp);
+ unlock(pp);
+}
+
+static void
+decrefp(Slot *pp)
+{
+ lock(pp);
+ if(pp->ref-- == 1)
+ slotdis(pp);
+ unlock(pp);
+}
+
+static ulong vexp[8] =
+{
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+static ulong vmant[16] =
+{
+ 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
+};
+
+static ulong
+microvolt(Slot *pp)
+{
+ uchar c;
+ ulong microvolts;
+ ulong exp;
+
+ if(readc(pp, &c) != 1)
+ return 0;
+ exp = vexp[c&0x7];
+ microvolts = vmant[(c>>3)&0xf]*exp;
+ while(c & 0x80){
+ if(readc(pp, &c) != 1)
+ return 0;
+ switch(c){
+ case 0x7d:
+ break; /* high impedence when sleeping */
+ case 0x7e:
+ case 0x7f:
+ microvolts = 0; /* no connection */
+ break;
+ default:
+ exp /= 10;
+ microvolts += exp*(c&0x7f);
+ }
+ }
+ return microvolts;
+}
+
+static ulong
+nanoamps(Slot *pp)
+{
+ uchar c;
+ ulong nanoamps;
+
+ if(readc(pp, &c) != 1)
+ return 0;
+ nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
+ while(c & 0x80){
+ if(readc(pp, &c) != 1)
+ return 0;
+ if(c == 0x7d || c == 0x7e || c == 0x7f)
+ nanoamps = 0;
+ }
+ return nanoamps;
+}
+
+/*
+ * only nominal voltage is important for config
+ */
+static ulong
+power(Slot *pp)
+{
+ uchar feature;
+ ulong mv;
+
+ mv = 0;
+ if(readc(pp, &feature) != 1)
+ return 0;
+ if(feature & 1)
+ mv = microvolt(pp);
+ if(feature & 2)
+ microvolt(pp);
+ if(feature & 4)
+ microvolt(pp);
+ if(feature & 8)
+ nanoamps(pp);
+ if(feature & 0x10)
+ nanoamps(pp);
+ if(feature & 0x20)
+ nanoamps(pp);
+ if(feature & 0x40)
+ nanoamps(pp);
+ return mv/1000000;
+}
+
+static ulong mantissa[16] =
+{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };
+
+static ulong exponent[8] =
+{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };
+
+static ulong
+ttiming(Slot *pp, int scale)
+{
+ uchar unscaled;
+ ulong nanosecs;
+
+ if(readc(pp, &unscaled) != 1)
+ return 0;
+ nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
+ nanosecs = nanosecs * vexp[scale];
+ return nanosecs;
+}
+
+static void
+timing(Slot *pp, Conftab *ct)
+{
+ uchar c, i;
+
+ if(readc(pp, &c) != 1)
+ return;
+ i = c&0x3;
+ if(i != 3)
+ ct->maxwait = ttiming(pp, i); /* max wait */
+ i = (c>>2)&0x7;
+ if(i != 7)
+ ct->readywait = ttiming(pp, i); /* max ready/busy wait */
+ i = (c>>5)&0x7;
+ if(i != 7)
+ ct->otherwait = ttiming(pp, i); /* reserved wait */
+}
+
+static void
+iospaces(Slot *pp, Conftab *ct)
+{
+ uchar c;
+ int i, nio;
+
+ ct->nio = 0;
+ if(readc(pp, &c) != 1)
+ return;
+
+ ct->bit16 = ((c>>5)&3) >= 2;
+ if(!(c & 0x80)){
+ ct->io[0].start = 0;
+ ct->io[0].len = 1<<(c&0x1f);
+ ct->nio = 1;
+ return;
+ }
+
+ if(readc(pp, &c) != 1)
+ return;
+
+ nio = (c&0xf)+1;
+ for(i = 0; i < nio; i++){
+ ct->io[i].start = getlong(pp, (c>>4)&0x3);
+ ct->io[0].len = getlong(pp, (c>>6)&0x3);
+ }
+ ct->nio = nio;
+}
+
+static void
+irq(Slot *pp, Conftab *ct)
+{
+ uchar c;
+
+ if(readc(pp, &c) != 1)
+ return;
+ ct->irqtype = c & 0xe0;
+ if(c & 0x10)
+ ct->irqs = getlong(pp, 2);
+ else
+ ct->irqs = 1<<(c&0xf);
+ ct->irqs &= 0xDEB8; /* levels available to card */
+}
+
+static void
+memspace(Slot *pp, int asize, int lsize, int host)
+{
+ ulong haddress, address, len;
+
+ len = getlong(pp, lsize)*256;
+ address = getlong(pp, asize)*256;
+ USED(len, address);
+ if(host){
+ haddress = getlong(pp, asize)*256;
+ USED(haddress);
+ }
+}
+
+static void
+tentry(Slot *pp, int )
+{
+ uchar c, i, feature;
+ Conftab *ct;
+
+ if(pp->nctab >= Maxctab)
+ return;
+ if(readc(pp, &c) != 1)
+ return;
+ ct = &pp->ctab[pp->nctab++];
+
+ /* copy from last default config */
+ if(pp->def)
+ *ct = *pp->def;
+
+ ct->index = c & 0x3f;
+
+ /* is this the new default? */
+ if(c & 0x40)
+ pp->def = ct;
+
+ /* memory wait specified? */
+ if(c & 0x80){
+ if(readc(pp, &i) != 1)
+ return;
+ if(i&0x80)
+ ct->memwait = 1;
+ }
+
+ if(readc(pp, &feature) != 1)
+ return;
+ switch(feature&0x3){
+ case 1:
+ ct->vpp1 = ct->vpp2 = power(pp);
+ break;
+ case 2:
+ power(pp);
+ ct->vpp1 = ct->vpp2 = power(pp);
+ break;
+ case 3:
+ power(pp);
+ ct->vpp1 = power(pp);
+ ct->vpp2 = power(pp);
+ break;
+ default:
+ break;
+ }
+ if(feature&0x4)
+ timing(pp, ct);
+ if(feature&0x8)
+ iospaces(pp, ct);
+ if(feature&0x10)
+ irq(pp, ct);
+ switch((feature>>5)&0x3){
+ case 1:
+ memspace(pp, 0, 2, 0);
+ break;
+ case 2:
+ memspace(pp, 2, 2, 0);
+ break;
+ case 3:
+ if(readc(pp, &c) != 1)
+ return;
+ for(i = 0; i <= (c&0x7); i++)
+ memspace(pp, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
+ break;
+ }
+ pp->configed++;
+}
+
+static void
+tvers1(Slot *pp, int )
+{
+ uchar c, major, minor;
+ int i;
+
+ if(readc(pp, &major) != 1)
+ return;
+ if(readc(pp, &minor) != 1)
+ return;
+ for(i = 0; i < sizeof(pp->verstr)-1; i++){
+ if(readc(pp, &c) != 1)
+ return;
+ if(c == 0)
+ c = '\n';
+ if(c == 0xff)
+ break;
+ pp->verstr[i] = c;
+ }
+ pp->verstr[i] = 0;
+}
M mpc/devrtc.c => mpc/devrtc.c +30 -18
@@ 7,16 7,9 @@
#include "io.h"
-/*
- * MPC8xx real time clock
- * FADS board option switch
- * interrupt statistics
- */
-
enum{
Qrtc = 1,
- Qswitch,
- Qintstat,
+ Qnvram,
/* sccr */
RTDIV= 1<<24,
@@ 25,14 18,18 @@ enum{
/* rtcsc */
RTE= 1<<0,
R38K= 1<<4,
+
+ Nvoff= 4*1024, /* where usable nvram lives */
+ Nvsize= 4*1024,
};
static QLock rtclock; /* mutex on clock operations */
+static Lock nvrtlock;
+
static Dirtab rtcdir[]={
"rtc", {Qrtc, 0}, 12, 0666,
- "switch", {Qswitch, 0}, 0, 0444,
- "intstat", {Qintstat, 0}, 0, 0444,
+ "nvram", {Qnvram, 0}, Nvsize, 0664,
};
#define NRTC (sizeof(rtcdir)/sizeof(rtcdir[0]))
@@ 79,9 76,8 @@ rtcopen(Chan *c, int omode)
if(strcmp(up->user, eve)!=0 && omode!=OREAD)
error(Eperm);
break;
- case Qswitch:
- case Qintstat:
- if(omode!=OREAD)
+ case Qnvram:
+ if(strcmp(up->user, eve)!=0)
error(Eperm);
break;
}
@@ 97,7 93,6 @@ static long
rtcread(Chan *c, void *buf, long n, vlong offset)
{
ulong t;
-// char *b;
if(c->qid.path & CHDIR)
return devdirread(c, buf, n, rtcdir, NRTC, devgen);
@@ 107,8 102,16 @@ rtcread(Chan *c, void *buf, long n, vlong offset)
t = m->iomem->rtc;
n = readnum(offset, buf, n, t, 12);
return n;
- case Qswitch:
- return readnum(offset, buf, n, 0xf/*(m->bcsr[2]>>19)&0xF*/, 12);
+ case Qnvram:
+ if(offset >= Nvsize)
+ return 0;
+ t = offset;
+ if(t + n > Nvsize)
+ n = Nvsize - t;
+ ilock(&nvrtlock);
+ memmove(buf, (uchar*)(NVRAMMEM + Nvoff + t), n);
+ iunlock(&nvrtlock);
+ return n;
}
error(Egreg);
return 0; /* not reached */
@@ 120,6 123,7 @@ rtcwrite(Chan *c, void *buf, long n, vlong offset)
ulong secs;
char *cp, *ep;
IMM *io;
+ ulong t;
switch(c->qid.path){
case Qrtc:
@@ 145,8 149,16 @@ rtcwrite(Chan *c, void *buf, long n, vlong offset)
io->rtck = ~KEEP_ALIVE_KEY;
iopunlock();
return n;
- case Qswitch:
- return 0;
+ case Qnvram:
+ if(offset >= Nvsize)
+ return 0;
+ t = offset;
+ if(t + n > Nvsize)
+ n = Nvsize - t;
+ ilock(&nvrtlock);
+ memmove((uchar*)(NVRAMMEM + Nvoff + offset), buf, n);
+ iunlock(&nvrtlock);
+ return n;
}
error(Egreg);
return 0; /* not reached */
A mpc/devsac.c => mpc/devsac.c +647 -0
@@ 0,0 1,647 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+/*
+ * Rather than reading /adm/users, which is a lot of work for
+ * a toy program, we assume all groups have the form
+ * NNN:user:user:
+ * meaning that each user is the leader of his own group.
+ */
+
+enum
+{
+ OPERM = 0x3, /* mask of all permission types in open mode */
+ Nram = 512,
+};
+
+typedef struct SacPath SacPath;
+typedef struct Sac Sac;
+typedef struct SacHeader SacHeader;
+typedef struct SacDir SacDir;
+
+enum {
+ Magic = 0x5acf5,
+};
+
+struct SacDir
+{
+ char name[NAMELEN];
+ char uid[NAMELEN];
+ char gid[NAMELEN];
+ uchar qid[4];
+ uchar mode[4];
+ uchar atime[4];
+ uchar mtime[4];
+ uchar length[8];
+ uchar blocks[8];
+};
+
+struct SacHeader
+{
+ uchar magic[4];
+ uchar length[8];
+ uchar blocksize[4];
+ uchar md5[16];
+};
+
+
+struct Sac
+{
+ SacDir;
+ SacPath *path;
+};
+
+struct SacPath
+{
+ Ref;
+ SacPath *up;
+ vlong blocks;
+ int entry;
+};
+
+enum
+{
+ Pexec = 1,
+ Pwrite = 2,
+ Pread = 4,
+ Pother = 1,
+ Pgroup = 8,
+ Powner = 64,
+};
+
+uchar *data = SACMEM;
+int blocksize;
+Sac root;
+
+void sacstat(SacDir*, char*);
+void io(void);
+void usage(void);
+ulong getl(void *p);
+vlong getv(void *p);
+void init(char*);
+Sac *saccpy(Sac *s);
+Sac *saclookup(Sac *s, char *name);
+int sacdirread(Sac *s, char *p, long off, long cnt);
+void loadblock(void *buf, uchar *offset, int blocksize);
+void sacfree(Sac*);
+
+void
+devinit(void)
+{
+ SacHeader *hdr;
+ hdr = (SacHeader*)data;
+ if(getl(hdr->magic) != Magic) {
+print("devsac: bad magic");
+ return;
+ }
+ blocksize = getl(hdr->blocksize);
+ root.SacDir = *(SacDir*)(data + sizeof(SacHeader));
+}
+
+static Chan*
+sacattach(char* spec)
+{
+ Chan *c;
+ int dev;
+
+ dev = atoi(spec);
+ if(dev != 0)
+ error("bad specification");
+
+ // check if init found sac file system in memory
+ if(blocksize == 0)
+ error("devsac: bad magic");
+
+ c = devattach('C', spec);
+ c->qid = (Qid){getl(root.qid), 0};
+ c->dev = dev;
+ c->aux = saccpy(&root);
+ return c;
+}
+
+Chan*
+sacclone(Chan *c, Chan *nc)
+{
+ nc = devclone(c, nc);
+ nc->aux = saccpy(c->aux);
+ return nc;
+}
+
+int
+devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen)
+{
+ Sac *sac;
+
+ isdir(c);
+ sac = c->aux;
+ if(strcmp(name, ".") == 0)
+ return 1;
+ sac = saclookup(sac, name);
+ if(sac == nil) {
+ strncpy(up->error, Enonexist, NAMELEN);
+ return 0;
+ }
+ c->aux = sac;
+ c->qid = (Qid){getl(sac->qid), 0};
+ op = c->path;
+ c->path = ptenter(&syspt, op, name);
+ decref(op);
+ return 1;
+}
+
+char *
+ropen(Fid *f)
+{
+ int mode, trunc;
+
+ if(f->open)
+ return Eisopen;
+ if(f->busy == 0)
+ return Enotexist;
+ mode = rhdr.mode;
+ if(f->qid.path & CHDIR){
+ if(mode != OREAD)
+ return Eperm;
+ thdr.qid = f->qid;
+ return 0;
+ }
+ if(mode & ORCLOSE)
+ return Erdonly;
+ trunc = mode & OTRUNC;
+ mode &= OPERM;
+ if(mode==OWRITE || mode==ORDWR || trunc)
+ return Erdonly;
+ if(mode==OREAD)
+ if(!perm(f, f->sac, Pread))
+ return Eperm;
+ if(mode==OEXEC)
+ if(!perm(f, f->sac, Pexec))
+ return Eperm;
+ thdr.qid = f->qid;
+ f->open = 1;
+ return 0;
+}
+
+char *
+rcreate(Fid *f)
+{
+ if(f->open)
+ return Eisopen;
+ if(f->busy == 0)
+ return Enotexist;
+ return Erdonly;
+}
+
+char*
+rread(Fid *f)
+{
+ Sac *sac;
+ char *buf, *buf2;
+ long off;
+ int n, cnt, i, j;
+ uchar *blocks;
+ vlong length;
+
+ if(f->busy == 0)
+ return Enotexist;
+ sac = f->sac;
+ thdr.count = 0;
+ off = rhdr.offset;
+ buf = thdr.data;
+ cnt = rhdr.count;
+ if(f->qid.path & CHDIR){
+ cnt = (rhdr.count/DIRLEN)*DIRLEN;
+ if(off%DIRLEN)
+ return "i/o error";
+ thdr.count = sacdirread(sac, buf, off, cnt);
+ return 0;
+ }
+ length = getv(sac->length);
+ if(off >= length) {
+ rhdr.count = 0;
+ return 0;
+ }
+ if(cnt > length-off)
+ cnt = length-off;
+ thdr.count = cnt;
+ if(cnt == 0)
+ return 0;
+ blocks = data + getv(sac->blocks);
+ buf2 = malloc(blocksize);
+ while(cnt > 0) {
+ i = off/blocksize;
+ loadblock(buf2, blocks+i*8, blocksize);
+ j = off-i*blocksize;
+ n = blocksize-j;
+ if(n > cnt)
+ n = cnt;
+ memmove(buf, buf2+j, n);
+ cnt -= n;
+ off += n;
+ }
+ free(buf2);
+ return 0;
+}
+
+char*
+sacwrite(Fid *f)
+{
+ if(f->busy == 0)
+ return Enotexist;
+ return Erdonly;
+}
+
+char *
+rclunk(Fid *f)
+{
+ f->busy = 0;
+ f->open = 0;
+ free(f->user);
+ sacfree(f->sac);
+ return 0;
+}
+
+char *
+rremove(Fid *f)
+{
+ f->busy = 0;
+ f->open = 0;
+ free(f->user);
+ sacfree(f->sac);
+ return Erdonly;
+}
+
+char *
+rstat(Fid *f)
+{
+ if(f->busy == 0)
+ return Enotexist;
+ sacstat(f->sac, thdr.stat);
+ return 0;
+}
+
+char *
+rwstat(Fid *f)
+{
+ if(f->busy == 0)
+ return Enotexist;
+ return Erdonly;
+}
+
+Sac*
+saccpy(Sac *s)
+{
+ Sac *ss;
+
+ ss = malloc(sizeof(Sac));
+ *ss = *s;
+ if(ss->path)
+ incref(ss->path);
+ return ss;
+}
+
+SacPath *
+sacpathalloc(SacPath *p, vlong blocks, int entry)
+{
+ SacPath *pp = malloc(sizeof(SacPath));
+ pp->ref = 1;
+ pp->blocks = blocks;
+ pp->entry = entry;
+ pp->up = p;
+ return pp;
+}
+
+static void
+sacpathfree(SacPath *p)
+{
+ if(p == nil)
+ return;
+ if(decref(p) > 0)
+ return;
+ sacpathfree(p->up);
+ free(p);
+}
+
+
+void
+sacfree(Sac *s)
+{
+ sacpathfree(s->path);
+ free(s);
+}
+
+void
+sacstat(SacDir *s, char *buf)
+{
+ Dir dir;
+
+ memmove(dir.name, s->name, NAMELEN);
+ dir.qid = (Qid){getl(s->qid), 0};
+ dir.mode = getl(s->mode);
+ dir.length = getv(s->length);
+ if(dir.mode &CHDIR)
+ dir.length *= DIRLEN;
+ strcpy(dir.uid, s->uid);
+ strcpy(dir.gid, s->gid);
+ dir.atime = getl(s->atime);
+ dir.mtime = getl(s->mtime);
+ convD2M(&dir, buf);
+}
+
+void
+loadblock(void *buf, uchar *offset, int blocksize)
+{
+ vlong block, n;
+
+ block = getv(offset);
+ if(block < 0) {
+ block = -block;
+ n = getv(offset+8);
+ if(n < 0)
+ n = -n;
+ n -= block;
+//fprint(2, "blocksize = %d, block = %lld n = %lld\n", blocksize, block, n);
+ if(unsac(buf, data+block, blocksize, n)<0)
+ panic("unsac failed!");
+ } else {
+ memmove(buf, data+block, blocksize);
+ }
+}
+
+Sac*
+sacparent(Sac *s)
+{
+ uchar *blocks;
+ SacDir *buf;
+ int per, i;
+ SacPath *p;
+
+ p = s->path;
+ if(p == nil || p->up == nil) {
+ pathfree(p);
+ *s = root;
+ return s;
+ }
+ p = p->up;
+
+//fprint(2, "sacparent = %lld %d\n", p->blocks, p->entry);
+ blocks = data + p->blocks;
+ per = blocksize/sizeof(SacDir);
+ i = p->entry/per;
+ buf = malloc(per*sizeof(SacDir));
+ loadblock(buf, blocks + i*8, per*sizeof(SacDir));
+ s->SacDir = buf[p->entry-i*per];
+//fprint(2, "sacparent = %s\n", s->name);
+ free(buf);
+ incref(p);
+ pathfree(s->path);
+ s->path = p;
+ return s;
+}
+
+int
+sacdirread(Sac *s, char *p, long off, long cnt)
+{
+ uchar *blocks;
+ SacDir *buf;
+ int iblock, per, i, j, ndir;
+
+ blocks = data + getv(s->blocks);
+ per = blocksize/sizeof(SacDir);
+ ndir = getv(s->length);
+ off /= DIRLEN;
+ cnt /= DIRLEN;
+ if(off >= ndir)
+ return 0;
+ if(cnt > ndir-off)
+ cnt = ndir-off;
+ iblock = -1;
+ buf = malloc(per*sizeof(SacDir));
+ for(i=off; i<off+cnt; i++) {
+ j = i/per;
+ if(j != iblock) {
+ loadblock(buf, blocks + j*8, per*sizeof(SacDir));
+ iblock = j;
+ }
+ j *= per;
+ sacstat(buf+i-j, p);
+ p += DIRLEN;
+ }
+ free(buf);
+ return cnt*DIRLEN;
+}
+
+Sac*
+saclookup(Sac *s, char *name)
+{
+ int ndir;
+ int top, bot, i, j, k, per;
+ uchar *blocks;
+ SacDir *buf;
+ int iblock;
+ SacDir *sd;
+
+ if(strcmp(name, "..") == 0)
+ return sacparent(s);
+ blocks = data + getv(s->blocks);
+ per = blocksize/sizeof(SacDir);
+ ndir = getv(s->length);
+ buf = malloc(per*sizeof(SacDir));
+ iblock = -1;
+
+ if(1) {
+ // linear search
+ for(i=0; i<ndir; i++) {
+ j = i/per;
+ if(j != iblock) {
+ loadblock(buf, blocks + j*8, per*sizeof(SacDir));
+ iblock = j;
+ }
+ j *= per;
+ sd = buf+i-j;
+ k = strcmp(name, sd->name);
+ if(k == 0) {
+//print("walk %s %lld %d\n", name, getv(s->blocks), i);
+ s->path = sacpathalloc(s->path, getv(s->blocks), i);
+ s->SacDir = *sd;
+ free(buf);
+ return s;
+ }
+ }
+ free(buf);
+ return 0;
+ }
+
+ // binary search
+ top = ndir;
+ bot = 0;
+ while(bot != top){
+if(bot>top)
+sysfatal("binary serach failed: %d %d\n", bot, top);
+ i = (bot+top)>>1;
+ j = i/per;
+ if(j != iblock) {
+ loadblock(buf, blocks + j*8, per*sizeof(SacDir));
+ iblock = j;
+ }
+ j *= per;
+ sd = buf+i-j;
+ k = strcmp(name, sd->name);
+ if(k == 0) {
+ s->path = sacpathalloc(s->path, getv(s->blocks), i);
+ s->SacDir = *sd;
+ free(buf);
+ }
+ if(k < 0) {
+ top = i;
+ sd = buf;
+ if(strcmp(name, sd->name) < 0)
+ top = j;
+ } else {
+ bot = i+1;
+ if(ndir-j < per)
+ i = ndir-j;
+ else
+ i = per;
+ sd = buf+i-1;
+ if(strcmp(name, sd->name) > 0)
+ bot = j+i;
+ }
+ }
+ return 0;
+}
+
+Fid *
+newfid(int fid)
+{
+ Fid *f, *ff;
+
+ ff = 0;
+ for(f = fids; f; f = f->next)
+ if(f->fid == fid)
+ return f;
+ else if(!ff && !f->busy)
+ ff = f;
+ if(ff){
+ ff->fid = fid;
+ return ff;
+ }
+ f = malloc(sizeof *f);
+//fprint(2, "newfid\n");
+ memset(f, 0 , sizeof(Fid));
+ f->fid = fid;
+ f->next = fids;
+ fids = f;
+ return f;
+}
+
+void
+io(void)
+{
+ char *err;
+ int n;
+
+ for(;;){
+ /*
+ * reading from a pipe or a network device
+ * will give an error after a few eof reads
+ * however, we cannot tell the difference
+ * between a zero-length read and an interrupt
+ * on the processes writing to us,
+ * so we wait for the error
+ */
+ n = read(mfd[0], mdata, sizeof mdata);
+ if(n == 0)
+ continue;
+ if(n < 0)
+ error("mount read");
+ if(convM2S(mdata, &rhdr, n) == 0)
+ continue;
+
+ if(debug)
+ fprint(2, "sacfs:<-%F\n", &rhdr);
+
+ thdr.data = mdata + MAXMSG;
+ if(!fcalls[rhdr.type])
+ err = "bad fcall type";
+ else
+ err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
+ if(err){
+ thdr.type = Rerror;
+ strncpy(thdr.ename, err, ERRLEN);
+ }else{
+ thdr.type = rhdr.type + 1;
+ thdr.fid = rhdr.fid;
+ }
+ thdr.tag = rhdr.tag;
+ if(debug)
+ fprint(2, "ramfs:->%F\n", &thdr);/**/
+ n = convS2M(&thdr, mdata);
+ if(write(mfd[1], mdata, n) != n)
+ error("mount write");
+ }
+}
+
+int
+perm(Fid *f, Sac *s, int p)
+{
+ ulong perm = getl(s->mode);
+ if((p*Pother) & perm)
+ return 1;
+ if(strcmp(f->user, s->gid)==0 && ((p*Pgroup) & perm))
+ return 1;
+ if(strcmp(f->user, s->uid)==0 && ((p*Powner) & perm))
+ return 1;
+ return 0;
+}
+
+
+ulong
+getl(void *p)
+{
+ uchar *a = p;
+
+ return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
+}
+
+vlong
+getv(void *p)
+{
+ uchar *a = p;
+ ulong l0, l1;
+ vlong v;
+
+ l0 = (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
+ a += 4;
+ l1 = (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
+
+ v = l0;
+ v <<= 32;
+ v |= l1;
+ return v;
+}
+
+Dev sacdevtab = {
+ 'C',
+ "sac",
+
+ devreset,
+ sacinit,
+ sacattach,
+ sacclone,
+ sacwalk,
+ sacstat,
+ sacopen,
+ devcreate,
+ sacclose,
+ sacread,
+ devbread,
+ sacwrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
M mpc/devuart.c => mpc/devuart.c +27 -11
@@ 11,7 11,7 @@
enum {
FADS823 = 1,
- Rbufsize= 512,
+ Rbufsize= 32, // read buffer size
Nuart= 3, /* max per machine (SMC1, SMC2, SCC2) */
CTLS= 's'&037,
CTLQ= 'q'&037,
@@ 188,8 188,6 @@ struct Uart
Queue *iq;
Queue *oq;
- /* staging areas to avoid some of the per character costs */
- uchar istage[Rbufsize][2]; /* double buffered */
int rdrx; /* last buffer read */
Lock plock; /* for output variables */
@@ 230,12 228,22 @@ uartsetbuf(Uart *up)
{
IOCparam *p;
BD *bd;
+ int n;
+ uchar *buf;
p = up->param;
p->rfcr = 0x18;
p->tfcr = 0x18;
p->mrblr = Rbufsize;
+ // allocate buffer for receive
+ // the buffers need to be CACHELINESZ aligned and
+ // a multiple of CACHELINESZ long in order for
+ // the manul cache coherence to work
+ n = 2*ROUND(Rbufsize, CACHELINESZ)+CACHELINESZ-1;
+ buf = malloc(n);
+ buf = (uchar*)ROUND((long)buf, CACHELINESZ);
+
if((bd = up->rxb) == nil){
bd = bdalloc(2);
up->rxb = bd;
@@ 243,12 251,12 @@ uartsetbuf(Uart *up)
p->rbase = (ushort)bd;
bd->status = BDEmpty|BDInt;
bd->length = 0;
- bd->addr = PADDR(up->istage[0]);
+ bd->addr = PADDR(buf);
bd++;
bd->status = BDEmpty|BDInt|BDWrap;
bd->length = 0;
- bd->addr = PADDR(up->istage[1]);
- dcflush(up->istage, sizeof(up->istage));
+ bd->addr = PADDR(buf + ROUND(Rbufsize, CACHELINESZ));
+ dcflush(buf, 2*ROUND(Rbufsize, CACHELINESZ));
up->rdrx = 0;
if((bd = up->txb) == nil){
@@ 288,7 296,7 @@ smcsetup(Uart *up)
/* SMC protocol parameters */
p = (Uartsmc*)up->param;
up->brkcr = &p->brkcr;
- p->maxidl = 1;
+ p->maxidl = 10;
p->brkln = 0;
p->brkec = 0;
p->brkcr = 1;
@@ 892,6 900,8 @@ uartspecial(int port, int baud, Queue **in, Queue **out, int (*putc)(Queue*, int
p->opens++;
}
+int lastc = 'x';
+
static int
uartinput(Uart *p, BD *bd)
{
@@ 922,8 932,10 @@ uartinput(Uart *p, BD *bd)
}
/* BUG? should discard on/off char? */
}
- if(p->putc)
+ if(p->putc) {
(*p->putc)(p->iq, ch);
+ lastc = ch;
+ }
}
}
if(p->putc == nil && l > 0)
@@ 1021,6 1033,7 @@ uartintr(Uart *p, int events)
iunlock(&p->plock);
}
}
+#ifdef XXX
eieio();
/* TO DO: modem status isn't available on 82xFADS */
if(dokick && p->cts && !p->blocked){
@@ 1030,7 1043,10 @@ uartintr(Uart *p, int events)
iunlock(&p->plock);
}
cpmop(RestartTx, p->cpmid, 0);
- } else if (events & TXE)
+ } else
+#endif
+
+ if (events & TXE)
cpmop(RestartTx, p->cpmid, 0);
}
@@ 1215,8 1231,8 @@ uartstatus(Chan*, Uart *p, void *buf, long n, long offset)
IMM *io;
char str[256];
- sprint(str, "opens %d ferr %lud oerr %lud crcerr %lud baud %lud perr %lud intr %lud", p->opens,
- p->frame, p->overrun, p->crcerr, p->baud, p->perror, p->interrupts);
+ sprint(str, "opens %d ferr %lud oerr %lud crcerr %lud baud %lud perr %lud intr %lud lastc = %c", p->opens,
+ p->frame, p->overrun, p->crcerr, p->baud, p->perror, p->interrupts, lastc);
/* TO DO: cts, dsr, ring, dcd, dtr, rts aren't all available on 82xFADS */
io = m->iomem;
if(p->scc){
A mpc/ether589.c => mpc/ether589.c +156 -0
@@ 0,0 1,156 @@
+/*
+ * 3C589 and 3C562.
+ * To do:
+ * check xcvr10Base2 still works (is GlobalReset necessary?).
+ * pull the station address out of the card space for the 3C562,
+ * it has no EEPROM.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+#include "etherif.h"
+
+enum { /* all windows */
+ CommandR = 0x000E,
+ IntStatusR = 0x000E,
+};
+
+enum { /* Commands */
+ GlobalReset = 0x0000,
+ SelectRegisterWindow = 0x0001,
+ RxReset = 0x0005,
+ TxReset = 0x000B,
+ AcknowledgeInterrupt = 0x000D,
+};
+
+enum { /* IntStatus bits */
+ commandInProgress = 0x1000,
+};
+
+#define COMMAND(port, cmd, a) outs((port)+CommandR, ((cmd)<<11)|(a))
+#define STATUS(port) ins((port)+IntStatusR)
+
+enum { /* Window 0 - setup */
+ Wsetup = 0x0000,
+ /* registers */
+ ManufacturerID = 0x0000, /* 3C5[08]*, 3C59[27] */
+ ProductID = 0x0002, /* 3C5[08]*, 3C59[27] */
+ ConfigControl = 0x0004, /* 3C5[08]*, 3C59[27] */
+ AddressConfig = 0x0006, /* 3C5[08]*, 3C59[27] */
+ ResourceConfig = 0x0008, /* 3C5[08]*, 3C59[27] */
+ EepromCommand = 0x000A,
+ EepromData = 0x000C,
+ /* AddressConfig Bits */
+ autoSelect9 = 0x0080,
+ xcvrMask9 = 0xC000,
+ /* ConfigControl bits */
+ Ena = 0x0001,
+ base10TAvailable9 = 0x0200,
+ coaxAvailable9 = 0x1000,
+ auiAvailable9 = 0x2000,
+ /* EepromCommand bits */
+ EepromReadRegister = 0x0080,
+ EepromBusy = 0x8000,
+};
+
+enum { /* Window 1 - operating set */
+ Wop = 0x0001,
+};
+
+enum { /* Window 3 - FIFO management */
+ Wfifo = 0x0003,
+ /* registers */
+ InternalConfig = 0x0000, /* 3C509B, 3C589, 3C59[0257] */
+ /* InternalConfig bits */
+ xcvr10BaseT = 0x00000000,
+ xcvr10Base2 = 0x00300000,
+};
+
+enum { /* Window 4 - diagnostic */
+ Wdiagnostic = 0x0004,
+ /* registers */
+ MediaStatus = 0x000A,
+ /* MediaStatus bits */
+ linkBeatDetect = 0x0800,
+};
+
+extern int etherelnk3reset(Ether*);
+
+static int
+configASIC(Ether* ether, int port, int xcvr)
+{
+ int x;
+
+ /* set Window 0 configuration registers */
+ COMMAND(port, SelectRegisterWindow, Wsetup);
+ outs(port+ConfigControl, Ena);
+
+ /* IRQ must be 3 on 3C589/3C562 */
+ outs(port + ResourceConfig, 0x3F00);
+
+ x = ins(port+AddressConfig) & ~xcvrMask9;
+ x |= (xcvr>>20)<<14;
+ outs(port+AddressConfig, x);
+
+ COMMAND(port, TxReset, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+ COMMAND(port, RxReset, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+
+ return etherelnk3reset(ether);
+}
+
+static int
+reset(Ether* ether)
+{
+ int slot;
+ int port;
+
+ if(ether->irq == 0)
+ ether->irq = 10;
+ if(ether->port == 0)
+ ether->port = 0x240;
+ port = ether->port;
+
+ if((slot = pcmspecial(ether->type, ether)) < 0)
+ return -1;
+
+ /* try configuring as a 10BaseT */
+ if(configASIC(ether, port, xcvr10BaseT) < 0){
+ pcmspecialclose(slot);
+ return -1;
+ }
+ delay(100);
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ if(ins(port+MediaStatus) & linkBeatDetect){
+ COMMAND(port, SelectRegisterWindow, Wop);
+ print("#l%d: xcvr10BaseT %s\n", ether->ctlrno, ether->type);
+ return 0;
+ }
+
+ /* try configuring as a 10base2 */
+ COMMAND(port, GlobalReset, 0);
+ if(configASIC(ether, port, xcvr10Base2) < 0){
+ pcmspecialclose(slot);
+ return -1;
+ }
+ print("#l%d: xcvr10Base2 %s\n", ether->ctlrno, ether->type);
+
+ return 0;
+}
+
+void
+ether589link(void)
+{
+ addethercard("3C589", reset);
+ addethercard("3C562", reset);
+ addethercard("589E", reset);
+}
A mpc/etherelnk3.c => mpc/etherelnk3.c +1854 -0
@@ 0,0 1,1854 @@
+/*
+ * Etherlink III, Fast EtherLink and Fast EtherLink XL adapters.
+ * To do:
+ * check robustness in the face of errors (e.g. busmaster & rxUnderrun);
+ * RxEarly and busmaster;
+ * autoSelect;
+ * PCI latency timer and master enable;
+ * errata list;
+ * rewrite all initialisation;
+ * handle the cyclone adapter.
+ *
+ * Product ID:
+ * 9150 ISA 3C509[B]
+ * 9050 ISA 3C509[B]-TP
+ * 9450 ISA 3C509[B]-COMBO
+ * 9550 ISA 3C509[B]-TPO
+ *
+ * 9350 EISA 3C579
+ * 9250 EISA 3C579-TP
+ *
+ * 5920 EISA 3C592-[TP|COMBO|TPO]
+ * 5970 EISA 3C597-TX Fast Etherlink 10BASE-T/100BASE-TX
+ * 5971 EISA 3C597-T4 Fast Etherlink 10BASE-T/100BASE-T4
+ * 5972 EISA 3C597-MII Fast Etherlink 10BASE-T/MII
+ *
+ * 5900 PCI 3C590-[TP|COMBO|TPO]
+ * 5950 PCI 3C595-TX Fast Etherlink Shared 10BASE-T/100BASE-TX
+ * 5951 PCI 3C595-T4 Fast Etherlink Shared 10BASE-T/100BASE-T4
+ * 5952 PCI 3C595-MII Fast Etherlink 10BASE-T/MII
+ *
+ * 9000 PCI 3C900-TPO Etherlink III XL PCI 10BASE-T
+ * 9001 PCI 3C900-COMBO Etherlink III XL PCI 10BASE-T/10BASE-2/AUI
+ * 9005 PCI 3C900B-COMBO Etherlink III XL PCI 10BASE-T/10BASE-2/AUI
+ * 9050 PCI 3C905-TX Fast Etherlink XL Shared 10BASE-T/100BASE-TX
+ * 9051 PCI 3C905-T4 Fast Etherlink Shared 10BASE-T/100BASE-T4
+ * 9055 PCI 3C905B-TX Fast Etherlink Shared 10BASE-T/100BASE-TX
+ *
+ * 9058 PCMCIA 3C589[B]-[TP|COMBO]
+ *
+ * 627C MCA 3C529
+ * 627D MCA 3C529-TP
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+#include "etherif.h"
+
+#define XCVRDEBUG if(0)print
+
+enum {
+ IDport = 0x0110, /* anywhere between 0x0100 and 0x01F0 */
+};
+
+enum { /* all windows */
+ CommandR = 0x000E,
+ IntStatusR = 0x000E,
+};
+
+enum { /* Commands */
+ GlobalReset = 0x0000,
+ SelectRegisterWindow = 0x0001,
+ EnableDcConverter = 0x0002,
+ RxDisable = 0x0003,
+ RxEnable = 0x0004,
+ RxReset = 0x0005,
+ Stall = 0x0006, /* 3C90x */
+ TxDone = 0x0007,
+ RxDiscard = 0x0008,
+ TxEnable = 0x0009,
+ TxDisable = 0x000A,
+ TxReset = 0x000B,
+ RequestInterrupt = 0x000C,
+ AcknowledgeInterrupt = 0x000D,
+ SetInterruptEnable = 0x000E,
+ SetIndicationEnable = 0x000F, /* SetReadZeroMask */
+ SetRxFilter = 0x0010,
+ SetRxEarlyThresh = 0x0011,
+ SetTxAvailableThresh = 0x0012,
+ SetTxStartThresh = 0x0013,
+ StartDma = 0x0014, /* initiate busmaster operation */
+ StatisticsEnable = 0x0015,
+ StatisticsDisable = 0x0016,
+ DisableDcConverter = 0x0017,
+ SetTxReclaimThresh = 0x0018, /* PIO-only adapters */
+ PowerUp = 0x001B, /* not all adapters */
+ PowerDownFull = 0x001C, /* not all adapters */
+ PowerAuto = 0x001D, /* not all adapters */
+};
+
+enum { /* (Global|Rx|Tx)Reset command bits */
+ tpAuiReset = 0x0001, /* 10BaseT and AUI transceivers */
+ endecReset = 0x0002, /* internal Ethernet encoder/decoder */
+ networkReset = 0x0004, /* network interface logic */
+ fifoReset = 0x0008, /* FIFO control logic */
+ aismReset = 0x0010, /* autoinitialise state-machine logic */
+ hostReset = 0x0020, /* bus interface logic */
+ dmaReset = 0x0040, /* bus master logic */
+ vcoReset = 0x0080, /* on-board 10Mbps VCO */
+ updnReset = 0x0100, /* upload/download (Rx/TX) logic */
+
+ resetMask = 0x01FF,
+};
+
+enum { /* Stall command bits */
+ upStall = 0x0000,
+ upUnStall = 0x0001,
+ dnStall = 0x0002,
+ dnUnStall = 0x0003,
+};
+
+enum { /* SetRxFilter command bits */
+ receiveIndividual = 0x0001, /* match station address */
+ receiveMulticast = 0x0002,
+ receiveBroadcast = 0x0004,
+ receiveAllFrames = 0x0008, /* promiscuous */
+};
+
+enum { /* StartDma command bits */
+ Upload = 0x0000, /* transfer data from adapter to memory */
+ Download = 0x0001, /* transfer data from memory to adapter */
+};
+
+enum { /* IntStatus bits */
+ interruptLatch = 0x0001,
+ hostError = 0x0002, /* Adapter Failure */
+ txComplete = 0x0004,
+ txAvailable = 0x0008,
+ rxComplete = 0x0010,
+ rxEarly = 0x0020,
+ intRequested = 0x0040,
+ updateStats = 0x0080,
+ transferInt = 0x0100, /* Bus Master Transfer Complete */
+ dnComplete = 0x0200,
+ upComplete = 0x0400,
+ busMasterInProgress = 0x0800,
+ commandInProgress = 0x1000,
+
+ interruptMask = 0x07FE,
+};
+
+#define COMMAND(port, cmd, a) outs((port)+CommandR, ((cmd)<<11)|(a))
+#define STATUS(port) ins((port)+IntStatusR)
+
+enum { /* Window 0 - setup */
+ Wsetup = 0x0000,
+ /* registers */
+ ManufacturerID = 0x0000, /* 3C5[08]*, 3C59[27] */
+ ProductID = 0x0002, /* 3C5[08]*, 3C59[27] */
+ ConfigControl = 0x0004, /* 3C5[08]*, 3C59[27] */
+ AddressConfig = 0x0006, /* 3C5[08]*, 3C59[27] */
+ ResourceConfig = 0x0008, /* 3C5[08]*, 3C59[27] */
+ EepromCommand = 0x000A,
+ EepromData = 0x000C,
+ /* AddressConfig Bits */
+ autoSelect9 = 0x0080,
+ xcvrMask9 = 0xC000,
+ /* ConfigControl bits */
+ Ena = 0x0001,
+ base10TAvailable9 = 0x0200,
+ coaxAvailable9 = 0x1000,
+ auiAvailable9 = 0x2000,
+ /* EepromCommand bits */
+ EepromReadRegister = 0x0080,
+ EepromBusy = 0x8000,
+};
+
+#define EEPROMCMD(port, cmd, a) outs((port)+EepromCommand, (cmd)|(a))
+#define EEPROMBUSY(port) (ins((port)+EepromCommand) & EepromBusy)
+#define EEPROMDATA(port) ins((port)+EepromData)
+
+enum { /* Window 1 - operating set */
+ Wop = 0x0001,
+ /* registers */
+ Fifo = 0x0000,
+ RxError = 0x0004, /* 3C59[0257] only */
+ RxStatus = 0x0008,
+ Timer = 0x000A,
+ TxStatus = 0x000B,
+ TxFree = 0x000C,
+ /* RxError bits */
+ rxOverrun = 0x0001,
+ runtFrame = 0x0002,
+ alignmentError = 0x0004, /* Framing */
+ crcError = 0x0008,
+ oversizedFrame = 0x0010,
+ dribbleBits = 0x0080,
+ /* RxStatus bits */
+ rxBytes = 0x1FFF, /* 3C59[0257] mask */
+ rxBytes9 = 0x07FF, /* 3C5[078]9 mask */
+ rxError9 = 0x3800, /* 3C5[078]9 error mask */
+ rxOverrun9 = 0x0000,
+ oversizedFrame9 = 0x0800,
+ dribbleBits9 = 0x1000,
+ runtFrame9 = 0x1800,
+ alignmentError9 = 0x2000, /* Framing */
+ crcError9 = 0x2800,
+ rxError = 0x4000,
+ rxIncomplete = 0x8000,
+ /* TxStatus Bits */
+ txStatusOverflow = 0x0004,
+ maxCollisions = 0x0008,
+ txUnderrun = 0x0010,
+ txJabber = 0x0020,
+ interruptRequested = 0x0040,
+ txStatusComplete = 0x0080,
+};
+
+enum { /* Window 2 - station address */
+ Wstation = 0x0002,
+
+ ResetOp905B = 0x000C,
+};
+
+enum { /* Window 3 - FIFO management */
+ Wfifo = 0x0003,
+ /* registers */
+ InternalConfig = 0x0000, /* 3C509B, 3C589, 3C59[0257] */
+ OtherInt = 0x0004, /* 3C59[0257] */
+ RomControl = 0x0006, /* 3C509B, 3C59[27] */
+ MacControl = 0x0006, /* 3C59[0257] */
+ ResetOptions = 0x0008, /* 3C59[0257] */
+ MediaOptions = 0x0008, /* 3C905B */
+ RxFree = 0x000A,
+ /* InternalConfig bits */
+ disableBadSsdDetect = 0x00000100,
+ ramLocation = 0x00000200, /* 0 external, 1 internal */
+ ramPartition5to3 = 0x00000000,
+ ramPartition3to1 = 0x00010000,
+ ramPartition1to1 = 0x00020000,
+ ramPartition3to5 = 0x00030000,
+ ramPartitionMask = 0x00030000,
+ xcvr10BaseT = 0x00000000,
+ xcvrAui = 0x00100000, /* 10BASE5 */
+ xcvr10Base2 = 0x00300000,
+ xcvr100BaseTX = 0x00400000,
+ xcvr100BaseFX = 0x00500000,
+ xcvrMii = 0x00600000,
+ xcvrMask = 0x00700000,
+ autoSelect = 0x01000000,
+ /* MacControl bits */
+ deferExtendEnable = 0x0001,
+ deferTimerSelect = 0x001E, /* mask */
+ fullDuplexEnable = 0x0020,
+ allowLargePackets = 0x0040,
+ extendAfterCollision = 0x0080, /* 3C90xB */
+ flowControlEnable = 0x0100, /* 3C90xB */
+ vltEnable = 0x0200, /* 3C90xB */
+ /* ResetOptions bits */
+ baseT4Available = 0x0001,
+ baseTXAvailable = 0x0002,
+ baseFXAvailable = 0x0004,
+ base10TAvailable = 0x0008,
+ coaxAvailable = 0x0010,
+ auiAvailable = 0x0020,
+ miiConnector = 0x0040,
+};
+
+enum { /* Window 4 - diagnostic */
+ Wdiagnostic = 0x0004,
+ /* registers */
+ VcoDiagnostic = 0x0002,
+ FifoDiagnostic = 0x0004,
+ NetworkDiagnostic = 0x0006,
+ PhysicalMgmt = 0x0008,
+ MediaStatus = 0x000A,
+ BadSSD = 0x000C,
+ UpperBytesOk = 0x000D,
+ /* FifoDiagnostic bits */
+ txOverrun = 0x0400,
+ rxUnderrun = 0x2000,
+ receiving = 0x8000,
+ /* PhysicalMgmt bits */
+ mgmtClk = 0x0001,
+ mgmtData = 0x0002,
+ mgmtDir = 0x0004,
+ cat5LinkTestDefeat = 0x8000,
+ /* MediaStatus bits */
+ dataRate100 = 0x0002,
+ crcStripDisable = 0x0004,
+ enableSqeStats = 0x0008,
+ collisionDetect = 0x0010,
+ carrierSense = 0x0020,
+ jabberGuardEnable = 0x0040,
+ linkBeatEnable = 0x0080,
+ jabberDetect = 0x0200,
+ polarityReversed = 0x0400,
+ linkBeatDetect = 0x0800,
+ txInProg = 0x1000,
+ dcConverterEnabled = 0x4000,
+ auiDisable = 0x8000, /* 10BaseT transceiver selected */
+};
+
+enum { /* Window 5 - internal state */
+ Wstate = 0x0005,
+ /* registers */
+ TxStartThresh = 0x0000,
+ TxAvailableThresh = 0x0002,
+ RxEarlyThresh = 0x0006,
+ RxFilter = 0x0008,
+ InterruptEnable = 0x000A,
+ IndicationEnable = 0x000C,
+};
+
+enum { /* Window 6 - statistics */
+ Wstatistics = 0x0006,
+ /* registers */
+ CarrierLost = 0x0000,
+ SqeErrors = 0x0001,
+ MultipleColls = 0x0002,
+ SingleCollFrames = 0x0003,
+ LateCollisions = 0x0004,
+ RxOverruns = 0x0005,
+ FramesXmittedOk = 0x0006,
+ FramesRcvdOk = 0x0007,
+ FramesDeferred = 0x0008,
+ UpperFramesOk = 0x0009,
+ BytesRcvdOk = 0x000A,
+ BytesXmittedOk = 0x000C,
+};
+
+enum { /* Window 7 - bus master operations */
+ Wmaster = 0x0007,
+ /* registers */
+ MasterAddress = 0x0000,
+ MasterLen = 0x0006,
+ MasterStatus = 0x000C,
+ /* MasterStatus bits */
+ masterAbort = 0x0001,
+ targetAbort = 0x0002,
+ targetRetry = 0x0004,
+ targetDisc = 0x0008,
+ masterDownload = 0x1000,
+ masterUpload = 0x4000,
+ masterInProgress = 0x8000,
+
+ masterMask = 0xD00F,
+};
+
+enum { /* 3C90x extended register set */
+ PktStatus = 0x0020, /* 32-bits */
+ DnListPtr = 0x0024, /* 32-bits, 8-byte aligned */
+ FragAddr = 0x0028, /* 32-bits */
+ FragLen = 0x002C, /* 16-bits */
+ ListOffset = 0x002E, /* 8-bits */
+ TxFreeThresh = 0x002F, /* 8-bits */
+ UpPktStatus = 0x0030, /* 32-bits */
+ FreeTimer = 0x0034, /* 16-bits */
+ UpListPtr = 0x0038, /* 32-bits, 8-byte aligned */
+
+ /* PktStatus bits */
+ fragLast = 0x00000001,
+ dnCmplReq = 0x00000002,
+ dnStalled = 0x00000004,
+ upCompleteX = 0x00000008,
+ dnCompleteX = 0x00000010,
+ upRxEarlyEnable = 0x00000020,
+ armCountdown = 0x00000040,
+ dnInProg = 0x00000080,
+ counterSpeed = 0x00000010, /* 0 3.2uS, 1 320nS */
+ countdownMode = 0x00000020,
+ /* UpPktStatus bits (dpd->control) */
+ upPktLenMask = 0x00001FFF,
+ upStalled = 0x00002000,
+ upError = 0x00004000,
+ upPktComplete = 0x00008000,
+ upOverrun = 0x00010000, /* RxError<<16 */
+ upRuntFrame = 0x00020000,
+ upAlignmentError = 0x00040000,
+ upCRCError = 0x00080000,
+ upOversizedFrame = 0x00100000,
+ upDribbleBits = 0x00800000,
+ upOverflow = 0x01000000,
+
+ dnIndicate = 0x80000000, /* FrameStartHeader (dpd->control) */
+
+ updnLastFrag = 0x80000000, /* (dpd->len) */
+
+ Nup = 32,
+ Ndn = 64,
+};
+
+/*
+ * Up/Dn Packet Descriptors.
+ * The hardware info (np, control, addr, len) must be 8-byte aligned
+ * and this structure size must be a multiple of 8.
+ */
+typedef struct Pd Pd;
+typedef struct Pd {
+ ulong np; /* next pointer */
+ ulong control; /* FSH or UpPktStatus */
+ ulong addr;
+ ulong len;
+
+ Pd* next;
+ Block* bp;
+} Pd;
+
+typedef struct {
+ Lock wlock; /* window access */
+
+ int attached;
+ int busmaster;
+ Block* rbp; /* receive buffer */
+
+ Block* txbp; /* FIFO -based transmission */
+ int txthreshold;
+ int txbusy;
+
+ int nup; /* full-busmaster -based reception */
+ void* upbase;
+ Pd* upr;
+ Pd* uphead;
+
+ int ndn; /* full-busmaster -based transmission */
+ void* dnbase;
+ Pd* dnr;
+ Pd* dnhead;
+ Pd* dntail;
+ int dnq;
+
+ long interrupts; /* statistics */
+ long timer;
+ long stats[BytesRcvdOk+3];
+
+ int upqmax;
+ int upqmaxhw;
+ ulong upinterrupts;
+ ulong upqueued;
+ ulong upstalls;
+ int dnqmax;
+ int dnqmaxhw;
+ ulong dninterrupts;
+ ulong dnqueued;
+
+ int xcvr; /* transceiver type */
+ int rxstatus9; /* old-style RxStatus register */
+ int rxearly; /* RxEarlyThreshold */
+ int ts; /* threshold shift */
+ int upenabled;
+ int dnenabled;
+} Ctlr;
+
+static void
+init905(Ctlr* ctlr)
+{
+ Block *bp;
+ Pd *pd, *prev;
+
+ /*
+ * Create rings for the receive and transmit sides.
+ * Take care with alignment:
+ * make sure ring base is 8-byte aligned;
+ * make sure each entry is 8-byte aligned.
+ */
+ ctlr->upbase = malloc((ctlr->nup+1)*sizeof(Pd));
+ ctlr->upr = (Pd*)ROUNDUP((ulong)ctlr->upbase, 8);
+
+ prev = ctlr->upr;
+ for(pd = &ctlr->upr[ctlr->nup-1]; pd >= ctlr->upr; pd--){
+ pd->np = PADDR(&prev->np);
+ pd->control = 0;
+ bp = allocb(sizeof(Etherpkt));
+ pd->addr = PADDR(bp->rp);
+ pd->len = updnLastFrag|sizeof(Etherpkt);
+
+ pd->next = prev;
+ prev = pd;
+ pd->bp = bp;
+ }
+ ctlr->uphead = ctlr->upr;
+
+ ctlr->dnbase = malloc((ctlr->ndn+1)*sizeof(Pd));
+ ctlr->dnr = (Pd*)ROUNDUP((ulong)ctlr->dnbase, 8);
+
+ prev = ctlr->dnr;
+ for(pd = &ctlr->dnr[ctlr->ndn-1]; pd >= ctlr->dnr; pd--){
+ pd->next = prev;
+ prev = pd;
+ }
+ ctlr->dnhead = ctlr->dnr;
+ ctlr->dntail = ctlr->dnr;
+ ctlr->dnq = 0;
+}
+
+static Block*
+rbpalloc(Block* (*f)(int))
+{
+ Block *bp;
+ ulong addr;
+
+ /*
+ * The receive buffers must be on a 32-byte
+ * boundary for EISA busmastering.
+ */
+ if(bp = f(ROUNDUP(sizeof(Etherpkt), 4) + 31)){
+ addr = (ulong)bp->base;
+ addr = ROUNDUP(addr, 32);
+ bp->rp = (uchar*)addr;
+ }
+
+ return bp;
+}
+
+static uchar*
+startdma(Ether* ether, ulong address)
+{
+ int port, status, w;
+ uchar *wp;
+
+ port = ether->port;
+
+ w = (STATUS(port)>>13) & 0x07;
+ COMMAND(port, SelectRegisterWindow, Wmaster);
+
+ wp = KADDR(inl(port+MasterAddress));
+ status = ins(port+MasterStatus);
+ if(status & (masterInProgress|targetAbort|masterAbort))
+ print("#l%d: BM status 0x%uX\n", ether->ctlrno, status);
+ outs(port+MasterStatus, masterMask);
+ outl(port+MasterAddress, address);
+ outs(port+MasterLen, sizeof(Etherpkt));
+ COMMAND(port, StartDma, Upload);
+
+ COMMAND(port, SelectRegisterWindow, w);
+ return wp;
+}
+
+static void
+promiscuous(void* arg, int on)
+{
+ int filter, port;
+ Ether *ether;
+
+ ether = (Ether*)arg;
+ port = ether->port;
+
+ filter = receiveBroadcast|receiveIndividual;
+ if(ether->nmaddr)
+ filter |= receiveMulticast;
+ if(on)
+ filter |= receiveAllFrames;
+ COMMAND(port, SetRxFilter, filter);
+}
+
+static void
+multicast(void* arg, uchar *addr, int on)
+{
+ int filter, port;
+ Ether *ether;
+
+ USED(addr, on);
+
+ ether = (Ether*)arg;
+ port = ether->port;
+
+ filter = receiveBroadcast|receiveIndividual;
+ if(ether->nmaddr)
+ filter |= receiveMulticast;
+ if(ether->prom)
+ filter |= receiveAllFrames;
+ COMMAND(port, SetRxFilter, filter);
+}
+
+static void
+attach(Ether* ether)
+{
+ int port, x;
+ Ctlr *ctlr;
+
+ ctlr = ether->ctlr;
+ ilock(&ctlr->wlock);
+ if(ctlr->attached){
+ iunlock(&ctlr->wlock);
+ return;
+ }
+
+ port = ether->port;
+
+ /*
+ * Set the receiver packet filter for this and broadcast addresses,
+ * set the interrupt masks for all interrupts, enable the receiver
+ * and transmitter.
+ */
+ promiscuous(ether, ether->prom);
+
+ x = interruptMask;
+ if(ctlr->busmaster == 1)
+ x &= ~(rxEarly|rxComplete);
+ else{
+ if(ctlr->dnenabled)
+ x &= ~transferInt;
+ if(ctlr->upenabled)
+ x &= ~(rxEarly|rxComplete);
+ }
+ COMMAND(port, SetIndicationEnable, x);
+ COMMAND(port, SetInterruptEnable, x);
+
+ COMMAND(port, RxEnable, 0);
+ COMMAND(port, TxEnable, 0);
+
+ /*
+ * Prime the busmaster channel for receiving directly into a
+ * receive packet buffer if necessary.
+ */
+ if(ctlr->busmaster == 1)
+ startdma(ether, PADDR(ctlr->rbp->rp));
+ else{
+ if(ctlr->upenabled)
+ outl(port+UpListPtr, PADDR(&ctlr->uphead->np));
+ }
+
+ ctlr->attached = 1;
+ iunlock(&ctlr->wlock);
+}
+
+static void
+statistics(Ether* ether)
+{
+ int port, i, u, w;
+ Ctlr *ctlr;
+
+ port = ether->port;
+ ctlr = ether->ctlr;
+
+ /*
+ * 3C59[27] require a read between a PIO write and
+ * reading a statistics register.
+ */
+ w = (STATUS(port)>>13) & 0x07;
+ COMMAND(port, SelectRegisterWindow, Wstatistics);
+ STATUS(port);
+
+ for(i = 0; i < UpperFramesOk; i++)
+ ctlr->stats[i] += inb(port+i) & 0xFF;
+ u = inb(port+UpperFramesOk) & 0xFF;
+ ctlr->stats[FramesXmittedOk] += (u & 0x30)<<4;
+ ctlr->stats[FramesRcvdOk] += (u & 0x03)<<8;
+ ctlr->stats[BytesRcvdOk] += ins(port+BytesRcvdOk) & 0xFFFF;
+ ctlr->stats[BytesRcvdOk+1] += ins(port+BytesXmittedOk) & 0xFFFF;
+
+ switch(ctlr->xcvr){
+
+ case xcvrMii:
+ case xcvr100BaseTX:
+ case xcvr100BaseFX:
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ STATUS(port);
+ ctlr->stats[BytesRcvdOk+2] += inb(port+BadSSD);
+ break;
+ }
+
+ COMMAND(port, SelectRegisterWindow, w);
+}
+
+static void
+txstart(Ether* ether)
+{
+ int port, len;
+ Ctlr *ctlr;
+ Block *bp;
+
+ port = ether->port;
+ ctlr = ether->ctlr;
+
+ /*
+ * Attempt to top-up the transmit FIFO. If there's room simply
+ * stuff in the packet length (unpadded to a dword boundary), the
+ * packet data (padded) and remove the packet from the queue.
+ * If there's no room post an interrupt for when there is.
+ * This routine is called both from the top level and from interrupt
+ * level and expects to be called with ctlr->wlock already locked
+ * and the correct register window (Wop) in place.
+ */
+ for(;;){
+ if(ctlr->txbp){
+ bp = ctlr->txbp;
+ ctlr->txbp = 0;
+ }
+ else{
+ bp = qget(ether->oq);
+ if(bp == nil)
+ break;
+ }
+
+ len = ROUNDUP(BLEN(bp), 4);
+ if(len+4 <= ins(port+TxFree)){
+ outl(port+Fifo, BLEN(bp));
+ outsl(port+Fifo, bp->rp, len/4);
+
+ freeb(bp);
+
+ ether->outpackets++;
+ }
+ else{
+ ctlr->txbp = bp;
+ if(ctlr->txbusy == 0){
+ ctlr->txbusy = 1;
+ COMMAND(port, SetTxAvailableThresh, len>>ctlr->ts);
+ }
+ break;
+ }
+ }
+}
+
+static void
+txstart905(Ether* ether)
+{
+ Ctlr *ctlr;
+ int port, stalled, timeo;
+ Block *bp;
+ Pd *pd;
+
+ ctlr = ether->ctlr;
+ port = ether->port;
+ /*
+ * Free any completed packets.
+ */
+ pd = ctlr->dntail;
+ while(ctlr->dnq){
+ if(PADDR(&pd->np) == inl(port+DnListPtr))
+ break;
+ if(pd->bp){
+ freeb(pd->bp);
+ pd->bp = nil;
+ }
+ ctlr->dnq--;
+ pd = pd->next;
+ }
+ ctlr->dntail = pd;
+
+ stalled = 0;
+ while(ctlr->dnq < (ctlr->ndn-1)){
+ bp = qget(ether->oq);
+ if(bp == nil)
+ break;
+
+ pd = ctlr->dnhead->next;
+ pd->np = 0;
+ pd->control = dnIndicate|BLEN(bp);
+ pd->addr = PADDR(bp->rp);
+ pd->len = updnLastFrag|BLEN(bp);
+ pd->bp = bp;
+
+ if(stalled == 0 && ctlr->dnq && inl(port+DnListPtr)){
+ COMMAND(port, Stall, dnStall);
+ for(timeo = 100; (STATUS(port) & commandInProgress) && timeo; timeo--)
+ ;
+ if(timeo == 0)
+ print("#l%d: dnstall %d\n", ether->ctlrno, timeo);
+ stalled = 1;
+ }
+
+ coherence();
+ ctlr->dnhead->np = PADDR(&pd->np);
+ ctlr->dnhead->control &= ~dnIndicate;
+ ctlr->dnhead = pd;
+ if(ctlr->dnq == 0)
+ ctlr->dntail = pd;
+ ctlr->dnq++;
+
+ ctlr->dnqueued++;
+ }
+
+ if(ctlr->dnq > ctlr->dnqmax)
+ ctlr->dnqmax = ctlr->dnq;
+
+ /*
+ * If the adapter is not currently processing anything
+ * and there is something on the queue, start it processing.
+ */
+ if(inl(port+DnListPtr) == 0 && ctlr->dnq)
+ outl(port+DnListPtr, PADDR(&ctlr->dnhead->np));
+ if(stalled)
+ COMMAND(port, Stall, dnUnStall);
+}
+
+static void
+transmit(Ether* ether)
+{
+ Ctlr *ctlr;
+ int port, w;
+
+ port = ether->port;
+ ctlr = ether->ctlr;
+
+ ilock(&ctlr->wlock);
+ if(ctlr->dnenabled)
+ txstart905(ether);
+ else{
+ w = (STATUS(port)>>13) & 0x07;
+ COMMAND(port, SelectRegisterWindow, Wop);
+ txstart(ether);
+ COMMAND(port, SelectRegisterWindow, w);
+ }
+ iunlock(&ctlr->wlock);
+}
+
+static void
+receive905(Ether* ether)
+{
+ Ctlr *ctlr;
+ int len, port, q;
+ Pd *pd;
+ Block *bp;
+
+ ctlr = ether->ctlr;
+ port = ether->port;
+
+ if(inl(port+UpPktStatus) & upStalled)
+ ctlr->upstalls++;
+ q = 0;
+ for(pd = ctlr->uphead; pd->control & upPktComplete; pd = pd->next){
+ if(pd->control & upError){
+ if(pd->control & upOverrun)
+ ether->overflows++;
+ if(pd->control & (upOversizedFrame|upRuntFrame))
+ ether->buffs++;
+ if(pd->control & upAlignmentError)
+ ether->frames++;
+ if(pd->control & upCRCError)
+ ether->crcs++;
+ }
+ else if(bp = iallocb(sizeof(Etherpkt)+4)){
+ len = pd->control & rxBytes;
+ pd->bp->wp = pd->bp->rp+len;
+ etheriq(ether, pd->bp, 1);
+ pd->bp = bp;
+ pd->addr = PADDR(bp->rp);
+ coherence();
+ }
+
+ pd->control = 0;
+ COMMAND(port, Stall, upUnStall);
+
+ q++;
+ }
+ ctlr->uphead = pd;
+
+ ctlr->upqueued += q;
+ if(q > ctlr->upqmax)
+ ctlr->upqmax = q;
+}
+
+static void
+receive(Ether* ether)
+{
+ int len, port, rxerror, rxstatus;
+ Ctlr *ctlr;
+ Block *bp;
+
+ port = ether->port;
+ ctlr = ether->ctlr;
+
+ while(((rxstatus = ins(port+RxStatus)) & rxIncomplete) == 0){
+ if(ctlr->busmaster == 1 && (STATUS(port) & busMasterInProgress))
+ break;
+
+ /*
+ * If there was an error, log it and continue.
+ * Unfortunately the 3C5[078]9 has the error info in the status register
+ * and the 3C59[0257] implement a separate RxError register.
+ */
+ if(rxstatus & rxError){
+ if(ctlr->rxstatus9){
+ switch(rxstatus & rxError9){
+
+ case rxOverrun9:
+ ether->overflows++;
+ break;
+
+ case oversizedFrame9:
+ case runtFrame9:
+ ether->buffs++;
+ break;
+
+ case alignmentError9:
+ ether->frames++;
+ break;
+
+ case crcError9:
+ ether->crcs++;
+ break;
+
+ }
+ }
+ else{
+ rxerror = inb(port+RxError);
+ if(rxerror & rxOverrun)
+ ether->overflows++;
+ if(rxerror & (oversizedFrame|runtFrame))
+ ether->buffs++;
+ if(rxerror & alignmentError)
+ ether->frames++;
+ if(rxerror & crcError)
+ ether->crcs++;
+ }
+ }
+
+ /*
+ * If there was an error or a new receive buffer can't be
+ * allocated, discard the packet and go on to the next.
+ */
+ if((rxstatus & rxError) || (bp = rbpalloc(iallocb)) == 0){
+ COMMAND(port, RxDiscard, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+
+ if(ctlr->busmaster == 1)
+ startdma(ether, PADDR(ctlr->rbp->rp));
+
+ continue;
+ }
+
+ /*
+ * A valid receive packet awaits:
+ * if using PIO, read it into the buffer;
+ * discard the packet from the FIFO;
+ * if using busmastering, start a new transfer for
+ * the next packet and as a side-effect get the
+ * end-pointer of the one just received;
+ * pass the packet on to whoever wants it.
+ */
+ if(ctlr->busmaster == 0 || ctlr->busmaster == 2){
+ len = (rxstatus & rxBytes9);
+ ctlr->rbp->wp = ctlr->rbp->rp + len;
+ insl(port+Fifo, ctlr->rbp->rp, HOWMANY(len, 4));
+ }
+
+ COMMAND(port, RxDiscard, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+
+ if(ctlr->busmaster == 1)
+ ctlr->rbp->wp = startdma(ether, PADDR(bp->rp));
+
+ etheriq(ether, ctlr->rbp, 1);
+ ctlr->rbp = bp;
+ }
+}
+
+static void
+interrupt(Ureg*, void* arg)
+{
+ Ether *ether;
+ int port, status, s, w, x;
+ Ctlr *ctlr;
+
+ ether = arg;
+ port = ether->port;
+ ctlr = ether->ctlr;
+
+ ilock(&ctlr->wlock);
+ w = (STATUS(port)>>13) & 0x07;
+ COMMAND(port, SelectRegisterWindow, Wop);
+
+ ctlr->interrupts++;
+ ctlr->timer += inb(port+Timer) & 0xFF;
+ while((status = STATUS(port)) & (interruptMask|interruptLatch)){
+ if(status & hostError){
+ /*
+ * Adapter failure, try to find out why, reset if
+ * necessary. What happens if Tx is active and a reset
+ * occurs, need to retransmit? This probably isn't right.
+ */
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ x = ins(port+FifoDiagnostic);
+ COMMAND(port, SelectRegisterWindow, Wop);
+ print("#l%d: status 0x%uX, diag 0x%uX\n",
+ ether->ctlrno, status, x);
+
+ if(x & txOverrun){
+ if(ctlr->busmaster == 0)
+ COMMAND(port, TxReset, 0);
+ else
+ COMMAND(port, TxReset, (updnReset|dmaReset));
+ COMMAND(port, TxEnable, 0);
+ }
+
+ if(x & rxUnderrun){
+ /*
+ * This shouldn't happen...
+ * Reset the receiver and restore the filter and RxEarly
+ * threshold before re-enabling.
+ * Need to restart any busmastering?
+ */
+ COMMAND(port, SelectRegisterWindow, Wstate);
+ s = (port+RxFilter) & 0x000F;
+ COMMAND(port, SelectRegisterWindow, Wop);
+ COMMAND(port, RxReset, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+ COMMAND(port, SetRxFilter, s);
+ COMMAND(port, SetRxEarlyThresh, ctlr->rxearly>>ctlr->ts);
+ COMMAND(port, RxEnable, 0);
+ }
+
+ status &= ~hostError;
+ }
+
+ if(status & (transferInt|rxComplete)){
+ receive(ether);
+ status &= ~(transferInt|rxComplete);
+ }
+
+ if(status & (upComplete)){
+ COMMAND(port, AcknowledgeInterrupt, upComplete);
+ receive905(ether);
+ status &= ~upComplete;
+ ctlr->upinterrupts++;
+ }
+
+ if(status & txComplete){
+ /*
+ * Pop the TxStatus stack, accumulating errors.
+ * Adjust the TX start threshold if there was an underrun.
+ * If there was a Jabber or Underrun error, reset
+ * the transmitter, taking care not to reset the dma logic
+ * as a busmaster receive may be in progress.
+ * For all conditions enable the transmitter.
+ */
+ s = 0;
+ do{
+ if(x = inb(port+TxStatus))
+ outb(port+TxStatus, 0);
+ s |= x;
+ }while(STATUS(port) & txComplete);
+
+ if(s & txUnderrun){
+ if(ctlr->dnenabled){
+ while(inl(port+PktStatus) & dnInProg)
+ ;
+ }
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ while(ins(port+MediaStatus) & txInProg)
+ ;
+ COMMAND(port, SelectRegisterWindow, Wop);
+ if(ctlr->txthreshold < ETHERMAXTU)
+ ctlr->txthreshold += ETHERMINTU;
+ }
+
+ /*
+ * According to the manual, maxCollisions does not require
+ * a TxReset, merely a TxEnable. However, evidence points to
+ * it being necessary on the 3C905. The jury is still out.
+ * On busy or badly configured networks maxCollisions can
+ * happen frequently enough for messages to be annoying so
+ * keep quiet about them by popular request.
+ */
+ if(s & (txJabber|txUnderrun|maxCollisions)){
+ if(ctlr->busmaster == 0)
+ COMMAND(port, TxReset, 0);
+ else
+ COMMAND(port, TxReset, (updnReset|dmaReset));
+ while(STATUS(port) & commandInProgress)
+ ;
+ COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts);
+ if(ctlr->busmaster == 2)
+ outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));
+ if(ctlr->dnenabled)
+ status |= dnComplete;
+ }
+
+ if(s & ~(txStatusComplete|maxCollisions))
+ print("#l%d: txstatus 0x%uX, threshold %d\n",
+ ether->ctlrno, s, ctlr->txthreshold);
+ COMMAND(port, TxEnable, 0);
+ ether->oerrs++;
+ status &= ~txComplete;
+ status |= txAvailable;
+ }
+
+ if(status & txAvailable){
+ COMMAND(port, AcknowledgeInterrupt, txAvailable);
+ ctlr->txbusy = 0;
+ txstart(ether);
+ status &= ~txAvailable;
+ }
+
+ if(status & dnComplete){
+ COMMAND(port, AcknowledgeInterrupt, dnComplete);
+ txstart905(ether);
+ status &= ~dnComplete;
+ ctlr->dninterrupts++;
+ }
+
+ if(status & updateStats){
+ statistics(ether);
+ status &= ~updateStats;
+ }
+
+ /*
+ * Currently, this shouldn't happen.
+ */
+ if(status & rxEarly){
+ COMMAND(port, AcknowledgeInterrupt, rxEarly);
+ status &= ~rxEarly;
+ }
+
+ /*
+ * Panic if there are any interrupts not dealt with.
+ */
+ if(status & interruptMask)
+ panic("#l%d: interrupt mask 0x%uX\n", ether->ctlrno, status);
+
+ COMMAND(port, AcknowledgeInterrupt, interruptLatch);
+ }
+
+ COMMAND(port, SelectRegisterWindow, w);
+ iunlock(&ctlr->wlock);
+}
+
+static long
+ifstat(Ether* ether, void* a, long n, ulong offset)
+{
+ char *p;
+ int len;
+ Ctlr *ctlr;
+
+ if(n == 0)
+ return 0;
+
+ ctlr = ether->ctlr;
+
+ ilock(&ctlr->wlock);
+ statistics(ether);
+ iunlock(&ctlr->wlock);
+
+ p = malloc(READSTR);
+ len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts);
+ len += snprint(p+len, READSTR-len, "timer: %lud\n", ctlr->timer);
+ len += snprint(p+len, READSTR-len, "carrierlost: %lud\n", ctlr->stats[CarrierLost]);
+ len += snprint(p+len, READSTR-len, "sqeerrors: %lud\n", ctlr->stats[SqeErrors]);
+ len += snprint(p+len, READSTR-len, "multiplecolls: %lud\n", ctlr->stats[MultipleColls]);
+ len += snprint(p+len, READSTR-len, "singlecollframes: %lud\n", ctlr->stats[SingleCollFrames]);
+ len += snprint(p+len, READSTR-len, "latecollisions: %lud\n", ctlr->stats[LateCollisions]);
+ len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n", ctlr->stats[RxOverruns]);
+ len += snprint(p+len, READSTR-len, "framesxmittedok: %lud\n", ctlr->stats[FramesXmittedOk]);
+ len += snprint(p+len, READSTR-len, "framesrcvdok: %lud\n", ctlr->stats[FramesRcvdOk]);
+ len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->stats[FramesDeferred]);
+ len += snprint(p+len, READSTR-len, "bytesrcvdok: %lud\n", ctlr->stats[BytesRcvdOk]);
+ len += snprint(p+len, READSTR-len, "bytesxmittedok: %lud\n", ctlr->stats[BytesRcvdOk+1]);
+
+ if(ctlr->upenabled){
+ if(ctlr->upqmax > ctlr->upqmaxhw)
+ ctlr->upqmaxhw = ctlr->upqmax;
+ len += snprint(p+len, READSTR-len, "up: q %lud i %lud m %d h %d s %lud\n",
+ ctlr->upqueued, ctlr->upinterrupts,
+ ctlr->upqmax, ctlr->upqmaxhw, ctlr->upstalls);
+ ctlr->upqmax = 0;
+ }
+ if(ctlr->dnenabled){
+ if(ctlr->dnqmax > ctlr->dnqmaxhw)
+ ctlr->dnqmaxhw = ctlr->dnqmax;
+ len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d h %d\n",
+ ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax, ctlr->dnqmaxhw);
+ ctlr->dnqmax = 0;
+ }
+
+ snprint(p+len, READSTR-len, "badssd: %lud\n", ctlr->stats[BytesRcvdOk+2]);
+
+ n = readstr(offset, a, n, p);
+ free(p);
+
+ return n;
+}
+
+static void
+txrxreset(int port)
+{
+ COMMAND(port, TxReset, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+ COMMAND(port, RxReset, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+}
+
+typedef struct Adapter {
+ int port;
+ int irq;
+ int tbdf;
+} Adapter;
+static Block* adapter;
+
+static void
+tcmadapter(int port, int irq, int tbdf)
+{
+ Block *bp;
+ Adapter *ap;
+
+ bp = allocb(sizeof(Adapter));
+ ap = (Adapter*)bp->rp;
+ ap->port = port;
+ ap->irq = irq;
+ ap->tbdf = tbdf;
+
+ bp->next = adapter;
+ adapter = bp;
+}
+
+/*
+ * Write two 0 bytes to identify the IDport and then reset the
+ * ID sequence. Then send the ID sequence to the card to get
+ * the card into command state.
+ */
+static void
+idseq(void)
+{
+ int i;
+ uchar al;
+ static int reset, untag;
+
+ /*
+ * One time only:
+ * reset any adapters listening
+ */
+ if(reset == 0){
+ outb(IDport, 0);
+ outb(IDport, 0);
+ outb(IDport, 0xC0);
+ delay(20);
+ reset = 1;
+ }
+
+ outb(IDport, 0);
+ outb(IDport, 0);
+ for(al = 0xFF, i = 0; i < 255; i++){
+ outb(IDport, al);
+ if(al & 0x80){
+ al <<= 1;
+ al ^= 0xCF;
+ }
+ else
+ al <<= 1;
+ }
+
+ /*
+ * One time only:
+ * write ID sequence to get the attention of all adapters;
+ * untag all adapters.
+ * If a global reset is done here on all adapters it will confuse
+ * any ISA cards configured for EISA mode.
+ */
+ if(untag == 0){
+ outb(IDport, 0xD0);
+ untag = 1;
+ }
+}
+
+static ulong
+activate(void)
+{
+ int i;
+ ushort x, acr;
+
+ /*
+ * Do the little configuration dance:
+ *
+ * 2. write the ID sequence to get to command state.
+ */
+ idseq();
+
+ /*
+ * 3. Read the Manufacturer ID from the EEPROM.
+ * This is done by writing the IDPort with 0x87 (0x80
+ * is the 'read EEPROM' command, 0x07 is the offset of
+ * the Manufacturer ID field in the EEPROM).
+ * The data comes back 1 bit at a time.
+ * A delay seems necessary between reading the bits.
+ *
+ * If the ID doesn't match, there are no more adapters.
+ */
+ outb(IDport, 0x87);
+ delay(20);
+ for(x = 0, i = 0; i < 16; i++){
+ delay(20);
+ x <<= 1;
+ x |= inb(IDport) & 0x01;
+ }
+ if(x != 0x6D50)
+ return 0;
+
+ /*
+ * 3. Read the Address Configuration from the EEPROM.
+ * The Address Configuration field is at offset 0x08 in the EEPROM).
+ */
+ outb(IDport, 0x88);
+ for(acr = 0, i = 0; i < 16; i++){
+ delay(20);
+ acr <<= 1;
+ acr |= inb(IDport) & 0x01;
+ }
+
+ return (acr & 0x1F)*0x10 + 0x200;
+}
+
+static char* tcmpcmcia[] = {
+ "3C589", /* 3COM 589[ABCD] */
+ "3C562", /* 3COM 562 */
+ "589E", /* 3COM Megahertz 589E */
+ nil,
+};
+
+static int
+tcm5XXpcmcia(Ether* ether)
+{
+ int i;
+
+ for(i = 0; tcmpcmcia[i] != nil; i++){
+ if(!cistrcmp(ether->type, tcmpcmcia[i]))
+ return ether->port;
+ }
+
+ return 0;
+}
+
+static void
+setxcvr(int port, int xcvr, int is9)
+{
+ int x;
+
+ if(is9){
+ COMMAND(port, SelectRegisterWindow, Wsetup);
+ x = ins(port+AddressConfig) & ~xcvrMask9;
+ x |= (xcvr>>20)<<14;
+ outs(port+AddressConfig, x);
+ }
+ else{
+ COMMAND(port, SelectRegisterWindow, Wfifo);
+ x = inl(port+InternalConfig) & ~xcvrMask;
+ x |= xcvr;
+ outl(port+InternalConfig, x);
+ }
+
+ txrxreset(port);
+}
+
+static void
+setfullduplex(int port)
+{
+ int x;
+
+ COMMAND(port, SelectRegisterWindow, Wfifo);
+ x = ins(port+MacControl);
+ outs(port+MacControl, fullDuplexEnable|x);
+
+ txrxreset(port);
+}
+
+static int
+miimdi(int port, int n)
+{
+ int data, i;
+
+ /*
+ * Read n bits from the MII Management Register.
+ */
+ data = 0;
+ for(i = n-1; i >= 0; i--){
+ if(ins(port) & mgmtData)
+ data |= (1<<i);
+ microdelay(1);
+ outs(port, mgmtClk);
+ microdelay(1);
+ outs(port, 0);
+ microdelay(1);
+ }
+
+ return data;
+}
+
+static void
+miimdo(int port, int bits, int n)
+{
+ int i, mdo;
+
+ /*
+ * Write n bits to the MII Management Register.
+ */
+ for(i = n-1; i >= 0; i--){
+ if(bits & (1<<i))
+ mdo = mgmtDir|mgmtData;
+ else
+ mdo = mgmtDir;
+ outs(port, mdo);
+ microdelay(1);
+ outs(port, mdo|mgmtClk);
+ microdelay(1);
+ outs(port, mdo);
+ microdelay(1);
+ }
+}
+
+static int
+miir(int port, int phyad, int regad)
+{
+ int data, w;
+
+ w = (STATUS(port)>>13) & 0x07;
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ port += PhysicalMgmt;
+
+ /*
+ * Preamble;
+ * ST+OP+PHYAD+REGAD;
+ * TA + 16 data bits.
+ */
+ miimdo(port, 0xFFFFFFFF, 32);
+ miimdo(port, 0x1800|(phyad<<5)|regad, 14);
+ data = miimdi(port, 18);
+
+ port -= PhysicalMgmt;
+ COMMAND(port, SelectRegisterWindow, w);
+
+ if(data & 0x10000)
+ return -1;
+
+ return data & 0xFFFF;
+}
+
+static void
+scanphy(int port)
+{
+ int i, x;
+
+ for(i = 0; i < 32; i++){
+ if((x = miir(port, i, 2)) == -1 || x == 0)
+ continue;
+ x <<= 6;
+ x |= miir(port, i, 3)>>10;
+ XCVRDEBUG("phy%d: oui %uX reg1 %uX\n", i, x, miir(port, i, 1));
+ USED(x);
+ }
+}
+
+#ifdef notdef
+static struct xxx {
+ int available;
+ int next;
+} xxx[8] = {
+ { base10TAvailable, 1, }, /* xcvr10BaseT -> xcvrAui */
+ { auiAvailable, 3, }, /* xcvrAui -> xcvr10Base2 */
+ { 0, -1, },
+ { coaxAvailable, -1, }, /* xcvr10Base2 -> nowhere */
+ { baseTXAvailable, 5, }, /* xcvr100BaseTX-> xcvr100BaseFX */
+ { baseFXAvailable, -1, }, /* xcvr100BaseFX-> nowhere */
+ { miiConnector, -1, }, /* xcvrMii -> nowhere */
+ { 0, -1, },
+};
+#endif /* notdef */
+
+static int
+autoselect(int port, int xcvr, int is9)
+{
+ int media, x;
+
+ USED(xcvr);
+
+ /*
+ * Pathetic attempt at automatic media selection.
+ * Really just to get the Fast Etherlink 10BASE-T/100BASE-TX
+ * cards operational.
+ * It's a bonus if it works for anything else.
+ */
+ if(is9){
+ COMMAND(port, SelectRegisterWindow, Wsetup);
+ x = ins(port+ConfigControl);
+ media = 0;
+ if(x & base10TAvailable9)
+ media |= base10TAvailable;
+ if(x & coaxAvailable9)
+ media |= coaxAvailable;
+ if(x & auiAvailable9)
+ media |= auiAvailable;
+ }
+ else{
+ COMMAND(port, SelectRegisterWindow, Wfifo);
+ media = ins(port+ResetOptions);
+ }
+ XCVRDEBUG("autoselect: media %uX\n", media);
+
+ if(media & miiConnector)
+ return xcvrMii;
+
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ XCVRDEBUG("autoselect: media status %uX\n", ins(port+MediaStatus));
+
+ if(media & baseTXAvailable){
+ /*
+ * Must have InternalConfig register.
+ */
+ setxcvr(port, xcvr100BaseTX, is9);
+
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
+ outs(port+MediaStatus, linkBeatEnable|x);
+ delay(10);
+
+ if(ins(port+MediaStatus) & linkBeatDetect)
+ return xcvr100BaseTX;
+ outs(port+MediaStatus, x);
+ }
+
+ if(media & base10TAvailable){
+ setxcvr(port, xcvr10BaseT, is9);
+
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ x = ins(port+MediaStatus) & ~dcConverterEnabled;
+ outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x);
+ delay(100);
+
+ XCVRDEBUG("autoselect: 10BaseT media status %uX\n", ins(port+MediaStatus));
+ if(ins(port+MediaStatus) & linkBeatDetect)
+ return xcvr10BaseT;
+ outs(port+MediaStatus, x);
+ }
+
+ /*
+ * Botch.
+ */
+ return autoSelect;
+}
+
+static int
+eepromdata(int port, int offset)
+{
+ COMMAND(port, SelectRegisterWindow, Wsetup);
+ while(EEPROMBUSY(port))
+ ;
+ EEPROMCMD(port, EepromReadRegister, offset);
+ while(EEPROMBUSY(port))
+ ;
+ return EEPROMDATA(port);
+}
+
+int
+etherelnk3reset(Ether* ether)
+{
+ int anar, anlpar, busmaster, did, i, phyaddr, port, rxearly, rxstatus9, x, xcvr;
+ Block *bp, **bpp;
+ Adapter *ap;
+ uchar ea[Eaddrlen];
+ Ctlr *ctlr;
+
+ /*
+ * Any adapter matches if no ether->port is supplied,
+ * otherwise the ports must match.
+ */
+ port = 0;
+ bpp = &adapter;
+ for(bp = *bpp; bp; bp = bp->next){
+ ap = (Adapter*)bp->rp;
+ if(ether->port == 0 || ether->port == ap->port){
+ port = ap->port;
+ ether->irq = ap->irq;
+ ether->tbdf = ap->tbdf;
+ *bpp = bp->next;
+ freeb(bp);
+ break;
+ }
+ bpp = &bp->next;
+ }
+ if(port == 0 && (port = tcm5XXpcmcia(ether)) == 0)
+ return -1;
+
+ /*
+ * Read the DeviceID from the EEPROM, it's at offset 0x03,
+ * and do something depending on capabilities.
+ */
+ switch(did = eepromdata(port, 0x03)){
+
+ case 0x9000:
+ case 0x9001:
+ case 0x9005:
+ case 0x9050:
+ case 0x9051:
+ case 0x9055:
+ if(BUSTYPE(ether->tbdf) != BusPCI)
+ goto buggery;
+ busmaster = 2;
+ goto vortex;
+
+ case 0x5900:
+ case 0x5920:
+ case 0x5950:
+ case 0x5951:
+ case 0x5952:
+ case 0x5970:
+ case 0x5971:
+ case 0x5972:
+ busmaster = 1;
+ vortex:
+ COMMAND(port, SelectRegisterWindow, Wfifo);
+ xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask);
+ rxearly = 8188;
+ rxstatus9 = 0;
+ break;
+
+ buggery:
+ default:
+ busmaster = 0;
+ COMMAND(port, SelectRegisterWindow, Wsetup);
+ x = ins(port+AddressConfig);
+ xcvr = ((x & xcvrMask9)>>14)<<20;
+ if(x & autoSelect9)
+ xcvr |= autoSelect;
+ rxearly = 2044;
+ rxstatus9 = 1;
+ break;
+ }
+
+ /*
+ * Check if the adapter's station address is to be overridden.
+ * If not, read it from the EEPROM and set in ether->ea prior to loading the
+ * station address in Wstation. The EEPROM returns 16-bits at a time.
+ */
+ memset(ea, 0, Eaddrlen);
+ if(memcmp(ea, ether->ea, Eaddrlen) == 0){
+ for(i = 0; i < Eaddrlen/2; i++){
+ x = eepromdata(port, i);
+ ether->ea[2*i] = x>>8;
+ ether->ea[2*i+1] = x;
+ }
+ }
+
+ COMMAND(port, SelectRegisterWindow, Wstation);
+ for(i = 0; i < Eaddrlen; i++)
+ outb(port+i, ether->ea[i]);
+
+ /*
+ * Enable the transceiver if necessary and determine whether
+ * busmastering can be used. Due to bugs in the first revision
+ * of the 3C59[05], don't use busmastering at 10Mbps.
+ */
+ XCVRDEBUG("reset: xcvr %uX\n", xcvr);
+/*
+ * forgive me, but i am weak
+ */
+if(did == 0x9055){
+ xcvr = xcvrMii;
+ XCVRDEBUG("9055 reset ops 0x%uX\n",
+ ins(port+ResetOp905B));
+}
+else
+ if(xcvr & autoSelect)
+ xcvr = autoselect(port, xcvr, rxstatus9);
+ XCVRDEBUG("autoselect returns: xcvr %uX, did 0x%uX\n", xcvr, did);
+ switch(xcvr){
+
+ case xcvrMii:
+ /*
+ * Quick hack.
+ scanphy(port);
+ */
+ phyaddr = 24;
+for(i = 0; i < 7; i++)
+ XCVRDEBUG(" %2.2uX", miir(port, phyaddr, i));
+XCVRDEBUG("\n");
+
+{ int phystat, timeo;
+ for(timeo = 0; timeo < 30; timeo++){
+ phystat = miir(port, phyaddr, 0x01);
+ if(phystat & 0x20)
+ break;
+ XCVRDEBUG(" %2.2uX", phystat);
+ delay(100);
+ }
+ XCVRDEBUG(" %2.2uX", miir(port, phyaddr, 0x01));
+ XCVRDEBUG("\n");
+}
+
+ anar = miir(port, phyaddr, 0x04);
+ anlpar = miir(port, phyaddr, 0x05) & 0x03E0;
+ anar &= anlpar;
+ miir(port, phyaddr, 0x00);
+ XCVRDEBUG("mii an: %uX anlp: %uX r0:%uX r1:%uX\n",
+ anar, anlpar, miir(port, phyaddr, 0x00),
+ miir(port, phyaddr, 0x01));
+ for(i = 0; i < ether->nopt; i++){
+ if(cistrcmp(ether->opt[i], "fullduplex") == 0)
+ anar |= 0x0100;
+ else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
+ anar |= 0x0100;
+ else if(cistrcmp(ether->opt[i], "force100") == 0)
+ anar |= 0x0080;
+ }
+ XCVRDEBUG("mii anar: %uX\n", anar);
+ if(anar & 0x0100){ /* 100BASE-TXFD */
+ ether->mbps = 100;
+ setfullduplex(port);
+ }
+ else if(anar & 0x0200) /* 100BASE-T4 */
+ ;
+ else if(anar & 0x0080) /* 100BASE-TX */
+ ether->mbps = 100;
+ else if(anar & 0x0040) /* 10BASE-TFD */
+ setfullduplex(port);
+ else /* 10BASE-T */
+ ;
+ break;
+
+ case xcvr100BaseTX:
+ case xcvr100BaseFX:
+ COMMAND(port, SelectRegisterWindow, Wfifo);
+ x = inl(port+InternalConfig) & ~ramPartitionMask;
+ outl(port+InternalConfig, x|ramPartition1to1);
+
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
+ x |= linkBeatEnable;
+ outs(port+MediaStatus, x);
+
+ if(x & dataRate100)
+ ether->mbps = 100;
+ break;
+
+ case xcvr10BaseT:
+ /*
+ * Enable Link Beat and Jabber to start the
+ * transceiver.
+ */
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ x = ins(port+MediaStatus) & ~dcConverterEnabled;
+ x |= linkBeatEnable|jabberGuardEnable;
+ outs(port+MediaStatus, x);
+
+ if((did & 0xFF00) == 0x5900)
+ busmaster = 0;
+ break;
+
+ case xcvr10Base2:
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable);
+ outs(port+MediaStatus, x);
+
+ /*
+ * Start the DC-DC converter.
+ * Wait > 800 microseconds.
+ */
+ COMMAND(port, EnableDcConverter, 0);
+ delay(1);
+ break;
+ }
+
+ /*
+ * Wop is the normal operating register set.
+ * The 3C59[0257] adapters allow access to more than one register window
+ * at a time, but there are situations where switching still needs to be
+ * done, so just do it.
+ * Clear out any lingering Tx status.
+ */
+ COMMAND(port, SelectRegisterWindow, Wop);
+ while(inb(port+TxStatus))
+ outb(port+TxStatus, 0);
+
+ /*
+ * Allocate a controller structure, clear out the
+ * adapter statistics, clear the statistics logged into ctlr
+ * and enable statistics collection. Xcvr is needed in order
+ * to collect the BadSSD statistics.
+ */
+ ether->ctlr = malloc(sizeof(Ctlr));
+ ctlr = ether->ctlr;
+
+ ilock(&ctlr->wlock);
+ ctlr->xcvr = xcvr;
+ statistics(ether);
+ memset(ctlr->stats, 0, sizeof(ctlr->stats));
+
+ ctlr->busmaster = busmaster;
+ ctlr->xcvr = xcvr;
+ ctlr->rxstatus9 = rxstatus9;
+ ctlr->rxearly = rxearly;
+ if(rxearly >= 2048)
+ ctlr->ts = 2;
+
+ COMMAND(port, StatisticsEnable, 0);
+
+ /*
+ * Allocate any receive buffers.
+ */
+ switch(ctlr->busmaster){
+
+ case 2:
+ ctlr->dnenabled = 1;
+
+ /*
+ * 10MUpldBug.
+ * Disabling is too severe, can use receive busmastering at
+ * 100Mbps OK, but how to tell which rate is actually being used -
+ * the 3c905 always seems to have dataRate100 set?
+ * Believe the bug doesn't apply if upRxEarlyEnable is set
+ * and the threshold is set such that uploads won't start
+ * until the whole packet has been received.
+ */
+ ctlr->upenabled = 1;
+ x = eepromdata(port, 0x0F);
+ if(!(x & 0x01))
+ outl(port+PktStatus, upRxEarlyEnable);
+
+ if(ctlr->upenabled || ctlr->dnenabled){
+ ctlr->nup = Nup;
+ ctlr->ndn = Ndn;
+ init905(ctlr);
+ }
+ else
+ ctlr->rbp = rbpalloc(allocb);
+ outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));
+ break;
+
+ default:
+ ctlr->rbp = rbpalloc(allocb);
+ break;
+ }
+
+ /*
+ * Set a base TxStartThresh which will be incremented
+ * if any txUnderrun errors occur and ensure no RxEarly
+ * interrupts happen.
+ */
+ ctlr->txthreshold = ETHERMAXTU/2;
+ COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts);
+ COMMAND(port, SetRxEarlyThresh, rxearly>>ctlr->ts);
+
+ iunlock(&ctlr->wlock);
+
+ /*
+ * Linkage to the generic ethernet driver.
+ */
+ ether->port = port;
+ ether->attach = attach;
+ ether->transmit = transmit;
+ ether->interrupt = interrupt;
+ ether->ifstat = ifstat;
+
+ ether->promiscuous = promiscuous;
+ ether->multicast = multicast;
+ ether->arg = ether;
+
+ return 0;
+}
+
+void
+etherelnk3link(void)
+{
+ addethercard("elnk3", etherelnk3reset);
+ addethercard("3C509", etherelnk3reset);
+}
M mpc/etherscc.c => mpc/etherscc.c +0 -2
@@ 394,8 394,6 @@ sccsetup(Ctlr *ctlr, SCC *scc, uchar *ea)
Etherparam *p;
IMM *io;
-print("sccsetup\n");
-
io = ioplock();
p = (Etherparam*)KADDR(SCC1P);
M mpc/fns.h => mpc/fns.h +18 -3
@@ 19,8 19,8 @@ void delay(int);
ulong draminit(ulong*);
void dtlbmiss(void);
void dumpregs(Ureg*);
-//void eieio(void);
-#define eieio()
+void eieio(void);
+//#define eieio()
void evenaddr(ulong);
void faultpower(Ureg*, ulong addr, int read);
void firmware(int);
@@ 42,11 42,17 @@ void gotopc(ulong);
void icflush(void*, ulong);
void idle(void);
#define idlehands() /* nothing to do in the runproc */
-int iprint(char*, ...);
+int inb(int);
+void insb(int, void*, int);
+ushort ins(int);
+void inss(int, void*, int);
+ulong inl(int);
+void insl(int, void*, int);
void intr(Ureg*);
void intrenable(int, void (*)(Ureg*, void*), void*, int);
int intrstats(char*, int);
void intrvec(void);
+int iprint(char*, ...);
void itlbmiss(void);
int isaconfig(char*, int, ISAConf*);
void kbdinit(void);
@@ 58,6 64,14 @@ void mapinit(RMap*, Map*, int);
void mathinit(void);
void mmuinit(void);
ulong* mmuwalk(ulong*, ulong, int);
+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 pcmspecial(char*, ISAConf*);
+void pcmspecialclose(int);
#define procrestore(p)
void procsave(Proc*);
void procsetup(Proc*);
@@ 78,6 92,7 @@ void trapinit(void);
void trapvec(void);
void uartinstall(void);
void uartwait(void); /* debugging */
+int unsac(uchar *dst, uchar *src, int n, int nsrc);
void wbflush(void);
#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
A mpc/inb.s => mpc/inb.s +119 -0
@@ 0,0 1,119 @@
+#include "mem.h"
+
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+TEXT inb(SB), $0
+ OR $ISAMEM, R3
+ MOVBZ (R3), R3
+ RETURN
+
+TEXT insb(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $1, R4
+insb1:
+ MOVBZ (R3), R7
+ MOVBU R7, 1(R4)
+ BDNZ insb1
+ RETURN
+
+TEXT outb(SB), $0
+ MOVW v+4(FP), R4
+ OR $ISAMEM, R3
+ EIEIO
+ MOVB R4, (R3)
+ RETURN
+
+TEXT outsb(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $1, R4
+outsb1:
+ EIEIO
+ MOVBZU 1(R4), R7
+ MOVB R7, (R3)
+ BDNZ outsb1
+ RETURN
+
+TEXT ins(SB), $0
+ OR $ISAMEM, R3
+ EIEIO
+ MOVHBR (R3), R3
+ RETURN
+
+TEXT inss(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $2, R4
+inss1:
+ EIEIO
+ MOVHZ (R3), R7
+ MOVHU R7, 2(R4)
+ BDNZ inss1
+ RETURN
+
+TEXT outs(SB), $0
+ MOVW v+4(FP), R4
+ OR $ISAMEM, R3
+ EIEIO
+ MOVHBR R4, (R3)
+ RETURN
+
+TEXT outss(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $2, R4
+outss1:
+ EIEIO
+ MOVHZU 2(R4), R7
+ MOVH R7, (R3)
+ BDNZ outss1
+ RETURN
+
+TEXT inl(SB), $0
+ OR $ISAMEM, R3
+ EIEIO
+ MOVWBR (R3), R3
+ RETURN
+
+TEXT insl(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $4, R4
+insl1:
+ EIEIO
+ MOVW (R3), R7
+ MOVWU R7, 4(R4)
+ BDNZ insl1
+ RETURN
+
+TEXT outl(SB), $0
+ MOVW v+4(FP), R4
+ OR $ISAMEM, R3
+ EIEIO
+ MOVWBR R4, (R3)
+ RETURN
+
+TEXT outsl(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $ISAMEM, R3
+ SUB $4, R4
+outsl1:
+ EIEIO
+ MOVWU 4(R4), R7
+ MOVW R7, (R3)
+ BDNZ outsl1
+ RETURN
A mpc/inbc.c => mpc/inbc.c +134 -0
@@ 0,0 1,134 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+int
+inb(int port)
+{
+ return *(uchar*)(port + ISAMEM);
+}
+
+ushort
+ins(int port)
+{
+ int x = *(ushort*)(port + ISAMEM);
+ return ((x&0xff) << 8) | (x>>8);
+}
+
+ulong
+inl(int port)
+{
+ ulong x = *(ulong*)(port + ISAMEM);
+//print("inl %d\n", port);
+ return (x << 24) | ((x&0xff00)<<8) | ((x>>8)&0xff00) | (x>>24);
+}
+
+void
+outb(int port, int val)
+{
+//print("outb %d %ux\n", port, val);
+ *(uchar*)(port + ISAMEM) = val;
+}
+
+void
+outs(int port, ushort val)
+{
+//print("outs %d %ux\n", port, val);
+ int x = (val<<8) | (val>>8);
+ *(ushort*)(port + ISAMEM) = x;
+}
+
+void
+outl(int port, ulong val)
+{
+//print("outl %d %ulx\n", port, val);
+ ulong x = (val << 24) | ((val&0xff00)<<8) | ((val>>8)&0xff00) | (val>>24);
+ *(ulong*)(port + ISAMEM) = x;
+}
+
+void
+insb(int port, void *buf, int len)
+{
+ int i;
+ uchar *p, *q;
+
+//print("insb %d %d\n", port, len);
+ p = (uchar*)(port + ISAMEM);
+ q = buf;
+ for(i = 0; i < len; i++){
+ *q++ = *p;
+ }
+}
+
+void
+inss(int port, void *buf, int len)
+{
+ int i;
+ ushort *p, *q;
+
+//print("inss %d %d\n", port, len);
+ p = (ushort*)(port + ISAMEM);
+ q = buf;
+ for(i = 0; i < len; i++){
+ *q++ = *p;
+ }
+}
+
+void
+insl(int port, void *buf, int len)
+{
+ int i;
+ ulong *p, *q;
+
+//print("insl %d %d\n", port, len);
+ p = (ulong*)(port + ISAMEM);
+ q = buf;
+ for(i = 0; i < len; i++){
+ *q++ = *p;
+ }
+}
+
+void
+outsb(int port, void *buf, int len)
+{
+ int i;
+ uchar *p, *q;
+
+//print("outsb %d %d\n", port, len);
+ p = (uchar*)(port + ISAMEM);
+ q = buf;
+ for(i = 0; i < len; i++){
+ *p = *q++;
+ }
+}
+
+void
+outss(int port, void *buf, int len)
+{
+ int i;
+ ushort *p, *q;
+
+//print("outss %d %d\n", port, len);
+ p = (ushort*)(port + ISAMEM);
+ q = buf;
+ for(i = 0; i < len; i++){
+ *p = *q++;
+ }
+}
+
+void
+outsl(int port, void *buf, int len)
+{
+ int i;
+ ulong *p, *q;
+
+//print("outsl %d %d\n", port, len);
+ p = (ulong*)(port + ISAMEM);
+ q = buf;
+ for(i = 0; i < len; i++){
+ *p = *q++;
+ }
+}
M mpc/io.h => mpc/io.h +24 -2
@@ 324,8 324,7 @@ struct IMM {
ulong option;
} pcmr[8];
uchar rsv3[0xe0-0xc0];
- ulong pgcra;
- ulong pgcrb;
+ ulong pgcr[2];
ulong pscr;
uchar rsv4[0xf0-0xec];
ulong pipr;
@@ 554,3 553,26 @@ struct IMM {
uchar siram[512];
ushort lcdmap[256];
};
+
+
+enum {
+ BusCBUS = 0, /* Corollary CBUS */
+ BusCBUSII, /* Corollary CBUS II */
+ BusEISA, /* Extended ISA */
+ BusFUTURE, /* IEEE Futurebus */
+ BusINTERN, /* Internal bus */
+ BusISA, /* Industry Standard Architecture */
+ BusMBI, /* Multibus I */
+ BusMBII, /* Multibus II */
+ BusMCA, /* Micro Channel Architecture */
+ BusMPI, /* MPI */
+ BusMPSA, /* MPSA */
+ BusNUBUS, /* Apple Macintosh NuBus */
+ BusPCI, /* Peripheral Component Interconnect */
+ BusPCMCIA, /* PC Memory Card International Association */
+ BusTC, /* DEC TurboChannel */
+ BusVL, /* VESA Local bus */
+ BusVME, /* VMEbus */
+ BusXPRESS, /* Express System Bus */
+};
+
M mpc/l.s => mpc/l.s +18 -8
@@ 163,16 163,16 @@ TEXT kernelmmu(SB), $0
* set:
* PowerPC mode
* Page protection mode - no 1K pages
- * CI when MMU is disbaled - this will change
+ * ~CI when MMU is disbaled
* WT when DMMU is disbaled - this will change
* disable protected TLB for the momment
* ignore user/supervisor state when looking for TLB
* set first tlb entry to 28 - first lockable entry
*/
- MOVW $(MMUCIDEF|(31<<8)), R4
+ MOVW $((31<<8)), R4
MOVW R4, SPR(MI_CTR) /* i-mmu control */
ISYNC
- MOVW $(MMUCIDEF|MMUWTDEF|(31<<8)), R4
+ MOVW $((31<<8)), R4
MOVW R4, SPR(MD_CTR) /* d-mmu control */
ISYNC
@@ 197,14 197,24 @@ ltlb:
BDNZ ltlb
/* lock kernel entries in tlb - also reset tlb index*/
- MOVW $(MMUCIDEF|MMURSV4), R4
+ MOVW $(MMURSV4), R4
MOVW R4, SPR(MI_CTR) /* i-mmu control */
ISYNC
- MOVW $(MMUCIDEF|MMUWTDEF|MMURSV4), R4
+ MOVW $(MMURSV4), R4
MOVW R4, SPR(MD_CTR) /* d-mmu control */
ISYNC
- /* enable MMU */
+ /* enable i-cache */
+ MOVW $(1<<25), R4
+ MOVW R4, SPR(IC_CST)
+ ISYNC
+
+ /* enable d-cache */
+ MOVW $(1<<25), R4
+ MOVW R4, SPR(DC_CST)
+ ISYNC
+
+ /* enable MMU */
MOVW MSR, R4
OR $(MSR_IR|MSR_DR), R4
MOVW R4, MSR
@@ 684,8 694,8 @@ GLOBL isavetbl+0(SB), $4
TEXT tlbtab(SB), $-4
/* epn, rpn, twc */
- TLBE(DRAMMEM|MMUEV, MMUPS8M|MMUWT|MMUV, DRAMMEM|MMUPP|MMUSPS|MMUSH|MMUCI|MMUV) /* DRAM, 8M */
- TLBE((DRAMMEM+8*(1<<20))|MMUEV, MMUPS8M|MMUWT|MMUV, (DRAMMEM+8*(1<<20))|MMUPP|MMUSPS|MMUSH|MMUCI|MMUV) /* DRAM, second 8M */
+ TLBE(DRAMMEM|MMUEV, MMUPS8M|MMUWT|MMUV, DRAMMEM|MMUPP|MMUSPS|MMUSH|MMUV) /* DRAM, 8M */
+ TLBE((DRAMMEM+8*(1<<20))|MMUEV, MMUPS8M|MMUWT|MMUV, (DRAMMEM+8*(1<<20))|MMUPP|MMUSPS|MMUSH|MMUV) /* DRAM, second 8M */
TLBE(INTMEM|MMUEV, MMUPS8M|MMUWT|MMUV, INTMEM|MMUPP|MMUSPS|MMUSH|MMUCI|MMUV) /* IO space 8M */
TEXT tlbtabe(SB), $-4
RETURN
M mpc/main.c => mpc/main.c +19 -7
@@ 39,6 39,11 @@ if(0) {
delay(1000);
}
}
+// turn on pcmcia
+*(uchar*)(NVRAMMEM+0x100001) |= 0x60;
+//print("sr1=%ux sr2=%ux\n", *(uchar*)(NVRAMMEM+0x100000), *(uchar*)(NVRAMMEM+0x100001));
+
+//print("sccr=%ulx\n", m->iomem->sccr);
pageinit();
procinit0();
initseg();
@@ 46,7 51,6 @@ if(0) {
links();
chandevreset();
swapinit();
-print("usrinit\n");
userinit();
predawn = 0;
schedinit();
@@ 70,6 74,8 @@ machinit(void)
m->speed = osc*(mf+1);
m->cpuhz = m->speed*MHz; /* general system clock (cycles) */
m->clockgen = osc*MHz; /* clock generator frequency (cycles) */
+
+ *(ushort*)&(io->memc[4].base) = 0x8060;
}
void
@@ 202,6 208,8 @@ exit(int ispanic)
else
delay(1000);
+ for(;;)
+ ;
// arch->reset();
}
@@ 248,7 256,7 @@ confinit(void)
ulong pa;
conf.nmach = 1; /* processors */
- conf.nproc = 200; /* processes */
+ conf.nproc = 30; /* processes */
// hard wire for now
pa = 0xffd00000; // leave 1 Meg for kernel
@@ 257,8 265,11 @@ confinit(void)
conf.npage0 = nbytes/BY2PG;
conf.base0 = pa;
- conf.npage1 = 0;
- conf.base1 = 0;
+ pa = 0xfff04000;
+ nbytes = 1024*1024 - 0x4000;
+
+ conf.npage1 = nbytes/BY2PG;
+ conf.base1 = pa;
conf.npage = conf.npage0 + conf.npage1;
@@ 266,9 277,9 @@ confinit(void)
conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
/* set up other configuration parameters */
- conf.nswap = conf.npage*3;
- conf.nswppo = 4096;
- conf.nimage = 200;
+ conf.nswap = 0; // conf.npage*3;
+ conf.nswppo = 0; // 4096;
+ conf.nimage = 20;
conf.copymode = 0; /* copy on write */
}
@@ 296,6 307,7 @@ getcfields(char* lp, char** fields, int n, char* sep)
static char BOOTARGS[] =
"ether0=type=SCC port=1 ea=08003e27df94\r\n"
+ "ether1=type=589E port=0x300\r\n"
"vgasize=640x480x8\r\n"
"kernelpercent=40\r\n"
"console=0 lcd\r\nbaud=9600\r\n";
M mpc/mem.h => mpc/mem.h +3 -2
@@ 123,7 123,7 @@
/*
* portable MMU bits for fault.c - though still machine specific
*/
-#define PTEVALID (MMUPP|MMUSH|MMUCI|MMUV)
+#define PTEVALID (MMUPP|MMUSH|MMUV)
#define PTEWRITE (2<<10)
#define PTERONLY (3<<10)
#define PTEUNCACHED (1<<4)
@@ 177,9 177,10 @@
* atlas board registers
*/
#define INTMEM 0x80000000
+#define ISAMEM 0x80100000
#define FLASH0MEM 0x80200000
#define FLASH1MEM 0x80400000
-#define SDRAMMEM 0x03000000
+#define NVRAMMEM 0x80600000
#define DRAMMEM 0xff000000 /* to 0xffffffff: 16 Meg */
#define SIRAM (INTMEM+0xC00)
M mpc/mmu.c => mpc/mmu.c +22 -1
@@ 34,11 34,32 @@ mmurelease(Proc* proc)
void
-putmmu(ulong va, ulong pa, Page*)
+putmmu(ulong va, ulong pa, Page *pg)
{
int x, r;
+ char *ctl;
+
+//if((va&0x8000000) == 0)
//print("putmmu va=%ux pa=%ux\n", va, pa);
x = splhi();
r = _putmmu(va, pa);
+
+ ctl = &pg->cachectl[m->machno];
+ switch(*ctl) {
+ default:
+ panic("putmmu: %d\n", *ctl);
+ break;
+ case PG_NOFLUSH:
+ break;
+ case PG_TXTFLUSH:
+ icflush((void*)pg->va, BY2PG);
+ *ctl = PG_NOFLUSH;
+ break;
+ case PG_NEWCOL:
+ dcflush((void*)pg->va, BY2PG);
+ *ctl = PG_NOFLUSH;
+ break;
+ }
+
splx(x);
}
A mpc/nocache.c => mpc/nocache.c +39 -0
@@ 0,0 1,39 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+// No file caching
+
+void
+cinit(void)
+{
+}
+
+void
+copen(Chan *c)
+{
+print("copen called!\n");
+ USED(c);
+}
+
+int
+cread(Chan *c, uchar *buf, int len, vlong off)
+{
+ USED(c, buf, len, off);
+ return 0;
+}
+
+void
+cupdate(Chan *c, uchar *buf, int len, vlong off)
+{
+ USED(c, buf, len, off);
+}
+
+void
+cwrite(Chan* c, uchar *buf, int len, vlong off)
+{
+ USED(c, buf, len, off);
+}
M mpc/trap.c => mpc/trap.c +5 -1
@@ 212,7 212,7 @@ faultpower(Ureg *ureg, ulong addr, int read)
char buf[ERRLEN];
user = (ureg->srr1 & MSR_PR) != 0;
-//print("fault: pc = %ux, addr = %ux read = %d user = %d stack=%ux\n", ureg->pc, addr, read, user, &ureg);
+//print("fault: pid=%d pc = %ux, addr = %ux read = %d user = %d stack=%ux\n", up->pid, ureg->pc, addr, read, user, &ureg);
insyscall = up->insyscall;
up->insyscall = 1;
spllo();
@@ 222,6 222,7 @@ faultpower(Ureg *ureg, ulong addr, int read)
dumpregs(ureg);
panic("fault: 0x%lux\n", addr);
}
+print("sys: trap: fault %s addr=0x%lux\n", read? "read" : "write", addr);
sprint(buf, "sys: trap: fault %s addr=0x%lux",
read? "read" : "write", addr);
postnote(up, 1, buf, NDebug);
@@ 674,6 675,8 @@ notify(Ureg* ur)
ulong s, sp;
Note *n;
+print("***notify\n");
+
if(up->procctl)
procctl(up);
if(up->nnote == 0)
@@ 749,6 752,7 @@ noted(Ureg* ureg, ulong arg0)
Ureg *nureg;
ulong oureg, sp;
+print("***noted\n");
qlock(&up->debug);
if(arg0!=NRSTR && !up->notified) {
qunlock(&up->debug);
A mpc/unsac.c => mpc/unsac.c +401 -0
@@ 0,0 1,401 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+typedef struct Huff Huff;
+
+typedef struct Decode Decode;
+
+enum
+{
+ ZBase = 2, /* base of code to encode 0 runs */
+ LitBase = ZBase-1, /* base of literal values */
+ MaxLit = 256,
+
+ MaxLeaf = MaxLit+LitBase,
+ MaxHuffBits = 15, /* max bits in a huffman code */
+ MaxSelHuffBits = 15, /* max bits for a table selector huffman code */
+
+ Nhuffblock = 16*1024, /* symbols encoded before output */
+ Nhuffslop = 64, /* slop for stuffing zeros, etc. */
+};
+
+struct Huff
+{
+ int minbits;
+ int maxbits;
+ int flatbits;
+ ulong flat[1<<8];
+ ulong maxcode[MaxHuffBits+1];
+ ulong last[MaxHuffBits+1];
+ ulong decode[MaxLeaf];
+};
+
+struct Decode{
+ Huff tab;
+ int ndec;
+ int nbits;
+ ulong bits;
+ int nzero;
+ int base;
+ ulong maxblocksym;
+
+ jmp_buf errjmp;
+
+ uchar *src; /* input buffer */
+ uchar *smax; /* limit */
+};
+
+static void fatal(Decode *dec, char*, ...);
+
+static int hdec(Decode*);
+static void hflush(Decode*);
+static void hbflush(Decode*);
+static ulong bitget(Decode*, int);
+static int mtf(uchar*, int);
+
+int
+unsac(uchar *dst, uchar *src, int n, int nsrc)
+{
+ Decode dec;
+ uchar *buf, front[256];
+ ulong *suflink, sums[256];
+ ulong sum;
+ int i, m, I, j, c;
+
+ buf = malloc(n+2);
+ suflink = malloc((n+2) * sizeof *suflink);
+
+ if(waserror()) {
+ free(buf);
+ free(suflink);
+ nexterror();
+ }
+
+ dec.src = src;
+ dec.smax = src + nsrc;
+
+ dec.nbits = 0;
+ dec.bits = 0;
+ dec.nzero = 0;
+ for(i = 0; i < 256; i++)
+ front[i] = i;
+
+ n++;
+ I = bitget(&dec, 16);
+ if(I >= n)
+ fatal(&dec, "corrupted input file: n=%d I=%d", n, I);
+
+ /*
+ * decode the character usage map
+ */
+ for(i = 0; i < 256; i++)
+ sums[i] = 0;
+ c = bitget(&dec, 1);
+ for(i = 0; i < 256; ){
+ m = bitget(&dec, 8) + 1;
+ while(m--){
+ if(i >= 256)
+ fatal(&dec, "bad format encoding char map %d", m);
+ front[i++] = c;
+ }
+ c = c ^ 1;
+ }
+
+ /*
+ * initialize mtf state
+ */
+ c = 0;
+ for(i = 0; i < 256; i++)
+ if(front[i])
+ front[c++] = i;
+ dec.maxblocksym = c + LitBase;
+
+ /*
+ * huffman decoding, move to front decoding,
+ * along with character counting
+ */
+ hbflush(&dec);
+ for(i = 0; i < n; i++){
+ if(i == I)
+ continue;
+ m = hdec(&dec);
+
+ /*
+ * move to front
+ */
+ c = front[m];
+ for(; m > 0; m--)
+ front[m] = front[m-1];
+ front[0] = c;
+
+ buf[i] = c;
+ sums[c]++;
+ }
+
+ sum = 1;
+ for(i = 0; i < 256; i++){
+ c = sums[i];
+ sums[i] = sum;
+ sum += c;
+ }
+
+ /*
+ * calculate the row step for column step array
+ * by calculating it for backwards moves and inverting it
+ */
+ suflink[0] = I;
+ for(j = 0; j < I; j++)
+ suflink[sums[buf[j]]++] = j;
+ for(j++; j < n; j++)
+ suflink[sums[buf[j]]++] = j;
+
+ /*
+ * to recover the suffix array, aka suffix array for input
+ * j = 0;
+ * for(i = I; i != 0; i = suflink[i])
+ * sarray[i] = j++;
+ * sarray[i] = j++;
+ * note that suflink[i] = sarrayinv[sarray[i] + 1]
+ */
+
+ /*
+ * produce the decoded data forwards
+ */
+ n--;
+ i = I;
+ for(j = 0; j < n; j++){
+ i = suflink[i];
+ dst[j] = buf[i];
+ }
+
+ poperror();
+ free(buf);
+ free(suflink);
+ return n;
+}
+
+static ulong
+bitget(Decode *dec, int nb)
+{
+ int c;
+
+ while(dec->nbits < nb){
+ if(dec->src >= dec->smax)
+ fatal(dec, "premature eof 1");
+ c = *dec->src++;
+ dec->bits <<= 8;
+ dec->bits |= c;
+ dec->nbits += 8;
+ }
+ dec->nbits -= nb;
+ return (dec->bits >> dec->nbits) & ((1 << nb) - 1);
+}
+
+static void
+fillbits(Decode *dec)
+{
+ int c;
+
+ while(dec->nbits < 24){
+ if(dec->src >= dec->smax)
+ fatal(dec, "premature eof 2: nbits %d", dec->nbits);
+ c = *dec->src++;
+ dec->bits <<= 8;
+ dec->bits |= c;
+ dec->nbits += 8;
+ }
+}
+
+/*
+ * decode one symbol
+ */
+static int
+hdecsym(Decode *dec, Huff *h)
+{
+ long c;
+ int b;
+
+ dec->bits &= (1 << dec->nbits) - 1;
+ for(b = h->flatbits; (c = dec->bits >> (dec->nbits - b)) > h->maxcode[b]; b++)
+ ;
+ if(b > h->maxbits)
+ fatal(dec, "too many bits consumed: b=%d minbits=%d maxbits=%d", b, h->minbits, h->maxbits);
+ dec->nbits -= b;
+ c = h->decode[h->last[b] - c];
+
+ return c;
+}
+
+static int
+hdec(Decode *dec)
+{
+ ulong c;
+
+ dec->ndec++;
+ if(dec->nzero){
+ dec->nzero--;
+ return 0;
+ }
+
+ if(dec->nbits < dec->tab.maxbits)
+ fillbits(dec);
+ dec->bits &= (1 << dec->nbits) - 1;
+ c = dec->tab.flat[dec->bits >> (dec->nbits - dec->tab.flatbits)];
+ if(c == ~0)
+ c = hdecsym(dec, &dec->tab);
+ else{
+ dec->nbits -= c & 0xff;
+ c >>= 8;
+ }
+
+ /*
+ * reverse funny run-length coding
+ */
+ if(c < ZBase){
+ dec->nzero = dec->base << c;
+ dec->base <<= 1;
+ dec->nzero--;
+ return 0;
+ }
+
+ dec->base = 1;
+ c -= LitBase;
+ return c;
+}
+
+static void
+hbflush(Decode *dec)
+{
+ dec->base = 1;
+ dec->ndec = 0;
+ hflush(dec);
+}
+
+static void
+hufftab(Decode *dec, Huff *h, ulong *hb, ulong *bitcount, int maxleaf, int maxbits, int flatbits)
+{
+ ulong c, code, nc[MaxHuffBits+1];
+ int i, b, ec;
+
+ code = 0;
+ c = 0;
+ h->minbits = maxbits;
+ for(b = 1; b <= maxbits; b++){
+ h->last[b] = c;
+ if(c == 0)
+ h->minbits = b;
+ c += bitcount[b];
+ nc[b] = code << 1;
+ code = (code << 1) + bitcount[b];
+ if(code > (1 << b))
+ fatal(dec, "corrupted huffman table");
+ h->maxcode[b] = code - 1;
+ h->last[b] += code - 1;
+ }
+ if(code != (1 << maxbits))
+ fatal(dec, "huffman table not full %d %d", code, 1<<maxbits);
+ h->maxbits = b;
+ if(flatbits > b)
+ flatbits = b;
+ h->flatbits = flatbits;
+
+ b = 1 << flatbits;
+ for(i = 0; i < b; i++)
+ h->flat[i] = ~0;
+
+ for(i = 0; i < maxleaf; i++){
+ b = hb[i];
+ if(b == 0)
+ continue;
+ c = nc[b]++;
+ if(b <= flatbits){
+if(c > (1<<(b+1)))fatal(dec, "xx1");
+ code = (i << 8) | b;
+ ec = (c + 1) << (flatbits - b);
+ if(ec > (1<<flatbits))
+ fatal(dec, "too big: ec=%d c=%d %d b=%d nc=%d\n", ec, c, c & ((1<<b)-1), b, nc[b]);
+ for(c <<= (flatbits - b); c < ec; c++)
+ h->flat[c] = code;
+ }else{
+ c = h->last[b] - c;
+ if(c >= maxleaf)
+ fatal(dec, "corrupted huffman table: c=%d maxleaf=%d i=%d b=%d maxbits=%d last=%d, nc=%d",
+ c, maxleaf, i, b, maxbits, h->last[b], nc[b]);
+ h->decode[c] = i;
+ }
+ }
+}
+
+static void
+hflush(Decode *dec)
+{
+ Huff codetab;
+ ulong bitcount[MaxHuffBits+1], hb[MaxLeaf];
+ uchar tmtf[MaxHuffBits+1];
+ int i, b, m, maxbits;
+
+ /*
+ * read the tables for the tables
+ */
+ for(i = 0; i <= MaxHuffBits; i++)
+ bitcount[i] = 0;
+ maxbits = 0;
+ for(i = 0; i <= MaxHuffBits; i++){
+ b = bitget(dec, 4);
+ hb[i] = b;
+ bitcount[b]++;
+ if(b > maxbits)
+ maxbits = b;
+ }
+ hufftab(dec, &codetab, hb, bitcount, MaxHuffBits+1, maxbits, 8);
+ for(i = 0; i <= MaxHuffBits; i++)
+ tmtf[i] = i;
+ for(i = 0; i <= MaxHuffBits; i++)
+ bitcount[i] = 0;
+ maxbits = 0;
+ for(i = 0; i < dec->maxblocksym; i++){
+ if(dec->nbits <= codetab.maxbits)
+ fillbits(dec);
+ dec->bits &= (1 << dec->nbits) - 1;
+ m = codetab.flat[dec->bits >> (dec->nbits - codetab.flatbits)];
+ if(m == ~0)
+ m = hdecsym(dec, &codetab);
+ else{
+ dec->nbits -= m & 0xff;
+ m >>= 8;
+ }
+ b = tmtf[m];
+ for(; m > 0; m--)
+ tmtf[m] = tmtf[m-1];
+ tmtf[0] = b;
+
+ if(b > MaxHuffBits)
+ fatal(dec, "bit length %d too large, max %d i %d maxval %d", b, MaxHuffBits, i, dec->maxblocksym);
+ hb[i] = b;
+ bitcount[b]++;
+ if(b > maxbits)
+ maxbits = b;
+ }
+ for(; i < MaxLeaf; i++)
+ hb[i] = 0;
+
+ hufftab(dec, &dec->tab, hb, bitcount, MaxLeaf, maxbits, 8);
+}
+
+static void
+fatal(Decode *dec, char *fmt, ...)
+{
+ char buf[128];
+ va_list arg;
+
+ va_start(arg, fmt);
+ doprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+
+ print("devsac: %s\n", buf);
+ error(buf);
+}