M pc/dat.h => pc/dat.h +1 -0
@@ 7,6 7,7 @@ typedef struct MMU MMU;
typedef struct Mach Mach;
typedef struct Notsave Notsave;
typedef struct PCArch PCArch;
+typedef struct PCIcfg PCIcfg;
typedef struct PCMmap PCMmap;
typedef struct Page Page;
typedef struct PMMU PMMU;
M pc/ether509.c => pc/ether509.c +49 -4
@@ 369,8 369,9 @@ interrupt(Ureg *ur, void *arg)
typedef struct Adapter Adapter;
struct Adapter {
- Adapter *next;
- ulong port;
+ Adapter* next;
+ ulong port;
+ PCIcfg* pcicfg;
};
static Adapter *adapter;
@@ 562,6 563,37 @@ tcm579(Ether *ether)
return 0;
}
+static PCIcfg*
+tcm590(Ether *ether)
+{
+ PCIcfg* pcicfg;
+ static uchar devno = 0;
+ ulong port;
+ Adapter *ap;
+
+ pcicfg = malloc(sizeof(PCIcfg));
+ while(devno < 16){
+ pcicfg->vid = 0x10B7;
+ pcicfg->did = 0;
+ if(pcimatch(0, devno++, pcicfg) == 0)
+ continue;
+
+ port = pcicfg->baseaddr[0] & ~0x01;
+ if(ether->port == 0 || ether->port == port)
+ return pcicfg;
+
+ ap = malloc(sizeof(Adapter));
+ ap->pcicfg = pcicfg;
+ pcicfg = malloc(sizeof(PCIcfg));
+ ap->port = port;
+ ap->next = adapter;
+ adapter = ap;
+ }
+ free(pcicfg);
+
+ return 0;
+}
+
/*
* Get configuration parameters.
*/
@@ 573,6 605,7 @@ ether509reset(Ether *ether)
ushort x, acr;
ulong port;
Adapter *ap, **app;
+ PCIcfg *pcicfg;
/*
* Any adapter matches if no ether->port is supplied,
@@ 583,9 616,11 @@ ether509reset(Ether *ether)
* and finally for a PCMCIA card.
*/
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;
@@ 593,6 628,8 @@ ether509reset(Ether *ether)
}
if(strcmp(ether->type, "3C589") == 0)
port = ether->port;
+ if(port == 0 && (pcicfg = tcm590(ether)))
+ port = pcicfg->baseaddr[0] & ~0x01;
if(port == 0)
port = tcm579(ether);
if(port == 0)
@@ 606,7 643,7 @@ ether509reset(Ether *ether)
* The EEPROM command is 8 bits, the lower 6 bits being
* the address offset.
*/
- if(strcmp(ether->type, "3C589") != 0)
+ if(strcmp(ether->type, "3C589") != 0 && pcicfg == 0)
ether->irq = (ins(port+ResourceConfig)>>12) & 0x0F;
for(eax = 0, i = 0; i < 3; i++, eax += 2){
while(ins(port+EEPROMcmd) & 0x8000)
@@ 618,7 655,15 @@ ether509reset(Ether *ether)
ea[eax] = (x>>8) & 0xFF;
ea[eax+1] = x & 0xFF;
}
- acr = ins(port+AddressConfig);
+ if(pcicfg == 0)
+ acr = ins(port+AddressConfig);
+ else{
+ ether->irq = pcicfg->irq;
+ acr = Xcvr10BaseT;
+ COMMAND(port, SelectWindow, 3);
+ print("internal config = 0x%8.8luX\n", inl(port+0x00));
+ free(pcicfg);
+ }
/*
* Finished with window 0. Now set the ethernet address
M pc/fns.h => pc/fns.h +2 -1
@@ 62,7 62,8 @@ void outs(int, ushort);
void outss(int, void*, int);
void outl(int, ulong);
void outsl(int, void*, int);
-void pcicreset(void);
+void pcicfgr(uchar, uchar, uchar, uchar, void*, int);
+int pcimatch(uchar, uchar, PCIcfg*);
PCMmap* pcmmap(int, ulong, int, int);
int pcmspecial(char*, ISAConf*);
void pcmspecialclose(int);
M pc/io.h => pc/io.h +37 -0
@@ 33,3 33,40 @@ enum {
MaxEISA = 16,
EISAconfig = 0xC80,
};
+
+/*
+ * PCI Local Bus support.
+ * Quick hack until we figure out how to
+ * deal with EISA, PCI, PCMCIA, PnP, etc.
+ */
+enum { /* configuration mechanism #1 */
+ PCIaddr = 0xCF8, /* CONFIG_ADDRESS */
+ PCIdata = 0xCFC, /* CONFIG_DATA */
+
+ /* configuration mechanism #2 */
+ PCIcse = 0xCF8, /* configuration space enable */
+ PCIforward = 0xCFA, /* which bus */
+};
+
+typedef struct PCIcfg {
+ ushort vid; /* vendor ID */
+ ushort did; /* device ID */
+ ushort command;
+ ushort status;
+ uchar rid; /* revision ID */
+ uchar loclass; /* specific register-level programming interface */
+ uchar subclass;
+ uchar baseclass;
+ uchar clsize; /* cache line size */
+ uchar latency; /* latency timer */
+ uchar header; /* header type */
+ uchar bist; /* built-in self-test */
+ ulong baseaddr[6]; /* memory or I/O base address registers */
+ ulong reserved28[2];
+ ulong romaddr; /* expansion ROM base address */
+ ulong reserved34[2];
+ uchar irq; /* interrupt line */
+ uchar irp; /* interrupt pin */
+ uchar mingnt; /* burst period length */
+ uchar maxlat; /* maximum latency between bursts */
+} PCIcfg;
A pc/pci.c => pc/pci.c +52 -0
@@ 0,0 1,52 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+static Lock pcicfglock;
+
+/*
+ * Read a chunk of PCI configuration space.
+ * Assumes arguments are within limits and regno and
+ * nbytes are DWORD aligned.
+ */
+void
+pcicfgr(uchar busno, uchar devno, uchar funcno, uchar regno, void* data, int nbytes)
+{
+ ulong base, *p;
+ int 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--){
+ *p = inl(base);
+ p++;
+ base += sizeof(ulong);
+ }
+
+ outb(PCIcse, 0x00);
+ unlock(&pcicfglock);
+}
+
+int
+pcimatch(uchar busno, uchar 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;
+}