Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/pci Add pciconf_resource_reserve. This allows MD cod...
details: https://anonhg.NetBSD.org/src/rev/66ac09c3e6b3
branches: trunk
changeset: 940570:66ac09c3e6b3
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Sat Oct 10 15:22:15 2020 +0000
description:
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.
diffstat:
sys/dev/pci/pciconf.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++-
sys/dev/pci/pciconf.h | 3 +-
2 files changed, 143 insertions(+), 4 deletions(-)
diffs (214 lines):
diff -r ae583e60a0ed -r 66ac09c3e6b3 sys/dev/pci/pciconf.c
--- a/sys/dev/pci/pciconf.c Sat Oct 10 14:25:21 2020 +0000
+++ b/sys/dev/pci/pciconf.c Sat Oct 10 15:22:15 2020 +0000
@@ -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_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 @@
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 @@
(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 @@
{
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 @@
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
diff -r ae583e60a0ed -r 66ac09c3e6b3 sys/dev/pci/pciconf.h
--- a/sys/dev/pci/pciconf.h Sat Oct 10 14:25:21 2020 +0000
+++ b/sys/dev/pci/pciconf.h Sat Oct 10 15:22:15 2020 +0000
@@ -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 @@
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
Home |
Main Index |
Thread Index |
Old Index