jehanne/sys/src/kern/amd64/msi.c

121 lines
2.0 KiB
C

#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 */
if((s = getconf("*nomsi")) != nil && jehanne_atoi(s) != 0)
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;
}