summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2020-11-21 16:02:21 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2020-11-21 16:02:21 +0100
commit1376d39ef1194c76e97035a1af110a59e4ad8257 (patch)
tree0025763d0b5c7be90716dfa767957d525272561b
parentcedded7b50e91344eb469efee354ee8682e33cf3 (diff)
downloadplan9front-1376d39ef1194c76e97035a1af110a59e4ad8257.tar.xz
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.
-rw-r--r--sys/src/9/bcm64/pcibcm.c23
-rw-r--r--sys/src/9/pc/mp.c19
-rw-r--r--sys/src/9/port/pci.c62
-rw-r--r--sys/src/9/port/pci.h5
4 files changed, 74 insertions, 35 deletions
diff --git a/sys/src/9/bcm64/pcibcm.c b/sys/src/9/bcm64/pcibcm.c
index c1270f51c..5a6780465 100644
--- a/sys/src/9/bcm64/pcibcm.c
+++ b/sys/src/9/bcm64/pcibcm.c
@@ -110,13 +110,6 @@ pcicfgrw8(int tbdf, int rno, int data, int read)
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 @@ static Lock pciisrlk;
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 @@ pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a)
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 @@ pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a)
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
diff --git a/sys/src/9/pc/mp.c b/sys/src/9/pc/mp.c
index 60b720c81..87aca1b1c 100644
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -411,13 +411,6 @@ Findbus:
}
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 @@ htmsienable(Pcidev *pdev)
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 @@ msiintrenable(Vctl *v)
}
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;
diff --git a/sys/src/9/port/pci.c b/sys/src/9/port/pci.c
index 5c4125424..3efe83b00 100644
--- a/sys/src/9/port/pci.c
+++ b/sys/src/9/port/pci.c
@@ -753,7 +753,7 @@ pcireset(void)
/* don't mess with the bridges */
if(p->ccrb == 0x06)
continue;
- pciclrbme(p);
+ pcidisable(p);
}
}
@@ -870,7 +870,63 @@ pcihtcap(Pcidev *p, int cap)
}
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;
@@ -1009,5 +1065,7 @@ pcidisable(Pcidev *p)
{
if(p == nil)
return;
+ pcimsixdisable(p);
+ pcimsidisable(p);
pciclrbme(p);
}
diff --git a/sys/src/9/port/pci.h b/sys/src/9/port/pci.h
index 176117119..fc84d1e2b 100644
--- a/sys/src/9/port/pci.h
+++ b/sys/src/9/port/pci.h
@@ -199,6 +199,7 @@ struct Pcidev
} prefa;
int pmrb; /* power management register block */
+ int msi; /* MSI capability register block */
};
enum {
@@ -248,6 +249,10 @@ extern void pciclrmwi(Pcidev* p);
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);