tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

PCI: disable I/O or mem before probing BAR size



Hello,
while trying to boot a Xen PVH kernel as dom0, I found that Xen doesn't
allow changing memory-mapped PCI BARs if memory decode is enabled in the
command register. FreeBSD disables I/O or memory decoding in the command
register before wiriing 0xffffffff for probing the BAR size/type, and
re-enables it after. The attached patch (forget the printf, they're for
debugging a issue with Xen only) does something similar for NetBSD.
With this (and a few others hacks) I can boot a GENERIC kernel as
PVH dom0. It also still boots fine on my core i5 laptop.

Does anyone see a problem with this ?

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: dev/pci/pci_map.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pci_map.c,v
retrieving revision 1.39
diff -u -p -u -r1.39 pci_map.c
--- dev/pci/pci_map.c	2 Dec 2019 17:13:13 -0000	1.39
+++ dev/pci/pci_map.c	4 May 2020 19:06:39 -0000
@@ -49,7 +49,7 @@ static int
 pci_io_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
 {
-	pcireg_t address, mask;
+	pcireg_t address, mask, csr;
 	int s;
 
 	if (reg < PCI_MAPREG_START ||
@@ -75,9 +75,14 @@ pci_io_find(pci_chipset_tag_t pc, pcitag
 	 */
 	s = splhigh();
 	address = pci_conf_read(pc, tag, reg);
+	/* Disable decoding via the command register before writing all-1 */
+	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
+	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
+	    csr & ~PCI_COMMAND_IO_ENABLE) ;
 	pci_conf_write(pc, tag, reg, 0xffffffff);
 	mask = pci_conf_read(pc, tag, reg);
 	pci_conf_write(pc, tag, reg, address);
+	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
 	splx(s);
 
 	if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
@@ -107,6 +112,7 @@ pci_mem_find(pci_chipset_tag_t pc, pcita
 	pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff;
 	uint64_t waddress, wmask;
 	int s, is64bit, isrom;
+	pcireg_t csr;
 
 	is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT);
 	isrom = (reg == PCI_MAPREG_ROM);
@@ -138,6 +144,11 @@ pci_mem_find(pci_chipset_tag_t pc, pcita
 	 */
 	s = splhigh();
 	address = pci_conf_read(pc, tag, reg);
+	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
+	/* Disable decoding via the command register before writing all-1 */
+	printf("mem_find write csr D 0x%x 0x%x\n", csr, address);
+	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
+	    csr & ~PCI_COMMAND_MEM_ENABLE) ;
 	pci_conf_write(pc, tag, reg, 0xffffffff);
 	mask = pci_conf_read(pc, tag, reg);
 	pci_conf_write(pc, tag, reg, address);
@@ -149,6 +160,8 @@ pci_mem_find(pci_chipset_tag_t pc, pcita
 			pci_conf_write(pc, tag, reg + 4, address1);
 		}
 	}
+	printf("mem_find write csr 0x%x 0x%x 0x%x\n", csr, address, mask);
+	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
 	splx(s);
 
 	if (!isrom) {
@@ -240,14 +253,27 @@ pci_mapreg_type(pci_chipset_tag_t pc, pc
 int
 pci_mapreg_probe(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *typep)
 {
-	pcireg_t address, mask;
+	pcireg_t address, mask, csr;
 	int s;
 
 	s = splhigh();
 	address = pci_conf_read(pc, tag, reg);
+	/* Disable decoding via the command register before writing all-1 */
+	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
+	if (PCI_MAPREG_TYPE(address) == PCI_MAPREG_TYPE_IO) {
+		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
+		    csr & ~PCI_COMMAND_IO_ENABLE);
+	} else {
+		printf("pci_mapreg_probe: write c/s D MEM 0x%x 0x%x\n", csr, address);
+		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
+		    csr & ~PCI_COMMAND_MEM_ENABLE);
+	}
 	pci_conf_write(pc, tag, reg, 0xffffffff);
 	mask = pci_conf_read(pc, tag, reg);
 	pci_conf_write(pc, tag, reg, address);
+	if (PCI_MAPREG_TYPE(address) == PCI_MAPREG_TYPE_MEM) 
+		printf("pci_mapreg_probe: write c/s E 0x%x 0x%x 0x%x\n", csr, address, mask);
+	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
 	splx(s);
 
 	if (mask == 0) /* unimplemented mapping register */


Home | Main Index | Thread Index | Old Index