M pc/devether.c => pc/devether.c +7 -8
@@ 101,7 101,7 @@ etherwstat(Chan *c, char *dp)
}
void
-etherrloop(Ether *ctlr, Etherpkt *pkt, long len, int tome)
+etherrloop(Ether *ctlr, Etherpkt *pkt, long len)
{
Block *bp;
ushort type;
@@ 111,7 111,7 @@ etherrloop(Ether *ctlr, Etherpkt *pkt, long len, int tome)
type = (pkt->type[0]<<8)|pkt->type[1];
ep = &ctlr->f[Ntypes];
for(fp = ctlr->f; fp < ep; fp++){
- if((f = *fp) && ((tome && f->type==type) || f->type < 0)){
+ if((f = *fp) && (f->type == type || f->type < 0)){
if(f->type > -2){
if(qproduce(f->in, pkt->d, len) < 0)
ctlr->soverflows++;
@@ 139,18 139,17 @@ etherrloop(Ether *ctlr, Etherpkt *pkt, long len, int tome)
static int
etherwloop(Ether *ctlr, Etherpkt *pkt, long len)
{
- int s, tome, bcast;
+ int s, different;
- tome = memcmp(pkt->d, ctlr->ea, sizeof(pkt->d)) == 0;
- bcast = memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)) == 0;
- if(!tome && !bcast && ctlr->prom==0 && ctlr->all==0)
+ different = memcmp(pkt->d, ctlr->ea, sizeof(pkt->d));
+ if(different && memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)))
return 0;
s = splhi();
- etherrloop(ctlr, pkt, len, tome||bcast);
+ etherrloop(ctlr, pkt, len);
splx(s);
- return tome;
+ return different == 0;
}
long
M pc/ether2000.c => pc/ether2000.c +3 -3
@@ 48,8 48,8 @@ reset(Ether *ether)
ether->size = 16*1024;
port = ether->port;
- ether->private = malloc(sizeof(Dp8390));
- dp8390 = ether->private;
+ ether->ctlr = malloc(sizeof(Dp8390));
+ dp8390 = ether->ctlr;
dp8390->bit16 = 1;
dp8390->ram = 0;
@@ 81,7 81,7 @@ reset(Ether *ether)
memset(buf, 0, sizeof(buf));
dp8390read(dp8390, buf, 0, sizeof(buf));
if((buf[0x0E] & 0xFF) != 0x57 || (buf[0x0F] & 0xFF) != 0x57){
- free(ether->private);
+ free(ether->ctlr);
return -1;
}
M pc/ether4100.c => pc/ether4100.c +2 -2
@@ 52,8 52,8 @@ reset(Ether *ether)
ether->size = 16*1024;
port = ether->port;
- ether->private = malloc(sizeof(Dp8390));
- dp8390 = ether->private;
+ ether->ctlr = malloc(sizeof(Dp8390));
+ dp8390 = ether->ctlr;
dp8390->bit16 = 1;
dp8390->ram = 0;
M pc/ether509.c => pc/ether509.c +6 -6
@@ 190,7 190,7 @@ receive(Ether *ether)
/*
* Copy the packet to whoever wants it.
*/
- etherrloop(ether, ðer->rpkt, len, 1);
+ etherrloop(ether, ðer->rpkt, len);
}
/*
@@ 571,16 571,16 @@ static PCIcfg*
tcm590(Ether *ether)
{
PCIcfg* pcicfg;
- static uchar devno = 0;
- ulong port;
+ static int devno = 0;
+ int port;
Adapter *ap;
pcicfg = malloc(sizeof(PCIcfg));
- while(devno < 16){
+ for(;;){
pcicfg->vid = 0x10B7;
pcicfg->did = 0;
- if(pcimatch(0, devno++, pcicfg) == 0)
- continue;
+ if((devno = pcimatch(0, devno, pcicfg)) == -1)
+ break;
port = pcicfg->baseaddr[0] & ~0x01;
COMMAND(port, GlobalReset, 0);
A pc/ether79c970.c => pc/ether79c970.c +491 -0
@@ 0,0 1,491 @@
+/*
+ * AM79C970
+ * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus
+ * To do:
+ * only issue transmit interrupt if necessary?
+ * dynamically increase rings as necessary?
+ * use Block's as receive buffers?
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+#include "etherif.h"
+
+enum {
+ Lognrdre = 6,
+ Nrdre = (1<<Lognrdre), /* receive descriptor ring entries */
+ Logntdre = 4,
+ Ntdre = (1<<Logntdre), /* transmit descriptor ring entries */
+
+ Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */
+};
+
+enum { /* DWIO I/O resource map */
+ Aprom = 0x0000, /* physical address */
+ Rdp = 0x0010, /* register data port */
+ Rap = 0x0014, /* register address port */
+ Sreset = 0x0018, /* software reset */
+ Bdp = 0x001C, /* bus configuration register data port */
+};
+
+enum { /* CSR0 */
+ Init = 0x0001, /* begin initialisation */
+ Strt = 0x0002, /* enable chip */
+ Stop = 0x0004, /* disable chip */
+ Tdmd = 0x0008, /* transmit demand */
+ Txon = 0x0010, /* transmitter on */
+ Rxon = 0x0020, /* receiver on */
+ Iena = 0x0040, /* interrupt enable */
+ Intr = 0x0080, /* interrupt flag */
+ Idon = 0x0100, /* initialisation done */
+ Tint = 0x0200, /* transmit interrupt */
+ Rint = 0x0400, /* receive interrupt */
+ Merr = 0x0800, /* memory error */
+ Miss = 0x1000, /* missed frame */
+ Cerr = 0x2000, /* collision */
+ Babl = 0x4000, /* transmitter timeout */
+ Err = 0x8000, /* Babl|Cerr|Miss|Merr */
+};
+
+enum { /* CSR3 */
+ Bswp = 0x0004, /* byte swap */
+ Emba = 0x0008, /* enable modified back-off algorithm */
+ Dxmt2pd = 0x0010, /* disable transmit two part deferral */
+ Lappen = 0x0020, /* look-ahead packet processing enable */
+ Idonm = 0x0100, /* initialisation done mask */
+ Tintm = 0x0200, /* transmit interrupt mask */
+ Rintm = 0x0400, /* receive interrupt mask */
+ Merrm = 0x0800, /* memory error mask */
+ Missm = 0x1000, /* missed frame mask */
+ Bablm = 0x4000, /* babl mask */
+};
+
+enum { /* CSR4 */
+ ApadXmt = 0x0800, /* auto pad transmit */
+};
+
+enum { /* CSR15 */
+ Prom = 0x8000, /* promiscuous mode */
+};
+
+typedef struct { /* Initialisation Block */
+ ushort mode;
+ uchar rlen; /* upper 4 bits */
+ uchar tlen; /* upper 4 bits */
+ uchar padr[6];
+ uchar res[2];
+ uchar ladr[8];
+ ulong rdra;
+ ulong tdra;
+} Iblock;
+
+typedef struct { /* receive descriptor ring entry */
+ ulong rbadr;
+ ulong rmd1; /* status|bcnt */
+ ulong rmd2; /* rcc|rpc|mcnt */
+ ulong rmd3; /* reserved */
+} Rdre;
+
+typedef struct { /* transmit descriptor ring entry */
+ ulong tbadr;
+ ulong tmd1; /* status|bcnt */
+ ulong tmd2; /* errors */
+ ulong tmd3; /* reserved */
+} Tdre;
+
+enum { /* [RT]dre status bits */
+ Enp = 0x01000000, /* end of packet */
+ Stp = 0x02000000, /* start of packet */
+ RxBuff = 0x04000000, /* buffer error */
+ TxDef = 0x04000000, /* deferred */
+ RxCrc = 0x08000000, /* CRC error */
+ TxOne = 0x08000000, /* one retry needed */
+ RxOflo = 0x10000000, /* overflow error */
+ TxMore = 0x10000000, /* more than one retry needed */
+ Fram = 0x20000000, /* framing error */
+ RxErr = 0x40000000, /* Fram|Oflo|Crc|RxBuff */
+ TxErr = 0x40000000, /* Uflo|Lcol|Lcar|Rtry */
+ Own = 0x80000000,
+};
+
+typedef struct {
+ Lock raplock; /* registers other than CSR0 */
+
+ Iblock iblock;
+
+ Rdre* rdr; /* receive descriptor ring */
+ void* rrb; /* receive ring buffers */
+ int rdrx; /* index into rdr */
+
+ Rendez trendez; /* wait here for free tdre */
+ Tdre* tdr; /* transmit descriptor ring */
+ void* trb; /* transmit ring buffers */
+ int tdrx; /* index into tdr */
+} Ctlr;
+
+static void
+attach(Ether* ether)
+{
+ int port;
+
+ port = ether->port;
+ outl(port+Rdp, Iena|Strt);
+}
+
+static void
+ringinit(Ctlr* ctlr)
+{
+ int i, x;
+
+ /*
+ * Initialise the receive and transmit buffer rings. The ring
+ * entries must be aligned on 16-byte boundaries.
+ */
+ if(ctlr->rdr == 0)
+ ctlr->rdr = xspanalloc(Nrdre*sizeof(Rdre), 0x10, 0);
+ if(ctlr->rrb == 0)
+ ctlr->rrb = xalloc(Nrdre*Rbsize);
+ x = PADDR(ctlr->rrb);
+ for(i = 0; i < Nrdre; i++){
+ ctlr->rdr[i].rbadr = x;
+ x += Rbsize;
+ ctlr->rdr[i].rmd1 = Own|(-Rbsize & 0xFFFF);
+ }
+ ctlr->rdrx = 0;
+
+ if(ctlr->tdr == 0)
+ ctlr->tdr = xspanalloc(Ntdre*sizeof(Tdre), 0x10, 0);
+ if(ctlr->trb == 0)
+ ctlr->trb = xalloc(Ntdre*Rbsize);
+ x = PADDR(ctlr->trb);
+ for(i = 0; i < Ntdre; i++){
+ ctlr->tdr[i].tbadr = x;
+ x += Rbsize;
+ }
+ ctlr->tdrx = 0;
+}
+
+static void
+promiscuous(void* arg, int on)
+{
+ Ether *ether;
+ int port, x;
+ Ctlr *ctlr;
+
+ ether = arg;
+ port = ether->port;
+ ctlr = ether->ctlr;
+
+ /*
+ * Put the chip into promiscuous mode. First we must wait until
+ * anyone transmitting is done, then we can stop the chip and put
+ * it in promiscuous mode. Restarting is made harder by the chip
+ * reloading the transmit and receive descriptor pointers with their
+ * base addresses when Strt is set (unlike the older Lance chip),
+ * so the rings must be re-initialised.
+ */
+ qlock(ðer->tlock);
+
+ ilock(&ctlr->raplock);
+ outl(port+Rdp, Stop);
+
+ outl(port+Rap, 15);
+ x = inl(port+Rdp) & ~Prom;
+ if(on)
+ x |= Prom;
+ outl(port+Rdp, x);
+ outl(port+Rap, 0);
+
+ ringinit(ctlr);
+ outl(port+Rdp, Iena|Strt);
+ iunlock(&ctlr->raplock);
+
+ qunlock(ðer->tlock);
+}
+
+static int
+owntdre(void* arg)
+{
+ return (((Tdre*)arg)->tmd1 & Own) == 0;
+}
+
+static long
+write(Ether* ether, void* buf, long n)
+{
+ int port;
+ Ctlr *ctlr;
+ Tdre *tdre;
+ Etherpkt *pkt;
+
+ port = ether->port;
+ ctlr = ether->ctlr;
+
+ /*
+ * Wait for a transmit ring descriptor (and hence a buffer) to become
+ * free. If none become free after a reasonable period, give up.
+ */
+ tdre = &ctlr->tdr[ctlr->tdrx];
+ tsleep(&ctlr->trendez, owntdre, tdre, 100);
+ if(owntdre(tdre) == 0)
+ return 0;
+
+ /*
+ * Copy the packet to the transmit buffer and fill in our
+ * source ethernet address. There's no need to pad to ETHERMINTU
+ * here as we set ApadXmit in CSR4.
+ */
+ pkt = KADDR(tdre->tbadr);
+ memmove(pkt->d, buf, n);
+ memmove(pkt->s, ether->ea, sizeof(pkt->s));
+
+ /*
+ * Give ownership of the descriptor to the chip, increment the
+ * software ring descriptor pointer and tell the chip to poll.
+ */
+ tdre->tmd2 = 0;
+ tdre->tmd1 = Own|Stp|Enp|(-n & 0xFFFF);
+ ctlr->tdrx = NEXT(ctlr->tdrx, Ntdre);
+ outl(port+Rdp, Iena|Tdmd);
+
+ ether->outpackets++;
+ return n;
+}
+
+static void
+interrupt(Ureg*, void* arg)
+{
+ Ether *ether;
+ int port, csr0, status;
+ Ctlr *ctlr;
+ Rdre *rdre;
+ Etherpkt *pkt;
+
+ ether = arg;
+ port = ether->port;
+ ctlr = ether->ctlr;
+
+ /*
+ * Acknowledge all interrupts and whine about those that shouldn't
+ * happen.
+ */
+ csr0 = inl(port+Rdp);
+ outl(port+Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
+ if(csr0 & (Babl|Miss|Merr))
+ print("AMD70C970#%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);
+
+ /*
+ * Receiver interrupt: run round the descriptor ring logging
+ * errors and passing valid receive data up to the higher levels
+ * until we encounter a descriptor still owned by the chip.
+ */
+ if(csr0 & Rint){
+ rdre = &ctlr->rdr[ctlr->rdrx];
+ while(((status = rdre->rmd1) & Own) == 0){
+ if(status & RxErr){
+ if(status & RxBuff)
+ ether->buffs++;
+ if(status & RxCrc)
+ ether->crcs++;
+ if(status & RxOflo)
+ ether->overflows++;
+ }
+ else{
+ ether->inpackets++;
+ pkt = KADDR(rdre->rbadr);
+ etherrloop(ether, pkt, (rdre->rmd2 & 0x0FFF)-4);
+ }
+
+ /*
+ * Finished with this descriptor, reinitialise it,
+ * give it back to the chip, then on to the next...
+ */
+ rdre->rmd2 = 0;
+ rdre->rmd1 = Own|(-Rbsize & 0xFFFF);
+
+ ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
+ rdre = &ctlr->rdr[ctlr->rdrx];
+ }
+ }
+
+ /*
+ * Transmitter interrupt: wakeup anyone waiting for a free descriptor.
+ */
+ if(csr0 & Tint)
+ wakeup(&ctlr->trendez);
+}
+
+typedef struct Adapter Adapter;
+struct Adapter {
+ Adapter* next;
+ int port;
+ PCIcfg* pcicfg;
+};
+static Adapter *adapter;
+
+static PCIcfg*
+amd79c90(Ether* ether)
+{
+ PCIcfg *pcicfg;
+ static int devno = 0;
+ int port;
+ Adapter *ap;
+
+ pcicfg = malloc(sizeof(PCIcfg));
+ for(;;){
+ pcicfg->vid = 0x1022;
+ pcicfg->did = 0x2000;
+ if((devno = pcimatch(0, devno, pcicfg)) == -1)
+ break;
+
+ port = pcicfg->baseaddr[0] & ~0x01;
+ if(ether->port == 0 || ether->port == port)
+ return pcicfg;
+
+ ap = malloc(sizeof(Adapter));
+ ap->pcicfg = pcicfg;
+ ap->port = port;
+ ap->next = adapter;
+ adapter = ap;
+
+ pcicfg = malloc(sizeof(PCIcfg));
+ }
+ free(pcicfg);
+
+ return 0;
+}
+
+static int
+reset(Ether* ether)
+{
+ int port, x;
+ PCIcfg *pcicfg;
+ Adapter *ap, **app;
+ uchar ea[Eaddrlen];
+ Ctlr *ctlr;
+
+ /*
+ * Any adapter matches if no ether->port is supplied, otherwise the
+ * ports must match. First see if we've already found an adapter that fits
+ * the bill. If not then scan for another.
+ */
+ port = 0;
+ pcicfg = 0;
+ for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){
+ if(ether->port == 0 || ether->port == ap->port){
+ port = ap->port;
+ pcicfg = ap->pcicfg;
+ *app = ap->next;
+ free(ap);
+ break;
+ }
+ }
+ if(port == 0 && (pcicfg = amd79c90(ether))){
+ port = pcicfg->baseaddr[0] & ~0x01;
+ ether->irq = pcicfg->irq;
+ }
+ if(port == 0)
+ return -1;
+
+ if(pcicfg)
+ free(pcicfg);
+
+ /*
+ * How can we tell what mode we're in at this point - if we're in WORD
+ * mode then the only 32-bit access we are allowed to make is a write to
+ * the RDP, which forces the chip to DWORD mode; if we're in DWORD mode
+ * then we're not allowed to make any non-DWORD accesses?
+ * Assuming we do a DWORD write to the RDP, how can we tell what we're
+ * about to overwrite as we can't reliably access the RAP?
+ *
+ * Force DWORD mode by writing to RDP, doing a reset then writing to RDP
+ * again; at least we know what state we're in now. The value of RAP after
+ * a reset is 0, so the second DWORD write will be to CSR0.
+ * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
+ * Set the auto pad transmit in CSR4.
+ */
+ outl(port+Rdp, 0x00);
+ inl(port+Sreset);
+ outl(port+Rdp, Stop);
+
+ outl(port+Rap, 20);
+ outl(port+Bdp, 0x0002);
+
+ outl(port+Rap, 4);
+ x = inl(port+Rdp) & 0xFFFF;
+ outl(port+Rdp, ApadXmt|x);
+
+ outl(port+Rap, 0);
+
+ /*
+ * Check if we are going to override the adapter's station address.
+ * If not, read it from the I/O-space and set in ether->ea prior to loading the
+ * station address in the initialisation block.
+ */
+ memset(ea, 0, Eaddrlen);
+ if(memcmp(ea, ether->ea, Eaddrlen) == 0){
+ x = inl(port+Aprom);
+ ether->ea[0] = x & 0xFF;
+ ether->ea[1] = (x>>8) & 0xFF;
+ ether->ea[2] = (x>>16) & 0xFF;
+ ether->ea[3] = (x>>24) & 0xFF;
+ x = inl(port+Aprom+4);
+ ether->ea[4] = x & 0xFF;
+ ether->ea[5] = (x>>8) & 0xFF;
+ }
+
+ /*
+ * Allocate a controller structure and start to fill in the
+ * initialisation block (must be DWORD aligned).
+ */
+ ether->ctlr = malloc(sizeof(Ctlr));
+ ctlr = ether->ctlr;
+
+ ctlr->iblock.rlen = Lognrdre<<4;
+ ctlr->iblock.tlen = Logntdre<<4;
+ memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr));
+
+ ringinit(ctlr);
+ ctlr->iblock.rdra = PADDR(ctlr->rdr);
+ ctlr->iblock.tdra = PADDR(ctlr->tdr);
+
+ /*
+ * Point the chip at the initialisation block and tell it to go.
+ * Mask the Idon interrupt and poll for completion. Strt and interrupt
+ * enables will be set later when we're ready to attach to the network.
+ */
+ x = PADDR(&ctlr->iblock);
+ outl(port+Rap, 1);
+ outl(port+Rdp, x & 0xFFFF);
+ outl(port+Rap, 2);
+ outl(port+Rdp, (x>>16) & 0xFFFF);
+ outl(port+Rap, 3);
+ outl(port+Rdp, Idonm);
+ outl(port+Rap, 0);
+ outl(port+Rdp, Init);
+
+ while((inl(port+Rdp) & Idon) == 0)
+ ;
+ outl(port+Rdp, Idon|Stop);
+
+ ether->port = port;
+ ether->attach = attach;
+ ether->write = write;
+ ether->interrupt = interrupt;
+
+ ether->promiscuous = promiscuous;
+ ether->arg = ether;
+
+ return 0;
+}
+
+void
+ether79c970link(void)
+{
+ addethercard("AMD79C970", reset);
+}
M pc/ether8003.c => pc/ether8003.c +2 -2
@@ 104,8 104,8 @@ reset(Ether *ether)
if(sum != 0xFF)
return -1;
- ether->private = malloc(sizeof(Dp8390));
- dp8390 = ether->private;
+ ether->ctlr = malloc(sizeof(Dp8390));
+ dp8390 = ether->ctlr;
dp8390->ram = 1;
/*
M pc/ether8390.c => pc/ether8390.c +10 -10
@@ 189,7 189,7 @@ dp8390ring(Dp8390 *dp8390)
void
dp8390setea(Ether *ether)
{
- ulong port = ((Dp8390*)ether->private)->dp8390;
+ ulong port = ((Dp8390*)ether->ctlr)->dp8390;
uchar cr;
int i;
@@ 210,7 210,7 @@ dp8390setea(Ether *ether)
void
dp8390getea(Ether *ether)
{
- ulong port = ((Dp8390*)ether->private)->dp8390;
+ ulong port = ((Dp8390*)ether->ctlr)->dp8390;
uchar cr;
int i;
@@ 384,7 384,7 @@ receive(Ether *ether)
Hdr hdr;
ulong port, data, len, len1;
- dp8390 = ether->private;
+ dp8390 = ether->ctlr;
port = dp8390->dp8390;
for(curr = getcurr(dp8390); dp8390->nxtpkt != curr; curr = getcurr(dp8390)){
ether->inpackets++;
@@ 455,7 455,7 @@ receive(Ether *ether)
/*
* Copy the packet to whoever wants it.
*/
- etherrloop(ether, ðer->rpkt, len, 1);
+ etherrloop(ether, ðer->rpkt, len);
}
/*
@@ 484,7 484,7 @@ write(Ether *ether, void *buf, long len)
ulong port;
Etherpkt *pkt;
- dp8390 = ether->private;
+ dp8390 = ether->ctlr;
port = dp8390->dp8390;
tsleep(ðer->tr, istxavail, ether, 10000);
@@ 534,7 534,7 @@ overflow(Ether *ether)
uchar txp;
int resend;
- dp8390 = ether->private;
+ dp8390 = ether->ctlr;
port = dp8390->dp8390;
/*
@@ 572,7 572,7 @@ interrupt(Ureg *ur, void *arg)
USED(ur);
ether = arg;
- dp8390 = ether->private;
+ dp8390 = ether->ctlr;
port = dp8390->dp8390;
/*
@@ 631,7 631,7 @@ interrupt(Ureg *ur, void *arg)
static void
promiscuous(void *arg, int on)
{
- Dp8390 *dp8390 = ((Ether*)arg)->private;
+ Dp8390 *dp8390 = ((Ether*)arg)->ctlr;
/*
* Set/reset promiscuous mode.
@@ 645,7 645,7 @@ promiscuous(void *arg, int on)
static void
attach(Ether *ether)
{
- Dp8390 *dp8390 = ether->private;
+ Dp8390 *dp8390 = ether->ctlr;
/*
* Enable the chip for transmit/receive.
@@ 663,7 663,7 @@ dp8390reset(Ether *ether)
Dp8390 *dp8390;
ulong port;
- dp8390 = ether->private;
+ dp8390 = ether->ctlr;
port = dp8390->dp8390;
/*
M pc/etherif.h => pc/etherif.h +3 -2
@@ 6,11 6,12 @@ enum {
typedef struct Ether Ether;
struct Ether {
ISAConf; /* hardware info */
+ int ctlrno;
void (*attach)(Ether*); /* filled in by reset routine */
long (*write)(Ether*, void*, long);
void (*interrupt)(Ureg*, void*);
- void *private;
+ void *ctlr;
Etherpkt tpkt; /* transmit buffer */
Etherpkt rpkt; /* receive buffer */
@@ 22,7 23,7 @@ struct Ether {
Netif;
};
-extern void etherrloop(Ether*, Etherpkt*, long, int);
+extern void etherrloop(Ether*, Etherpkt*, long);
extern void addethercard(char*, int(*)(Ether*));
/*
M pc/fns.h => pc/fns.h +3 -2
@@ 62,8 62,9 @@ void outs(int, ushort);
void outss(int, void*, int);
void outl(int, ulong);
void outsl(int, void*, int);
-void pcicfgr(uchar, uchar, uchar, uchar, void*, int);
-int pcimatch(uchar, uchar, PCIcfg*);
+void pcicfgr(int, int, int, int, void*, int);
+void pcicfgw(int, int, int, int, void*, int);
+int pcimatch(int, int, PCIcfg*);
PCMmap* pcmmap(int, ulong, int, int);
int pcmspecial(char*, ISAConf*);
void pcmspecialclose(int);
M pc/pci.c => pc/pci.c +39 -14
@@ 14,10 14,10 @@ static Lock pcicfglock;
* nbytes are DWORD aligned.
*/
void
-pcicfgr(uchar busno, uchar devno, uchar funcno, uchar regno, void* data, int nbytes)
+pcicfgr(int busno, int devno, int funcno, int regno, void* data, int nbytes)
{
- ulong base, *p;
- int len;
+ ulong* p;
+ int base, len;
lock(&pcicfglock);
outb(PCIcse, 0x80|((funcno & 0x07)<<1));
@@ 28,7 28,29 @@ pcicfgr(uchar busno, uchar devno, uchar funcno, uchar regno, void* data, int nby
for(len = nbytes/sizeof(ulong); len > 0; len--){
*p = inl(base);
p++;
- base += sizeof(ulong);
+ base += sizeof(*p);
+ }
+
+ outb(PCIcse, 0x00);
+ unlock(&pcicfglock);
+}
+
+void
+pcicfgw(int busno, int devno, int funcno, int regno, void* data, int nbytes)
+{
+ ulong* p;
+ int base, len;
+
+ lock(&pcicfglock);
+ outb(PCIcse, 0x80|((funcno & 0x07)<<1));
+ outb(PCIforward, busno);
+
+ base = (0xC000|(devno<<8)) + regno;
+ p = data;
+ for(len = nbytes/sizeof(ulong); len > 0; len--){
+ outl(base, *p);
+ p++;
+ base += sizeof(*p);
}
outb(PCIcse, 0x00);
@@ 36,17 58,20 @@ pcicfgr(uchar busno, uchar devno, uchar funcno, uchar regno, void* data, int nby
}
int
-pcimatch(uchar busno, uchar devno, PCIcfg* pcicfg)
+pcimatch(int busno, int devno, PCIcfg* pcicfg)
{
ulong l;
- l = 0;
- pcicfgr(busno, devno, 0, 0, &l, sizeof(ulong));
- if((l & 0xFFFF) != pcicfg->vid)
- return 0;
- if(pcicfg->did && ((l>>16) & 0xFFFF) != pcicfg->did)
- return 0;
- pcicfgr(busno, devno, 0, 0, pcicfg, sizeof(PCIcfg));
-
- return 1;
+ while(devno < MaxPCI){
+ l = 0;
+ pcicfgr(busno, devno, 0, 0, &l, sizeof(ulong));
+ devno++;
+ if((l & 0xFFFF) != pcicfg->vid)
+ continue;
+ if(pcicfg->did && ((l>>16) & 0xFFFF) != pcicfg->did)
+ continue;
+ pcicfgr(busno, devno-1, 0, 0, pcicfg, sizeof(PCIcfg));
+ return devno;
+ }
+ return -1;
}