ref: fe668572ff7b8c8968f78bd9173d7d1c6e624a23
parent: 318a980c63b8e65ae6c791c88a84937fbf7e5937
author: aiju <[email protected]>
date: Sun May 15 20:35:16 EDT 2011
added basic MSI and PCI capabilities support
--- a/sys/src/9/pc/etherbcm.c
+++ b/sys/src/9/pc/etherbcm.c
@@ -547,8 +547,7 @@
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);
}
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -124,6 +124,7 @@
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*);
--- a/sys/src/9/pc/io.h
+++ b/sys/src/9/pc/io.h
@@ -112,6 +112,7 @@
PciBAR0 = 0x10, /* base address */
PciBAR1 = 0x14,
+ PciCAP = 0x34, /* capabilities pointer */
PciINTL = 0x3C, /* interrupt line */
PciINTP = 0x3D, /* interrupt pin */
};
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -838,10 +838,61 @@
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.
--- a/sys/src/9/pc/pci.c
+++ b/sys/src/9/pc/pci.c
@@ -1486,3 +1486,14 @@
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;
+}