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* pcimatch(Pcidev*, int, int);
|
||||||
Pcidev* pcimatchtbdf(int);
|
Pcidev* pcimatchtbdf(int);
|
||||||
int pcicap(Pcidev*, int);
|
int pcicap(Pcidev*, int);
|
||||||
|
int pcihtcap(Pcidev*, int);
|
||||||
void pcireset(void);
|
void pcireset(void);
|
||||||
int pciscan(int, Pcidev**);
|
int pciscan(int, Pcidev**);
|
||||||
void pcisetbme(Pcidev*);
|
void pcisetbme(Pcidev*);
|
||||||
|
|
|
@ -576,6 +576,65 @@ enum {
|
||||||
MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
|
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
|
static int
|
||||||
msiintrenable(Vctl *v)
|
msiintrenable(Vctl *v)
|
||||||
{
|
{
|
||||||
|
@ -592,6 +651,8 @@ msiintrenable(Vctl *v)
|
||||||
print("msiintrenable: could not find Pcidev for tbdf %uX\n", tbdf);
|
print("msiintrenable: could not find Pcidev for tbdf %uX\n", tbdf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if(htmsienable(pci) < 0)
|
||||||
|
return -1;
|
||||||
cap = pcicap(pci, PciCapMSI);
|
cap = pcicap(pci, PciCapMSI);
|
||||||
if(cap < 0)
|
if(cap < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1416,38 +1416,75 @@ pciclrmwi(Pcidev* p)
|
||||||
pcicfgw16(p, PciPCR, p->pcr);
|
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
|
int
|
||||||
pcicap(Pcidev *p, int cap)
|
pcicap(Pcidev *p, int cap)
|
||||||
{
|
{
|
||||||
int i, c, off;
|
return enumcaps(p, matchcap, cap);
|
||||||
|
}
|
||||||
|
|
||||||
/* status register bit 4 has capabilities */
|
int
|
||||||
if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
|
pcihtcap(Pcidev *p, int cap)
|
||||||
return -1;
|
{
|
||||||
switch(pcicfgr8(p, PciHDT) & 0x7F){
|
return enumcaps(p, matchhtcap, cap);
|
||||||
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
|
static int
|
||||||
|
|
Loading…
Reference in a new issue