shithub: riscv

Download patch

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