Module Name:    src
Committed By:   jmcneill
Date:           Sat Oct 10 15:22:15 UTC 2020

Modified Files:
        src/sys/dev/pci: pciconf.c pciconf.h

Log Message:
Add pciconf_resource_reserve. This allows MD code to mark specific memory
and I/O regions as in use. When pciconf finds a device already configured
to use one of these regions, the device config is left as-is.


To generate a diff of this commit:
cvs rdiff -u -r1.48 -r1.49 src/sys/dev/pci/pciconf.c
cvs rdiff -u -r1.14 -r1.15 src/sys/dev/pci/pciconf.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/pciconf.c
diff -u src/sys/dev/pci/pciconf.c:1.48 src/sys/dev/pci/pciconf.c:1.49
--- src/sys/dev/pci/pciconf.c:1.48	Wed Jul  8 13:12:35 2020
+++ src/sys/dev/pci/pciconf.c	Sat Oct 10 15:22:15 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: pciconf.c,v 1.48 2020/07/08 13:12:35 thorpej Exp $	*/
+/*	$NetBSD: pciconf.c,v 1.49 2020/10/10 15:22:15 jmcneill Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -65,7 +65,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pciconf.c,v 1.48 2020/07/08 13:12:35 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pciconf.c,v 1.49 2020/10/10 15:22:15 jmcneill Exp $");
 
 #include "opt_pci.h"
 
@@ -117,6 +117,16 @@ struct pciconf_resources {
 	struct pciconf_resource resources[PCICONF_RESOURCE_NTYPES];
 };
 
+struct pciconf_resource_rsvd {
+	int		type;
+	uint64_t	start;
+	bus_size_t	size;
+	LIST_ENTRY(pciconf_resource_rsvd) next;
+};
+
+static LIST_HEAD(, pciconf_resource_rsvd) pciconf_resource_reservations =
+    LIST_HEAD_INITIALIZER(pciconf_resource_reservations);
+
 typedef struct _s_pciconf_dev_t {
 	int		ipin;
 	int		iline;
@@ -506,6 +516,73 @@ err:
 	return NULL;
 }
 
+static bool
+pci_resource_is_reserved(int type, uint64_t addr, uint64_t size)
+{
+	struct pciconf_resource_rsvd *rsvd;
+
+	LIST_FOREACH(rsvd, &pciconf_resource_reservations, next) {
+		if (rsvd->type != type)
+			continue;
+		if (rsvd->start <= addr + size && rsvd->start + rsvd->size >= addr)
+			return true;
+	}
+
+	return false;
+}
+
+static bool
+pci_device_is_reserved(pciconf_bus_t *pb, pcitag_t tag)
+{
+	pcireg_t base, base64, mask, mask64;
+	uint64_t addr, size;
+	int br, width;
+
+	/*
+	 * Look to see if this device is enabled and one of the resources
+	 * is already in use (firmware configured console device). If so,
+	 * skip resource assignment and use firmware values.
+	 */
+	width = 4;
+	for (br = PCI_MAPREG_START; br < PCI_MAPREG_END; br += width) {
+
+		base = pci_conf_read(pb->pc, tag, br);
+		pci_conf_write(pb->pc, tag, br, 0xffffffff);
+		mask = pci_conf_read(pb->pc, tag, br);
+		pci_conf_write(pb->pc, tag, br, base);
+		width = 4;
+
+		switch (PCI_MAPREG_TYPE(base)) {
+		case PCI_MAPREG_TYPE_IO:
+			addr = PCI_MAPREG_IO_ADDR(base);
+			size = PCI_MAPREG_IO_SIZE(mask);
+			if (pci_resource_is_reserved(PCI_CONF_MAP_IO, addr, size))
+				return true;
+			break;
+		case PCI_MAPREG_TYPE_MEM:
+			if (PCI_MAPREG_MEM_TYPE(base) == PCI_MAPREG_MEM_TYPE_64BIT) {
+				base64 = pci_conf_read(pb->pc, tag, br + 4);
+				pci_conf_write(pb->pc, tag, br + 4, 0xffffffff);
+				mask64 = pci_conf_read(pb->pc, tag, br + 4);
+				pci_conf_write(pb->pc, tag, br + 4, base64);
+				addr = (uint64_t)PCI_MAPREG_MEM64_ADDR(
+				      (((uint64_t)base64) << 32) | base);
+				size = (uint64_t)PCI_MAPREG_MEM64_SIZE(
+				      (((uint64_t)mask64) << 32) | mask);
+				width = 8;
+			} else {
+				addr = PCI_MAPREG_MEM_ADDR(base);
+				size = PCI_MAPREG_MEM_SIZE(mask);
+			}
+			if (pci_resource_is_reserved(PCI_CONF_MAP_MEM, addr, size))
+				return true;
+			break;
+		}
+	}
+
+	return false;
+}
+
 static int
 pci_do_device_query(pciconf_bus_t *pb, pcitag_t tag, int dev, int func,
     int mode)
