pci: add pcicap

This commit is contained in:
cinap_lenrek 2012-02-11 00:49:39 +01:00
parent 69ef714c5c
commit 1d58cb8832
4 changed files with 58 additions and 54 deletions

View file

@ -128,7 +128,7 @@ void pcihinv(Pcidev*);
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*);

View file

@ -216,6 +216,23 @@ enum { /* type 2 pre-defined header */
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
{

View file

@ -906,15 +906,9 @@ msiintrenable(Vctl *v)
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;

View file

@ -1402,53 +1402,46 @@ pciclrmwi(Pcidev* p)
pcicfgw16(p, PciPCR, p->pcr);
}
int
pcicap(Pcidev *p, int cap)
{
int i, c, off;
/* 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;
}
static int
pcigetpmrb(Pcidev* p)
{
int ptr;
if(p->pmrb != 0)
return p->pmrb;
p->pmrb = -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;
if(p->pmrb != 0)
return p->pmrb;
return p->pmrb = pcicap(p, PciCapPMG);
}
int