git: 9front

Download patch

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