ref: 1376d39ef1194c76e97035a1af110a59e4ad8257
parent: cedded7b50e91344eb469efee354ee8682e33cf3
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Nov 21 11:02:21 EST 2020
kernel: add portable pcimsienable()/pcimsidisable(), disable MSI/MSI-X on pcidisable()/pcireset() This avoids some duplication in the pci support code and allows pcireset() to diable MSI and MSI-X interrupts when disabling or reseting a device.
--- a/sys/src/9/bcm64/pcibcm.c
+++ b/sys/src/9/bcm64/pcibcm.c
@@ -110,13 +110,6 @@
return data;
}
-enum {
- MSICtrl = 0x02, /* message control register (16 bit) */
- MSIAddr = 0x04, /* message address register (64 bit) */
- MSIData32 = 0x08, /* message data register for 32 bit MSI (16 bit) */
- MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
-};
-
typedef struct Pciisr Pciisr;
struct Pciisr {
void (*f)(Ureg*, void*);
@@ -130,9 +123,7 @@
void
pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a)
{
- int cap, ok64;
- u32int dat;
- u64int adr;
+ ulong dat;
Pcidev *p;
Pciisr *isr;
@@ -140,8 +131,9 @@
print("pciintrenable: %T: unknown device\n", tbdf);
return;
}
- if((cap = pcicap(p, PciCapMSI)) < 0){
- print("pciintrenable: %T: no MSI cap\n", tbdf);
+
+ if(pcimsidisable(p) < 0){
+ print("pciintrenable: %T: device doesnt support msi\n", tbdf);
return;
}
@@ -170,14 +162,9 @@
return;
}
- adr = MSI_TARGET_ADDR;
- ok64 = (pcicfgr16(p, cap + MSICtrl) & (1<<7)) != 0;
- pcicfgw32(p, cap + MSIAddr, adr);
- if(ok64) pcicfgw32(p, cap + MSIAddr + 4, adr>>32);
dat = regs[MISC_MSI_DATA_CONFIG];
dat = ((dat >> 16) & (dat & 0xFFFF)) | (isr-pciisr);
- pcicfgw16(p, cap + (ok64 ? MSIData64 : MSIData32), dat);
- pcicfgw16(p, cap + MSICtrl, 1);
+ pcimsienable(p, MSI_TARGET_ADDR, dat);
}
void
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -411,13 +411,6 @@
}
enum {
- MSICtrl = 0x02, /* message control register (16 bit) */
- MSIAddr = 0x04, /* message address register (64 bit) */
- MSIData32 = 0x08, /* message data register for 32 bit MSI (16 bit) */
- MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
-};
-
-enum {
HTMSIMapping = 0xA8,
HTMSIFlags = 0x02,
HTMSIFlagsEn = 0x01,
@@ -479,7 +472,7 @@
static int
msiintrenable(Vctl *v)
{
- int tbdf, vno, cap, cpu, ok64;
+ int tbdf, vno, cpu;
Pcidev *pci;
if(getconf("*nomsi") != nil)
@@ -494,16 +487,12 @@
}
if(htmsienable(pci) < 0)
return -1;
- cap = pcicap(pci, PciCapMSI);
- if(cap < 0)
+ if(pcimsidisable(pci) < 0)
return -1;
vno = allocvector();
cpu = mpintrcpu();
- ok64 = (pcicfgr16(pci, cap + MSICtrl) & (1<<7)) != 0;
- pcicfgw32(pci, cap + MSIAddr, (0xFEE << 20) | (cpu << 12));
- if(ok64) pcicfgw32(pci, cap + MSIAddr + 4, 0);
- pcicfgw16(pci, cap + (ok64 ? MSIData64 : MSIData32), vno | (1<<14));
- pcicfgw16(pci, cap + MSICtrl, 1);
+ if(pcimsienable(pci, 0xFEE00000ULL | (cpu << 12), vno | (1<<14)) < 0)
+ return -1;
v->isr = lapicisr;
v->eoi = lapiceoi;
return vno;
--- a/sys/src/9/port/pci.c
+++ b/sys/src/9/port/pci.c
@@ -753,7 +753,7 @@
/* don't mess with the bridges */
if(p->ccrb == 0x06)
continue;
- pciclrbme(p);
+ pcidisable(p);
}
}
@@ -870,8 +870,64 @@
}
static int
-pcigetpmrb(Pcidev* p)
+pcigetmsi(Pcidev *p)
{
+ if(p->msi != 0)
+ return p->msi;
+ return p->msi = pcicap(p, PciCapMSI);
+}
+
+enum {
+ MSICtrl = 0x02, /* message control register (16 bit) */
+ MSIAddr = 0x04, /* message address register (64 bit) */
+ MSIData32 = 0x08, /* message data register for 32 bit MSI (16 bit) */
+ MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
+};
+
+int
+pcimsienable(Pcidev *p, uvlong addr, ulong data)
+{
+ int off, ok64;
+
+ if((off = pcigetmsi(p)) < 0)
+ return -1;
+ ok64 = (pcicfgr16(p, off + MSICtrl) & (1<<7)) != 0;
+ pcicfgw32(p, off + MSIAddr, addr);
+ if(ok64) pcicfgw32(p, off + MSIAddr+4, addr >> 32);
+ pcicfgw16(p, off + (ok64 ? MSIData64 : MSIData32), data);
+ pcicfgw16(p, off + MSICtrl, 1);
+ return 0;
+}
+
+int
+pcimsidisable(Pcidev *p)
+{
+ int off;
+
+ if((off = pcigetmsi(p)) < 0)
+ return -1;
+ pcicfgw16(p, off + MSICtrl, 0);
+ return 0;
+}
+
+enum {
+ MSIXCtrl = 0x02,
+};
+
+static int
+pcimsixdisable(Pcidev *p)
+{
+ int off;
+
+ if((off = pcicap(p, PciCapMSIX)) < 0)
+ return -1;
+ pcicfgw16(p, off + MSIXCtrl, 0);
+ return 0;
+}
+
+static int
+pcigetpmrb(Pcidev *p)
+{
if(p->pmrb != 0)
return p->pmrb;
return p->pmrb = pcicap(p, PciCapPMG);
@@ -1009,5 +1065,7 @@
{
if(p == nil)
return;
+ pcimsixdisable(p);
+ pcimsidisable(p);
pciclrbme(p);
}
--- a/sys/src/9/port/pci.h
+++ b/sys/src/9/port/pci.h
@@ -199,6 +199,7 @@
} prefa;
int pmrb; /* power management register block */
+ int msi; /* MSI capability register block */
};
enum {
@@ -248,6 +249,10 @@
extern int pcicap(Pcidev *p, int cap);
extern int pcihtcap(Pcidev *p, int cap);
+
+extern int pcimsienable(Pcidev *p, uvlong addr, ulong data);
+extern int pcimsidisable(Pcidev *p);
+
extern int pcigetpms(Pcidev* p);
extern int pcisetpms(Pcidev* p, int state);