diff options
author | Jennifer Averett <jennifer.averett@oarcorp.com> | 2012-07-09 10:23:19 -0500 |
---|---|---|
committer | Jennifer Averett <jennifer.averett@oarcorp.com> | 2012-07-09 10:23:19 -0500 |
commit | 1e36900df6705e7b4e6882e618d3bfe498fe5665 (patch) | |
tree | 88998efee236f6fab426d46deed84f6c7b434f22 | |
parent | Modified I386_BUS_SPACE_xxx values. (diff) | |
download | rtems-libbsd-1e36900df6705e7b4e6882e618d3bfe498fe5665.tar.bz2 |
Added nexus resource routines.
-rw-r--r-- | rtemsbsd/src/rtems-bsd-nexus.c | 305 | ||||
-rw-r--r-- | rtemsbsd/src/rtems-bsd-pci_bus.c | 1 |
2 files changed, 303 insertions, 3 deletions
diff --git a/rtemsbsd/src/rtems-bsd-nexus.c b/rtemsbsd/src/rtems-bsd-nexus.c index 259bf42a..6b85207e 100644 --- a/rtemsbsd/src/rtems-bsd-nexus.c +++ b/rtemsbsd/src/rtems-bsd-nexus.c @@ -46,26 +46,320 @@ #include <freebsd/sys/bus.h> #include <freebsd/sys/kernel.h> #include <freebsd/sys/module.h> +#include <freebsd/sys/rman.h> +#include <freebsd/sys/malloc.h> + +#if defined(__i386__) +#include <freebsd/machine/rtems-bsd-config.h> +#define I386_BUS_SPACE_MEM 0 /* space is mem space */ +#endif + +/* XXX */ +#define NUM_IO_INTS 30 + +#ifdef __amd64__ +#define BUS_SPACE_IO AMD64_BUS_SPACE_IO +#define BUS_SPACE_MEM AMD64_BUS_SPACE_MEM +#else +#define BUS_SPACE_IO I386_BUS_SPACE_IO +#define BUS_SPACE_MEM I386_BUS_SPACE_MEM +#endif + + +#define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev)) + +static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device"); +struct rman irq_rman, drq_rman, port_rman, mem_rman; +struct nexus_device { + struct resource_list nx_resources; +}; + +void +nexus_init_resources(void) +{ + int irq; + + /* + * 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 + * multi-ISA-bus systems. PCI interrupts are routed to the ISA + * component, so in a way, PCI can be a partial child of an ISA bus(!). + * APIC interrupts are global though. + */ + irq_rman.rm_start = 0; + irq_rman.rm_type = RMAN_ARRAY; + irq_rman.rm_descr = "Interrupt request lines"; + irq_rman.rm_end = NUM_IO_INTS - 1; + if (rman_init(&irq_rman)) + panic("nexus_init_resources irq_rman"); + /* + * We search for regions of existing IRQs and add those to the IRQ + * resource manager. + */ + for (irq = 0; irq < NUM_IO_INTS; irq++) +#ifndef __rtems__ + if (intr_lookup_source(irq) != NULL) +#endif + if (rman_manage_region(&irq_rman, irq, irq) != 0) + panic("nexus_init_resources irq_rmand"); + + /* + * ISA DMA on PCI systems is implemented in the ISA part of each + * PCI->ISA bridge and the channels can be duplicated if there are + * multiple bridges. (eg: laptops with docking stations) + */ + drq_rman.rm_start = 0; +#ifdef PC98 + drq_rman.rm_end = 3; +#else + drq_rman.rm_end = 7; +#endif + drq_rman.rm_type = RMAN_ARRAY; + drq_rman.rm_descr = "DMA request lines"; + /* XXX drq 0 not available on some machines */ + if (rman_init(&drq_rman) + || rman_manage_region(&drq_rman, + drq_rman.rm_start, drq_rman.rm_end)) + panic("nexus_init_resources drq_rman"); + + /* + * However, IO ports and Memory truely are global at this level, + * as are APIC interrupts (however many IO APICS there turn out + * to be on large systems..) + */ + port_rman.rm_start = 0; + port_rman.rm_end = 0xffff; + port_rman.rm_type = RMAN_ARRAY; + port_rman.rm_descr = "I/O ports"; + if (rman_init(&port_rman) + || rman_manage_region(&port_rman, 0, 0xffff)) + panic("nexus_init_resources port_rman"); + + mem_rman.rm_start = 0; + mem_rman.rm_end = ~0u; + mem_rman.rm_type = RMAN_ARRAY; + mem_rman.rm_descr = "I/O memory addresses"; + if (rman_init(&mem_rman) + || rman_manage_region(&mem_rman, 0, ~0)) + panic("nexus_init_resources mem_rman"); +} + +static int +nexus_attach(device_t dev) +{ + + nexus_init_resources(); + bus_generic_probe(dev); + + /* + * Explicitly add the legacy0 device here. Other platform + * types (such as ACPI), use their own nexus(4) subclass + * driver to override this routine and add their own root bus. + */ + if (BUS_ADD_CHILD(dev, 10, "legacy", 0) == NULL) + panic("legacy: could not attach"); + bus_generic_attach(dev); + return 0; +} static int nexus_probe(device_t dev) { size_t unit = 0; - +#if 0 /* FIXME */ for (unit = 0; _bsd_nexus_devices [unit] != NULL; ++unit) { device_add_child(dev, _bsd_nexus_devices [unit], unit); } - +#endif device_set_desc(dev, "RTEMS Nexus device"); return (0); } +static device_t +nexus_add_child(device_t bus, u_int order, const char *name, int unit) +{ + device_t child; + struct nexus_device *ndev; + + ndev = malloc(sizeof(struct nexus_device), M_NEXUSDEV, M_NOWAIT|M_ZERO); + if (!ndev) + return(0); + 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); +} + +/* + * Allocate a resource on behalf of child. NB: child is usually going to be a + * child of one of our descendants, not a direct child of nexus0. + * (Exceptions include npx.) + */ +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) { + case SYS_RES_IRQ: +printf( "nexus_alloc_resource: IRQ\n" ); + rm = &irq_rman; + break; + + case SYS_RES_DRQ: +printf( "nexus_alloc_resource: DRQ\n" ); + rm = &drq_rman; + break; + + case SYS_RES_IOPORT: +printf( "nexus_alloc_resource: IO\n" ); + rm = &port_rman; + break; + + case SYS_RES_MEMORY: +printf( "nexus_alloc_resource: Memory\n" ); + rm = &mem_rman; + break; + + default: + return 0; + } + + rv = rman_reserve_resource(rm, start, end, count, flags, child); +printf( "nexus_alloc_resource: rman_reserve_resource ==> %d\n", rv ); + if (rv == 0) + return 0; + rman_set_rid(rv, *rid); + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { +printf( "nexus_alloc_resource: bus_activate_resource failed\n", rv ); + rman_release_resource(rv); + return 0; + } + } + + return rv; +} + +static int +nexus_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ +#ifdef PC98 + bus_space_handle_t bh; + int error; +#endif + void *vaddr; + + /* + * If this is a memory resource, map it into the kernel. + */ + switch (type) { + case SYS_RES_IOPORT: +#ifdef PC98 + error = i386_bus_space_handle_alloc(I386_BUS_SPACE_IO, + rman_get_start(r), rman_get_size(r), &bh); + if (error) + return (error); + rman_set_bushandle(r, bh); +#else + rman_set_bushandle(r, rman_get_start(r)); +#endif + rman_set_bustag(r, BUS_SPACE_IO); + break; + case SYS_RES_MEMORY: +#ifdef PC98 + error = i386_bus_space_handle_alloc(I386_BUS_SPACE_MEM, + rman_get_start(r), rman_get_size(r), &bh); + if (error) + return (error); +#endif + rman_set_bustag(r, BUS_SPACE_MEM); +#ifdef PC98 + /* PC-98: the type of bus_space_handle_t is the structure. */ + bh->bsh_base = (bus_addr_t) vaddr; + rman_set_bushandle(r, bh); +#else + /* IBM-PC: the type of bus_space_handle_t is u_int */ + rman_set_bushandle(r, (bus_space_handle_t) vaddr); +#endif + } + return (rman_activate_resource(r)); +} + +static int +nexus_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + +#ifdef PC98 + if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { + bus_space_handle_t bh; + + bh = rman_get_bushandle(r); + i386_bus_space_handle_free(rman_get_bustag(r), bh, bh->bsh_sz); + } +#endif + return (rman_deactivate_resource(r)); +} + +static int +nexus_release_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + if (rman_get_flags(r) & RF_ACTIVE) { + int error = bus_deactivate_resource(child, type, rid, r); + if (error) + return error; + } + return (rman_release_resource(r)); +} + static device_method_t nexus_methods [] = { /* Device interface */ DEVMETHOD(device_probe, nexus_probe), - DEVMETHOD(device_attach, bus_generic_attach), + DEVMETHOD(device_attach, nexus_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), @@ -73,6 +367,11 @@ static device_method_t nexus_methods [] = { /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_add_child, nexus_add_child), + DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), + DEVMETHOD(bus_release_resource, nexus_release_resource), + DEVMETHOD(bus_activate_resource, nexus_activate_resource), + DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), { 0, 0 } }; diff --git a/rtemsbsd/src/rtems-bsd-pci_bus.c b/rtemsbsd/src/rtems-bsd-pci_bus.c index 67288cea..62cd96c1 100644 --- a/rtemsbsd/src/rtems-bsd-pci_bus.c +++ b/rtemsbsd/src/rtems-bsd-pci_bus.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include <freebsd/local/pcib_if.h> #include <rtems/pci.h> +#include <freebsd/machine/bus.h> int pcibios_pcib_route_interrupt(device_t pcib, device_t dev, int pin) |