diff options
| author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-09 00:44:08 +0200 |
|---|---|---|
| committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-09 00:44:08 +0200 |
| commit | 8aff0e5be65f795b8982bef7a1ec327ed8f114bf (patch) | |
| tree | fda7fd0a24c55819d41bd166fb50dce86362188d | |
| parent | 058188117b75beb7eb2831b989ce9f2aed9926d0 (diff) | |
| download | plan9front-8aff0e5be65f795b8982bef7a1ec327ed8f114bf.tar.xz | |
mp/pci: msi support for hypertransport platform
| -rw-r--r-- | sys/src/9/pc/fns.h | 1 | ||||
| -rw-r--r-- | sys/src/9/pc/mp.c | 61 | ||||
| -rw-r--r-- | sys/src/9/pc/pci.c | 95 |
3 files changed, 128 insertions, 29 deletions
diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h index 176b36aae..8ed2e8566 100644 --- a/sys/src/9/pc/fns.h +++ b/sys/src/9/pc/fns.h @@ -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*); diff --git a/sys/src/9/pc/mp.c b/sys/src/9/pc/mp.c index 27eee1da6..70ce1ee43 100644 --- a/sys/src/9/pc/mp.c +++ b/sys/src/9/pc/mp.c @@ -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; diff --git a/sys/src/9/pc/pci.c b/sys/src/9/pc/pci.c index 334edee83..e19608269 100644 --- a/sys/src/9/pc/pci.c +++ b/sys/src/9/pc/pci.c @@ -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; - - /* 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; + return enumcaps(p, matchcap, cap); +} + +int +pcihtcap(Pcidev *p, int cap) +{ + return enumcaps(p, matchhtcap, cap); } static int |
