From 369e2c4473245603dd587818b7550eb11546e345 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 13 Nov 2013 12:51:17 +0100 Subject: nexus: Add table based Nexus device initialization --- Makefile | 1 + freebsd-to-rtems.py | 1 + rtemsbsd/bsp/bsp-bsd-nexus-devices.c | 68 ++++++ rtemsbsd/include/rtems/bsd/bsd.h | 22 ++ rtemsbsd/rtems/rtems-bsd-nexus.c | 461 ++++++++++++----------------------- 5 files changed, 246 insertions(+), 307 deletions(-) create mode 100644 rtemsbsd/bsp/bsp-bsd-nexus-devices.c diff --git a/Makefile b/Makefile index 569dc7e2..1181ab6a 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,7 @@ LIB_C_FILES += rtemsbsd/rtems/syslog.c LIB_C_FILES += rtemsbsd/sys/dev/usb/controller/ehci_mpc83xx.c LIB_C_FILES += rtemsbsd/sys/dev/usb/controller/ohci_lpc24xx.c LIB_C_FILES += rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c +LIB_C_FILES += rtemsbsd/bsp/bsp-bsd-nexus-devices.c LIB_GEN_FILES += rtemsbsd/rtems/rtems-kvm-symbols.c LIB_C_FILES += rtemsbsd/rtems/rtems-kvm-symbols.c rtemsbsd/rtems/rtems-kvm-symbols.c: rtemsbsd/rtems/generate_kvm_symbols diff --git a/freebsd-to-rtems.py b/freebsd-to-rtems.py index a36799d3..b29bcb19 100755 --- a/freebsd-to-rtems.py +++ b/freebsd-to-rtems.py @@ -654,6 +654,7 @@ rtems.addRTEMSSourceFiles( 'sys/dev/usb/controller/ehci_mpc83xx.c', 'sys/dev/usb/controller/ohci_lpc24xx.c', 'sys/dev/usb/controller/ohci_lpc32xx.c', + 'bsp/bsp-bsd-nexus-devices.c', ] ) diff --git a/rtemsbsd/bsp/bsp-bsd-nexus-devices.c b/rtemsbsd/bsp/bsp-bsd-nexus-devices.c new file mode 100644 index 00000000..4f1e1a1f --- /dev/null +++ b/rtemsbsd/bsp/bsp-bsd-nexus-devices.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include + +#if defined(LIBBSP_ARM_REALVIEW_PBX_A9_BSP_H) +#include + +static const rtems_bsd_device_resource smc0_res[] = { + { + .type = RTEMS_BSD_RES_MEMORY, + .start_request = 0, + .start_actual = 0x4e000000 + }, { + .type = RTEMS_BSD_RES_IRQ, + .start_request = 0, + .start_actual = RVPBXA9_IRQ_ETHERNET + } +}; + +const rtems_bsd_device rtems_bsd_nexus_devices[] = { + { + .name = "smc", + .unit = 0, + .resource_count = RTEMS_ARRAY_SIZE(smc0_res), + .resources = &smc0_res[0] + } +}; + +SYSINIT_DRIVER_REFERENCE(smc, nexus); +#else +const rtems_bsd_device rtems_bsd_nexus_devices[0]; +#endif + +const size_t rtems_bsd_nexus_device_count = + RTEMS_ARRAY_SIZE(rtems_bsd_nexus_devices); diff --git a/rtemsbsd/include/rtems/bsd/bsd.h b/rtemsbsd/include/rtems/bsd/bsd.h index d7348420..5e847118 100644 --- a/rtemsbsd/include/rtems/bsd/bsd.h +++ b/rtemsbsd/include/rtems/bsd/bsd.h @@ -46,6 +46,28 @@ extern "C" { #include +typedef enum { + RTEMS_BSD_RES_IRQ = 1, + RTEMS_BSD_RES_MEMORY = 3 +} rtems_bsd_device_resource_type; + +typedef struct { + rtems_bsd_device_resource_type type; + unsigned long start_request; + unsigned long start_actual; +} rtems_bsd_device_resource; + +typedef struct { + const char *name; + int unit; + size_t resource_count; + const rtems_bsd_device_resource *resources; +} rtems_bsd_device; + +extern const rtems_bsd_device rtems_bsd_nexus_devices[]; + +extern const size_t rtems_bsd_nexus_device_count; + rtems_status_code rtems_bsd_initialize(void); rtems_status_code rtems_bsd_initialize_with_interrupt_server(void); diff --git a/rtemsbsd/rtems/rtems-bsd-nexus.c b/rtemsbsd/rtems/rtems-bsd-nexus.c index a23f5abe..12c5f360 100644 --- a/rtemsbsd/rtems/rtems-bsd-nexus.c +++ b/rtemsbsd/rtems/rtems-bsd-nexus.c @@ -7,10 +7,10 @@ */ /* - * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved. + * Copyright (c) 2009-2013 embedded brains GmbH. All rights reserved. * * embedded brains GmbH - * Obere Lagerstr. 30 + * Dornierstr. 4 * 82178 Puchheim * Germany * @@ -38,7 +38,6 @@ */ #include -#include #include #include @@ -49,366 +48,215 @@ #include #include -#include -#include -#include -#include +#include #include -#include - -/* XXX Note: These defines should be moved. */ -#if defined(__i386__) - #define BUS_SPACE_IO I386_BUS_SPACE_IO - #define BUS_SPACE_MEM I386_BUS_SPACE_MEM -#elif defined(__amd64__) - #define BUS_SPACE_IO AMD64_BUS_SPACE_IO - #define BUS_SPACE_MEM AMD64_BUS_SPACE_MEM -#else - #warning "Bus space information not implemented for this architecture!!" - #warning "Defaulting Bus space information!!" - #define BUS_SPACE_IO 0 - #define BUS_SPACE_MEM 1 -#endif - -/* XXX - Just a guess */ -#define NUM_IO_INTS 30 - -#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++) - 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"); +RTEMS_STATIC_ASSERT(SYS_RES_MEMORY == RTEMS_BSD_RES_MEMORY, RTEMS_BSD_RES_MEMORY); - 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"); -} +RTEMS_STATIC_ASSERT(SYS_RES_IRQ == RTEMS_BSD_RES_IRQ, RTEMS_BSD_RES_IRQ); -static int -nexus_attach(device_t dev) -{ +static struct rman mem_rman; - 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 struct rman irq_rman; static int nexus_probe(device_t dev) { -#if 0 - /* FIXME */ - size_t unit = 0; + int err; + size_t i; - 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"); + mem_rman.rm_start = 0; + mem_rman.rm_end = ~0UL; + mem_rman.rm_type = RMAN_ARRAY; + mem_rman.rm_descr = "I/O memory addresses"; + err = rman_init(&mem_rman) != 0; + BSD_ASSERT(err == 0); + err = rman_manage_region(&mem_rman, mem_rman.rm_start, mem_rman.rm_end); + BSD_ASSERT(err == 0); + + irq_rman.rm_start = 0; + irq_rman.rm_end = ~0UL; + irq_rman.rm_type = RMAN_ARRAY; + irq_rman.rm_descr = "Interrupt vectors"; + err = rman_init(&irq_rman) != 0; + BSD_ASSERT(err == 0); + err = rman_manage_region(&irq_rman, irq_rman.rm_start, irq_rman.rm_end); + BSD_ASSERT(err == 0); + + for (i = 0; i < rtems_bsd_nexus_device_count; ++i) { + const rtems_bsd_device *nd = &rtems_bsd_nexus_devices[i]; + + device_add_child(dev, nd->name, nd->unit); + } + return (0); } -static device_t -nexus_add_child(device_t bus, u_int order, const char *name, int unit) + +static bool +nexus_get_start(const rtems_bsd_device *nd, int type, u_long *start) { - device_t child; - struct nexus_device *ndev; + u_long sr = *start; + size_t i; - ndev = malloc(sizeof(struct nexus_device), M_NEXUSDEV, M_NOWAIT|M_ZERO); - if (!ndev) - return(0); - resource_list_init(&ndev->nx_resources); + for (i = 0; i < nd->resource_count; ++i) { + const rtems_bsd_device_resource *dr = &nd->resources[i]; - child = device_add_child_ordered(bus, order, name, unit); + if (dr->type == type && dr->start_request == sr) { + *start = dr->start_actual; - /* should we free this in nexus_child_detached? */ - device_set_ivars(child, ndev); + return (true); + } + } - return(child); + return (false); } -/* - * 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) + 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; + struct resource *rv; + struct rman *rm; + size_t i; switch (type) { + case SYS_RES_MEMORY: + rm = &mem_rman; + break; case SYS_RES_IRQ: rm = &irq_rman; break; + default: + return (NULL); + } - case SYS_RES_DRQ: - rm = &drq_rman; - break; - - case SYS_RES_IOPORT: - rm = &port_rman; - break; + for (i = 0; i < rtems_bsd_nexus_device_count; ++i) { + const rtems_bsd_device *nd = &rtems_bsd_nexus_devices[i]; - case SYS_RES_MEMORY: - rm = &mem_rman; - break; - - default: - return 0; + if (strcmp(device_get_name(child), nd->name) == 0 + && device_get_unit(child) == nd->unit) { + if (!nexus_get_start(nd, type, &start)) { + return (NULL); + }; + } else { + return (NULL); + } } rv = rman_reserve_resource(rm, start, end, count, flags, child); - if (rv == 0) - return 0; - rman_set_rid(rv, *rid); - - if (needactivate) { - if (bus_activate_resource(child, type, *rid, rv)) { - rman_release_resource(rv); - return 0; - } + if (rv != NULL) { + rman_set_rid(rv, *rid); + rman_set_bushandle(rv, rman_get_start(rv)); } - return rv; + return (rv); } static int -nexus_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) +nexus_release_resource(device_t bus, device_t child, int type, int rid, + struct resource *res) { -#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)); + return (rman_release_resource(res)); } -static int -nexus_deactivate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) +struct nexus_intr { + driver_filter_t *filt; + driver_intr_t *intr; + void *arg; +}; + +static void +nexus_intr_with_filter(void *arg) { + struct nexus_intr *ni; + int status; -#ifdef PC98 - if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { - bus_space_handle_t bh; + ni = arg; - bh = rman_get_bushandle(r); - i386_bus_space_handle_free(rman_get_bustag(r), bh, bh->bsh_sz); + status = (*ni->filt)(ni->arg); + if ((status & FILTER_SCHEDULE_THREAD) != 0) { + (*ni->intr)(ni->arg); } -#endif - return (rman_deactivate_resource(r)); } static int -nexus_release_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) +nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, + driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { - 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)); -} + int err; + struct nexus_intr *ni; + + ni = malloc(sizeof(*ni), M_TEMP, M_WAITOK); + if (ni != NULL) { + rtems_status_code sc; + rtems_interrupt_handler rh; + void *ra; + + ni->filt = filt; + ni->intr = intr; + ni->arg = arg; + + *cookiep = ni; + + if (filt == NULL) { + rh = intr; + ra = arg; + } else { + rh = nexus_intr_with_filter; + ra = ni; + } -static int -bspExtInstallSharedISR(int irqLine, void (*isr)(void *), void * uarg, int flags) -{ - return rtems_interrupt_handler_install( - irqLine, - "BSD Interrupt", - RTEMS_INTERRUPT_SHARED, - isr, - uarg - ); -} + sc = rtems_interrupt_server_handler_install(RTEMS_ID_NONE, + rman_get_start(res), device_get_nameunit(child), + RTEMS_INTERRUPT_UNIQUE, rh, ra); + if (sc == RTEMS_SUCCESSFUL) { + err = 0; + } else { + free(ni, M_TEMP); -int -intr_add_handler(const char *name, int vector, driver_filter_t filter, - driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep) -{ - int rval; - - rval = bspExtInstallSharedISR(vector, handler, arg, 0); - return rval; + err = EINVAL; + } + } else { + err = ENOMEM; + } + + return (err); } static int -nexus_setup_intr(device_t bus, device_t child, struct resource *irq, - int flags, driver_filter_t filter, void (*ihand)(void *), - void *arg, void **cookiep) +nexus_teardown_intr(device_t dev, device_t child, struct resource *res, + void *cookie) { - int error; - - /* somebody tried to setup an irq that failed to allocate! */ - if (irq == NULL) - panic("nexus_setup_intr: NULL irq resource!"); - - *cookiep = 0; - if ((rman_get_flags(irq) & RF_SHAREABLE) == 0) - flags |= INTR_EXCL; - - /* - * We depend here on rman_activate_resource() being idempotent. - */ - error = rman_activate_resource(irq); - if (error) - return (error); + int err; + struct nexus_intr *ni; + rtems_status_code sc; + rtems_interrupt_handler rh; + void *ra; + + ni = cookie; + + if (ni->filt == NULL) { + rh = ni->intr; + ra = ni->arg; + } else { + rh = nexus_intr_with_filter; + ra = ni->arg; + } - error = intr_add_handler(device_get_nameunit(child), - rman_get_start(irq), filter, ihand, arg, flags, cookiep); + sc = rtems_interrupt_server_handler_install(RTEMS_ID_NONE, + rman_get_start(res), device_get_nameunit(child), + RTEMS_INTERRUPT_UNIQUE, rh, ra); + err = sc == RTEMS_SUCCESSFUL ? 0 : EINVAL; - return (error); + return (err); } - -static device_method_t nexus_methods [] = { +static device_method_t nexus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, nexus_probe), - DEVMETHOD(device_attach, nexus_attach), + DEVMETHOD(device_attach, bus_generic_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), @@ -416,12 +264,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), - DEVMETHOD(bus_setup_intr, nexus_setup_intr), + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), + DEVMETHOD(bus_release_resource, nexus_release_resource), + DEVMETHOD(bus_setup_intr, nexus_setup_intr), + DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), { 0, 0 } }; -- cgit v1.2.3