@@ -595,6 +672,14 @@ pci_do_device_query(pciconf_bus_t *pb, p
 				(pd->min_gnt + pd->max_lat);
 	}
 
+	if (PCI_HDRTYPE_TYPE(bhlc) == PCI_HDRTYPE_DEVICE &&
+	    pci_device_is_reserved(pb, tag)) {
+		/*
+		 * Device already configured by firmware.
+		 */
+		return 0;
+	}
+
 	width = 4;
 	for (br = reg_start; br < reg_end; br += width) {
 #if 0
@@ -1312,7 +1397,9 @@ pciconf_resource_add(struct pciconf_reso
 {
 	bus_addr_t end = start + (size - 1);
 	struct pciconf_resource *r;
-	int error;
+	struct pciconf_resource_rsvd *rsvd;
+	int error, rsvd_type, align;
+	vmem_addr_t result;
 	bool first;
 
 	if (size == 0 || end <= start)
@@ -1341,10 +1428,61 @@ pciconf_resource_add(struct pciconf_reso
 
 	r->total_size += size;
 
+	switch (type) {
+	case PCICONF_RESOURCE_IO:
+		rsvd_type = PCI_CONF_MAP_IO;
+		align = 0x1000;
+		break;
+	case PCICONF_RESOURCE_MEM:
+	case PCICONF_RESOURCE_PREFETCHABLE_MEM:
+		rsvd_type = PCI_CONF_MAP_MEM;
+		align = 0x100000;
+		break;
+	default:
+		rsvd_type = 0;
+		align = 0;
+		break;
+	}
+
+	/*
+	 * Exclude reserved ranges from available resources
+	 */
+	LIST_FOREACH(rsvd, &pciconf_resource_reservations, next) {
+		if (rsvd->type != rsvd_type)
+			continue;
+		/*
+		 * The reserved range may not be within our resource window.
+		 * That's fine, so ignore the error.
+		 */
+		(void)vmem_xalloc(r->arena, rsvd->size, align, 0, 0,
+				  rsvd->start, rsvd->start + rsvd->size,
+				  VM_BESTFIT | VM_NOSLEEP,
+				  &result);
+	}
+
 	return 0;
 }
 
 /*
+ * pciconf_resource_reserve:
+ *
+ *	Mark a pci configuration resource as in-use. Devices
+ *	already configured to use these resources are skipped
+ *	during resource assignment.
+ */
+void
+pciconf_resource_reserve(int type, bus_addr_t start, bus_size_t size)
+{
+	struct pciconf_resource_rsvd *rsvd;
+
+	rsvd = kmem_zalloc(sizeof(*rsvd), KM_SLEEP);
+	rsvd->type = type;
+	rsvd->start = start;
+	rsvd->size = size;
+	LIST_INSERT_HEAD(&pciconf_resource_reservations, rsvd, next);
+}
+
+/*
  * Let's configure the PCI bus.
  * This consists of basically scanning for all existing devices,
  * identifying their needs, and then making another pass over them

Index: src/sys/dev/pci/pciconf.h
diff -u src/sys/dev/pci/pciconf.h:1.14 src/sys/dev/pci/pciconf.h:1.15
--- src/sys/dev/pci/pciconf.h:1.14	Tue Jul  7 03:38:49 2020
+++ src/sys/dev/pci/pciconf.h	Sat Oct 10 15:22:15 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: pciconf.h,v 1.14 2020/07/07 03:38:49 thorpej Exp $	*/
+/*	$NetBSD: pciconf.h,v 1.15 2020/10/10 15:22:15 jmcneill Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -51,6 +51,7 @@ struct pciconf_resources *
 void	pciconf_resource_fini(struct pciconf_resources *);
 int	pciconf_resource_add(struct pciconf_resources *, int,
 	    bus_addr_t, bus_size_t);
+void	pciconf_resource_reserve(int, bus_addr_t, bus_size_t);
 
 /*
  * args: pci_chipset_tag_t, resources, firstbus, cacheline_size

Reply via email to