summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraiju <aiju@phicode.de>2011-05-16 00:35:16 +0000
committeraiju <aiju@phicode.de>2011-05-16 00:35:16 +0000
commitfe668572ff7b8c8968f78bd9173d7d1c6e624a23 (patch)
treed58b903cb39a409ae4e06bac7fd8aba8e54dabba
parent318a980c63b8e65ae6c791c88a84937fbf7e5937 (diff)
downloadplan9front-fe668572ff7b8c8968f78bd9173d7d1c6e624a23.tar.xz
added basic MSI and PCI capabilities support
-rw-r--r--sys/src/9/pc/etherbcm.c3
-rw-r--r--sys/src/9/pc/fns.h1
-rw-r--r--sys/src/9/pc/io.h1
-rw-r--r--sys/src/9/pc/mp.c51
-rw-r--r--sys/src/9/pc/pci.c11
5 files changed, 65 insertions, 2 deletions
diff --git a/sys/src/9/pc/etherbcm.c b/sys/src/9/pc/etherbcm.c
index 48963c247..2be054e60 100644
--- a/sys/src/9/pc/etherbcm.c
+++ b/sys/src/9/pc/etherbcm.c
@@ -547,8 +547,7 @@ bcminit(Ether *edev)
csr32(ctlr, MACHash+12) = -1;
for(i = 0; i < 8; i++) csr32(ctlr, ReceiveRules + 8 * i) = 0;
csr32(ctlr, ReceiveRulesConfiguration) = 1 << 3;
- csr32(ctlr, MSIMode) &= ~Enable;
- while(csr32(ctlr, MSIMode) & Enable);
+ csr32(ctlr, MSIMode) |= Enable;
csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA);
}
diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h
index bce829162..4af1813e8 100644
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -124,6 +124,7 @@ void pcihinv(Pcidev*);
uchar pciipin(Pcidev*, uchar);
Pcidev* pcimatch(Pcidev*, int, int);
Pcidev* pcimatchtbdf(int);
+int pcinextcap(Pcidev*, int);
void pcireset(void);
int pciscan(int, Pcidev**);
void pcisetbme(Pcidev*);
diff --git a/sys/src/9/pc/io.h b/sys/src/9/pc/io.h
index ba2399b7a..eb8dac7e8 100644
--- a/sys/src/9/pc/io.h
+++ b/sys/src/9/pc/io.h
@@ -112,6 +112,7 @@ enum { /* type 0 & type 1 pre-defined header */
PciBAR0 = 0x10, /* base address */
PciBAR1 = 0x14,
+ PciCAP = 0x34, /* capabilities pointer */
PciINTL = 0x3C, /* interrupt line */
PciINTP = 0x3D, /* interrupt pin */
};
diff --git a/sys/src/9/pc/mp.c b/sys/src/9/pc/mp.c
index ee094341b..77ac729ec 100644
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -838,11 +838,62 @@ mpintrenablex(Vctl* v, int tbdf)
return -1;
}
+enum {
+ MSICtrl = 0x02, /* message control register (16 bit) */
+ MSIAddr = 0x04, /* message address register (64 bit) */
+ MSIData = 0x0C, /* message data register (16 bit) */
+};
+
+static int
+msiintrenable(Vctl *v)
+{
+ int tbdf, vno, cap, cpu;
+ Pcidev *pci;
+
+ if(getconf("*msi") == nil)
+ return -1;
+ tbdf = v->tbdf;
+ if(tbdf == BUSUNKNOWN || BUSTYPE(tbdf) != BusPCI)
+ return -1;
+ pci = pcimatchtbdf(tbdf);
+ if(pci == nil) {
+ print("msiintrenable: could not find Pcidev for tbdf %.8x\n", tbdf);
+ return -1;
+ }
+ cap = 0;
+ for(;;) {
+ cap = pcinextcap(pci, cap);
+ if(cap == 0)
+ return -1;
+ if(pcicfgr8(pci, cap) == 0x05) /* MSI block */
+ break;
+ }
+
+ vno = VectorAPIC + (incref(&mpvnoref)-1)*8;
+ if(vno > MaxVectorAPIC) {
+ print("msiintrenable: vno %d\n", vno);
+ return -1;
+ }
+ cpu = mpintrcpu();
+ pcicfgw32(pci, cap + MSIAddr, (0xFEE << 20) | (cpu << 12));
+ pcicfgw32(pci, cap + MSIAddr + 4, 0);
+ pcicfgw16(pci, cap + MSIData, vno | (1<<14));
+ pcicfgw16(pci, cap + MSICtrl, 1);
+ print("msiintrenable: success with tbdf %.8x, vector %d, cpu %d\n", tbdf, vno, cpu);
+ v->isr = lapicisr;
+ v->eoi = lapiceoi;
+ return vno;
+}
+
int
mpintrenable(Vctl* v)
{
int irq, tbdf, vno;
+ vno = msiintrenable(v);
+ if(vno != -1)
+ return vno;
+
/*
* If the bus is known, try it.
* BUSUNKNOWN is given both by [E]ISA devices and by
diff --git a/sys/src/9/pc/pci.c b/sys/src/9/pc/pci.c
index 1443a31dc..6ad5d3663 100644
--- a/sys/src/9/pc/pci.c
+++ b/sys/src/9/pc/pci.c
@@ -1486,3 +1486,14 @@ pcisetpms(Pcidev* p, int state)
return ostate;
}
+
+int
+pcinextcap(Pcidev *pci, int offset)
+{
+ if(offset == 0) {
+ if((pcicfgr16(pci, PciPSR) & (1<<4)) == 0)
+ return 0; /* no capabilities */
+ offset = PciCAP-1;
+ }
+ return pcicfgr8(pci, offset+1) & ~3;
+}