ref: 48bbe060fc050ad326bc21eceedc0c27cea9cb01
parent: 0b2722648256726751d8bf7032b5ad0e73fdc132
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Sun Sep 8 20:44:08 EDT 2013
mp/pci: msi support for hypertransport platform
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -138,6 +138,7 @@
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*);
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -576,7 +576,66 @@
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)
{int tbdf, vno, cap, cpu, ok64;
@@ -592,6 +651,8 @@
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;
--- a/sys/src/9/pc/pci.c
+++ b/sys/src/9/pc/pci.c
@@ -1416,38 +1416,75 @@
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
--
⑨