From 1376d39ef1194c76e97035a1af110a59e4ad8257 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 21 Nov 2020 16:02:21 +0100 Subject: [PATCH] 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. --- sys/src/9/bcm64/pcibcm.c | 23 ++++----------- sys/src/9/pc/mp.c | 19 +++--------- sys/src/9/port/pci.c | 62 ++++++++++++++++++++++++++++++++++++++-- sys/src/9/port/pci.h | 5 ++++ 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 @@ -410,13 +410,6 @@ Findbus: return -1; } -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, @@ -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);