mp/pci: msi support for hypertransport platform

This commit is contained in:
cinap_lenrek 2013-09-09 00:44:08 +02:00
parent 058188117b
commit 8aff0e5be6
3 changed files with 127 additions and 28 deletions

View file

@ -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*);

View file

@ -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;

View file

@ -1416,10 +1416,10 @@ pciclrmwi(Pcidev* p)
pcicfgw16(p, PciPCR, p->pcr);
}
int
pcicap(Pcidev *p, int cap)
static int
enumcaps(Pcidev *p, int (*fmatch)(Pcidev*, int, int, int), int arg)
{
int i, c, off;
int i, r, cap, off;
/* status register bit 4 has capabilities */
if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
@ -1440,16 +1440,53 @@ pcicap(Pcidev *p, int cap)
if(off < 0x40 || (off & 3))
break;
off &= ~3;
c = pcicfgr8(p, off);
if(c == 0xff)
cap = pcicfgr8(p, off);
if(cap == 0xff)
break;
if(c == cap)
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)
{
return enumcaps(p, matchcap, cap);
}
int
pcihtcap(Pcidev *p, int cap)
{
return enumcaps(p, matchhtcap, cap);
}
static int
pcigetpmrb(Pcidev* p)
{