mp/pci: msi support for hypertransport platform
This commit is contained in:
parent
058188117b
commit
8aff0e5be6
3 changed files with 127 additions and 28 deletions
|
@ -138,6 +138,7 @@ uchar pciipin(Pcidev*, uchar);
|
|||
Pcidev* pcimatch(Pcidev*, int, int);
|
||||
Pcidev* pcimatchtbdf(int);
|
||||
int pcicap(Pcidev*, int);
|
||||
int pcihtcap(Pcidev*, int);
|
||||
void pcireset(void);
|
||||
int pciscan(int, Pcidev**);
|
||||
void pcisetbme(Pcidev*);
|
||||
|
|
|
@ -576,6 +576,65 @@ enum {
|
|||
MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
|
||||
};
|
||||
|
||||
enum {
|
||||
HTMSIMapping = 0xA8,
|
||||
HTMSIFlags = 0x02,
|
||||
HTMSIFlagsEn = 0x01,
|
||||
};
|
||||
|
||||
static int
|
||||
htmsicapenable(Pcidev *p)
|
||||
{
|
||||
int cap, flags;
|
||||
|
||||
if((cap = pcihtcap(p, HTMSIMapping)) <= 0)
|
||||
return -1;
|
||||
flags = pcicfgr8(p, cap + HTMSIFlags);
|
||||
if((flags & HTMSIFlagsEn) == 0)
|
||||
pcicfgw8(p, cap + HTMSIFlags, flags | HTMSIFlagsEn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
htmsienable(Pcidev *pdev)
|
||||
{
|
||||
Pcidev *p;
|
||||
|
||||
p = nil;
|
||||
while((p = pcimatch(p, 0x1022, 0)) != nil)
|
||||
if(p->did == 0x1103 || p->did == 0x1203)
|
||||
break;
|
||||
|
||||
if(p == nil)
|
||||
return 0; /* not hypertransport platform */
|
||||
|
||||
p = nil;
|
||||
while((p = pcimatch(p, 0x10de, 0)) != nil){
|
||||
switch(p->did){
|
||||
case 0x02f0: /* NVIDIA NFORCE C51 MEMC0 */
|
||||
case 0x02f1: /* NVIDIA NFORCE C51 MEMC1 */
|
||||
case 0x02f2: /* NVIDIA NFORCE C51 MEMC2 */
|
||||
case 0x02f3: /* NVIDIA NFORCE C51 MEMC3 */
|
||||
case 0x02f4: /* NVIDIA NFORCE C51 MEMC4 */
|
||||
case 0x02f5: /* NVIDIA NFORCE C51 MEMC5 */
|
||||
case 0x02f6: /* NVIDIA NFORCE C51 MEMC6 */
|
||||
case 0x02f7: /* NVIDIA NFORCE C51 MEMC7 */
|
||||
case 0x0369: /* NVIDIA NFORCE MCP55 MEMC */
|
||||
htmsicapenable(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(htmsicapenable(pdev) == 0)
|
||||
return 0;
|
||||
|
||||
for(p = pdev->parent; p != nil; p = p->parent)
|
||||
if(htmsicapenable(p) == 0)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
msiintrenable(Vctl *v)
|
||||
{
|
||||
|
@ -592,6 +651,8 @@ msiintrenable(Vctl *v)
|
|||
print("msiintrenable: could not find Pcidev for tbdf %uX\n", tbdf);
|
||||
return -1;
|
||||
}
|
||||
if(htmsienable(pci) < 0)
|
||||
return -1;
|
||||
cap = pcicap(pci, PciCapMSI);
|
||||
if(cap < 0)
|
||||
return -1;
|
||||
|
|
|
@ -1416,38 +1416,75 @@ pciclrmwi(Pcidev* p)
|
|||
pcicfgw16(p, PciPCR, p->pcr);
|
||||
}
|
||||
|
||||
static int
|
||||
enumcaps(Pcidev *p, int (*fmatch)(Pcidev*, int, int, int), int arg)
|
||||
{
|
||||
int i, r, cap, 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;
|
||||
cap = pcicfgr8(p, off);
|
||||
if(cap == 0xff)
|
||||
break;
|
||||
r = (*fmatch)(p, cap, off, arg);
|
||||
if(r < 0)
|
||||
break;
|
||||
if(r == 0)
|
||||
return off;
|
||||
off++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
matchcap(Pcidev *p, int cap, int off, int arg)
|
||||
{
|
||||
USED(off);
|
||||
return cap != arg;
|
||||
}
|
||||
|
||||
static int
|
||||
matchhtcap(Pcidev *p, int cap, int off, int arg)
|
||||
{
|
||||
int mask;
|
||||
|
||||
if(cap != PciCapHTC)
|
||||
return 1;
|
||||
if(arg == 0x00 || arg == 0x20)
|
||||
mask = 0xE0;
|
||||
else
|
||||
mask = 0xF8;
|
||||
cap = pcicfgr8(p, off+3);
|
||||
return (cap & mask) != arg;
|
||||
}
|
||||
|
||||
int
|
||||
pcicap(Pcidev *p, int cap)
|
||||
{
|
||||
int i, c, off;
|
||||
return enumcaps(p, matchcap, cap);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
int
|
||||
pcihtcap(Pcidev *p, int cap)
|
||||
{
|
||||
return enumcaps(p, matchhtcap, cap);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
Loading…
Reference in a new issue