#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; } int bus_alloc_resources(device_t dev, struct resource_spec *rs, struct resource **res) { int i; for (i = 0; rs[i].type != -1; i++) res[i] = NULL; for (i = 0; rs[i].type != -1; i++) { res[i] = bus_alloc_resource_any(dev, rs[i].type, &rs[i].rid, rs[i].flags); if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) { bus_release_resources(dev, rs, res); return (ENXIO); } } return (0); } void bus_release_resources(device_t dev, const struct resource_spec *rs, struct resource **res) { int i; for (i = 0; rs[i].type != -1; i++) if (res[i] != NULL) { bus_release_resource( dev, rs[i].type, rs[i].rid, res[i]); res[i] = NULL; } } 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 ( 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; } *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; unsigned sz = tag->maxsize + tag->alignment; if ( ! (*p_map = malloc(sz, M_DEVBUF, M_NOWAIT)) ) return ENOMEM; a = ((uintptr_t)*p_map + tag->alignment - 1 ) & ~(tag->alignment - 1); *p_vaddr = (void*)a; if ( (BUS_DMA_ZERO & flags) ) memset(*p_map, 0, sz); return 0; } void bus_dmamem_free(bus_dma_tag_t tag, void *vaddr, bus_dmamap_t map) { free(map, M_DEVBUF); } /* Dummy handle for Giant mutex */ uint32_t __busdma_dummy_Giant = 0; int resource_int_value(const char *name, int unit, const char *resname, int *result) { /* not implemented */ return ENOENT; } int resource_long_value(const char *name, int unit, const char *resname, long *result) { /* not implemented */ return ENOENT; }