ref: 4d7c195804991b9c762f9a859679282c7014bbbb
parent: 4e4f2aca32c3409a5fca3341dccd14318c18f9b1
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Oct 7 17:52:53 EDT 2018
pc, pc64: add pcienable() and pcidisable() functions pcienable() puts a device in fully powered on state and does some missing initialization that UEFI might have skipped such as I/O and Memory requests being disabled. pcidisable() is ment to shutdown the device, but currently just disables dma to prevent accidents.
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -147,6 +147,8 @@
void pcisetioe(Pcidev*);
void pcisetmwi(Pcidev*);
int pcisetpms(Pcidev*, int);
+void pcienable(Pcidev*);
+void pcidisable(Pcidev*);
void pcmcisread(PCMslot*);
int pcmcistuple(int, int, int, void*, int);
PCMmap* pcmmap(int, ulong, int, int);
--- a/sys/src/9/pc/pci.c
+++ b/sys/src/9/pc/pci.c
@@ -1560,3 +1560,68 @@
}
return pcicfgr8(pci, offset+1) & ~3;
}
+
+void
+pcienable(Pcidev *p)
+{
+ uint pcr;
+ int i;
+
+ if(p == nil)
+ return;
+
+ pcienable(p->parent);
+
+ switch(pcisetpms(p, 0)){
+ case 1:
+ print("pcienable %T: wakeup from D1\n", p->tbdf);
+ break;
+ case 2:
+ print("pcienable %T: wakeup from D2\n", p->tbdf);
+ if(p->bridge != nil)
+ delay(100); /* B2: minimum delay 50ms */
+ else
+ delay(1); /* D2: minimum delay 200µs */
+ break;
+ case 3:
+ print("pcienable %T: wakeup from D3\n", p->tbdf);
+ delay(100); /* D3: minimum delay 50ms */
+
+ /* restore registers */
+ for(i = 0; i < 6; i++)
+ pcicfgw32(p, PciBAR0+i*4, p->mem[i].bar);
+ pcicfgw8(p, PciINTL, p->intl);
+ pcicfgw8(p, PciLTR, p->ltr);
+ pcicfgw8(p, PciCLS, p->cls);
+ pcicfgw16(p, PciPCR, p->pcr);
+ break;
+ }
+
+ if(p->bridge != nil)
+ pcr = IOen|MEMen|MASen;
+ else {
+ pcr = 0;
+ for(i = 0; i < 6; i++){
+ if(p->mem[i].size == 0)
+ continue;
+ if(p->mem[i].bar & 1)
+ pcr |= IOen;
+ else
+ pcr |= MEMen;
+ }
+ }
+
+ if((p->pcr & pcr) != pcr){
+ print("pcienable %T: pcr %ux->%ux\n", p->tbdf, p->pcr, p->pcr|pcr);
+ p->pcr |= pcr;
+ pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr, 0);
+ }
+}
+
+void
+pcidisable(Pcidev *p)
+{
+ if(p == nil)
+ return;
+ pciclrbme(p);
+}
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -146,6 +146,8 @@
void pcisetioe(Pcidev*);
void pcisetmwi(Pcidev*);
int pcisetpms(Pcidev*, int);
+void pcienable(Pcidev*);
+void pcidisable(Pcidev*);
void pcmcisread(PCMslot*);
int pcmcistuple(int, int, int, void*, int);
PCMmap* pcmmap(int, ulong, int, int);