From 4d7c195804991b9c762f9a859679282c7014bbbb Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 7 Oct 2018 21:52:53 +0200 Subject: [PATCH] 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. --- sys/src/9/pc/fns.h | 2 ++ sys/src/9/pc/pci.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ sys/src/9/pc64/fns.h | 2 ++ 3 files changed, 69 insertions(+) diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h index d36609844..bbaafdaa6 100644 --- a/sys/src/9/pc/fns.h +++ b/sys/src/9/pc/fns.h @@ -147,6 +147,8 @@ void pcisetbme(Pcidev*); 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); diff --git a/sys/src/9/pc/pci.c b/sys/src/9/pc/pci.c index 85d052954..72874f2ae 100644 --- a/sys/src/9/pc/pci.c +++ b/sys/src/9/pc/pci.c @@ -1560,3 +1560,68 @@ pcinextcap(Pcidev *pci, int offset) } 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); +} diff --git a/sys/src/9/pc64/fns.h b/sys/src/9/pc64/fns.h index 7edaed4bc..e993e60b1 100644 --- a/sys/src/9/pc64/fns.h +++ b/sys/src/9/pc64/fns.h @@ -146,6 +146,8 @@ void pcisetbme(Pcidev*); 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);