summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authormsmith <msmith@FreeBSD.org>2000-09-27 00:51:42 +0000
committermsmith <msmith@FreeBSD.org>2000-09-27 00:51:42 +0000
commit89141ecf1bb47193882bedd0f4df88ae939ff33b (patch)
tree414f7431f8be18bca4da5d1b862d9ebd2ba3e82d /sys/i386
parent16ca3f5f60100bb6edd40ced1d8868795bb96e19 (diff)
downloadFreeBSD-src-89141ecf1bb47193882bedd0f4df88ae939ff33b.zip
FreeBSD-src-89141ecf1bb47193882bedd0f4df88ae939ff33b.tar.gz
Since the nexus is responsible for creating the I/O resources (ports, memory)
it ought to be able to deal with devices directly attached to it having allocations of such resources. Make it so.
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/i386/legacy.c150
-rw-r--r--sys/i386/i386/nexus.c150
2 files changed, 296 insertions, 4 deletions
diff --git a/sys/i386/i386/legacy.c b/sys/i386/i386/legacy.c
index 07552fc..dee1a87 100644
--- a/sys/i386/i386/legacy.c
+++ b/sys/i386/i386/legacy.c
@@ -46,6 +46,7 @@
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/malloc.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <sys/rman.h>
@@ -73,10 +74,21 @@
#include <i386/isa/intr_machdep.h>
#include <sys/rtprio.h>
+MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device");
+
+struct nexus_device {
+ struct resource_list nx_resources;
+};
+
+#define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev))
+
static struct rman irq_rman, drq_rman, port_rman, mem_rman;
static int nexus_probe(device_t);
static int nexus_attach(device_t);
+static int nexus_print_resources(struct resource_list *rl, const char *name, int type,
+ const char *format);
+static int nexus_print_all_resources(device_t dev);
static int nexus_print_child(device_t, device_t);
static device_t nexus_add_child(device_t bus, int order, const char *name,
int unit);
@@ -92,6 +104,9 @@ static int nexus_setup_intr(device_t, device_t, struct resource *, int flags,
void (*)(void *), void *, void **);
static int nexus_teardown_intr(device_t, device_t, struct resource *,
void *);
+static int nexus_set_resource(device_t, device_t, int, int, u_long, u_long);
+static int nexus_get_resource(device_t, device_t, int, int, u_long *, u_long *);
+static void nexus_delete_resource(device_t, device_t, int, int);
static device_method_t nexus_methods[] = {
/* Device interface */
@@ -113,6 +128,9 @@ static device_method_t nexus_methods[] = {
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
DEVMETHOD(bus_setup_intr, nexus_setup_intr),
DEVMETHOD(bus_teardown_intr, nexus_teardown_intr),
+ DEVMETHOD(bus_set_resource, nexus_set_resource),
+ DEVMETHOD(bus_get_resource, nexus_get_resource),
+ DEVMETHOD(bus_delete_resource, nexus_delete_resource),
{ 0, 0 }
};
@@ -132,6 +150,17 @@ nexus_probe(device_t dev)
device_quiet(dev); /* suppress attach message for neatness */
+ /*
+ * XXX working notes:
+ *
+ * - IRQ resource creation should be moved to the PIC/APIC driver.
+ * - DRQ resource creation should be moved to the DMAC driver.
+ * - The above should be sorted to probe earlier than any child busses.
+ *
+ * - Leave I/O and memory creation here, as child probes may need them.
+ * (especially eg. ACPI)
+ */
+
/*
* IRQ's are on the mainboard on old systems, but on the ISA part
* of PCI->ISA bridges. There would be multiple sets of IRQs on
@@ -236,12 +265,58 @@ nexus_attach(device_t dev)
}
static int
+nexus_print_resources(struct resource_list *rl, const char *name, int type,
+ const char *format)
+{
+ struct resource_list_entry *rle;
+ int printed, retval;
+
+ printed = 0;
+ retval = 0;
+ /* Yes, this is kinda cheating */
+ SLIST_FOREACH(rle, rl, link) {
+ if (rle->type == type) {
+ if (printed == 0)
+ retval += printf(" %s ", name);
+ else if (printed > 0)
+ retval += printf(",");
+ printed++;
+ retval += printf(format, rle->start);
+ if (rle->count > 1) {
+ retval += printf("-");
+ retval += printf(format, rle->start +
+ rle->count - 1);
+ }
+ }
+ }
+ return retval;
+}
+
+static int
+nexus_print_all_resources(device_t dev)
+{
+ struct nexus_device *ndev = DEVTONX(dev);
+ struct resource_list *rl = &ndev->nx_resources;
+ int retval = 0;
+
+ if (SLIST_FIRST(rl))
+ retval += printf(" at");
+
+ retval += nexus_print_resources(rl, "port", SYS_RES_IOPORT, "%#lx");
+ retval += nexus_print_resources(rl, "iomem", SYS_RES_MEMORY, "%#lx");
+ retval += nexus_print_resources(rl, "irq", SYS_RES_IRQ, "%ld");
+
+ return retval;
+}
+
+static int
nexus_print_child(device_t bus, device_t child)
{
int retval = 0;
retval += bus_print_child_header(bus, child);
- retval += printf(" on motherboard\n");
+ retval += nexus_print_all_resources(child);
+ retval += printf(" on motherboard\n"); /* XXX "motherboard", ick */
return (retval);
}
@@ -249,7 +324,21 @@ nexus_print_child(device_t bus, device_t child)
static device_t
nexus_add_child(device_t bus, int order, const char *name, int unit)
{
- return device_add_child_ordered(bus, order, name, unit);
+ device_t child;
+ struct nexus_device *ndev;
+
+ ndev = malloc(sizeof(struct nexus_device), M_NEXUSDEV, M_NOWAIT);
+ if (!ndev)
+ return(0);
+ bzero(ndev, sizeof(struct nexus_device));
+ resource_list_init(&ndev->nx_resources);
+
+ child = device_add_child_ordered(bus, order, name, unit);
+
+ /* should we free this in nexus_child_detached? */
+ device_set_ivars(child, ndev);
+
+ return(child);
}
/*
@@ -261,10 +350,28 @@ static struct resource *
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
+ struct nexus_device *ndev = DEVTONX(child);
struct resource *rv;
+ struct resource_list_entry *rle;
struct rman *rm;
int needactivate = flags & RF_ACTIVE;
+ /*
+ * If this is an allocation of the "default" range for a given RID, and
+ * we know what the resources for this device are (ie. they aren't maintained
+ * by a child bus), then work out the start/end values.
+ */
+ if ((start == 0UL) && (end == ~0UL) && (count == 1)) {
+ if (ndev == NULL)
+ return(NULL);
+ rle = resource_list_find(&ndev->nx_resources, type, *rid);
+ if (rle == NULL)
+ return(NULL);
+ start = rle->start;
+ end = rle->end;
+ count = rle->count;
+ }
+
flags &= ~RF_ACTIVE;
switch (type) {
@@ -440,6 +547,45 @@ nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
return (inthand_remove(ih));
}
+static int
+nexus_set_resource(device_t dev, device_t child, int type, int rid, u_long start, u_long count)
+{
+ struct nexus_device *ndev = DEVTONX(child);
+ struct resource_list *rl = &ndev->nx_resources;
+
+ /* XXX this should return a success/failure indicator */
+ resource_list_add(rl, type, rid, start, start + count - 1, count);
+ return(0);
+}
+
+static int
+nexus_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp, u_long *countp)
+{
+ struct nexus_device *ndev = DEVTONX(child);
+ struct resource_list *rl = &ndev->nx_resources;
+ struct resource_list_entry *rle;
+
+ rle = resource_list_find(rl, type, rid);
+ device_printf(child, "type %d rid %d startp %p countp %p - got %p\n",
+ type, rid, startp, countp, rle);
+ if (!rle)
+ return(ENOENT);
+ if (startp)
+ *startp = rle->start;
+ if (countp)
+ *countp = rle->count;
+ return(0);
+}
+
+static void
+nexus_delete_resource(device_t dev, device_t child, int type, int rid)
+{
+ struct nexus_device *ndev = DEVTONX(child);
+ struct resource_list *rl = &ndev->nx_resources;
+
+ resource_list_delete(rl, type, rid);
+}
+
/*
* Placeholder which claims PnP 'devices' which describe system
* resources.
diff --git a/sys/i386/i386/nexus.c b/sys/i386/i386/nexus.c
index 07552fc..dee1a87 100644
--- a/sys/i386/i386/nexus.c
+++ b/sys/i386/i386/nexus.c
@@ -46,6 +46,7 @@
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/malloc.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <sys/rman.h>
@@ -73,10 +74,21 @@
#include <i386/isa/intr_machdep.h>
#include <sys/rtprio.h>
+MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device");
+
+struct nexus_device {
+ struct resource_list nx_resources;
+};
+
+#define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev))
+
static struct rman irq_rman, drq_rman, port_rman, mem_rman;
static int nexus_probe(device_t);
static int nexus_attach(device_t);
+static int nexus_print_resources(struct resource_list *rl, const char *name, int type,
+ const char *format);
+static int nexus_print_all_resources(device_t dev);
static int nexus_print_child(device_t, device_t);
static device_t nexus_add_child(device_t bus, int order, const char *name,
int unit);
@@ -92,6 +104,9 @@ static int nexus_setup_intr(device_t, device_t, struct resource *, int flags,
void (*)(void *), void *, void **);
static int nexus_teardown_intr(device_t, device_t, struct resource *,
void *);
+static int nexus_set_resource(device_t, device_t, int, int, u_long, u_long);
+static int nexus_get_resource(device_t, device_t, int, int, u_long *, u_long *);
+static void nexus_delete_resource(device_t, device_t, int, int);
static device_method_t nexus_methods[] = {
/* Device interface */
@@ -113,6 +128,9 @@ static device_method_t nexus_methods[] = {
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
DEVMETHOD(bus_setup_intr, nexus_setup_intr),
DEVMETHOD(bus_teardown_intr, nexus_teardown_intr),
+ DEVMETHOD(bus_set_resource, nexus_set_resource),
+ DEVMETHOD(bus_get_resource, nexus_get_resource),
+ DEVMETHOD(bus_delete_resource, nexus_delete_resource),
{ 0, 0 }
};
@@ -132,6 +150,17 @@ nexus_probe(device_t dev)
device_quiet(dev); /* suppress attach message for neatness */
+ /*
+ * XXX working notes:
+ *
+ * - IRQ resource creation should be moved to the PIC/APIC driver.
+ * - DRQ resource creation should be moved to the DMAC driver.
+ * - The above should be sorted to probe earlier than any child busses.
+ *
+ * - Leave I/O and memory creation here, as child probes may need them.
+ * (especially eg. ACPI)
+ */
+
/*
* IRQ's are on the mainboard on old systems, but on the ISA part
* of PCI->ISA bridges. There would be multiple sets of IRQs on
@@ -236,12 +265,58 @@ nexus_attach(device_t dev)
}
static int
+nexus_print_resources(struct resource_list *rl, const char *name, int type,
+ const char *format)
+{
+ struct resource_list_entry *rle;
+ int printed, retval;
+
+ printed = 0;
+ retval = 0;
+ /* Yes, this is kinda cheating */
+ SLIST_FOREACH(rle, rl, link) {
+ if (rle->type == type) {
+ if (printed == 0)
+ retval += printf(" %s ", name);
+ else if (printed > 0)
+ retval += printf(",");
+ printed++;
+ retval += printf(format, rle->start);
+ if (rle->count > 1) {
+ retval += printf("-");
+ retval += printf(format, rle->start +
+ rle->count - 1);
+ }
+ }
+ }
+ return retval;
+}
+
+static int
+nexus_print_all_resources(device_t dev)
+{
+ struct nexus_device *ndev = DEVTONX(dev);
+ struct resource_list *rl = &ndev->nx_resources;
+ int retval = 0;
+
+ if (SLIST_FIRST(rl))
+ retval += printf(" at");
+
+ retval += nexus_print_resources(rl, "port", SYS_RES_IOPORT, "%#lx");
+ retval += nexus_print_resources(rl, "iomem", SYS_RES_MEMORY, "%#lx");
+ retval += nexus_print_resources(rl, "irq", SYS_RES_IRQ, "%ld");
+
+ return retval;
+}
+
+static int
nexus_print_child(device_t bus, device_t child)
{
int retval = 0;
retval += bus_print_child_header(bus, child);
- retval += printf(" on motherboard\n");
+ retval += nexus_print_all_resources(child);
+ retval += printf(" on motherboard\n"); /* XXX "motherboard", ick */
return (retval);
}
@@ -249,7 +324,21 @@ nexus_print_child(device_t bus, device_t child)
static device_t
nexus_add_child(device_t bus, int order, const char *name, int unit)
{
- return device_add_child_ordered(bus, order, name, unit);
+ device_t child;
+ struct nexus_device *ndev;
+
+ ndev = malloc(sizeof(struct nexus_device), M_NEXUSDEV, M_NOWAIT);
+ if (!ndev)
+ return(0);
+ bzero(ndev, sizeof(struct nexus_device));
+ resource_list_init(&ndev->nx_resources);
+
+ child = device_add_child_ordered(bus, order, name, unit);
+
+ /* should we free this in nexus_child_detached? */
+ device_set_ivars(child, ndev);
+
+ return(child);
}
/*
@@ -261,10 +350,28 @@ static struct resource *
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
+ struct nexus_device *ndev = DEVTONX(child);
struct resource *rv;
+ struct resource_list_entry *rle;
struct rman *rm;
int needactivate = flags & RF_ACTIVE;
+ /*
+ * If this is an allocation of the "default" range for a given RID, and
+ * we know what the resources for this device are (ie. they aren't maintained
+ * by a child bus), then work out the start/end values.
+ */
+ if ((start == 0UL) && (end == ~0UL) && (count == 1)) {
+ if (ndev == NULL)
+ return(NULL);
+ rle = resource_list_find(&ndev->nx_resources, type, *rid);
+ if (rle == NULL)
+ return(NULL);
+ start = rle->start;
+ end = rle->end;
+ count = rle->count;
+ }
+
flags &= ~RF_ACTIVE;
switch (type) {
@@ -440,6 +547,45 @@ nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
return (inthand_remove(ih));
}
+static int
+nexus_set_resource(device_t dev, device_t child, int type, int rid, u_long start, u_long count)
+{
+ struct nexus_device *ndev = DEVTONX(child);
+ struct resource_list *rl = &ndev->nx_resources;
+
+ /* XXX this should return a success/failure indicator */
+ resource_list_add(rl, type, rid, start, start + count - 1, count);
+ return(0);
+}
+
+static int
+nexus_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp, u_long *countp)
+{
+ struct nexus_device *ndev = DEVTONX(child);
+ struct resource_list *rl = &ndev->nx_resources;
+ struct resource_list_entry *rle;
+
+ rle = resource_list_find(rl, type, rid);
+ device_printf(child, "type %d rid %d startp %p countp %p - got %p\n",
+ type, rid, startp, countp, rle);
+ if (!rle)
+ return(ENOENT);
+ if (startp)
+ *startp = rle->start;
+ if (countp)
+ *countp = rle->count;
+ return(0);
+}
+
+static void
+nexus_delete_resource(device_t dev, device_t child, int type, int rid)
+{
+ struct nexus_device *ndev = DEVTONX(child);
+ struct resource_list *rl = &ndev->nx_resources;
+
+ resource_list_delete(rl, type, rid);
+}
+
/*
* Placeholder which claims PnP 'devices' which describe system
* resources.
OpenPOWER on IntegriCloud