shithub: riscv

Download patch

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);