pci: add pcicap
This commit is contained in:
parent
69ef714c5c
commit
1d58cb8832
4 changed files with 58 additions and 54 deletions
|
@ -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*);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue