From 89376b7141edb6f927fb940c27391cda6e67c785 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 19 Feb 2009 19:55:40 +0000 Subject: Initial import. --- bsd_eth_drivers/libbsdport/sysbus.c | 267 ++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 bsd_eth_drivers/libbsdport/sysbus.c (limited to 'bsd_eth_drivers/libbsdport/sysbus.c') diff --git a/bsd_eth_drivers/libbsdport/sysbus.c b/bsd_eth_drivers/libbsdport/sysbus.c new file mode 100644 index 0000000..fc0ae0b --- /dev/null +++ b/bsd_eth_drivers/libbsdport/sysbus.c @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#if !RTEMS_REV_AT_LEAST(4,6,99) || !defined(BSP_SHARED_HANDLER_SUPPORT) + +#include + +#else + +static void noop(const rtems_irq_connect_data *unused) {}; +static int noop1(const rtems_irq_connect_data *unused) { return 0;}; + +/* Finally have an ISR arg but the API still sucks.. */ +static int +bspExtInstallSharedISR(int irqLine, void (*isr)(void *), void * uarg, int flags) +{ +rtems_irq_connect_data suck = {0}; + suck.name = irqLine; + suck.hdl = isr; + suck.handle = uarg; + suck.on = noop; + suck.off = noop; + suck.isOn = noop1; + return ! BSP_install_rtems_shared_irq_handler(&suck); +} + +static int +bspExtRemoveSharedISR(int irqLine, void (*isr)(void *), void *uarg) +{ +rtems_irq_connect_data suck = {0}; + suck.name = irqLine; + suck.hdl = isr; + suck.handle = uarg; + suck.on = noop; + suck.off = noop; + suck.isOn = noop1; + return ! BSP_remove_rtems_irq_handler(&suck); +} +#endif + + +struct resource * +bus_alloc_resource_any(device_t dev, int type, int *prid, unsigned flags) +{ +bus_addr_t ba; +int isio; + switch ( type ) { + default: + break; + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + { + libbsdport_u32_t d; + pci_read_config_dword( + dev->bushdr.pci.bus, + dev->bushdr.pci.dev, + dev->bushdr.pci.fun, + *prid, + &d); + ba = d; + isio = (ba & PCI_BASE_ADDRESS_SPACE_IO) ? 1 : 0; + if ( (type == SYS_RES_IOPORT) != (isio != 0) ) + return 0; /* wrong type */ + + return (struct resource *) ba; + } + case SYS_RES_IRQ: + { + uint8_t line; + pci_read_config_byte( + dev->bushdr.pci.bus, + dev->bushdr.pci.dev, + dev->bushdr.pci.fun, + PCI_INTERRUPT_LINE, + &line); + ba = line; + /* MSI not implemented */ + return (struct resource*) ba; + } + } + rtems_panic("bus_alloc_resource_any: unknown/unimplemented resource type %i\n", type); + /* never get here */ + return (struct resource*)0; +} + +struct irq_cookie { + device_t dev; + driver_filter_t handler; + void (*work)(void*); + void *arg; + /* cache methods */ + int (*irq_check_dis)(device_t d); + void (*irq_en) (device_t d); + struct task task; +}; + +static int +sysbus_isr(void *arg) +{ +struct irq_cookie *info = arg; +int rval; +#ifdef DEBUG + printk("Sysbus IRQ\n"); +#endif + /* Check if we have an IRQ pending and disable further interrupts */ + rval = info->irq_check_dis(info->dev); + if ( FILTER_HANDLED == rval ) { + /* enqueue work */ + taskqueue_enqueue(taskqueue_fast, &info->task); + } + return rval; +} + +static void +sysbus_taskfn(void *arg, int pending) +{ +struct irq_cookie *info = arg; + + /* do work */ + info->work(info->arg); + + /* reenable interrupts */ + if ( info->irq_en ) + info->irq_en(info->dev); +} + +int +bus_setup_intr(device_t dev, struct resource *r, int flags, driver_filter_t filter, driver_intr_t handler, void *arg, void **cookiep) +{ +int rval; +struct irq_cookie *info = 0; + + if ( filter && handler ) { + rtems_panic("bus_setup_intr for both: filter & handler not implemented\n"); + } + + if ( (flags & INTR_FAST) && filter ) { + rtems_panic("bus_setup_intr for both: filter & INTR_FAST not implemented\n"); + /* handler is a fast handler already */ + filter = (driver_filter_t) handler; + handler = 0; + } + + if ( handler ) { + if ( !dev->drv ) { + device_printf(dev, "bus_setup_intr: device has no driver attached\n"); + return EINVAL; + } else if ( !dev->drv->methods->irq_check_dis ) { + device_printf(dev, "bus_setup_intr: driver has no 'irq_dis' method\n"); + return EINVAL; + } + } + + if ( ! (info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT)) ) + return ENOMEM; + + info->dev = dev; + info->handler = filter; + info->work = handler; + info->arg = arg; + + if ( handler ) { + TASK_INIT(&info->task, 0, sysbus_taskfn, info); + /* make sure taskqueue facility is initialized */ + rtems_taskqueue_initialize(); + /* install our own filter */ + filter = sysbus_isr; + arg = info; + info->irq_check_dis = dev->drv->methods->irq_check_dis; + info->irq_en = dev->drv->methods->irq_en; + } else { + TASK_INIT(&info->task, 0, 0, 0); + } + + rval = bspExtInstallSharedISR((int)r, (void (*)(void*))filter, arg, 0); + + if ( rval ) { + free(info, M_DEVBUF); + return rval; + } + + if ( cookiep ) + *cookiep = info; + return rval; +} + +int +bus_teardown_intr(device_t dev, struct resource *r, void *cookiep) +{ +int rval; +struct irq_cookie *info = cookiep; + rval = bspExtRemoveSharedISR((int)r, (void (*)(void*))info->handler, info->arg); + if ( 0 == rval ) { + if ( info->task.ta_fn ) { + taskqueue_drain(taskqueue_fast, &info->task); + } + free(info, M_DEVBUF); + } + return rval; +} + +bus_space_handle_t +rman_get_bushandle(struct resource *r) +{ +bus_space_handle_t h = (bus_space_handle_t)r; +bus_space_handle_t msk = (PCI_BASE_ADDRESS_SPACE_IO & h) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK; + return h & msk; +} + +bus_space_tag_t +rman_get_bustag(struct resource *r) +{ +bus_space_handle_t h = (bus_space_handle_t)r; + return (PCI_BASE_ADDRESS_SPACE_IO & h) ? bus_space_io : bus_space_mem; +} + +int +bus_dma_tag_create(void *parent, unsigned alignment, unsigned bounds, uint32_t lowadd, uint32_t hiaddr, void (*filter)(void*), void *filterarg, unsigned maxsize, int nsegs, unsigned maxsegsize, unsigned flags, void (*lockfunc)(void*), void *lockarg, bus_dma_tag_t *ptag) +{ +bus_dma_tag_t tag; + if ( filter || lockfunc ) + return ENOTSUP; + if ( ! (tag = malloc(sizeof(*tag), M_DEVBUF, M_NOWAIT)) ) + return ENOMEM; + /* save some information */ + tag->alignment = alignment; + tag->maxsize = maxsize; + tag->maxsegs = nsegs; + *ptag = tag; + return 0; +} + +void +bus_dma_tag_destroy(bus_dma_tag_t tag) +{ + free(tag, M_DEVBUF); +} + +int +bus_dmamem_alloc(bus_dma_tag_t tag, void **p_vaddr, unsigned flags, bus_dmamap_t *p_map) +{ +uintptr_t a; + if ( ! (*p_map = malloc(tag->maxsize + tag->alignment, M_DEVBUF, M_NOWAIT)) ) + return ENOMEM; + a = ((uintptr_t)*p_map + tag->alignment - 1 ) & ~(tag->alignment - 1); + *p_vaddr = (void*)a; + return 0; +} + +void +bus_dmamem_free(bus_dma_tag_t tag, void *vaddr, bus_dmamap_t map) +{ + free(map, M_DEVBUF); +} -- cgit v1.2.3