2016-11-25 17:18:40 +01:00
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "io.h"
|
|
|
|
#include "apic.h"
|
|
|
|
|
|
|
|
enum {
|
|
|
|
Dpcicap = 1<<0,
|
|
|
|
Dmsicap = 1<<1,
|
|
|
|
Dvec = 1<<2,
|
|
|
|
Debug = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
/* address */
|
|
|
|
Msiabase = 0xfee00000u,
|
|
|
|
Msiadest = 1<<12, /* same as 63:56 of apic vector */
|
|
|
|
Msiaedest = 1<<4, /* same as 55:48 of apic vector */
|
|
|
|
Msialowpri = 1<<3, /* redirection hint */
|
|
|
|
Msialogical = 1<<2,
|
|
|
|
|
|
|
|
/* data */
|
|
|
|
Msidlevel = 1<<15,
|
|
|
|
Msidassert = 1<<14,
|
|
|
|
Msidlogical = 1<<11,
|
|
|
|
Msidmode = 1<<8, /* 3 bits; delivery mode */
|
|
|
|
Msidvector = 0xff<<0,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum{
|
|
|
|
/* msi capabilities */
|
|
|
|
Vmask = 1<<8,
|
|
|
|
Cap64 = 1<<7,
|
|
|
|
Mmesgmsk = 7<<4,
|
|
|
|
Mmcap = 7<<1,
|
|
|
|
Msienable = 1<<0,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
msicap(Pcidev *p)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
c = pcicap(p, PciCapMSI);
|
|
|
|
if(c == -1)
|
|
|
|
return 0;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
blacklist(Pcidev *p)
|
|
|
|
{
|
|
|
|
switch(p->vid<<16 | p->did){
|
|
|
|
case 0x11ab<<16 | 0x6485:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcimsienable(Pcidev *p, uint64_t vec)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
uint32_t c, f, d, datao, lopri, dmode, logical;
|
|
|
|
|
|
|
|
if(ioconf.nomsi)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
c = msicap(p);
|
|
|
|
if(c == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
f = pcicfgr16(p, c + 2) & ~Mmesgmsk;
|
|
|
|
|
|
|
|
if(blacklist(p) != 0)
|
|
|
|
return -1;
|
|
|
|
datao = 8;
|
|
|
|
d = vec>>48;
|
|
|
|
lopri = (vec & 0x700) == MTlp;
|
|
|
|
logical = (vec & Lm) != 0;
|
|
|
|
pcicfgw32(p, c + 4, Msiabase | Msiaedest * d
|
|
|
|
| Msialowpri * lopri | Msialogical * logical);
|
|
|
|
if(f & Cap64){
|
|
|
|
datao += 4;
|
|
|
|
pcicfgw32(p, c + 8, 0);
|
|
|
|
}
|
|
|
|
dmode = (vec >> 8) & 7;
|
|
|
|
pcicfgw16(p, c + datao, Msidassert | Msidlogical * logical
|
|
|
|
| Msidmode * dmode | (uint32_t)vec & 0xff);
|
|
|
|
if(f & Vmask)
|
|
|
|
pcicfgw32(p, c + datao + 4, 0);
|
|
|
|
|
|
|
|
/* leave vectors configured but disabled for debugging */
|
2017-04-19 23:33:14 +02:00
|
|
|
if((s = getconf("*nomsi")) != nil && jehanne_atoi(s) != 0)
|
2016-11-25 17:18:40 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
pcicfgw16(p, c + 2, f);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcimsimask(Pcidev *p, int mask)
|
|
|
|
{
|
|
|
|
uint32_t c, f;
|
|
|
|
|
|
|
|
c = msicap(p);
|
|
|
|
if(c == 0)
|
|
|
|
return -1;
|
|
|
|
f = pcicfgr16(p, c + 2) & ~Msienable;
|
|
|
|
if(mask){
|
|
|
|
pcicfgw16(p, c + 2, f & ~Msienable);
|
|
|
|
// pciclrbme(p); cheeze
|
|
|
|
}else{
|
|
|
|
pcisetbme(p);
|
|
|
|
pcicfgw16(p, c + 2, f | Msienable);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|