summaryrefslogtreecommitdiffstats
path: root/bsd_eth_drivers/libbsdport/sysbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsd_eth_drivers/libbsdport/sysbus.c')
-rw-r--r--bsd_eth_drivers/libbsdport/sysbus.c267
1 files changed, 267 insertions, 0 deletions
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 <rtems.h>
+#include <rtems/pci.h>
+#include <rtems/error.h>
+#include <sys/errno.h>
+#include <bsp.h>
+#include <devicet.h>
+#include <bsp/irq.h>
+#include <rtems/irq.h>
+
+#include <sys/taskqueue.h>
+
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <bsp/rtems_verscheck.h>
+
+#if !RTEMS_REV_AT_LEAST(4,6,99) || !defined(BSP_SHARED_HANDLER_SUPPORT)
+
+#include <bsp/bspExt.h>
+
+#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);
+}