ref: 1d58cb8832bd8ab7dd6e0fb94f32cfd0f145c8a4
parent: 69ef714c5cd695b620f1a6a70e5ec19d8331069a
author: cinap_lenrek <[email protected]>
date: Fri Feb 10 19:49:39 EST 2012
pci: add pcicap
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -128,7 +128,7 @@
uchar pciipin(Pcidev*, uchar);
Pcidev* pcimatch(Pcidev*, int, int);
Pcidev* pcimatchtbdf(int);
-int pcinextcap(Pcidev*, int);
+int pcicap(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
@@ -216,6 +216,23 @@
PciCBLMBAR = 0x44, /* legacy mode base address */
};
+/* capabilities */
+enum {
+ PciCapPMG = 0x01, /* power management */
+ PciCapAGP = 0x02,
+ PciCapVPD = 0x03, /* vital product data */
+ PciCapSID = 0x04, /* slot id */
+ PciCapMSI = 0x05,
+ PciCapCHS = 0x06, /* compact pci hot swap */
+ PciCapPCIX = 0x07,
+ PciCapHTC = 0x08, /* hypertransport irq conf */
+ PciCapVND = 0x09, /* vendor specific information */
+ PciCapPCIe = 0x10,
+ PciCapMSIX = 0x11,
+ PciCapSATA = 0x12,
+ PciCapHSW = 0x0c, /* hot swap */
+};
+
typedef struct Pcisiz Pcisiz;
struct Pcisiz
{
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -906,15 +906,9 @@
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;
- }
-
+ cap = pcicap(pci, PciCapMSI);
+ if(cap < 0)
+ return -1;
vno = allocvector();
cpu = mpintrcpu();
ok64 = (pcicfgr16(pci, cap + MSICtrl) & (1<<7)) != 0;
--- a/sys/src/9/pc/pci.c
+++ b/sys/src/9/pc/pci.c
@@ -1402,53 +1402,46 @@
pcicfgw16(p, PciPCR, p->pcr);
}
-static int
-pcigetpmrb(Pcidev* p)
+int
+pcicap(Pcidev *p, int cap)
{
- int ptr;
+ int i, c, off;
- if(p->pmrb != 0)
- return p->pmrb;
- p->pmrb = -1;
+ /* status register bit 4 has capabilities */
+ if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
+ return -1;
+ switch(pcicfgr8(p, PciHDT) & 0x7F){
+ default:
+ return -1;
+ case 0: /* etc */
+ case 1: /* pci to pci bridge */
+ off = 0x34;
+ break;
+ case 2: /* cardbus bridge */
+ off = 0x14;
+ break;
+ }
+ for(i = 48; i--;){
+ off = pcicfgr8(p, off);
+ if(off < 0x40 || (off & 3))
+ break;
+ off &= ~3;
+ c = pcicfgr8(p, off);
+ if(c == 0xff)
+ break;
+ if(c == cap)
+ return off;
+ off++;
+ }
+ return -1;
+}
- /*
- * If there are no extended capabilities implemented,
- * (bit 4 in the status register) assume there's no standard
- * power management method.
- * Find the capabilities pointer based on PCI header type.
- */
- if(!(pcicfgr16(p, PciPSR) & 0x0010))
- return -1;
- switch(pcicfgr8(p, PciHDT)){
- default:
- return -1;
- case 0: /* all other */
- case 1: /* PCI to PCI bridge */
- ptr = 0x34;
- break;
- case 2: /* CardBus bridge */
- ptr = 0x14;
- break;
- }
- ptr = pcicfgr32(p, ptr);
-
- while(ptr != 0){
- /*
- * Check for validity.
- * Can't be in standard header and must be double
- * word aligned.
- */
- if(ptr < 0x40 || (ptr & ~0xFC))
- return -1;
- if(pcicfgr8(p, ptr) == 0x01){
- p->pmrb = ptr;
- return ptr;
- }
-
- ptr = pcicfgr8(p, ptr+1);
- }
-
- return -1;
+static int
+pcigetpmrb(Pcidev* p)
+{
+ if(p->pmrb != 0)
+ return p->pmrb;
+ return p->pmrb = pcicap(p, PciCapPMG);
}
int