M alphapc/devarch.c => alphapc/devarch.c +2 -1
@@ 372,7 372,8 @@ Dev archdevtab = {
"arch",
devreset,
- devinit,
+ devinit,
+ devshutdown,
archattach,
archwalk,
archstat,
M alphapc/devether.c => alphapc/devether.c +1 -0
@@ 431,6 431,7 @@ Dev etherdevtab = {
etherreset,
devinit,
+ devshutdown,
etherattach,
etherwalk,
etherstat,
M alphapc/devvga.c => alphapc/devvga.c +2 -1
@@ 393,7 393,8 @@ Dev vgadevtab = {
"vga",
vgareset,
- devinit,
+ devinit,
+ devshutdown,
vgaattach,
vgawalk,
vgastat,
M alphapc/main.c => alphapc/main.c +14 -6
@@ 145,16 145,16 @@ init0(void)
chandevinit();
if(!waserror()){
- ksetenv("cputype", "alpha");
+ ksetenv("cputype", "alpha", 0);
sprint(tstr, "alpha %s alphapc", conffile);
- ksetenv("terminal", tstr);
+ ksetenv("terminal", tstr, 0);
if(cpuserver)
- ksetenv("service", "cpu");
+ ksetenv("service", "cpu", 0);
else
- ksetenv("service", "terminal");
+ ksetenv("service", "terminal", 0);
for(i = 0; i < nconf; i++)
- if(confname[i] && confname[i][0] != '*')
- ksetenv(confname[i], confval[i]);
+ if(confname[i])
+ ksetenv(confname[i], confval[i], 1);
poperror();
}
@@ 258,6 258,14 @@ procsave(Proc *p)
*/
}
+/* still too do */
+void
+reboot(void*, void*, ulong)
+{
+ exit(0);
+}
+
+
void
exit(int)
{
M bitsy/devether.c => bitsy/devether.c +1 -0
@@ 445,6 445,7 @@ Dev etherdevtab = {
etherreset,
devinit,
+ devshutdown,
etherattach,
etherwalk,
etherstat,
M bitsy/devflash.c => bitsy/devflash.c +1 -0
@@ 617,6 617,7 @@ Dev flashdevtab = {
devreset,
flashinit,
+ devshutdown,
flashattach,
flashwalk,
flashstat,
M bitsy/devpcmcia.c => bitsy/devpcmcia.c +1 -0
@@ 386,6 386,7 @@ Dev pcmciadevtab = {
pcmciareset,
devinit,
+ devshutdown,
pcmciaattach,
pcmciawalk,
pcmciastat,
M bitsy/devpenmouse.c => bitsy/devpenmouse.c +1 -0
@@ 430,6 430,7 @@ Dev penmousedevtab = {
penmousereset,
penmouseinit,
+ devshutdown,
penmouseattach,
penmousewalk,
penmousestat,
M bitsy/devsac.c => bitsy/devsac.c +1 -0
@@ 576,6 576,7 @@ Dev sacdevtab = {
devreset,
sacinit,
+ devshutdown,
sacattach,
sacwalk,
sacstat,
M bitsy/devuda1341.c => bitsy/devuda1341.c +1 -0
@@ 1382,6 1382,7 @@ Dev uda1341devtab = {
devreset,
audioinit,
+ devshutdown,
audioattach,
audiowalk,
audiostat,
M bitsy/devµc.c => bitsy/devµc.c +1 -0
@@ 417,6 417,7 @@ Dev µcdevtab = {
devreset,
µcinit,
+ devshutdown,
µcattach,
µcwalk,
µcstat,
M bitsy/main.c => bitsy/main.c +12 -4
@@ 51,6 51,14 @@ main(void)
schedinit();
}
+/* need to do better */
+void
+reboot(void*, void*, ulong)
+{
+ exit(0);
+}
+
+
/*
* exit kernel either on a panic or user request
*/
@@ 94,12 102,12 @@ init0(void)
chandevinit();
if(!waserror()){
- ksetenv("terminal", "bitsy");
- ksetenv("cputype", "arm");
+ ksetenv("terminal", "bitsy", 0);
+ ksetenv("cputype", "arm", 0);
if(cpuserver)
- ksetenv("service", "cpu");
+ ksetenv("service", "cpu", 0);
else
- ksetenv("service", "terminal");
+ ksetenv("service", "terminal", 0);
poperror();
}
kproc("alarm", alarmkproc, 0);
M boot/boot.h => boot/boot.h +2 -7
@@ 53,24 53,19 @@ extern int parsefields(char*, char**, int, char*);
/* methods */
extern void configil(Method*);
-extern int authil(void);
extern int connectil(void);
extern void configtcp(Method*);
-extern int authtcp(void);
extern int connecttcp(void);
extern void configlocal(Method*);
-extern int authlocal(void);
extern int connectlocal(void);
extern void configsac(Method*);
-extern int authsac(void);
extern int connectsac(void);
-extern void configpaq(Method*);
-extern int authpaq(void);
-extern int connectpaq(void);
+extern void configrc(Method*);
+extern int connectrc(void);
/* hack for passing authentication address */
extern char *authaddr;
M boot/local.c => boot/local.c +0 -6
@@ 49,12 49,6 @@ configlocal(Method *mp)
}
int
-authlocal(void)
-{
- return -1;
-}
-
-int
connectlocal(void)
{
int i, p[2];
A boot/rc.c => boot/rc.c +17 -0
@@ 0,0 1,17 @@
+#include <u.h>
+#include <libc.h>
+#include <../boot/boot.h>
+
+void
+configrc(Method *)
+{
+ execl("/rc", "/rc", "-m", "/rcmain", "-i", 0);
+ fatal("rc");
+}
+
+int
+connectrc(void)
+{
+ // does not get here
+ return -1;
+}
M boot/sac.c => boot/sac.c +0 -9
@@ 2,8 2,6 @@
#include <libc.h>
#include <../boot/boot.h>
-void configip(char* dev);
-
// HACK - take over from boot since file system is not
// available on a pipe
@@ 43,13 41,6 @@ configsac(Method *mp)
}
int
-authsac(void)
-{
- // does not get here
- return -1;
-}
-
-int
connectsac(void)
{
// does not get here
M ip/devip.c => ip/devip.c +2 -8
@@ 259,11 259,7 @@ ipreset(void)
{
nullmediumlink();
pktmediumlink();
-}
-static void
-ipinit(void)
-{
fmtinstall('i', eipconv);
fmtinstall('I', eipconv);
fmtinstall('E', eipconv);
@@ 1079,9 1075,6 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
free(cb);
nexterror();
}
- if(cb->nf < 1)
- error("short control request");
-
ct = lookupcmd(cb, ipctlmsg, nelem(ipctlmsg));
switch(ct->index){
case CMconnect:
@@ 1171,7 1164,8 @@ Dev ipdevtab = {
"ip",
ipreset,
- ipinit,
+ devinit,
+ devshutdown,
ipattach,
ipwalk,
ipstat,
M mtx/devarch.c => mtx/devarch.c +1 -0
@@ 372,6 372,7 @@ Dev archdevtab = {
devreset,
devinit,
+ devshutdown,
archattach,
archwalk,
archstat,
A mtx/devether.c => mtx/devether.c +467 -0
@@ 0,0 1,467 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+#include "etherif.h"
+
+static Ether *etherxx[MaxEther];
+
+Chan*
+etherattach(char* spec)
+{
+ ulong ctlrno;
+ char *p;
+ Chan *chan;
+
+ ctlrno = 0;
+ if(spec && *spec){
+ ctlrno = strtoul(spec, &p, 0);
+ if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
+ error(Ebadarg);
+ }
+ if(etherxx[ctlrno] == 0)
+ error(Enodev);
+
+ chan = devattach('l', spec);
+ chan->dev = ctlrno;
+ if(etherxx[ctlrno]->attach)
+ etherxx[ctlrno]->attach(etherxx[ctlrno]);
+ return chan;
+}
+
+static Walkqid*
+etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
+{
+ return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
+}
+
+static int
+etherstat(Chan* chan, uchar* dp, int n)
+{
+ return netifstat(etherxx[chan->dev], chan, dp, n);
+}
+
+static Chan*
+etheropen(Chan* chan, int omode)
+{
+ return netifopen(etherxx[chan->dev], chan, omode);
+}
+
+static void
+ethercreate(Chan*, char*, int, ulong)
+{
+}
+
+static void
+etherclose(Chan* chan)
+{
+ netifclose(etherxx[chan->dev], chan);
+}
+
+static long
+etherread(Chan* chan, void* buf, long n, vlong off)
+{
+ Ether *ether;
+ ulong offset = off;
+
+ ether = etherxx[chan->dev];
+ if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
+ /*
+ * With some controllers it is necessary to reach
+ * into the chip to extract statistics.
+ */
+ if(NETTYPE(chan->qid.path) == Nifstatqid)
+ return ether->ifstat(ether, buf, n, offset);
+ else if(NETTYPE(chan->qid.path) == Nstatqid)
+ ether->ifstat(ether, buf, 0, offset);
+ }
+
+ return netifread(ether, chan, buf, n, offset);
+}
+
+static Block*
+etherbread(Chan* chan, long n, ulong offset)
+{
+ return netifbread(etherxx[chan->dev], chan, n, offset);
+}
+
+static int
+etherwstat(Chan* chan, uchar* dp, int n)
+{
+ return netifwstat(etherxx[chan->dev], chan, dp, n);
+}
+
+static void
+etherrtrace(Netfile* f, Etherpkt* pkt, int len)
+{
+ int i, n;
+ Block *bp;
+
+ if(qwindow(f->in) <= 0)
+ return;
+ if(len > 58)
+ n = 58;
+ else
+ n = len;
+ bp = iallocb(64);
+ if(bp == nil)
+ return;
+ memmove(bp->wp, pkt->d, n);
+ i = TK2MS(MACHP(0)->ticks);
+ bp->wp[58] = len>>8;
+ bp->wp[59] = len;
+ bp->wp[60] = i>>24;
+ bp->wp[61] = i>>16;
+ bp->wp[62] = i>>8;
+ bp->wp[63] = i;
+ bp->wp += 64;
+ qpass(f->in, bp);
+}
+
+Block*
+etheriq(Ether* ether, Block* bp, int fromwire)
+{
+ Etherpkt *pkt;
+ ushort type;
+ int len, multi, tome, fromme;
+ Netfile **ep, *f, **fp, *fx;
+ Block *xbp;
+
+ ether->inpackets++;
+
+ pkt = (Etherpkt*)bp->rp;
+ len = BLEN(bp);
+ type = (pkt->type[0]<<8)|pkt->type[1];
+ fx = 0;
+ ep = ðer->f[Ntypes];
+
+ multi = pkt->d[0] & 1;
+ /* check for valid multcast addresses */
+ if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
+ if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
+ if(fromwire){
+ freeb(bp);
+ bp = 0;
+ }
+ return bp;
+ }
+ }
+
+ /* is it for me? */
+ tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
+ fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
+
+ /*
+ * Multiplex the packet to all the connections which want it.
+ * If the packet is not to be used subsequently (fromwire != 0),
+ * attempt to simply pass it into one of the connections, thereby
+ * saving a copy of the data (usual case hopefully).
+ */
+ for(fp = ether->f; fp < ep; fp++){
+ if(f = *fp)
+ if(f->type == type || f->type < 0)
+ if(tome || multi || f->prom){
+ /* Don't want to hear bridged packets */
+ if(f->bridge && !fromwire && !fromme)
+ continue;
+ if(!f->headersonly){
+ if(fromwire && fx == 0)
+ fx = f;
+ else if(xbp = iallocb(len)){
+ memmove(xbp->wp, pkt, len);
+ xbp->wp += len;
+ qpass(f->in, xbp);
+ }
+ else
+ ether->soverflows++;
+ }
+ else
+ etherrtrace(f, pkt, len);
+ }
+ }
+
+ if(fx){
+ if(qpass(fx->in, bp) < 0)
+ ether->soverflows++;
+ return 0;
+ }
+ if(fromwire){
+ freeb(bp);
+ return 0;
+ }
+
+ return bp;
+}
+
+static int
+etheroq(Ether* ether, Block* bp)
+{
+ int len, loopback, s;
+ Etherpkt *pkt;
+
+ ether->outpackets++;
+
+ /*
+ * Check if the packet has to be placed back onto the input queue,
+ * i.e. if it's a loopback or broadcast packet or the interface is
+ * 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;
+ if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
+ s = splhi();
+ etheriq(ether, bp, 0);
+ splx(s);
+ }
+
+ if(!loopback){
+ qbwrite(ether->oq, bp);
+ ether->transmit(ether);
+ } else
+ freeb(bp);
+
+ return len;
+}
+
+static long
+etherwrite(Chan* chan, void* buf, long n, vlong)
+{
+ Ether *ether;
+ Block *bp;
+ int nn;
+
+ ether = etherxx[chan->dev];
+ if(NETTYPE(chan->qid.path) != Ndataqid) {
+ nn = netifwrite(ether, chan, buf, n);
+ if(nn >= 0)
+ return nn;
+
+ if(ether->ctl!=nil)
+ return ether->ctl(ether,buf,n);
+
+ error(Ebadctl);
+ }
+
+ if(n > ether->maxmtu)
+ error(Etoobig);
+ if(n < ether->minmtu)
+ error(Etoosmall);
+
+ bp = allocb(n);
+ if(waserror()){
+ freeb(bp);
+ nexterror();
+ }
+ memmove(bp->rp, buf, n);
+ memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
+ poperror();
+ bp->wp += n;
+
+ return etheroq(ether, bp);
+}
+
+static long
+etherbwrite(Chan* chan, Block* bp, ulong)
+{
+ Ether *ether;
+ long n;
+
+ n = BLEN(bp);
+ if(NETTYPE(chan->qid.path) != Ndataqid){
+ if(waserror()) {
+ freeb(bp);
+ nexterror();
+ }
+ n = etherwrite(chan, bp->rp, n, 0);
+ poperror();
+ freeb(bp);
+ return n;
+ }
+ ether = etherxx[chan->dev];
+
+ if(n > ether->maxmtu){
+ freeb(bp);
+ error(Etoobig);
+ }
+ if(n < ether->minmtu){
+ freeb(bp);
+ error(Etoosmall);
+ }
+
+ return etheroq(ether, bp);
+}
+
+static struct {
+ char* type;
+ int (*reset)(Ether*);
+} cards[MaxEther+1];
+
+void
+addethercard(char* t, int (*r)(Ether*))
+{
+ static int ncard;
+
+ if(ncard == MaxEther)
+ panic("too many ether cards");
+ cards[ncard].type = t;
+ cards[ncard].reset = r;
+ ncard++;
+}
+
+int
+parseether(uchar *to, char *from)
+{
+ char nip[4];
+ char *p;
+ int i;
+
+ p = from;
+ for(i = 0; i < 6; i++){
+ if(*p == 0)
+ return -1;
+ nip[0] = *p++;
+ if(*p == 0)
+ return -1;
+ nip[1] = *p++;
+ nip[2] = 0;
+ to[i] = strtoul(nip, 0, 16);
+ if(*p == ':')
+ p++;
+ }
+ return 0;
+}
+
+static void
+etherreset(void)
+{
+ Ether *ether;
+ int i, n, ctlrno;
+ char name[32], buf[128];
+
+ for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
+ if(ether == 0)
+ ether = malloc(sizeof(Ether));
+ memset(ether, 0, sizeof(Ether));
+ ether->ctlrno = ctlrno;
+ ether->tbdf = BUSUNKNOWN;
+ ether->mbps = 10;
+ ether->minmtu = ETHERMINTU;
+ ether->maxmtu = ETHERMAXTU;
+ if(isaconfig("ether", ctlrno, ether) == 0)
+ continue;
+ for(n = 0; cards[n].type; n++){
+ if(cistrcmp(cards[n].type, ether->type))
+ continue;
+ for(i = 0; i < ether->nopt; i++){
+ if(strncmp(ether->opt[i], "ea=", 3))
+ continue;
+ if(parseether(ether->ea, ðer->opt[i][3]) == -1)
+ memset(ether->ea, 0, Eaddrlen);
+ }
+ 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;
+ snprint(name, sizeof(name), "ether%d", ctlrno);
+
+ /*
+ * If ether->irq is 0, it is a hack to indicate no interrupt
+ * used by ethersink.
+ */
+ if(ether->irq > 0)
+ intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
+
+ 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));
+ if(ether->size)
+ i += sprint(buf+i, " size 0x%luX", ether->size);
+ i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
+ ether->ea[0], ether->ea[1], ether->ea[2],
+ ether->ea[3], ether->ea[4], ether->ea[5]);
+ sprint(buf+i, "\n");
+ print(buf);
+
+ if(ether->mbps >= 100){
+ netifinit(ether, name, Ntypes, 256*1024);
+ if(ether->oq == 0)
+ ether->oq = qopen(256*1024, 1, 0, 0);
+ }
+ else{
+ netifinit(ether, name, Ntypes, 65*1024);
+ if(ether->oq == 0)
+ ether->oq = qopen(65*1024, 1, 0, 0);
+ }
+ if(ether->oq == 0)
+ panic("etherreset %s", name);
+ ether->alen = Eaddrlen;
+ memmove(ether->addr, ether->ea, Eaddrlen);
+ memset(ether->bcast, 0xFF, Eaddrlen);
+
+ etherxx[ctlrno] = ether;
+ ether = 0;
+ break;
+ }
+ }
+ if(ether)
+ free(ether);
+}
+
+#define POLY 0xedb88320
+
+/* really slow 32 bit crc for ethers */
+ulong
+ethercrc(uchar *p, int len)
+{
+ int i, j;
+ ulong crc, b;
+
+ crc = 0xffffffff;
+ for(i = 0; i < len; i++){
+ b = *p++;
+ for(j = 0; j < 8; j++){
+ crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
+ b >>= 1;
+ }
+ }
+ return crc;
+}
+
+Dev etherdevtab = {
+ 'l',
+ "ether",
+
+ etherreset,
+ devinit,
+ devshutdown,
+ etherattach,
+ etherwalk,
+ etherstat,
+ etheropen,
+ ethercreate,
+ etherclose,
+ etherread,
+ etherbread,
+ etherwrite,
+ etherbwrite,
+ devremove,
+ etherwstat,
+};
A mtx/ether2114x.c => mtx/ether2114x.c +1671 -0
@@ 0,0 1,1671 @@
+/*
+ * Digital Semiconductor DECchip 2114x PCI Fast Ethernet LAN Controller.
+ * To do:
+ * thresholds;
+ * ring sizing;
+ * handle more error conditions;
+ * tidy setup packet mess;
+ * push initialisation back to attach;
+ * full SROM decoding.
+ */
+#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 DEBUG (1)
+#define debug if(DEBUG)print
+
+enum {
+ Nrde = 64,
+ Ntde = 64,
+};
+
+#define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4)
+
+enum { /* CRS0 - Bus Mode */
+ Swr = 0x00000001, /* Software Reset */
+ Bar = 0x00000002, /* Bus Arbitration */
+ Dsl = 0x0000007C, /* Descriptor Skip Length (field) */
+ Ble = 0x00000080, /* Big/Little Endian */
+ Pbl = 0x00003F00, /* Programmable Burst Length (field) */
+ Cal = 0x0000C000, /* Cache Alignment (field) */
+ Cal8 = 0x00004000, /* 8 longword boundary alignment */
+ Cal16 = 0x00008000, /* 16 longword boundary alignment */
+ Cal32 = 0x0000C000, /* 32 longword boundary alignment */
+ Tap = 0x000E0000, /* Transmit Automatic Polling (field) */
+ Dbo = 0x00100000, /* Descriptor Byte Ordering Mode */
+ Rml = 0x00200000, /* Read Multiple */
+};
+
+enum { /* CSR[57] - Status and Interrupt Enable */
+ Ti = 0x00000001, /* Transmit Interrupt */
+ Tps = 0x00000002, /* Transmit Process Stopped */
+ Tu = 0x00000004, /* Transmit buffer Unavailable */
+ Tjt = 0x00000008, /* Transmit Jabber Timeout */
+ Unf = 0x00000020, /* transmit UNderFlow */
+ Ri = 0x00000040, /* Receive Interrupt */
+ Ru = 0x00000080, /* Receive buffer Unavailable */
+ Rps = 0x00000100, /* Receive Process Stopped */
+ Rwt = 0x00000200, /* Receive Watchdog Timeout */
+ Eti = 0x00000400, /* Early Transmit Interrupt */
+ Gte = 0x00000800, /* General purpose Timer Expired */
+ Fbe = 0x00002000, /* Fatal Bit Error */
+ Ais = 0x00008000, /* Abnormal Interrupt Summary */
+ Nis = 0x00010000, /* Normal Interrupt Summary */
+ Rs = 0x000E0000, /* Receive process State (field) */
+ Ts = 0x00700000, /* Transmit process State (field) */
+ Eb = 0x03800000, /* Error bits */
+};
+
+enum { /* CSR6 - Operating Mode */
+ Hp = 0x00000001, /* Hash/Perfect receive filtering mode */
+ Sr = 0x00000002, /* Start/stop Receive */
+ Ho = 0x00000004, /* Hash-Only filtering mode */
+ Pb = 0x00000008, /* Pass Bad frames */
+ If = 0x00000010, /* Inverse Filtering */
+ Sb = 0x00000020, /* Start/stop Backoff counter */
+ Pr = 0x00000040, /* Promiscuous Mode */
+ Pm = 0x00000080, /* Pass all Multicast */
+ Fd = 0x00000200, /* Full Duplex mode */
+ Om = 0x00000C00, /* Operating Mode (field) */
+ Fc = 0x00001000, /* Force Collision */
+ St = 0x00002000, /* Start/stop Transmission Command */
+ Tr = 0x0000C000, /* ThReshold control bits (field) */
+ Tr128 = 0x00000000,
+ Tr256 = 0x00004000,
+ Tr512 = 0x00008000,
+ Tr1024 = 0x0000C000,
+ Ca = 0x00020000, /* CApture effect enable */
+ Ps = 0x00040000, /* Port Select */
+ Hbd = 0x00080000, /* HeartBeat Disable */
+ Imm = 0x00100000, /* IMMediate mode */
+ Sf = 0x00200000, /* Store and Forward */
+ Ttm = 0x00400000, /* Transmit Threshold Mode */
+ Pcs = 0x00800000, /* PCS function */
+ Scr = 0x01000000, /* SCRambler mode */
+ Mbo = 0x02000000, /* Must Be One */
+ Ra = 0x40000000, /* Receive All */
+ Sc = 0x80000000, /* Special Capture effect enable */
+
+ TrMODE = Tr512, /* default transmission threshold */
+};
+
+enum { /* CSR9 - ROM and MII Management */
+ Scs = 0x00000001, /* serial ROM chip select */
+ Sclk = 0x00000002, /* serial ROM clock */
+ Sdi = 0x00000004, /* serial ROM data in */
+ Sdo = 0x00000008, /* serial ROM data out */
+ Ss = 0x00000800, /* serial ROM select */
+ Wr = 0x00002000, /* write */
+ Rd = 0x00004000, /* read */
+
+ Mdc = 0x00010000, /* MII management clock */
+ Mdo = 0x00020000, /* MII management write data */
+ Mii = 0x00040000, /* MII management operation mode (W) */
+ Mdi = 0x00080000, /* MII management data in */
+};
+
+enum { /* CSR12 - General-Purpose Port */
+ Gpc = 0x00000100, /* General Purpose Control */
+};
+
+typedef struct Des {
+ int status;
+ int control;
+ ulong addr;
+ Block* bp;
+} Des;
+
+enum { /* status */
+ Of = 0x00000001, /* Rx: OverFlow */
+ Ce = 0x00000002, /* Rx: CRC Error */
+ Db = 0x00000004, /* Rx: Dribbling Bit */
+ Re = 0x00000008, /* Rx: Report on MII Error */
+ Rw = 0x00000010, /* Rx: Receive Watchdog */
+ Ft = 0x00000020, /* Rx: Frame Type */
+ Cs = 0x00000040, /* Rx: Collision Seen */
+ Tl = 0x00000080, /* Rx: Frame too Long */
+ Ls = 0x00000100, /* Rx: Last deScriptor */
+ Fs = 0x00000200, /* Rx: First deScriptor */
+ Mf = 0x00000400, /* Rx: Multicast Frame */
+ Rf = 0x00000800, /* Rx: Runt Frame */
+ Dt = 0x00003000, /* Rx: Data Type (field) */
+ De = 0x00004000, /* Rx: Descriptor Error */
+ Fl = 0x3FFF0000, /* Rx: Frame Length (field) */
+ Ff = 0x40000000, /* Rx: Filtering Fail */
+
+ Def = 0x00000001, /* Tx: DEFerred */
+ Uf = 0x00000002, /* Tx: UnderFlow error */
+ Lf = 0x00000004, /* Tx: Link Fail report */
+ Cc = 0x00000078, /* Tx: Collision Count (field) */
+ Hf = 0x00000080, /* Tx: Heartbeat Fail */
+ Ec = 0x00000100, /* Tx: Excessive Collisions */
+ Lc = 0x00000200, /* Tx: Late Collision */
+ Nc = 0x00000400, /* Tx: No Carrier */
+ Lo = 0x00000800, /* Tx: LOss of carrier */
+ To = 0x00004000, /* Tx: Transmission jabber timeOut */
+
+ Es = 0x00008000, /* [RT]x: Error Summary */
+ Own = 0x80000000, /* [RT]x: OWN bit */
+};
+
+enum { /* control */
+ Bs1 = 0x000007FF, /* [RT]x: Buffer 1 Size */
+ Bs2 = 0x003FF800, /* [RT]x: Buffer 2 Size */
+
+ Ch = 0x01000000, /* [RT]x: second address CHained */
+ Er = 0x02000000, /* [RT]x: End of Ring */
+
+ Ft0 = 0x00400000, /* Tx: Filtering Type 0 */
+ Dpd = 0x00800000, /* Tx: Disabled PaDding */
+ Ac = 0x04000000, /* Tx: Add CRC disable */
+ Set = 0x08000000, /* Tx: SETup packet */
+ Ft1 = 0x10000000, /* Tx: Filtering Type 1 */
+ Fseg = 0x20000000, /* Tx: First SEGment */
+ Lseg = 0x40000000, /* Tx: Last SEGment */
+ Ic = 0x80000000, /* Tx: Interrupt on Completion */
+};
+
+enum { /* PHY registers */
+ Bmcr = 0, /* Basic Mode Control */
+ Bmsr = 1, /* Basic Mode Status */
+ Phyidr1 = 2, /* PHY Identifier #1 */
+ Phyidr2 = 3, /* PHY Identifier #2 */
+ Anar = 4, /* Auto-Negotiation Advertisment */
+ Anlpar = 5, /* Auto-Negotiation Link Partner Ability */
+ Aner = 6, /* Auto-Negotiation Expansion */
+};
+
+enum { /* Variants */
+ Tulip0 = (0x0009<<16)|0x1011,
+ Tulip3 = (0x0019<<16)|0x1011,
+ Pnic = (0x0002<<16)|0x11AD,
+ Pnic2 = (0xC115<<16)|0x11AD,
+};
+
+typedef struct Ctlr Ctlr;
+typedef struct Ctlr {
+ int port;
+ Pcidev* pcidev;
+ Ctlr* next;
+ int active;
+ int id; /* (pcidev->did<<16)|pcidev->vid */
+
+ uchar* srom;
+ int sromsz; /* address size in bits */
+ uchar* sromea; /* MAC address */
+ uchar* leaf;
+ int sct; /* selected connection type */
+ int k; /* info block count */
+ uchar* infoblock[16];
+ int sctk; /* sct block index */
+ int curk; /* current block index */
+ uchar* type5block;
+
+ int phy[32]; /* logical to physical map */
+ int phyreset; /* reset bitmap */
+ int curphyad;
+ int fdx;
+ int ttm;
+
+ uchar fd; /* option */
+ int medium; /* option */
+
+ int csr6; /* CSR6 - operating mode */
+ int mask; /* CSR[57] - interrupt mask */
+ int mbps;
+
+ Lock lock;
+
+ Des* rdr; /* receive descriptor ring */
+ int nrdr; /* size of rdr */
+ int rdrx; /* index into rdr */
+
+ Lock tlock;
+ Des* tdr; /* transmit descriptor ring */
+ int ntdr; /* size of tdr */
+ int tdrh; /* host index into tdr */
+ int tdri; /* interface index into tdr */
+ int ntq; /* descriptors active */
+ int ntqmax;
+ Block* setupbp;
+
+ ulong of; /* receive statistics */
+ ulong ce;
+ ulong cs;
+ ulong tl;
+ ulong rf;
+ ulong de;
+
+ ulong ru;
+ ulong rps;
+ ulong rwt;
+
+ ulong uf; /* transmit statistics */
+ ulong ec;
+ ulong lc;
+ ulong nc;
+ ulong lo;
+ ulong to;
+
+ ulong tps;
+ ulong tu;
+ ulong tjt;
+ ulong unf;
+} Ctlr;
+
+static Ctlr* ctlrhead;
+static Ctlr* ctlrtail;
+
+#define csr32r(c, r) (inl((c)->port+((r)*8)))
+#define csr32w(c, r, l) (outl((c)->port+((r)*8), (ulong)(l)))
+
+static void
+promiscuous(void* arg, int on)
+{
+ Ctlr *ctlr;
+
+ ctlr = ((Ether*)arg)->ctlr;
+ ilock(&ctlr->lock);
+ if(on)
+ ctlr->csr6 |= Pr;
+ else
+ ctlr->csr6 &= ~Pr;
+ csr32w(ctlr, 6, ctlr->csr6);
+ iunlock(&ctlr->lock);
+}
+
+static void
+attach(Ether* ether)
+{
+ Ctlr *ctlr;
+
+ ctlr = ether->ctlr;
+ ilock(&ctlr->lock);
+ if(!(ctlr->csr6 & Sr)){
+ ctlr->csr6 |= Sr;
+ csr32w(ctlr, 6, ctlr->csr6);
+ }
+ iunlock(&ctlr->lock);
+}
+
+static long
+ifstat(Ether* ether, void* a, long n, ulong offset)
+{
+ Ctlr *ctlr;
+ char *buf, *p;
+ int i, l, len;
+
+ ctlr = ether->ctlr;
+
+ ether->crcs = ctlr->ce;
+ ether->frames = ctlr->rf+ctlr->cs;
+ ether->buffs = ctlr->de+ctlr->tl;
+ ether->overflows = ctlr->of;
+
+ if(n == 0)
+ return 0;
+
+ p = malloc(READSTR);
+ l = snprint(p, READSTR, "Overflow: %lud\n", ctlr->of);
+ l += snprint(p+l, READSTR-l, "Ru: %lud\n", ctlr->ru);
+ l += snprint(p+l, READSTR-l, "Rps: %lud\n", ctlr->rps);
+ l += snprint(p+l, READSTR-l, "Rwt: %lud\n", ctlr->rwt);
+ l += snprint(p+l, READSTR-l, "Tps: %lud\n", ctlr->tps);
+ l += snprint(p+l, READSTR-l, "Tu: %lud\n", ctlr->tu);
+ l += snprint(p+l, READSTR-l, "Tjt: %lud\n", ctlr->tjt);
+ l += snprint(p+l, READSTR-l, "Unf: %lud\n", ctlr->unf);
+ l += snprint(p+l, READSTR-l, "CRC Error: %lud\n", ctlr->ce);
+ l += snprint(p+l, READSTR-l, "Collision Seen: %lud\n", ctlr->cs);
+ l += snprint(p+l, READSTR-l, "Frame Too Long: %lud\n", ctlr->tl);
+ l += snprint(p+l, READSTR-l, "Runt Frame: %lud\n", ctlr->rf);
+ l += snprint(p+l, READSTR-l, "Descriptor Error: %lud\n", ctlr->de);
+ l += snprint(p+l, READSTR-l, "Underflow Error: %lud\n", ctlr->uf);
+ l += snprint(p+l, READSTR-l, "Excessive Collisions: %lud\n", ctlr->ec);
+ l += snprint(p+l, READSTR-l, "Late Collision: %lud\n", ctlr->lc);
+ l += snprint(p+l, READSTR-l, "No Carrier: %lud\n", ctlr->nc);
+ l += snprint(p+l, READSTR-l, "Loss of Carrier: %lud\n", ctlr->lo);
+ l += snprint(p+l, READSTR-l, "Transmit Jabber Timeout: %lud\n",
+ ctlr->to);
+ l += snprint(p+l, READSTR-l, "csr6: %luX %uX\n", csr32r(ctlr, 6),
+ ctlr->csr6);
+ snprint(p+l, READSTR-l, "ntqmax: %d\n", ctlr->ntqmax);
+ ctlr->ntqmax = 0;
+ buf = a;
+ len = readstr(offset, buf, n, p);
+ if(offset > l)
+ offset -= l;
+ else
+ offset = 0;
+ buf += len;
+ n -= len;
+
+ l = snprint(p, READSTR, "srom:");
+ for(i = 0; i < (1<<(ctlr->sromsz)*sizeof(ushort)); i++){
+ if(i && ((i & 0x0F) == 0))
+ l += snprint(p+l, READSTR-l, "\n ");
+ l += snprint(p+l, READSTR-l, " %2.2uX", ctlr->srom[i]);
+ }
+
+ snprint(p+l, READSTR-l, "\n");
+ len += readstr(offset, buf, n, p);
+ free(p);
+
+ return len;
+}
+
+static void
+txstart(Ether* ether)
+{
+ Ctlr *ctlr;
+ Block *bp;
+ Des *des;
+ int control;
+
+ ctlr = ether->ctlr;
+ while(ctlr->ntq < (ctlr->ntdr-1)){
+ if(ctlr->setupbp){
+ bp = ctlr->setupbp;
+ ctlr->setupbp = 0;
+ control = Ic|Set|BLEN(bp);
+ }
+ else{
+ bp = qget(ether->oq);
+ if(bp == nil)
+ break;
+ control = Ic|Lseg|Fseg|BLEN(bp);
+ }
+
+ ctlr->tdr[PREV(ctlr->tdrh, ctlr->ntdr)].control &= ~Ic;
+ des = &ctlr->tdr[ctlr->tdrh];
+ des->bp = bp;
+ des->addr = PCIWADDR(bp->rp);
+ des->control |= control;
+ ctlr->ntq++;
+ coherence();
+ des->status = Own;
+ csr32w(ctlr, 1, 0);
+ ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr);
+ }
+
+ if(ctlr->ntq > ctlr->ntqmax)
+ ctlr->ntqmax = ctlr->ntq;
+}
+
+static void
+transmit(Ether* ether)
+{
+ Ctlr *ctlr;
+
+ ctlr = ether->ctlr;
+ ilock(&ctlr->tlock);
+ txstart(ether);
+ iunlock(&ctlr->tlock);
+}
+
+static void
+interrupt(Ureg*, void* arg)
+{
+ Ctlr *ctlr;
+ Ether *ether;
+ int len, status;
+ Des *des;
+ Block *bp;
+
+print("ether intr\n");
+ ether = arg;
+ ctlr = ether->ctlr;
+
+ while((status = csr32r(ctlr, 5)) & (Nis|Ais)){
+ /*
+ * Acknowledge the interrupts and mask-out
+ * the ones that are implicitly handled.
+ */
+ csr32w(ctlr, 5, status);
+ status &= (ctlr->mask & ~(Nis|Ti));
+
+ if(status & Ais){
+ if(status & Tps)
+ ctlr->tps++;
+ if(status & Tu)
+ ctlr->tu++;
+ if(status & Tjt)
+ ctlr->tjt++;
+ if(status & Ru)
+ ctlr->ru++;
+ if(status & Rps)
+ ctlr->rps++;
+ if(status & Rwt)
+ ctlr->rwt++;
+ status &= ~(Ais|Rwt|Rps|Ru|Tjt|Tu|Tps);
+ }
+
+ /*
+ * Received packets.
+ */
+ if(status & Ri){
+ des = &ctlr->rdr[ctlr->rdrx];
+ while(!(des->status & Own)){
+ if(des->status & Es){
+ if(des->status & Of)
+ ctlr->of++;
+ if(des->status & Ce)
+ ctlr->ce++;
+ if(des->status & Cs)
+ ctlr->cs++;
+ if(des->status & Tl)
+ ctlr->tl++;
+ if(des->status & Rf)
+ ctlr->rf++;
+ if(des->status & De)
+ ctlr->de++;
+ }
+ else if(bp = iallocb(Rbsz)){
+ len = ((des->status & Fl)>>16)-4;
+ des->bp->wp = des->bp->rp+len;
+ etheriq(ether, des->bp, 1);
+ des->bp = bp;
+ des->addr = PCIWADDR(bp->rp);
+ }
+
+ des->control &= Er;
+ des->control |= Rbsz;
+ coherence();
+ des->status = Own;
+
+ ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr);
+ des = &ctlr->rdr[ctlr->rdrx];
+ }
+ status &= ~Ri;
+ }
+
+ /*
+ * Check the transmit side:
+ * check for Transmit Underflow and Adjust
+ * the threshold upwards;
+ * free any transmitted buffers and try to
+ * top-up the ring.
+ */
+ if(status & Unf){
+ ctlr->unf++;
+ ilock(&ctlr->lock);
+ csr32w(ctlr, 6, ctlr->csr6 & ~St);
+ switch(ctlr->csr6 & Tr){
+ case Tr128:
+ len = Tr256;
+ break;
+ case Tr256:
+ len = Tr512;
+ break;
+ case Tr512:
+ len = Tr1024;
+ break;
+ default:
+ case Tr1024:
+ len = Sf;
+ break;
+ }
+ ctlr->csr6 = (ctlr->csr6 & ~Tr)|len;
+ csr32w(ctlr, 6, ctlr->csr6);
+ iunlock(&ctlr->lock);
+ csr32w(ctlr, 5, Tps);
+ status &= ~(Unf|Tps);
+ }
+
+ ilock(&ctlr->tlock);
+ while(ctlr->ntq){
+ des = &ctlr->tdr[ctlr->tdri];
+ if(des->status & Own)
+ break;
+
+ if(des->status & Es){
+ if(des->status & Uf)
+ ctlr->uf++;
+ if(des->status & Ec)
+ ctlr->ec++;
+ if(des->status & Lc)
+ ctlr->lc++;
+ if(des->status & Nc)
+ ctlr->nc++;
+ if(des->status & Lo)
+ ctlr->lo++;
+ if(des->status & To)
+ ctlr->to++;
+ ether->oerrs++;
+ }
+
+ freeb(des->bp);
+ des->control &= Er;
+
+ ctlr->ntq--;
+ ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr);
+ }
+ txstart(ether);
+ iunlock(&ctlr->tlock);
+
+ /*
+ * Anything left not catered for?
+ */
+ if(status)
+ panic("#l%d: status %8.8uX\n", ether->ctlrno, status);
+ }
+}
+
+static void
+ctlrinit(Ether* ether)
+{
+ Ctlr *ctlr;
+ Des *des;
+ Block *bp;
+ int i;
+ uchar bi[Eaddrlen*2];
+
+ ctlr = ether->ctlr;
+
+ /*
+ * Allocate and initialise the receive ring;
+ * allocate and initialise the transmit ring;
+ * unmask interrupts and start the transmit side;
+ * create and post a setup packet to initialise
+ * the physical ethernet address.
+ */
+ ctlr->rdr = xspanalloc(ctlr->nrdr*sizeof(Des), 8*sizeof(ulong), 0);
+ for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){
+ des->bp = iallocb(Rbsz);
+ if(des->bp == nil)
+ panic("can't allocate ethernet receive ring\n");
+ des->status = Own;
+ des->control = Rbsz;
+ des->addr = PCIWADDR(des->bp->rp);
+ }
+ ctlr->rdr[ctlr->nrdr-1].control |= Er;
+ ctlr->rdrx = 0;
+ csr32w(ctlr, 3, PCIWADDR(ctlr->rdr));
+
+ ctlr->tdr = xspanalloc(ctlr->ntdr*sizeof(Des), 8*sizeof(ulong), 0);
+ ctlr->tdr[ctlr->ntdr-1].control |= Er;
+ ctlr->tdrh = 0;
+ ctlr->tdri = 0;
+ csr32w(ctlr, 4, PCIWADDR(ctlr->tdr));
+
+ /*
+ * Clear any bits in the Status Register (CSR5) as
+ * the PNIC has a different reset value from a true 2114x.
+ */
+ ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti;
+ csr32w(ctlr, 5, ctlr->mask);
+ csr32w(ctlr, 7, ctlr->mask);
+ ctlr->csr6 |= St;
+ csr32w(ctlr, 6, ctlr->csr6);
+
+ for(i = 0; i < Eaddrlen/2; i++){
+ bi[i*4] = ether->ea[i*2];
+ bi[i*4+1] = ether->ea[i*2+1];
+ bi[i*4+2] = ether->ea[i*2+1];
+ bi[i*4+3] = ether->ea[i*2];
+ }
+ bp = iallocb(Eaddrlen*2*16);
+ if(bp == nil)
+ panic("can't allocate ethernet setup buffer\n");
+ memset(bp->rp, 0xFF, sizeof(bi));
+ for(i = sizeof(bi); i < sizeof(bi)*16; i += sizeof(bi))
+ memmove(bp->rp+i, bi, sizeof(bi));
+ bp->wp += sizeof(bi)*16;
+
+ ctlr->setupbp = bp;
+ ether->oq = qopen(256*1024, 1, 0, 0);
+ transmit(ether);
+}
+
+static void
+csr9w(Ctlr* ctlr, int data)
+{
+ csr32w(ctlr, 9, data);
+ microdelay(1);
+}
+
+static int
+miimdi(Ctlr* ctlr, int n)
+{
+ int data, i;
+
+ /*
+ * Read n bits from the MII Management Register.
+ */
+ data = 0;
+ for(i = n-1; i >= 0; i--){
+ if(csr32r(ctlr, 9) & Mdi)
+ data |= (1<<i);
+ csr9w(ctlr, Mii|Mdc);
+ csr9w(ctlr, Mii);
+ }
+ csr9w(ctlr, 0);
+
+ return data;
+}
+
+static void
+miimdo(Ctlr* ctlr, 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 = Mdo;
+ else
+ mdo = 0;
+ csr9w(ctlr, mdo);
+ csr9w(ctlr, mdo|Mdc);
+ csr9w(ctlr, mdo);
+ }
+}
+
+static int
+miir(Ctlr* ctlr, int phyad, int regad)
+{
+ int data, i;
+
+ if(ctlr->id == Pnic){
+ i = 1000;
+ csr32w(ctlr, 20, 0x60020000|(phyad<<23)|(regad<<18));
+ do{
+ microdelay(1);
+ data = csr32r(ctlr, 20);
+ }while((data & 0x80000000) && --i);
+
+ if(i == 0)
+ return -1;
+ return data & 0xFFFF;
+ }
+
+ /*
+ * Preamble;
+ * ST+OP+PHYAD+REGAD;
+ * TA + 16 data bits.
+ */
+ miimdo(ctlr, 0xFFFFFFFF, 32);
+ miimdo(ctlr, 0x1800|(phyad<<5)|regad, 14);
+ data = miimdi(ctlr, 18);
+
+ if(data & 0x10000)
+ return -1;
+
+ return data & 0xFFFF;
+}
+
+static void
+miiw(Ctlr* ctlr, int phyad, int regad, int data)
+{
+ /*
+ * Preamble;
+ * ST+OP+PHYAD+REGAD+TA + 16 data bits;
+ * Z.
+ */
+ miimdo(ctlr, 0xFFFFFFFF, 32);
+ data &= 0xFFFF;
+ data |= (0x05<<(5+5+2+16))|(phyad<<(5+2+16))|(regad<<(2+16))|(0x02<<16);
+ miimdo(ctlr, data, 32);
+ csr9w(ctlr, Mdc);
+ csr9w(ctlr, 0);
+}
+
+static int
+sromr(Ctlr* ctlr, int r)
+{
+ int i, op, data, size;
+
+ if(ctlr->id == Pnic){
+ i = 1000;
+ csr32w(ctlr, 19, 0x600|r);
+ do{
+ microdelay(1);
+ data = csr32r(ctlr, 19);
+ }while((data & 0x80000000) && --i);
+
+ if(ctlr->sromsz == 0)
+ ctlr->sromsz = 6;
+
+ return csr32r(ctlr, 9) & 0xFFFF;
+ }
+
+ /*
+ * This sequence for reading a 16-bit register 'r'
+ * in the EEPROM is taken straight from Section
+ * 7.4 of the 21140 Hardware Reference Manual.
+ */
+reread:
+ csr9w(ctlr, Rd|Ss);
+ csr9w(ctlr, Rd|Ss|Scs);
+ csr9w(ctlr, Rd|Ss|Sclk|Scs);
+ csr9w(ctlr, Rd|Ss);
+
+ op = 0x06;
+ for(i = 3-1; i >= 0; i--){
+ data = Rd|Ss|(((op>>i) & 0x01)<<2)|Scs;
+ csr9w(ctlr, data);
+ csr9w(ctlr, data|Sclk);
+ csr9w(ctlr, data);
+ }
+
+ /*
+ * First time through must work out the EEPROM size.
+ */
+ if((size = ctlr->sromsz) == 0)
+ size = 8;
+
+ for(size = size-1; size >= 0; size--){
+ data = Rd|Ss|(((r>>size) & 0x01)<<2)|Scs;
+ csr9w(ctlr, data);
+ csr9w(ctlr, data|Sclk);
+ csr9w(ctlr, data);
+ microdelay(1);
+ if(!(csr32r(ctlr, 9) & Sdo))
+ break;
+ }
+
+ data = 0;
+ for(i = 16-1; i >= 0; i--){
+ csr9w(ctlr, Rd|Ss|Sclk|Scs);
+ if(csr32r(ctlr, 9) & Sdo)
+ data |= (1<<i);
+ csr9w(ctlr, Rd|Ss|Scs);
+ }
+
+ csr9w(ctlr, 0);
+
+ if(ctlr->sromsz == 0){
+ ctlr->sromsz = 8-size;
+ goto reread;
+ }
+
+ return data & 0xFFFF;
+}
+
+static void
+softreset(Ctlr* ctlr)
+{
+ /*
+ * Soft-reset the controller and initialise bus mode.
+ * Delay should be >= 50 PCI cycles (2×S @ 25MHz).
+ */
+ csr32w(ctlr, 0, Swr);
+ microdelay(10);
+ csr32w(ctlr, 0, Rml|Cal16);
+ delay(1);
+}
+
+static int
+type5block(Ctlr* ctlr, uchar* block)
+{
+ int csr15, i, len;
+
+ /*
+ * Reset or GPR sequence. Reset should be once only,
+ * before the GPR sequence.
+ * Note 'block' is not a pointer to the block head but
+ * a pointer to the data in the block starting at the
+ * reset length value so type5block can be used for the
+ * sequences contained in type 1 and type 3 blocks.
+ * The SROM docs state the 21140 type 5 block is the
+ * same as that for the 21143, but the two controllers
+ * use different registers and sequence-element lengths
+ * so the 21140 code here is a guess for a real type 5
+ * sequence.
+ */
+ len = *block++;
+ if(ctlr->id != Tulip3){
+ for(i = 0; i < len; i++){
+ csr32w(ctlr, 12, *block);
+ block++;
+ }
+ return len;
+ }
+
+ for(i = 0; i < len; i++){
+ csr15 = *block++<<16;
+ csr15 |= *block++<<24;
+ csr32w(ctlr, 15, csr15);
+ debug("%8.8uX ", csr15);
+ }
+ return 2*len;
+}
+
+static int
+typephylink(Ctlr* ctlr, uchar*)
+{
+ int an, bmcr, bmsr, csr6, x;
+
+ /*
+ * Fail if
+ * auto-negotiataion enabled but not complete;
+ * no valid link established.
+ */
+ bmcr = miir(ctlr, ctlr->curphyad, Bmcr);
+ miir(ctlr, ctlr->curphyad, Bmsr);
+ bmsr = miir(ctlr, ctlr->curphyad, Bmsr);
+ debug("bmcr 0x%2.2uX bmsr 0x%2.2uX\n", bmcr, bmsr);
+ if(((bmcr & 0x1000) && !(bmsr & 0x0020)) || !(bmsr & 0x0004))
+ return 0;
+
+ if(bmcr & 0x1000){
+ an = miir(ctlr, ctlr->curphyad, Anar);
+ an &= miir(ctlr, ctlr->curphyad, Anlpar) & 0x3E0;
+ debug("an 0x%2.uX 0x%2.2uX 0x%2.2uX\n",
+ miir(ctlr, ctlr->curphyad, Anar),
+ miir(ctlr, ctlr->curphyad, Anlpar),
+ an);
+
+ if(an & 0x0100)
+ x = 0x4000;
+ else if(an & 0x0080)
+ x = 0x2000;
+ else if(an & 0x0040)
+ x = 0x1000;
+ else if(an & 0x0020)
+ x = 0x0800;
+ else
+ x = 0;
+ }
+ else if((bmcr & 0x2100) == 0x2100)
+ x = 0x4000;
+ else if(bmcr & 0x2000){
+ /*
+ * If FD capable, force it if necessary.
+ */
+ if((bmsr & 0x4000) && ctlr->fd){
+ miiw(ctlr, ctlr->curphyad, Bmcr, 0x2100);
+ x = 0x4000;
+ }
+ else
+ x = 0x2000;
+ }
+ else if(bmcr & 0x0100)
+ x = 0x1000;
+ else
+ x = 0x0800;
+
+ csr6 = Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE;
+ if(ctlr->fdx & x)
+ csr6 |= Fd;
+ if(ctlr->ttm & x)
+ csr6 |= Ttm;
+ debug("csr6 0x%8.8uX 0x%8.8uX 0x%8.8luX\n",
+ csr6, ctlr->csr6, csr32r(ctlr, 6));
+ if(csr6 != ctlr->csr6){
+ ctlr->csr6 = csr6;
+ csr32w(ctlr, 6, csr6);
+ }
+
+ return 1;
+}
+
+static int
+typephymode(Ctlr* ctlr, uchar* block, int wait)
+{
+ uchar *p;
+ int len, mc, nway, phyx, timeo;
+
+ if(DEBUG){
+ int i;
+
+ len = (block[0] & ~0x80)+1;
+ for(i = 0; i < len; i++)
+ debug("%2.2uX ", block[i]);
+ debug("\n");
+ }
+
+ if(block[1] == 1)
+ len = 1;
+ else if(block[1] == 3)
+ len = 2;
+ else
+ return -1;
+
+ /*
+ * Snarf the media capabilities, nway advertisment,
+ * FDX and TTM bitmaps.
+ */
+ p = &block[5+len*block[3]+len*block[4+len*block[3]]];
+ mc = *p++;
+ mc |= *p++<<8;
+ nway = *p++;
+ nway |= *p++<<8;
+ ctlr->fdx = *p++;
+ ctlr->fdx |= *p++<<8;
+ ctlr->ttm = *p++;
+ ctlr->ttm |= *p<<8;
+ debug("mc %4.4uX nway %4.4uX fdx %4.4uX ttm %4.4uX\n",
+ mc, nway, ctlr->fdx, ctlr->ttm);
+ USED(mc);
+
+ phyx = block[2];
+ ctlr->curphyad = ctlr->phy[phyx];
+
+ ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE;
+ //csr32w(ctlr, 6, ctlr->csr6);
+ if(typephylink(ctlr, block))
+ return 0;
+
+ if(!(ctlr->phyreset & (1<<phyx))){
+ debug("reset seq: len %d: ", block[3]);
+ if(ctlr->type5block)
+ type5block(ctlr, &ctlr->type5block[2]);
+ else
+ type5block(ctlr, &block[4+len*block[3]]);
+ debug("\n");
+ ctlr->phyreset |= (1<<phyx);
+ }
+
+ /*
+ * GPR sequence.
+ */
+ debug("gpr seq: len %d: ", block[3]);
+ type5block(ctlr, &block[3]);
+ debug("\n");
+
+ ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE;
+ //csr32w(ctlr, 6, ctlr->csr6);
+ if(typephylink(ctlr, block))
+ return 0;
+
+ /*
+ * Turn off auto-negotiation, set the auto-negotiation
+ * advertisment register then start the auto-negotiation
+ * process again.
+ */
+ miiw(ctlr, ctlr->curphyad, Bmcr, 0);
+ miiw(ctlr, ctlr->curphyad, Anar, nway|1);
+ miiw(ctlr, ctlr->curphyad, Bmcr, 0x1000);
+
+ if(!wait)
+ return 0;
+
+ for(timeo = 0; timeo < 30; timeo++){
+ if(typephylink(ctlr, block))
+ return 0;
+ delay(100);
+ }
+
+ return -1;
+}
+
+static int
+typesymmode(Ctlr *ctlr, uchar *block, int wait)
+{
+ uint gpmode, gpdata, command;
+
+ USED(wait);
+ gpmode = block[3] | ((uint) block[4] << 8);
+ gpdata = block[5] | ((uint) block[6] << 8);
+ command = (block[7] | ((uint) block[8] << 8)) & 0x71;
+ if (command & 0x8000) {
+ print("ether2114x.c: FIXME: handle type 4 mode blocks where cmd.active_invalid != 0\n");
+ return -1;
+ }
+ csr32w(ctlr, 15, gpmode);
+ csr32w(ctlr, 15, gpdata);
+ ctlr->csr6 = (command & 0x71) << 18;
+ csr32w(ctlr, 6, ctlr->csr6);
+ return 0;
+}
+
+static int
+type2mode(Ctlr* ctlr, uchar* block, int)
+{
+ uchar *p;
+ int csr6, csr13, csr14, csr15, gpc, gpd;
+
+ csr6 = Sc|Mbo|Ca|Sb|TrMODE;
+ debug("type2mode: medium 0x%2.2uX\n", block[2]);
+
+ /*
+ * Don't attempt full-duplex
+ * unless explicitly requested.
+ */
+ if((block[2] & 0x3F) == 0x04){ /* 10BASE-TFD */
+ if(!ctlr->fd)
+ return -1;
+ csr6 |= Fd;
+ }
+
+ /*
+ * Operating mode programming values from the datasheet
+ * unless media specific data is explicitly given.
+ */
+ p = &block[3];
+ if(block[2] & 0x40){
+ csr13 = (block[4]<<8)|block[3];
+ csr14 = (block[6]<<8)|block[5];
+ csr15 = (block[8]<<8)|block[7];
+ p += 6;
+ }
+ else switch(block[2] & 0x3F){
+ default:
+ return -1;
+ case 0x00: /* 10BASE-T */
+ csr13 = 0x00000001;
+ csr14 = 0x00007F3F;
+ csr15 = 0x00000008;
+ break;
+ case 0x01: /* 10BASE-2 */
+ csr13 = 0x00000009;
+ csr14 = 0x00000705;
+ csr15 = 0x00000006;
+ break;
+ case 0x02: /* 10BASE-5 (AUI) */
+ csr13 = 0x00000009;
+ csr14 = 0x00000705;
+ csr15 = 0x0000000E;
+ break;
+ case 0x04: /* 10BASE-TFD */
+ csr13 = 0x00000001;
+ csr14 = 0x00007F3D;
+ csr15 = 0x00000008;
+ break;
+ }
+ gpc = *p++<<16;
+ gpc |= *p++<<24;
+ gpd = *p++<<16;
+ gpd |= *p<<24;
+
+ csr32w(ctlr, 13, 0);
+ csr32w(ctlr, 14, csr14);
+ csr32w(ctlr, 15, gpc|csr15);
+ delay(10);
+ csr32w(ctlr, 15, gpd|csr15);
+ csr32w(ctlr, 13, csr13);
+
+ ctlr->csr6 = csr6;
+ csr32w(ctlr, 6, ctlr->csr6);
+
+ debug("type2mode: csr13 %8.8uX csr14 %8.8uX csr15 %8.8uX\n",
+ csr13, csr14, csr15);
+ debug("type2mode: gpc %8.8uX gpd %8.8uX csr6 %8.8uX\n",
+ gpc, gpd, csr6);
+
+ return 0;
+}
+
+static int
+type0link(Ctlr* ctlr, uchar* block)
+{
+ int m, polarity, sense;
+
+ m = (block[3]<<8)|block[2];
+ sense = 1<<((m & 0x000E)>>1);
+ if(m & 0x0080)
+ polarity = sense;
+ else
+ polarity = 0;
+
+ return (csr32r(ctlr, 12) & sense)^polarity;
+}
+
+static int
+type0mode(Ctlr* ctlr, uchar* block, int wait)
+{
+ int csr6, m, timeo;
+
+ csr6 = Sc|Mbo|Hbd|Ca|Sb|TrMODE;
+debug("type0: medium 0x%uX, fd %d: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
+ ctlr->medium, ctlr->fd, block[0], block[1], block[2], block[3]);
+ switch(block[0]){
+ default:
+ break;
+
+ case 0x04: /* 10BASE-TFD */
+ case 0x05: /* 100BASE-TXFD */
+ case 0x08: /* 100BASE-FXFD */
+ /*
+ * Don't attempt full-duplex
+ * unless explicitly requested.
+ */
+ if(!ctlr->fd)
+ return -1;
+ csr6 |= Fd;
+ break;
+ }
+
+ m = (block[3]<<8)|block[2];
+ if(m & 0x0001)
+ csr6 |= Ps;
+ if(m & 0x0010)
+ csr6 |= Ttm;
+ if(m & 0x0020)
+ csr6 |= Pcs;
+ if(m & 0x0040)
+ csr6 |= Scr;
+
+ csr32w(ctlr, 12, block[1]);
+ microdelay(10);
+ csr32w(ctlr, 6, csr6);
+ ctlr->csr6 = csr6;
+
+ if(!wait)
+ return 0;
+
+ for(timeo = 0; timeo < 30; timeo++){
+ if(type0link(ctlr, block))
+ return 0;
+ delay(100);
+ }
+
+ return -1;
+}
+
+static int
+mediaxx(Ether* ether, int wait)
+{
+ Ctlr* ctlr;
+ uchar *block;
+
+ ctlr = ether->ctlr;
+ block = ctlr->infoblock[ctlr->curk];
+ if(block[0] & 0x80){
+ switch(block[1]){
+ default:
+ return -1;
+ case 0:
+ if(ctlr->medium >= 0 && block[2] != ctlr->medium)
+ return 0;
+/* need this test? */ if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[2])
+ return 0;
+ if(type0mode(ctlr, block+2, wait))
+ return 0;
+ break;
+ case 1:
+ if(typephymode(ctlr, block, wait))
+ return 0;
+ break;
+ case 2:
+ debug("type2: medium %d block[2] %d\n",
+ ctlr->medium, block[2]);
+ if(ctlr->medium >= 0 && ((block[2] & 0x3F) != ctlr->medium))
+ return 0;
+ if(type2mode(ctlr, block, wait))
+ return 0;
+ break;
+ case 3:
+ if(typephymode(ctlr, block, wait))
+ return 0;
+ break;
+ case 4:
+ debug("type4: medium %d block[2] %d\n",
+ ctlr->medium, block[2]);
+ if(ctlr->medium >= 0 && ((block[2] & 0x3F) != ctlr->medium))
+ return 0;
+ if(typesymmode(ctlr, block, wait))
+ return 0;
+ break;
+ }
+ }
+ else{
+ if(ctlr->medium >= 0 && block[0] != ctlr->medium)
+ return 0;
+/* need this test? */if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[0])
+ return 0;
+ if(type0mode(ctlr, block, wait))
+ return 0;
+ }
+
+ if(ctlr->csr6){
+ if(!(ctlr->csr6 & Ps) || (ctlr->csr6 & Ttm))
+ return 10;
+ return 100;
+ }
+
+ return 0;
+}
+
+static int
+media(Ether* ether, int wait)
+{
+ Ctlr* ctlr;
+ int k, mbps;
+
+ ctlr = ether->ctlr;
+ for(k = 0; k < ctlr->k; k++){
+ mbps = mediaxx(ether, wait);
+ if(mbps > 0)
+ return mbps;
+ if(ctlr->curk == 0)
+ ctlr->curk = ctlr->k-1;
+ else
+ ctlr->curk--;
+ }
+
+ return 0;
+}
+
+static char* mediatable[9] = {
+ "10BASE-T", /* TP */
+ "10BASE-2", /* BNC */
+ "10BASE-5", /* AUI */
+ "100BASE-TX",
+ "10BASE-TFD",
+ "100BASE-TXFD",
+ "100BASE-T4",
+ "100BASE-FX",
+ "100BASE-FXFD",
+};
+
+static uchar en1207[] = { /* Accton EN1207-COMBO */
+ 0x00, 0x00, 0xE8, /* [0] vendor ethernet code */
+ 0x00, /* [3] spare */
+
+ 0x00, 0x08, /* [4] connection (LSB+MSB = 0x0800) */
+ 0x1F, /* [6] general purpose control */
+ 2, /* [7] block count */
+
+ 0x00, /* [8] media code (10BASE-TX) */
+ 0x0B, /* [9] general purpose port data */
+ 0x9E, 0x00, /* [10] command (LSB+MSB = 0x009E) */
+
+ 0x03, /* [8] media code (100BASE-TX) */
+ 0x1B, /* [9] general purpose port data */
+ 0x6D, 0x00, /* [10] command (LSB+MSB = 0x006D) */
+
+ /* There is 10BASE-2 as well, but... */
+};
+
+static uchar ana6910fx[] = { /* Adaptec (Cogent) ANA-6910FX */
+ 0x00, 0x00, 0x92, /* [0] vendor ethernet code */
+ 0x00, /* [3] spare */
+
+ 0x00, 0x08, /* [4] connection (LSB+MSB = 0x0800) */
+ 0x3F, /* [6] general purpose control */
+ 1, /* [7] block count */
+
+ 0x07, /* [8] media code (100BASE-FX) */
+ 0x03, /* [9] general purpose port data */
+ 0x2D, 0x00 /* [10] command (LSB+MSB = 0x000D) */
+};
+
+static uchar smc9332[] = { /* SMC 9332 */
+ 0x00, 0x00, 0xC0, /* [0] vendor ethernet code */
+ 0x00, /* [3] spare */
+
+ 0x00, 0x08, /* [4] connection (LSB+MSB = 0x0800) */
+ 0x1F, /* [6] general purpose control */
+ 2, /* [7] block count */
+
+ 0x00, /* [8] media code (10BASE-TX) */
+ 0x00, /* [9] general purpose port data */
+ 0x9E, 0x00, /* [10] command (LSB+MSB = 0x009E) */
+
+ 0x03, /* [8] media code (100BASE-TX) */
+ 0x09, /* [9] general purpose port data */
+ 0x6D, 0x00, /* [10] command (LSB+MSB = 0x006D) */
+};
+
+static uchar* leaf21140[] = {
+ en1207, /* Accton EN1207-COMBO */
+ ana6910fx, /* Adaptec (Cogent) ANA-6910FX */
+ smc9332, /* SMC 9332 */
+ nil,
+};
+
+/*
+ * Copied to ctlr->srom at offset 20.
+ */
+static uchar leafpnic[] = {
+ 0x00, 0x00, 0x00, 0x00, /* MAC address */
+ 0x00, 0x00,
+ 0x00, /* controller 0 device number */
+ 0x1E, 0x00, /* controller 0 info leaf offset */
+ 0x00, /* reserved */
+ 0x00, 0x08, /* selected connection type */
+ 0x00, /* general purpose control */
+ 0x01, /* block count */
+
+ 0x8C, /* format indicator and count */
+ 0x01, /* block type */
+ 0x00, /* PHY number */
+ 0x00, /* GPR sequence length */
+ 0x00, /* reset sequence length */
+ 0x00, 0x78, /* media capabilities */
+ 0xE0, 0x01, /* Nway advertisment */
+ 0x00, 0x50, /* FDX bitmap */
+ 0x00, 0x18, /* TTM bitmap */
+};
+
+static int
+srom(Ctlr* ctlr)
+{
+ int i, k, oui, phy, x;
+ uchar *p;
+
+ /*
+ * This is a partial decoding of the SROM format described in
+ * 'Digital Semiconductor 21X4 Serial ROM Format, Version 4.05,
+ * 2-Mar-98'. Only the 2114[03] are handled, support for other
+ * controllers can be added as needed.
+ * Do a dummy read first to get the size and allocate ctlr->srom.
+ */
+ sromr(ctlr, 0);
+ if(ctlr->srom == nil)
+ ctlr->srom = malloc((1<<ctlr->sromsz)*sizeof(ushort));
+ for(i = 0; i < (1<<ctlr->sromsz); i++){
+ x = sromr(ctlr, i);
+ ctlr->srom[2*i] = x;
+ ctlr->srom[2*i+1] = x>>8;
+ }
+
+ /*
+ * There are 2 SROM layouts:
+ * e.g. Digital EtherWORKS station address at offset 20;
+ * this complies with the 21140A SROM
+ * application note from Digital;
+ * e.g. SMC9332 station address at offset 0 followed by
+ * 2 additional bytes, repeated at offset
+ * 6; the 8 bytes are also repeated in
+ * reverse order at offset 8.
+ * To check which it is, read the SROM and check for the repeating
+ * patterns of the non-compliant cards; if that fails use the one at
+ * offset 20.
+ */
+ ctlr->sromea = ctlr->srom;
+ for(i = 0; i < 8; i++){
+ x = ctlr->srom[i];
+ if(x != ctlr->srom[15-i] || x != ctlr->srom[16+i]){
+ ctlr->sromea = &ctlr->srom[20];
+ break;
+ }
+ }
+
+ /*
+ * Fake up the SROM for the PNIC.
+ * It looks like a 21140 with a PHY.
+ * The MAC address is byte-swapped in the orginal SROM data.
+ */
+ if(ctlr->id == Pnic){
+ memmove(&ctlr->srom[20], leafpnic, sizeof(leafpnic));
+ for(i = 0; i < Eaddrlen; i += 2){
+ ctlr->srom[20+i] = ctlr->srom[i+1];
+ ctlr->srom[20+i+1] = ctlr->srom[i];
+ }
+ }
+
+ /*
+ * Next, try to find the info leaf in the SROM for media detection.
+ * If it's a non-conforming card try to match the vendor ethernet code
+ * and point p at a fake info leaf with compact 21140 entries.
+ */
+ if(ctlr->sromea == ctlr->srom){
+ p = nil;
+ for(i = 0; leaf21140[i] != nil; i++){
+ if(memcmp(leaf21140[i], ctlr->sromea, 3) == 0){
+ p = &leaf21140[i][4];
+ break;
+ }
+ }
+ if(p == nil)
+ return -1;
+ }
+ else
+ p = &ctlr->srom[(ctlr->srom[28]<<8)|ctlr->srom[27]];
+
+ /*
+ * Set up the info needed for later media detection.
+ * For the 21140, set the general-purpose mask in CSR12.
+ * The info block entries are stored in order of increasing
+ * precedence, so detection will work backwards through the
+ * stored indexes into ctlr->srom.
+ * If an entry is found which matches the selected connection
+ * type, save the index. Otherwise, start at the last entry.
+ * If any MII entries are found (type 1 and 3 blocks), scan
+ * for PHYs.
+ */
+ ctlr->leaf = p;
+ ctlr->sct = *p++;
+ ctlr->sct |= *p++<<8;
+ if(ctlr->id != Tulip3){
+ csr32w(ctlr, 12, Gpc|*p++);
+ delay(200);
+ }
+ ctlr->k = *p++;
+ if(ctlr->k >= nelem(ctlr->infoblock))
+ ctlr->k = nelem(ctlr->infoblock)-1;
+ ctlr->sctk = ctlr->k-1;
+ phy = 0;
+ for(k = 0; k < ctlr->k; k++){
+ ctlr->infoblock[k] = p;
+ /*
+ * The RAMIX PMC665 has a badly-coded SROM,
+ * hence the test for 21143 and type 3.
+ */
+ if((*p & 0x80) || (ctlr->id == Tulip3 && *(p+1) == 3)){
+ *p |= 0x80;
+ if(*(p+1) == 1 || *(p+1) == 3)
+ phy = 1;
+ if(*(p+1) == 5)
+ ctlr->type5block = p;
+ p += (*p & ~0x80)+1;
+ }
+ else{
+ debug("type0: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
+ p[0], p[1], p[2], p[3]);
+ if(ctlr->sct != 0x0800 && *p == (ctlr->sct & 0xFF))
+ ctlr->sctk = k;
+ p += 4;
+ }
+ }
+ ctlr->curk = ctlr->sctk;
+ debug("sct 0x%uX medium 0x%uX k %d curk %d phy %d\n",
+ ctlr->sct, ctlr->medium, ctlr->k, ctlr->curk, phy);
+
+ if(phy){
+ x = 0;
+ for(k = 0; k < nelem(ctlr->phy); k++){
+ if((oui = miir(ctlr, k, 2)) == -1 || oui == 0)
+ continue;
+ if(DEBUG){
+ oui = (oui & 0x3FF)<<6;
+ oui |= miir(ctlr, k, 3)>>10;
+ miir(ctlr, k, 1);
+ debug("phy%d: index %d oui %uX reg1 %uX\n",
+ x, k, oui, miir(ctlr, k, 1));
+ USED(oui);
+ }
+ ctlr->phy[x] = k;
+ }
+ }
+
+ ctlr->fd = 0;
+ ctlr->medium = -1;
+
+ return 0;
+}
+
+static void
+dec2114xpci(void)
+{
+ Ctlr *ctlr;
+ Pcidev *p;
+ int x;
+
+ p = nil;
+ while(p = pcimatch(p, 0, 0)){
+ if(p->ccrb != 0x02 || p->ccru != 0)
+ continue;
+ switch((p->did<<16)|p->vid){
+ default:
+ continue;
+
+ case Tulip3: /* 21143 */
+ /*
+ * Exit sleep mode.
+ */
+ x = pcicfgr32(p, 0x40);
+ x &= ~0xc0000000;
+ pcicfgw32(p, 0x40, x);
+ /*FALLTHROUGH*/
+
+ case Pnic: /* PNIC */
+ case Pnic2: /* PNIC-II */
+ case Tulip0: /* 21140 */
+ break;
+ }
+
+ /*
+ * bar[0] is the I/O port register address and
+ * bar[1] is the memory-mapped register address.
+ */
+ ctlr = malloc(sizeof(Ctlr));
+ ctlr->port = p->mem[0].bar & ~0x01;
+ ctlr->pcidev = p;
+ ctlr->id = (p->did<<16)|p->vid;
+
+ if(ioalloc(ctlr->port, p->mem[0].size, 0, "dec2114x") < 0){
+ print("dec2114x: port 0x%uX in use\n", ctlr->port);
+ free(ctlr);
+ continue;
+ }
+
+ /*
+ * Some cards (e.g. ANA-6910FX) seem to need the Ps bit
+ * set or they don't always work right after a hardware
+ * reset.
+ */
+ csr32w(ctlr, 6, Mbo|Ps);
+ softreset(ctlr);
+
+ if(srom(ctlr)){
+ iofree(ctlr->port);
+ free(ctlr);
+ continue;
+ }
+
+ switch(ctlr->id){
+ default:
+ break;
+
+ case Pnic: /* PNIC */
+ /*
+ * Turn off the jabber timer.
+ */
+ csr32w(ctlr, 15, 0x00000001);
+ break;
+ }
+
+ if(ctlrhead != nil)
+ ctlrtail->next = ctlr;
+ else
+ ctlrhead = ctlr;
+ ctlrtail = ctlr;
+ }
+}
+
+static int
+reset(Ether* ether)
+{
+ Ctlr *ctlr;
+ int i, x;
+ uchar ea[Eaddrlen];
+ static int scandone;
+
+ if(scandone == 0){
+ dec2114xpci();
+ scandone = 1;
+ }
+
+ /*
+ * Any adapter matches if no ether->port is supplied,
+ * otherwise the ports must match.
+ */
+ for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
+ if(ctlr->active)
+ continue;
+ if(ether->port == 0 || ether->port == ctlr->port){
+ ctlr->active = 1;
+ break;
+ }
+ }
+ if(ctlr == nil)
+ return -1;
+
+ ether->ctlr = ctlr;
+ ether->port = ctlr->port;
+ ether->irq = ctlr->pcidev->intl;
+ ether->tbdf = ctlr->pcidev->tbdf;
+
+ /*
+ * 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 the hardware.
+ */
+ memset(ea, 0, Eaddrlen);
+ if(memcmp(ea, ether->ea, Eaddrlen) == 0)
+ memmove(ether->ea, ctlr->sromea, Eaddrlen);
+
+ /*
+ * Look for a medium override in case there's no autonegotiation
+ * (no MII) or the autonegotiation fails.
+ */
+ for(i = 0; i < ether->nopt; i++){
+ if(cistrcmp(ether->opt[i], "FD") == 0){
+ ctlr->fd = 1;
+ continue;
+ }
+ for(x = 0; x < nelem(mediatable); x++){
+ debug("compare <%s> <%s>\n", mediatable[x],
+ ether->opt[i]);
+ if(cistrcmp(mediatable[x], ether->opt[i]))
+ continue;
+ ctlr->medium = x;
+
+ switch(ctlr->medium){
+ default:
+ ctlr->fd = 0;
+ break;
+
+ case 0x04: /* 10BASE-TFD */
+ case 0x05: /* 100BASE-TXFD */
+ case 0x08: /* 100BASE-FXFD */
+ ctlr->fd = 1;
+ break;
+ }
+ break;
+ }
+ }
+
+ ether->mbps = media(ether, 1);
+
+ /*
+ * Initialise descriptor rings, ethernet address.
+ */
+ ctlr->nrdr = Nrde;
+ ctlr->ntdr = Ntde;
+ pcisetbme(ctlr->pcidev);
+ ctlrinit(ether);
+
+ /*
+ * Linkage to the generic ethernet driver.
+ */
+ ether->attach = attach;
+ ether->transmit = transmit;
+ ether->interrupt = interrupt;
+ ether->ifstat = ifstat;
+
+ ether->arg = ether;
+ ether->promiscuous = promiscuous;
+
+ return 0;
+}
+
+void
+ether2114xlink(void)
+{
+ addethercard("21140", reset);
+ addethercard("2114x", reset);
+}
A mtx/etherif.h => mtx/etherif.h +36 -0
@@ 0,0 1,36 @@
+enum {
+ MaxEther = 24,
+ Ntypes = 8,
+};
+
+typedef struct Ether Ether;
+struct Ether {
+ ISAConf; /* hardware info */
+
+ int ctlrno;
+ int tbdf; /* type+busno+devno+funcno */
+ int mbps; /* Mbps */
+ int minmtu;
+ int maxmtu;
+ uchar ea[Eaddrlen];
+
+ void (*attach)(Ether*); /* filled in by reset routine */
+ void (*transmit)(Ether*);
+ void (*interrupt)(Ureg*, void*);
+ long (*ifstat)(Ether*, void*, long, ulong);
+ long (*ctl)(Ether*, void*, long); /* custom ctl messages */
+ void *ctlr;
+
+ Queue* oq;
+
+ Netif;
+};
+
+extern Block* etheriq(Ether*, Block*, int);
+extern void addethercard(char*, int(*)(Ether*));
+extern ulong ethercrc(uchar*, int);
+
+#define NEXT(x, l) (((x)+1)%(l))
+#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
+#define HOWMANY(x, y) (((x)+((y)-1))/(y))
+#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
M mtx/main.c => mtx/main.c +11 -3
@@ 80,6 80,7 @@ static struct
plan9ini[] =
{
{ "console", "0" },
+ { "ether0", "type=2114x" },
};
char*
@@ 115,11 116,11 @@ init0(void)
chandevinit();
if(!waserror()){
- ksetenv("cputype", "power");
+ ksetenv("cputype", "power", 0);
if(cpuserver)
- ksetenv("service", "cpu");
+ ksetenv("service", "cpu", 0);
else
- ksetenv("service", "terminal");
+ ksetenv("service", "terminal", 0);
/*
for(p = confenv; *p; p++) {
@@ 195,6 196,13 @@ userinit(void)
ready(p);
}
+/* still to do */
+void
+reboot(void*, void*, ulong)
+{
+ exit(0);
+}
+
void
exit(int ispanic)
{
M mtx/trap.c => mtx/trap.c +3 -0
@@ 24,6 24,7 @@ hwintrenable(Vctl *v)
irq = v->irq;
if(BUSTYPE(v->tbdf) == BusPCI) { /* MPIC? */
+print("add PCI intr %d\n", irq);
if(irq > 15) {
print("intrenable: pci irq %d out of range\n", v->irq);
return -1;
@@ 32,6 33,7 @@ hwintrenable(Vctl *v)
mpicenable(vec, v);
}
else {
+print("add pic intr %d\n", irq);
if(irq > MaxIrqPIC) {
print("intrenable: irq %d out of range\n", v->irq);
return -1;
@@ 348,6 350,7 @@ intr(Ureg *ureg)
vno = i8259intack();
mpiceoi(0);
}
+else print("non-pic %d\n", vno);
if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
panic("spurious intr %d", vno);
M pc/apbootstrap.s => pc/apbootstrap.s +3 -6
@@ 15,8 15,6 @@
#define INVD BYTE $0x0F; BYTE $0x08
#define WBINVD BYTE $0x0F; BYTE $0x09
-#define PADDR(a) ((a) & ~KZERO)
-
/*
* Macros for calculating offsets within the page directory base
* and page tables. Note that these are assembler-specific hence
@@ 64,9 62,8 @@ TEXT _apbootstrap(SB), $0 /* address APBOOTSTRAP+0x14 */
FARJUMP32(SELECTOR(2, SELGDT, 0), _ap32-KZERO(SB))
/*
- * There's a little mystery here - the Pentium Pro appears to need an identity
- * mmu map for the switch to virtual mode. The manual doesn't say this is necessary
- * and it isn't required on the Pentium.
+ * For Pentiums and higher, the code that enables paging must come from
+ * pages that are identity mapped.
* To this end double map KZERO at virtual 0 and undo the mapping once virtual
* nirvana has been obtained.
*/
@@ 109,5 106,5 @@ TEXT gdt(SB), $0
LONG $0xFFFF; LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
LONG $0xFFFF; LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
TEXT gdtptr(SB), $0
- WORD $(3*8)
+ WORD $(3*8-1)
LONG $gdt-KZERO(SB)
M pc/apm.c => pc/apm.c +0 -14
@@ 64,19 64,6 @@ setgdt(int sel, ulong base, ulong limit, int flag)
((base>>16)&0xFF) | SEGP | SEGPL(0) | flag;
}
-static void
-loadgdt(void)
-{
- ulong x;
- ushort ptr[3];
-
- ptr[0] = sizeof(m->gdt);
- x = (ulong)m->gdt;
- ptr[1] = x & 0xFFFF;
- ptr[2] = (x>>16) & 0xFFFF;
- lgdt(ptr);
-}
-
static ulong ax, cx, dx, di, ebx, esi;
static Ureg apmu;
static long
@@ 154,7 141,6 @@ apmlink(void)
setgdt(APMCSEG, ax<<4, ((esi&0xFFFF)-1)&0xFFFF, SEGEXEC|SEGR|SEGD);
setgdt(APMCSEG16, cx<<4, ((esi>>16)-1)&0xFFFF, SEGEXEC|SEGR);
setgdt(APMDSEG, dx<<4, (di-1)&0xFFFF, SEGDATA|SEGW|SEGD);
- loadgdt();
addarchfile("apm", 0660, apmread, apmwrite);
M pc/dat.h => pc/dat.h +1 -1
@@ 84,7 84,7 @@ struct Conf
ulong copymode; /* 0 is copy on write, 1 is copy on reference */
ulong ialloc; /* max interrupt time allocation in bytes */
ulong pipeqsize; /* size in bytes of pipe queues */
- int nuart; /* number of uart devices */
+ int nuart; /* number of uart devices */
};
/*
M pc/devarch.c => pc/devarch.c +1 -0
@@ 461,6 461,7 @@ Dev archdevtab = {
devreset,
devinit,
+ devshutdown,
archattach,
archwalk,
archstat,
M pc/devether.c => pc/devether.c +20 -0
@@ 425,6 425,25 @@ etherreset(void)
free(ether);
}
+static void
+ethershutdown(void)
+{
+ Ether *ether;
+ int i;
+
+ for(i = 0; i < MaxEther; i++){
+ ether = etherxx[i];
+ if(ether == nil)
+ continue;
+ if(ether->shutdown == nil) {
+ print("#l%d: no shutdown fuction\n", i);
+ continue;
+ }
+ (*ether->shutdown)(ether);
+ }
+}
+
+
#define POLY 0xedb88320
/* really slow 32 bit crc for ethers */
@@ 451,6 470,7 @@ Dev etherdevtab = {
etherreset,
devinit,
+ ethershutdown,
etherattach,
etherwalk,
etherstat,
M pc/devfloppy.c => pc/devfloppy.c +1 -0
@@ 1061,6 1061,7 @@ Dev floppydevtab = {
floppyreset,
devinit,
+ devshutdown,
floppyattach,
floppywalk,
floppystat,
M pc/devi82365.c => pc/devi82365.c +1 -0
@@ 870,6 870,7 @@ Dev i82365devtab = {
devreset,
devinit,
+ devshutdown,
i82365attach,
i82365walk,
i82365stat,
M pc/devlml.c => pc/devlml.c +2 -1
@@ 318,7 318,8 @@ Dev lmldevtab = {
"video",
lmlreset,
- devinit,
+ devinit,
+ devshutdown,
lmlattach,
lmlwalk,
lmlstat,
M pc/devlpt.c => pc/devlpt.c +1 -0
@@ 229,6 229,7 @@ Dev lptdevtab = {
devreset,
devinit,
+ devshutdown,
lptattach,
lptwalk,
lptstat,
M pc/devpccard.c => pc/devpccard.c +2 -1
@@ 1367,7 1367,8 @@ Dev pccarddevtab = {
"cardbus",
devreset,
- devinit,
+ devinit,
+ devshutdown,
pccardattach,
pccardwalk,
pccardstat,
M pc/devrtc.c => pc/devrtc.c +1 -0
@@ 308,6 308,7 @@ Dev rtcdevtab = {
devreset,
rtcinit,
+ devshutdown,
rtcattach,
rtcwalk,
rtcstat,
M pc/devusb.c => pc/devusb.c +1 -0
@@ 2307,6 2307,7 @@ Dev usbdevtab = {
usbreset,
usbinit,
+ devshutdown,
usbattach,
usbwalk,
usbstat,
M pc/devvga.c => pc/devvga.c +1 -0
@@ 447,6 447,7 @@ Dev vgadevtab = {
vgareset,
devinit,
+ devshutdown,
vgaattach,
vgawalk,
vgastat,
M pc/ether82543gc.c => pc/ether82543gc.c +8 -0
@@ 861,6 861,13 @@ gc82543detach(Ctlr* ctlr)
;
}
+static void
+gc82543shutdown(Ether* ether)
+{
+print("gc82543shutdown\n");
+ gc82543detach(ether->ctlr);
+}
+
static int
gc82543reset(Ctlr* ctlr)
{
@@ 994,6 1001,7 @@ gc82543pnp(Ether* edev)
edev->transmit = gc82543transmit;
edev->interrupt = gc82543interrupt;
edev->ifstat = gc82543ifstat;
+ edev->shutdown = gc82543shutdown;
edev->arg = edev;
edev->promiscuous = nil;
M pc/ether82557.c => pc/ether82557.c +13 -0
@@ 973,6 973,18 @@ scanphy(Ctlr* ctlr)
return -1;
}
+static void
+shutdown(Ether* ether)
+{
+ Ctlr *ctlr = ether->ctlr;
+
+print("ether82557 shutting down\n");
+ csr32w(ctlr, Port, 0);
+ delay(1);
+ csr8w(ctlr, Interrupt, InterruptM);
+}
+
+
static int
reset(Ether* ether)
{
@@ 1247,6 1259,7 @@ reset(Ether* ether)
ether->transmit = transmit;
ether->interrupt = interrupt;
ether->ifstat = ifstat;
+ ether->shutdown = shutdown;
ether->promiscuous = promiscuous;
ether->multicast = multicast;
M pc/etherif.h => pc/etherif.h +1 -0
@@ 19,6 19,7 @@ struct Ether {
void (*interrupt)(Ureg*, void*);
long (*ifstat)(Ether*, void*, long, ulong);
long (*ctl)(Ether*, void*, long); /* custom ctl messages */
+ void (*shutdown)(Ether*); /* shutdown hardware before reboot */
void *ctlr;
Queue* oq;
M pc/floppy.h => pc/floppy.h +0 -1
@@ 164,7 164,6 @@ floppysetup1(FController *fl)
fl->d[1].dt = equip & 0xf;
floppysetdef(&fl->d[1]);
}
-
intrenable(IrqFLOPPY, pcfloppyintr, fl, BUSUNKNOWN, "floppy");
}
M pc/fns.h => pc/fns.h +2 -2
@@ 1,7 1,6 @@
#include "../port/portfns.h"
void aamloop(int);
-void addconf(char*, char*);
Dirtab* addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,void*,long,vlong));
//void addscsilink(char*, Scsiio (*)(int, ISAConf*));
void archinit(void);
@@ 74,8 73,9 @@ void lgdt(ushort[3]);
void lidt(ushort[3]);
void links(void);
void ltr(ulong);
+void mach0init(void);
void mathinit(void);
-void meminit(ulong);
+void meminit(void);
#define mmuflushtlb(pdb) putcr3(pdb)
void mmuinit(void);
ulong mmukmap(ulong, ulong, int);
A pc/initcode.s => pc/initcode.s +23 -0
@@ 0,0 1,23 @@
+#include "/sys/src/libc/9syscall/sys.h"
+
+TEXT main(SB),$0
+
+ /*
+ * exec("/boot", bootv)
+ */
+ LEAL 4(SP),AX
+ PUSHL AX
+ LEAL boot(SB),AX
+ PUSHL AX
+ PUSHL $0
+ MOVL $EXEC,AX
+ INT $64
+
+ /*
+ * should never get here
+ */
+here:
+ JMP here
+
+GLOBL boot+0(SB),$6
+DATA boot+0(SB)/5,$"/boot"
M pc/l.s => pc/l.s +27 -34
@@ 24,29 24,29 @@
#define PTO(a) (((((a))>>12) & 0x03FF)<<2)
/*
- * Entered here from the bootstrap programme possibly via a jump to 0x00100020, so
- * need to make another jump to set the correct virtual address.
- * In protected mode with paging turned on, the first 4MB of physical memory mapped
- * to KZERO and up.
+ * For backwards compatiblity with 9load - should go away when 9load is changed
+ * 9load currently sets up the mmu, however the first 16MB of memory is identity
+ * mapped, so behave as if the mmu was not setup
*/
-TEXT _start0x00100020(SB),$0
- CLI
- MOVL $_start0x80100020(SB), AX
+TEXT _start0x80100020(SB),$0
+ MOVL $_start0x00100020(SB), AX
+ ANDL $~KZERO, AX
JMP* AX
-
/*
- * First check if the bootstrap programme left the first 4MB nicely mapped, otherwise
- * make the basic page tables for processor 0. Four pages are needed for the basic set:
- * a page directory, a page table for mapping the first 4MB of physical memory, and
- * virtual and physical pages for mapping the Mach structure.
+ * In protected mode with paging turned off and segment registers setup to linear map all memory.
+ * Entered via a jump to 0x00100020, the physical address of the virtual kernel entry point of 0x80100020
+ * Make the basic page tables for processor 0. Four pages are needed for the basic set:
+ * a page directory, a page table for mapping the first 4MB of physical memory to KZERO,
+ * and virtual and physical pages for mapping the Mach structure.
* The remaining PTEs will be allocated later when memory is sized.
+ * An identity mmu map is also needed for the switch to virtual mode. This
+ * identity mapping is removed once the MMU is going and the JMP has been made
+ * to virtual memory.
*/
-TEXT _start0x80100020(SB), $0
- MOVL CR3, AX /* check the page directory base */
- CMPL AX, $PADDR(CPU0PDB)
- JEQ _clearbss
+TEXT _start0x00100020(SB),$0
+ CLI /* make sure interrupts are off */
- MOVL $CPU0PDB, DI /* clear 4 pages for the tables etc. */
+ MOVL $PADDR(CPU0PDB), DI /* clear 4 pages for the tables etc. */
XORL AX, AX
MOVL $(4*BY2PG), CX
SHRL $2, CX
@@ 54,13 54,13 @@ TEXT _start0x80100020(SB), $0
CLD
REP; STOSL
- MOVL $CPU0PDB, AX
+ MOVL $PADDR(CPU0PDB), AX
ADDL $PDO(KZERO), AX /* page directory offset for KZERO */
MOVL $PADDR(CPU0PTE), (AX) /* PTE's for 0x80000000 */
MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */
ORL BX, (AX)
- MOVL $CPU0PTE, AX /* first page of page table */
+ MOVL $PADDR(CPU0PTE), AX /* first page of page table */
MOVL $1024, CX /* 1024 pages in 4MB */
_setpte:
MOVL BX, (AX)
@@ 68,7 68,7 @@ _setpte:
ADDL $4, AX
LOOP _setpte
- MOVL $CPU0PTE, AX
+ MOVL $PADDR(CPU0PTE), AX
ADDL $PTO(MACHADDR), AX /* page table entry offset for MACHADDR */
MOVL $PADDR(CPU0MACH), (AX) /* PTE for Mach */
MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */
@@ 76,18 76,12 @@ _setpte:
/*
* Now ready to use the new map. Make sure the processor options are what is wanted.
- * It is necessary on some processors to follow mode switching with a JMP instruction
+ * It is necessary on some processors to immediately follow mode switching with a JMP instruction
* to clear the prefetch queues.
- * There's a little mystery here - the Pentium Pro appears to need an identity
- * mmu map for the switch to virtual mode. The manual doesn't say this is necessary
- * and it isn't required on the Pentium.
- * To this end double map KZERO at virtual 0 and undo the mapping once virtual
- * nirvana has been attained.
*/
MOVL $PADDR(CPU0PDB), CX /* load address of page directory */
- MOVL CX, BX
- MOVL (PDO(KZERO))(BX), DX /* double-map KZERO at 0 */
- MOVL DX, (PDO(0))(BX)
+ MOVL (PDO(KZERO))(CX), DX /* double-map KZERO at 0 */
+ MOVL DX, (PDO(0))(CX)
MOVL CX, CR3
DELAY /* JMP .+2 */
@@ 95,9 89,9 @@ _setpte:
ORL $0x80010000, DX /* PG|WP */
ANDL $~0x6000000A, DX /* ~(CD|NW|TS|MP) */
- MOVL $_startpg(SB), AX
+ MOVL $_startpg(SB), AX /* this is a virtual address */
MOVL DX, CR0 /* turn on paging */
- JMP* AX
+ JMP* AX /* jump to the virtual nirvana */
/*
* Basic machine environment set, can clear BSS and create a stack.
@@ 107,9 101,7 @@ _setpte:
* be initialised here.
*/
TEXT _startpg(SB), $0
- MOVL CX, AX /* physical address of PDB */
- ORL $KZERO, AX
- MOVL $0, (PDO(0))(AX) /* undo double-map of KZERO at 0 */
+ MOVL $0, (PDO(0))(CX) /* undo double-map of KZERO at 0 */
MOVL CX, CR3 /* load and flush the mmu */
_clearbss:
@@ 126,6 118,7 @@ _clearbss:
MOVL SP, m(SB) /* initialise global Mach pointer */
MOVL $0, 0(SP) /* initialise m->machno */
+
ADDL $(MACHSIZE-4), SP /* initialise stack */
/*
M pc/main.c => pc/main.c +135 -80
@@ 7,27 7,28 @@
#include "ureg.h"
#include "init.h"
#include "pool.h"
+#include "reboot.h"
Mach *m;
-static uchar *sp; /* stack pointer for /boot */
-
/*
* Where configuration info is left for the loaded programme.
* This will turn into a structure as more is done by the boot loader
* (e.g. why parse the .ini file twice?).
- * There are XXX bytes available at CONFADDR.
+ * There are 3584 bytes available at CONFADDR.
*/
#define BOOTLINE ((char*)CONFADDR)
#define BOOTLINELEN 64
#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN))
#define BOOTARGSLEN (4096-0x200-BOOTLINELEN)
-#define MAXCONF 32
+#define MAXCONF 64
char bootdisk[KNAMELEN];
+Conf conf;
char *confname[MAXCONF];
char *confval[MAXCONF];
int nconf;
+uchar *sp; /* user stack of init proc */
static void
options(void)
@@ 71,18 72,16 @@ options(void)
void
main(void)
{
- conf.nmach = 1;
- MACHP(0) = (Mach*)CPU0MACH;
- m->pdb = (ulong*)CPU0PDB;
- machinit();
- active.machs = 1;
- active.exiting = 0;
+ mach0init();
options();
ioinit();
i8250console();
+
print("\nPlan 9\n");
+
cpuidentify();
screeninit();
+ meminit();
confinit();
archinit();
xinit();
@@ 108,6 107,19 @@ conf.monitor = 1;
}
void
+mach0init(void)
+{
+ conf.nmach = 1;
+ MACHP(0) = (Mach*)CPU0MACH;
+ m->pdb = (ulong*)CPU0PDB;
+
+ machinit();
+
+ active.machs = 1;
+ active.exiting = 0;
+}
+
+void
machinit(void)
{
int machno;
@@ 129,19 141,10 @@ machinit(void)
}
void
-ksetterm(char *f)
-{
- char buf[2*KNAMELEN];
-
- sprint(buf, f, conffile);
- ksetenv("terminal", buf);
-}
-
-void
init0(void)
{
int i;
- char tstr[32];
+ char buf[2*KNAMELEN];
up->nerrlab = 0;
@@ 159,17 162,15 @@ init0(void)
chandevinit();
if(!waserror()){
- strcpy(tstr, arch->id);
- strcat(tstr, " %s");
- ksetterm(tstr);
- ksetenv("cputype", "386");
+ snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
+ ksetenv("terminal", buf, 0);
+ ksetenv("cputype", "386", 0);
if(cpuserver)
- ksetenv("service", "cpu");
+ ksetenv("service", "cpu", 0);
else
- ksetenv("service", "terminal");
+ ksetenv("service", "terminal", 0);
for(i = 0; i < nconf; i++)
- if(confname[i] && confname[i][0] != '*')
- ksetenv(confname[i], confval[i]);
+ ksetenv(confname[i], confval[i], 1);
poperror();
}
kproc("alarm", alarmkproc, 0);
@@ 260,6 261,8 @@ bootargs(ulong base)
ac = 0;
av[ac++] = pusharg("/386/9dos");
+
+ /* when boot is changed to only use rc, this code can go away */
cp[BOOTLINELEN-1] = 0;
buf[0] = 0;
if(strncmp(cp, "fd", 2) == 0){
@@ 270,13 273,6 @@ bootargs(ulong base)
av[ac++] = pusharg(buf);
} else if(strncmp(cp, "ether", 5) == 0)
av[ac++] = pusharg("-n");
- if(buf[0]){
- cp = strchr(buf, '!');
- if(cp){
- strcpy(bootdisk, cp+1);
- addconf("bootdisk", bootdisk);
- }
- }
/* 4 byte word align stack */
sp = (uchar*)((ulong)sp & ~3);
@@ 290,18 286,6 @@ bootargs(ulong base)
sp += (USTKTOP - BY2PG) - base - sizeof(ulong);
}
-Conf conf;
-
-void
-addconf(char *name, char *val)
-{
- if(nconf >= MAXCONF)
- return;
- confname[nconf] = name;
- confval[nconf] = val;
- nconf++;
-}
-
char*
getconf(char *name)
{
@@ 313,24 297,47 @@ getconf(char *name)
return 0;
}
+static void
+writeconf(void)
+{
+ char *p, *q;
+ int n;
+
+ p = getconfenv();
+
+ if(waserror()) {
+ free(p);
+ nexterror();
+ }
+
+ /* convert to name=value\n format */
+ for(q=p; *q; q++) {
+ q += strlen(q);
+ *q = '=';
+ q += strlen(q);
+ *q = '\n';
+ }
+ n = q - p + 1;
+ if(n >= BOOTARGSLEN)
+ error("kernel configuration too large");
+ memset(BOOTLINE, 0, BOOTLINELEN);
+ memmove(BOOTARGS, p, n);
+ poperror();
+ free(p);
+}
+
void
confinit(void)
{
char *p;
int userpcnt;
- ulong kpages, maxmem;
+ ulong kpages;
- if(p = getconf("*maxmem"))
- maxmem = strtoul(p, 0, 0);
- else
- maxmem = 0;
if(p = getconf("*kernelpercent"))
userpcnt = 100 - strtol(p, 0, 0);
else
userpcnt = 0;
- meminit(maxmem);
-
conf.npage = conf.npage0 + conf.npage1;
conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
@@ 556,8 563,8 @@ procsave(Proc *p)
mmuflushtlb(PADDR(m->pdb));
}
-void
-exit(int ispanic)
+static void
+shutdown(int ispanic)
{
int ms, once;
@@ 588,7 595,56 @@ exit(int ispanic)
}
else
delay(1000);
+}
+
+void
+reboot(void *entry, void *code, ulong size)
+{
+ void (*f)(ulong, ulong, ulong);
+ ulong *pdb;
+
+ writeconf();
+
+ shutdown(0);
+
+ /*
+ * should be the only processor running now
+ */
+ print("shutting down...\n");
+ delay(200);
+
+ splhi();
+
+ /* turn off buffered serial console */
+ serialoq = nil;
+
+ /* shutdown devices */
+ chandevshutdown();
+
+ /*
+ * Modify the machine page table to directly map the low 4MB of memory
+ * This allows the reboot code to turn off the page mapping
+ */
+ pdb = m->pdb;
+ pdb[PDX(0)] = pdb[PDX(KZERO)];
+ mmuflushtlb(PADDR(pdb));
+
+ /* setup reboot trampoline function */
+ f = (void*)REBOOTADDR;
+ memmove(f, rebootcode, sizeof(rebootcode));
+
+ print("rebooting...\n");
+
+ /* off we go - never to return */
+ (*f)(PADDR(entry), PADDR(code), size);
+}
+
+
+void
+exit(int ispanic)
+{
+ shutdown(ispanic);
arch->reset();
}
@@ 596,33 652,32 @@ int
isaconfig(char *class, int ctlrno, ISAConf *isa)
{
char cc[32], *p;
- int i, n;
+ int i;
snprint(cc, sizeof cc, "%s%d", class, ctlrno);
- for(n = 0; n < nconf; n++){
- if(cistrcmp(confname[n], cc) != 0)
- continue;
- isa->nopt = tokenize(confval[n], isa->opt, NISAOPT);
- for(i = 0; i < isa->nopt; i++){
- p = isa->opt[i];
- if(cistrncmp(p, "type=", 5) == 0)
- isa->type = p + 5;
- else if(cistrncmp(p, "port=", 5) == 0)
- isa->port = strtoul(p+5, &p, 0);
- else if(cistrncmp(p, "irq=", 4) == 0)
- isa->irq = strtoul(p+4, &p, 0);
- else if(cistrncmp(p, "dma=", 4) == 0)
- isa->dma = strtoul(p+4, &p, 0);
- else if(cistrncmp(p, "mem=", 4) == 0)
- isa->mem = strtoul(p+4, &p, 0);
- else if(cistrncmp(p, "size=", 5) == 0)
- isa->size = strtoul(p+5, &p, 0);
- else if(cistrncmp(p, "freq=", 5) == 0)
- isa->freq = strtoul(p+5, &p, 0);
- }
- return 1;
+ p = getconf(cc);
+ if(p == nil)
+ return 0;
+
+ isa->nopt = tokenize(p, isa->opt, NISAOPT);
+ for(i = 0; i < isa->nopt; i++){
+ p = isa->opt[i];
+ if(cistrncmp(p, "type=", 5) == 0)
+ isa->type = p + 5;
+ else if(cistrncmp(p, "port=", 5) == 0)
+ isa->port = strtoul(p+5, &p, 0);
+ else if(cistrncmp(p, "irq=", 4) == 0)
+ isa->irq = strtoul(p+4, &p, 0);
+ else if(cistrncmp(p, "dma=", 4) == 0)
+ isa->dma = strtoul(p+4, &p, 0);
+ else if(cistrncmp(p, "mem=", 4) == 0)
+ isa->mem = strtoul(p+4, &p, 0);
+ else if(cistrncmp(p, "size=", 5) == 0)
+ isa->size = strtoul(p+5, &p, 0);
+ else if(cistrncmp(p, "freq=", 5) == 0)
+ isa->freq = strtoul(p+5, &p, 0);
}
- return 0;
+ return 1;
}
int
M pc/mem.h => pc/mem.h +9 -1
@@ 31,6 31,7 @@
* Fundamental addresses
*/
#define IDTADDR 0x80000800 /* idt */
+#define REBOOTADDR 0x00001000 /* reboot code - physical address */
#define APBOOTSTRAP 0x80001000 /* AP bootstrap code */
#define CONFADDR 0x80001200 /* info passed from boot loader */
#define CPU0PDB 0x80002000 /* bootstrap processor PDB */
@@ 75,8 76,8 @@
#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
-#define KESEL SELECTOR(KESEG, SELGDT, 0)
#define KDSEL SELECTOR(KDSEG, SELGDT, 0)
+#define KESEL SELECTOR(KESEG, SELGDT, 0)
#define UESEL SELECTOR(UESEG, SELGDT, 3)
#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0)
@@ 126,4 127,11 @@
#define PTEUSER (1<<2)
#define PTESIZE (1<<7)
+/*
+ * Macros for calculating offsets within the page directory base
+ * and page tables.
+ */
+#define PDX(va) ((((ulong)(va))>>22) & 0x03FF)
+#define PTX(va) ((((ulong)(va))>>12) & 0x03FF)
+
#define getpgcolor(a) 0
M pc/memory.c => pc/memory.c +42 -16
@@ 11,9 11,6 @@
#define MEMDEBUG 0
-#define PDX(va) ((((ulong)(va))>>22) & 0x03FF)
-#define PTX(va) ((((ulong)(va))>>12) & 0x03FF)
-
enum {
MemUPA = 0, /* unbacked physical address */
MemRAM = 1, /* physical memory */
@@ 77,9 74,19 @@ static RMap rmapumbrw = {
};
void
-memdebug(void)
+mapprint(RMap *rmap)
{
Map *mp;
+
+ print("%s\n", rmap->name);
+ for(mp = rmap->map; mp->size; mp++)
+ print("\t%8.8luX %8.8uX %8.8luX\n", mp->addr, mp->size, mp->addr+mp->size);
+}
+
+
+void
+memdebug(void)
+{
ulong maxpa, maxpa1, maxpa2;
if(MEMDEBUG == 0)
@@ 91,14 98,10 @@ memdebug(void)
print("maxpa = %luX -> %luX, maxpa1 = %luX maxpa2 = %luX\n",
maxpa, MB+maxpa*KB, maxpa1, maxpa2);
- for(mp = rmapram.map; mp->size; mp++)
- print("%8.8luX %8.8uX %8.8luX\n", mp->addr, mp->size, mp->addr+mp->size);
- for(mp = rmapumb.map; mp->size; mp++)
- print("%8.8luX %8.8uX %8.8luX\n", mp->addr, mp->size, mp->addr+mp->size);
- for(mp = rmapumbrw.map; mp->size; mp++)
- print("%8.8luX %8.8uX %8.8luX\n", mp->addr, mp->size, mp->addr+mp->size);
- for(mp = rmapupa.map; mp->size; mp++)
- print("%8.8luX %8.8uX %8.8luX\n", mp->addr, mp->size, mp->addr+mp->size);
+ mapprint(&rmapram);
+ mapprint(&rmapumb);
+ mapprint(&rmapumbrw);
+ mapprint(&rmapupa);
}
void
@@ 263,10 266,23 @@ umbscan(void)
}
}
+int
+touch(uchar *p, int n)
+{
+ int x;
+ int i;
+
+ x = 0;
+ for(i=0; i<n; i++)
+ x += p[i];
+ return x;
+}
+
+
static void
ramscan(ulong maxmem)
{
- ulong *k0, kzero, map, maxpa, pa, *pte, *table, *va, x;
+ ulong *k0, kzero, map, maxpa, pa, *pte, *table, *va, x, n;
int nvalid[NMemType];
uchar *bda;
@@ 284,11 300,14 @@ ramscan(ulong maxmem)
*/
x = PADDR(CPU0MACH+BY2PG);
bda = (uchar*)KADDR(0x400);
- mapfree(&rmapram, x, ((bda[0x14]<<8)|bda[0x13])*KB-x);
+ n = ((bda[0x14]<<8)|bda[0x13])*KB-x;
+ mapfree(&rmapram, x, n);
+ memset(KADDR(x), 0, n); /* keep us honest */
x = PADDR(PGROUND((ulong)end));
pa = MemMinMB*MB;
mapfree(&rmapram, x, pa-x);
+ memset(KADDR(x), 0, pa-x); /* keep us honest */
/*
* Check if the extended memory size can be obtained from the CMOS.
@@ 363,7 382,7 @@ ramscan(ulong maxmem)
pa += BY2PG;
}while(pa % MB);
mmuflushtlb(PADDR(m->pdb));
-// memset(va, 0, MB);
+ /* memset(va, 0, MB); so damn slow to memset all of memory */
}
else if(pa < 16*MB){
nvalid[MemUMB] += MB/BY2PG;
@@ 418,10 437,17 @@ ramscan(ulong maxmem)
}
void
-meminit(ulong maxmem)
+meminit(void)
{
Map *mp, *xmp;
ulong pa, *pte;
+ ulong maxmem;
+ char *p;
+
+ if(p = getconf("*maxmem"))
+ maxmem = strtoul(p, 0, 0);
+ else
+ maxmem = 0;
/*
* Set special attributes for memory between 640KB and 1MB:
M pc/mmu.c => pc/mmu.c +18 -6
@@ 10,7 10,7 @@
#define TSSSEGM(b,p) { ((b)<<16)|sizeof(Tss),\
((b)&0xFF000000)|(((b)>>16)&0xFF)|SEGTSS|SEGPL(p)|SEGP }
-Segdesc gdt[6] =
+Segdesc gdt[NGDT] =
{
[NULLSEG] { 0, 0}, /* null descriptor */
[KDSEG] DATASEGM(0), /* kernel data/stack */
@@ 20,9 20,6 @@ Segdesc gdt[6] =
[TSSSEG] TSSSEGM(0,0), /* tss segment */
};
-#define PDX(va) ((((ulong)(va))>>22) & 0x03FF)
-#define PTX(va) ((((ulong)(va))>>12) & 0x03FF)
-
static void
taskswitch(ulong pdb, ulong stack)
{
@@ 40,6 37,21 @@ taskswitch(ulong pdb, ulong stack)
}
void
+gdtinit(void)
+{
+ ulong x;
+ ushort ptr[3];
+
+ memmove(m->gdt, gdt, sizeof(m->gdt));
+
+ ptr[0] = sizeof(m->gdt)-1;
+ x = (ulong)m->gdt;
+ ptr[1] = x & 0xFFFF;
+ ptr[2] = (x>>16) & 0xFFFF;
+ lgdt(ptr);
+}
+
+void
mmuinit(void)
{
ulong x, *p;
@@ 53,13 65,13 @@ mmuinit(void)
m->gdt[TSSSEG].d0 = (x<<16)|sizeof(Tss);
m->gdt[TSSSEG].d1 = (x&0xFF000000)|((x>>16)&0xFF)|SEGTSS|SEGPL(0)|SEGP;
- ptr[0] = sizeof(m->gdt);
+ ptr[0] = sizeof(m->gdt)-1;
x = (ulong)m->gdt;
ptr[1] = x & 0xFFFF;
ptr[2] = (x>>16) & 0xFFFF;
lgdt(ptr);
- ptr[0] = sizeof(Segdesc)*256;
+ ptr[0] = sizeof(Segdesc)*256-1;
x = IDTADDR;
ptr[1] = x & 0xFFFF;
ptr[2] = (x>>16) & 0xFFFF;
M pc/mp.c => pc/mp.c +0 -3
@@ 348,9 348,6 @@ checkmtrr(void)
}
}
-#define PDX(va) ((((ulong)(va))>>22) & 0x03FF)
-#define PTX(va) ((((ulong)(va))>>12) & 0x03FF)
-
static void
squidboy(Apic* apic)
{
M pc/pci.c => pc/pci.c +6 -1
@@ 888,6 888,7 @@ pcicfginit(void)
out:
qunlock(&pcicfginitlock);
+
}
static int
@@ 1170,8 1171,12 @@ pcireset(void)
if(pcicfgmode == -1)
pcicfginit();
- for(p = pcilist; p != nil; p = p->list)
+ for(p = pcilist; p != nil; p = p->list) {
+ /* don't mess with the bridges */
+ if(p->ccrb == 0x06)
+ continue;
pciclrbme(p);
+ }
}
void
A pc/reboot.h => pc/reboot.h +7 -0
@@ 0,0 1,7 @@
+uchar rebootcode[]={
+0x8b,0x7c,0x24,0x04,0x89,0xf8,0x8b,0x74,0x24,0x08,0x8b,0x4c,0x24,0x0c,0x0f,0x20,
+0xc2,0x81,0xe2,0xff,0xff,0xff,0x7f,0x0f,0x22,0xc2,0x31,0xd2,0x0f,0x22,0xda,0x39,
+0xfe,0x7f,0x08,0x89,0xf2,0x01,0xca,0x39,0xfa,0x7f,0x07,0xfc,0xf3,0xa4,0x09,0xc0,
+0xff,0xe0,0x01,0xcf,0x01,0xce,0x4f,0x4e,0xfd,0xf3,0xa4,0xeb,0xf1,
+
+};
A pc/rebootcode.s => pc/rebootcode.s +54 -0
@@ 0,0 1,54 @@
+#include "mem.h"
+
+/*
+ * Turn off MMU, then memmory the new kernel to its correct location
+ * in physical memory. Then jumps the to start of the kernel.
+ */
+
+TEXT main(SB),$0
+ MOVL p1+0(FP), DI /* destination */
+ MOVL DI, AX /* entry point */
+ MOVL p2+4(FP), SI /* source */
+ MOVL n+8(FP), CX /* byte count */
+
+/*
+ * disable paging
+ */
+ MOVL CR0, DX
+ ANDL $~0x80000000, DX /* ~(PG) */
+ MOVL DX, CR0
+ MOVL $0, DX
+ MOVL DX, CR3
+
+/*
+ * the source and destination may overlap.
+ * determine whether to copy forward or backwards
+ */
+ CMPL SI, DI
+ JGT _forward
+ MOVL SI, DX
+ ADDL CX, DX
+ CMPL DX, DI
+ JGT _back
+
+_forward:
+ CLD
+ REP; MOVSB
+ JMP _startkernel
+
+_back:
+ ADDL CX, DI
+ ADDL CX, SI
+ SUBL $1, DI
+ SUBL $1, SI
+ STD
+ REP; MOVSB
+ JMP _startkernel
+/*
+ * JMP to kernel entry point. Note the true kernel entry point is
+ * the virtual address KZERO|AX, but this must wait until
+ * the MMU is enabled by the kernel in l.s
+ */
+_startkernel:
+ ORL AX, AX /* NOP: avoid link bug */
+ JMP* AX
M pc/uarti8250.c => pc/uarti8250.c +17 -4
@@ 165,7 165,7 @@ i8250status(Uart* uart, void* buf, long n, long offset)
ier = ctlr->sticky[Ier];
lcr = ctlr->sticky[Lcr];
snprint(p, READSTR,
- "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
+ "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d ier=%ux\n"
"dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",
uart->baud,
@@ 178,6 178,7 @@ i8250status(Uart* uart, void* buf, long n, long offset)
(mcr & Rts) != 0,
(lcr & Stb) ? 2: 1,
ctlr->fena,
+ ier,
uart->dev,
uart->type,
@@ 269,13 270,13 @@ i8250modemctl(Uart* uart, int on)
ilock(&uart->tlock);
if(on){
ctlr->sticky[Ier] |= Ems;
- csr8w(ctlr, Ier, 0);
+ csr8w(ctlr, Ier, ctlr->sticky[Ier]);
uart->modem = 1;
uart->cts = csr8r(ctlr, Msr) & Cts;
}
else{
ctlr->sticky[Ier] &= ~Ems;
- csr8w(ctlr, Ier, 0);
+ csr8w(ctlr, Ier, ctlr->sticky[Ier]);
uart->modem = 0;
uart->cts = 1;
}
@@ 525,7 526,7 @@ i8250disable(Uart* uart)
ctlr = uart->regs;
ctlr->sticky[Ier] = 0;
- csr8w(ctlr, Ier, 0);
+ csr8w(ctlr, Ier, ctlr->sticky[Ier]);
if(ctlr->iena != 0){
intrdisable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
@@ 562,6 563,18 @@ i8250enable(Uart* uart, int ie)
(*uart->phys->dtr)(uart, 1);
(*uart->phys->rts)(uart, 1);
+
+
+ /*
+ * During startup, the i8259 interrupt controler is reset.
+ * This may result in a lost interrupt from the i8250 uart.
+ * The i8250 thinks the interrupt is still outstanding and does not
+ * generate any further interrupts. To work around this we call the
+ * interrupt handler to clear any pending inerrupt events.
+ * Note this must be donw after setting Ier.
+ */
+ if(ie)
+ i8250interrupt(nil, uart);
}
void*
M port/chan.c => port/chan.c +12 -0
@@ 208,6 208,18 @@ chandevinit(void)
devtab[i]->init();
}
+void
+chandevshutdown(void)
+{
+ int i;
+
+ /* shutdown in reverse order */
+ for(i=0; devtab[i] != nil; i++)
+ ;
+ for(i--; i >= 0; i--)
+ devtab[i]->shutdown();
+}
+
Chan*
newchan(void)
{
M port/dev.c => port/dev.c +5 -0
@@ 78,6 78,11 @@ devinit(void)
{
}
+void
+devshutdown(void)
+{
+}
+
Chan*
devattach(int tc, char *spec)
{
M port/devaudio.c => port/devaudio.c +1 -0
@@ 1221,6 1221,7 @@ Dev audiodevtab = {
devreset,
audioinit,
+ devshutdown,
audioattach,
audiowalk,
audiostat,
M port/devbridge.c => port/devbridge.c +1 -0
@@ 1190,6 1190,7 @@ Dev bridgedevtab = {
devreset,
bridgeinit,
+ devshutdown,
bridgeattach,
bridgewalk,
bridgestat,
M port/devcap.c => port/devcap.c +1 -0
@@ 251,6 251,7 @@ Dev capdevtab = {
devreset,
devinit,
+ devshutdown,
capattach,
capwalk,
capstat,
M port/devcons.c => port/devcons.c +29 -22
@@ 50,6 50,18 @@ static int readbintime(char*, int);
static int writetime(char*, int);
static int writebintime(char*, int);
+enum
+{
+ CMreboot,
+ CMpanic,
+};
+
+Cmdtab reboottbl[] =
+{
+ CMreboot, "reboot", 0,
+ CMpanic, "panic", 0,
+};
+
void
printinit(void)
{
@@ 868,6 880,8 @@ conswrite(Chan *c, void *va, long n, vlong off)
int id, fd;
Chan *swc;
ulong offset = off;
+ Cmdbuf *cb;
+ Cmdtab *ct;
switch((ulong)c->qid.path){
case Qcons:
@@ 940,21 954,22 @@ conswrite(Chan *c, void *va, long n, vlong off)
case Qreboot:
if(!iseve())
error(Eperm);
- if(strncmp(a, "reboot", 6) == 0){
- print("conswrite: reboot\n");
- exit(0);
- }
- if(strncmp(a, "malloc", 6) == 0){ /* rsc bug */
- a = malloc(2);
- strcpy(a, "hi");
- free(a);
- a = malloc(2);
- strcpy(a, "helo");
- free(a);
- panic("not reached conswrite");
+ cb = parsecmd(a, n);
+
+ if(waserror()) {
+ free(cb);
+ nexterror();
}
- if(strncmp(a, "panic", 5) == 0)
+ ct = lookupcmd(cb, reboottbl, nelem(reboottbl));
+ switch(ct->index) {
+ case CMreboot:
+ rebootcmd(cb->nf-1, cb->f+1);
+ break;
+ case CMpanic:
panic("/dev/reboot");
+ }
+ poperror();
+ free(cb);
break;
case Qsysstat:
@@ 1009,21 1024,13 @@ conswrite(Chan *c, void *va, long n, vlong off)
return n;
}
-void
-setterm(char *f)
-{
- char buf[64];
-
- snprint(buf, sizeof buf, f, conffile);
- ksetenv("terminal", buf);
-}
-
Dev consdevtab = {
'c',
"cons",
devreset,
consinit,
+ devshutdown,
consattach,
conswalk,
consstat,
M port/devdraw.c => port/devdraw.c +1 -0
@@ 1925,6 1925,7 @@ Dev drawdevtab = {
devreset,
devinit,
+ devshutdown,
drawattach,
drawwalk,
drawstat,
M port/devdup.c => port/devdup.c +1 -0
@@ 130,6 130,7 @@ Dev dupdevtab = {
devreset,
devinit,
+ devshutdown,
dupattach,
dupwalk,
dupstat,
M port/devenv.c => port/devenv.c +87 -12
@@ 5,12 5,16 @@
#include "fns.h"
#include "../port/error.h"
-
enum
{
Maxenvsize = 16300,
};
+static Egrp *envgrp(Chan *c);
+static int envwriteable(Chan *c);
+
+static Egrp confegrp; /* global environment group containing the kernel configuration */
+
static int
envgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
{
@@ 22,7 26,7 @@ envgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
return 1;
}
- eg = up->egrp;
+ eg = envgrp(c);
qlock(eg);
for(e = eg->entries; e && s; e = e->link)
@@ 53,7 57,19 @@ envlookup(Egrp *eg, char *name, ulong qidpath)
static Chan*
envattach(char *spec)
{
- return devattach('e', spec);
+ Chan *c;
+ Egrp *egrp = nil;
+
+ if(spec && *spec) {
+ if(strcmp(spec, "c") == 0)
+ egrp = &confegrp;
+ if(egrp == nil)
+ error(Ebadarg);
+ }
+
+ c = devattach('e', spec);
+ c->aux = egrp;
+ return c;
}
static Walkqid*
@@ 66,7 82,7 @@ static int
envstat(Chan *c, uchar *db, int n)
{
if(c->qid.type & QTDIR)
- c->qid.vers = up->egrp->vers;
+ c->qid.vers = envgrp(c)->vers;
return devstat(c, db, n, 0, 0, envgen);
}
@@ 76,12 92,14 @@ envopen(Chan *c, int omode)
Egrp *eg;
Evalue *e;
- eg = up->egrp;
+ eg = envgrp(c);
if(c->qid.type & QTDIR) {
if(omode != OREAD)
error(Eperm);
}
else {
+ if(omode != OREAD && !envwriteable(c))
+ error(Eperm);
qlock(eg);
e = envlookup(eg, nil, c->qid.path);
if(e == 0) {
@@ 112,7 130,7 @@ envcreate(Chan *c, char *name, int omode, ulong)
error(Eperm);
omode = openmode(omode);
- eg = up->egrp;
+ eg = envgrp(c);
qlock(eg);
if(waserror()) {
@@ 151,7 169,7 @@ envremove(Chan *c)
if(c->qid.type & QTDIR)
error(Eperm);
- eg = up->egrp;
+ eg = envgrp(c);
qlock(eg);
l = &eg->entries;
for(e = *l; e; e = e->link) {
@@ 196,7 214,7 @@ envread(Chan *c, void *a, long n, vlong off)
if(c->qid.type & QTDIR)
return devdirread(c, a, n, 0, 0, envgen);
- eg = up->egrp;
+ eg = envgrp(c);
qlock(eg);
e = envlookup(eg, nil, c->qid.path);
if(e == 0) {
@@ 230,7 248,7 @@ envwrite(Chan *c, void *a, long n, vlong off)
if(vend > Maxenvsize)
error(Etoobig);
- eg = up->egrp;
+ eg = envgrp(c);
qlock(eg);
e = envlookup(eg, nil, c->qid.path);
if(e == 0) {
@@ 260,6 278,7 @@ Dev envdevtab = {
devreset,
devinit,
+ devshutdown,
envattach,
envwalk,
envstat,
@@ 314,17 333,73 @@ closeegrp(Egrp *eg)
}
}
+static Egrp*
+envgrp(Chan *c)
+{
+ if(c->aux == nil)
+ return up->egrp;
+ return c->aux;
+}
+
+static int
+envwriteable(Chan *c)
+{
+ return iseve() || c->aux == nil;
+}
+
/*
* to let the kernel set environment variables
*/
void
-ksetenv(char *ename, char *eval)
+ksetenv(char *ename, char *eval, int conf)
{
Chan *c;
char buf[2*KNAMELEN];
-
- sprint(buf, "#e/%s", ename);
+
+ snprint(buf, sizeof(buf), "#e%s/%s", conf?"c":"", ename);
c = namec(buf, Acreate, OWRITE, 0600);
devtab[c->type]->write(c, eval, strlen(eval), 0);
cclose(c);
}
+
+/*
+ * Return a copy of configuration environment as a sequence of strings.
+ * The strings alternate between name and value. A zero length name string
+ * indicates the end of the list
+ */
+char *
+getconfenv(void)
+{
+ Egrp *eg = &confegrp;
+ Evalue *e;
+ char *p, *q;
+ int n;
+
+ qlock(eg);
+ if(waserror()) {
+ qunlock(eg);
+ nexterror();
+ }
+
+ /* determine size */
+ n = 0;
+ for(e=eg->entries; e; e=e->link)
+ n += strlen(e->name) + e->len + 2;
+ p = malloc(n + 1);
+ if(p == nil)
+ error(Enomem);
+ q = p;
+ for(e=eg->entries; e; e=e->link) {
+ strcpy(q, e->name);
+ q += strlen(q) + 1;
+ memmove(q, e->value, e->len);
+ q[e->len] = 0;
+ /* move up to the first null */
+ q += strlen(q) + 1;
+ }
+ *q = 0;
+
+ poperror();
+ qunlock(eg);
+ return p;
+}
M port/devkprof.c => port/devkprof.c +1 -0
@@ 176,6 176,7 @@ Dev kprofdevtab = {
devreset,
kprofinit,
+ devshutdown,
kprofattach,
kprofwalk,
kprofstat,
M port/devloopback.c => port/devloopback.c +1 -0
@@ 748,6 748,7 @@ Dev loopbackdevtab = {
devreset,
loopbackinit,
+ devshutdown,
loopbackattach,
loopbackwalk,
loopbackstat,
M port/devmnt.c => port/devmnt.c +1 -1
@@ 450,7 450,6 @@ mntwalk(Chan *c, Chan *nc, char **name, int nname)
wq->qid[i] = r->reply.wqid[i];
Return:
-
poperror();
mntfree(r);
poperror();
@@ 1142,6 1141,7 @@ Dev mntdevtab = {
mntreset,
devinit,
+ devshutdown,
mntattach,
mntwalk,
mntstat,
M port/devmouse.c => port/devmouse.c +1 -0
@@ 435,6 435,7 @@ Dev mousedevtab = {
mousereset,
mouseinit,
+ devshutdown,
mouseattach,
mousewalk,
mousestat,
M port/devpipe.c => port/devpipe.c +1 -0
@@ 375,6 375,7 @@ Dev pipedevtab = {
devreset,
pipeinit,
+ devshutdown,
pipeattach,
pipewalk,
pipestat,
M port/devpnp.c => port/devpnp.c +1 -0
@@ 624,6 624,7 @@ Dev pnpdevtab = {
pnpreset,
devinit,
+ devshutdown,
pnpattach,
pnpwalk,
pnpstat,
M port/devproc.c => port/devproc.c +1 -0
@@ 920,6 920,7 @@ Dev procdevtab = {
devreset,
procinit,
+ devshutdown,
procattach,
procwalk,
procstat,
M port/devroot.c => port/devroot.c +1 -0
@@ 156,6 156,7 @@ Dev rootdevtab = {
rootreset,
devinit,
+ devshutdown,
rootattach,
rootwalk,
rootstat,
M port/devsd.c => port/devsd.c +1 -0
@@ 1448,6 1448,7 @@ Dev sddevtab = {
sdreset,
devinit,
+ devshutdown,
sdattach,
sdwalk,
sdstat,
M port/devsdp.c => port/devsdp.c +1 -0
@@ 935,6 935,7 @@ Dev sdpdevtab = {
devreset,
sdpinit,
+ devshutdown,
sdpattach,
sdpwalk,
sdpstat,
M port/devsrv.c => port/devsrv.c +2 -1
@@ 316,7 316,8 @@ Dev srvdevtab = {
"srv",
devreset,
- srvinit,
+ srvinit,
+ devshutdown,
srvattach,
srvwalk,
srvstat,
M port/devssl.c => port/devssl.c +1 -0
@@ 1229,6 1229,7 @@ Dev ssldevtab = {
devreset,
sslinit,
+ devshutdown,
sslattach,
sslwalk,
sslstat,
M port/devtls.c => port/devtls.c +1 -0
@@ 1666,6 1666,7 @@ Dev tlsdevtab = {
devreset,
tlsinit,
+ devshutdown,
tlsattach,
tlswalk,
tlsstat,
M port/devuart.c => port/devuart.c +1 -0
@@ 509,6 509,7 @@ Dev uartdevtab = {
uartreset,
devinit,
+ devshutdown,
uartattach,
uartwalk,
uartstat,
M port/portdat.h => port/portdat.h +1 -0
@@ 185,6 185,7 @@ struct Dev
void (*reset)(void);
void (*init)(void);
+ void (*shutdown)(void);
Chan* (*attach)(char*);
Walkqid* (*walk)(Chan*, Chan*, char**, int);
int (*stat)(Chan*, uchar*, int);
M port/portfns.h => port/portfns.h +6 -1
@@ 25,6 25,7 @@ int canqlock(QLock*);
int canrlock(RWlock*);
void chandevinit(void);
void chandevreset(void);
+void chandevshutdown(void);
void chanfree(Chan*);
void chanrec(Mnt*);
void checkalarms(void);
@@ 73,6 74,7 @@ void devpermcheck(char*, ulong, int);
void devpower(int);
void devremove(Chan*);
void devreset(void);
+void devshutdown(void);
int devstat(Chan*, uchar*, int, Dirtab*, int, Devgen*);
Walkqid* devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*);
int devwstat(Chan*, uchar*, int);
@@ 114,6 116,7 @@ void getcolor(ulong, ulong*, ulong*, ulong*);
ulong getmalloctag(void*);
ulong getrealloctag(void*);
void gotolabel(Label*);
+char* getconfenv(void);
int haswaitq(void*);
long hostdomainwrite(char*, int);
long hostownerwrite(char*, int);
@@ 142,7 145,7 @@ int kprint(char*, ...);
void kproc(char*, void(*)(void*), void*);
void kprocchild(Proc*, void (*)(void*), void*);
void (*kproftimer)(ulong);
-void ksetenv(char*, char*);
+void ksetenv(char*, char*, int);
void kstrcpy(char*, char*, int);
void kstrdup(char**, char*);
long latin1(Rune*, int);
@@ 270,6 273,8 @@ void rdb(void);
int readnum(ulong, char*, ulong, ulong, int);
int readstr(ulong, char*, ulong, char*);
void ready(Proc*);
+void rebootcmd(int, char**);
+void reboot(void*, void*, ulong);
void relocateseg(Segment*, ulong);
void renameuser(char*, char*);
void resched(char*);
A port/rebootcmd.c => port/rebootcmd.c +100 -0
@@ 0,0 1,100 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "a.out.h"
+
+static ulong
+l2be(long l)
+{
+ uchar *cp;
+
+ cp = (uchar*)&l;
+ return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
+}
+
+
+static void
+readn(Chan *c, void *vp, long n)
+{
+ char *p = vp;
+ long nn;
+
+ while(n > 0) {
+ nn = devtab[c->type]->read(c, p, n, c->offset);
+ if(nn == 0)
+ error(Eshort);
+ c->offset += nn;
+ p += nn;
+ n -= nn;
+ }
+}
+
+static void
+setbootcmd(int argc, char *argv[])
+{
+ char *buf, *p, *ep;
+ int i;
+
+ buf = malloc(1024);
+ if(buf == nil)
+ error(Enomem);
+ p = buf;
+ ep = buf + 1024;
+ for(i=0; i<argc; i++)
+ p = seprint(p, ep, "%q ", argv[i]);
+ *p = 0;
+ ksetenv("bootcmd", buf, 1);
+ free(buf);
+}
+
+void
+rebootcmd(int argc, char *argv[])
+{
+ Chan *c;
+ Exec exec;
+ ulong magic, text, rtext, entry, data, size;
+ uchar *p;
+
+ if(argc == 0)
+ exit(0);
+
+ c = namec(argv[0], Aopen, OEXEC, 0);
+ if(waserror()){
+ cclose(c);
+ nexterror();
+ }
+
+ readn(c, &exec, sizeof(Exec));
+ magic = l2be(exec.magic);
+ entry = l2be(exec.entry);
+ text = l2be(exec.text);
+ data = l2be(exec.data);
+ if(magic != AOUT_MAGIC)
+ error(Ebadexec);
+
+ /* round text out to page boundary */
+ rtext = PGROUND(entry+text)-entry;
+ size = rtext + data;
+ p = malloc(size);
+ if(p == nil)
+ error(Enomem);
+
+ if(waserror()){
+ free(p);
+ nexterror();
+ }
+
+ memset(p, 0, size);
+ readn(c, p, text);
+ readn(c, p + rtext, data);
+
+ ksetenv("bootfile", argv[0], 1);
+ setbootcmd(argc-1, argv+1);
+
+ reboot((void*)entry, p, size);
+
+ panic("return from reboot!");
+}