source: libbsdport/bsd_eth_drivers/libbsdport/sysbus.c @ 89376b7

B_20100615baselibbsdport-4-10-branch initial
Last change on this file since 89376b7 was 89376b7, checked in by Joel Sherrill <joel.sherrill@…>, on Feb 19, 2009 at 7:55:40 PM

Initial import.

  • Property mode set to 100644
File size: 6.1 KB
Line 
1#include <rtems.h>
2#include <rtems/pci.h>
3#include <rtems/error.h>
4#include <sys/errno.h>
5#include <bsp.h>
6#include <devicet.h>
7#include <bsp/irq.h>
8#include <rtems/irq.h>
9
10#include <sys/taskqueue.h>
11
12#include <sys/bus.h>
13#include <sys/malloc.h>
14
15#include <bsp/rtems_verscheck.h>
16
17#if !RTEMS_REV_AT_LEAST(4,6,99) || !defined(BSP_SHARED_HANDLER_SUPPORT)
18
19#include <bsp/bspExt.h>
20
21#else
22
23static void noop(const rtems_irq_connect_data *unused) {};
24static int  noop1(const rtems_irq_connect_data *unused) { return 0;};
25
26/* Finally have an ISR arg but the API still sucks.. */
27static int
28bspExtInstallSharedISR(int irqLine, void (*isr)(void *), void * uarg, int flags)
29{
30rtems_irq_connect_data suck = {0};
31        suck.name   = irqLine;
32        suck.hdl    = isr;
33        suck.handle = uarg;
34        suck.on     = noop;
35        suck.off    = noop;
36        suck.isOn   = noop1;
37        return ! BSP_install_rtems_shared_irq_handler(&suck);
38}
39
40static int
41bspExtRemoveSharedISR(int irqLine, void (*isr)(void *), void *uarg)
42{
43rtems_irq_connect_data suck = {0};
44        suck.name   = irqLine;
45        suck.hdl    = isr;
46        suck.handle = uarg;
47        suck.on     = noop;
48        suck.off    = noop;
49        suck.isOn   = noop1;
50        return ! BSP_remove_rtems_irq_handler(&suck);
51}
52#endif
53
54
55struct resource *
56bus_alloc_resource_any(device_t dev, int type, int *prid, unsigned flags)
57{
58bus_addr_t ba;
59int        isio;
60        switch ( type ) {
61                default:
62                        break;
63                case SYS_RES_IOPORT:
64                case SYS_RES_MEMORY:
65                        {
66                        libbsdport_u32_t d;
67                        pci_read_config_dword(
68                                dev->bushdr.pci.bus,
69                                dev->bushdr.pci.dev,
70                                dev->bushdr.pci.fun,
71                                *prid,
72                                &d);
73                        ba = d;
74                        isio = (ba & PCI_BASE_ADDRESS_SPACE_IO) ? 1 : 0;
75                        if ( (type == SYS_RES_IOPORT) != (isio != 0) )
76                                return 0;       /* wrong type */
77
78                        return (struct resource *) ba;
79                        }
80                case SYS_RES_IRQ:
81                        {
82                        uint8_t line;
83                        pci_read_config_byte(
84                                dev->bushdr.pci.bus,
85                                dev->bushdr.pci.dev,
86                                dev->bushdr.pci.fun,
87                                PCI_INTERRUPT_LINE,
88                                &line);
89                        ba = line;
90                        /* MSI not implemented */
91                        return (struct resource*) ba;
92                        }
93        }
94        rtems_panic("bus_alloc_resource_any: unknown/unimplemented resource type %i\n", type);
95        /* never get here */
96        return (struct resource*)0;
97}
98
99struct irq_cookie {
100        device_t        dev;
101        driver_filter_t handler;
102        void                    (*work)(void*);
103        void            *arg;
104        /* cache methods */
105        int                             (*irq_check_dis)(device_t d);
106        void                    (*irq_en)       (device_t d);
107        struct task     task;
108};
109
110static int
111sysbus_isr(void *arg)
112{
113struct irq_cookie *info = arg;
114int rval;
115#ifdef DEBUG
116        printk("Sysbus IRQ\n");
117#endif
118        /* Check if we have an IRQ pending and disable further interrupts */
119        rval = info->irq_check_dis(info->dev);
120        if ( FILTER_HANDLED == rval ) {
121                /* enqueue work */
122                taskqueue_enqueue(taskqueue_fast, &info->task);
123        }
124        return rval;
125}
126
127static void
128sysbus_taskfn(void *arg, int pending)
129{
130struct irq_cookie *info = arg;
131       
132        /* do work */
133        info->work(info->arg);
134       
135        /* reenable interrupts */
136        if ( info->irq_en )
137                info->irq_en(info->dev);
138}
139
140int
141bus_setup_intr(device_t dev, struct resource *r, int flags, driver_filter_t filter, driver_intr_t handler, void *arg, void **cookiep)
142{
143int                rval;
144struct irq_cookie *info = 0;
145
146        if ( filter && handler ) {
147                rtems_panic("bus_setup_intr for both: filter & handler not implemented\n");
148        }
149
150        if ( (flags & INTR_FAST) && filter ) {
151                rtems_panic("bus_setup_intr for both: filter & INTR_FAST not implemented\n");
152                /* handler is a fast handler already */
153                filter  = (driver_filter_t) handler;
154                handler = 0;
155        }
156
157        if ( handler ) {
158                if ( !dev->drv ) {
159                        device_printf(dev, "bus_setup_intr: device has no driver attached\n");
160                        return EINVAL;
161                } else if ( !dev->drv->methods->irq_check_dis ) {
162                        device_printf(dev, "bus_setup_intr: driver has no 'irq_dis' method\n");
163                        return EINVAL;
164                }
165        }
166
167        if ( ! (info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT)) )
168                return ENOMEM;
169
170        info->dev     = dev;
171        info->handler = filter;
172        info->work    = handler;
173        info->arg     = arg;
174
175        if ( handler ) {
176                TASK_INIT(&info->task, 0, sysbus_taskfn, info);
177                /* make sure taskqueue facility is initialized */
178                rtems_taskqueue_initialize();
179                /* install our own filter */
180                filter = sysbus_isr;
181                arg    = info;
182                info->irq_check_dis = dev->drv->methods->irq_check_dis;
183                info->irq_en        = dev->drv->methods->irq_en;
184        } else {
185                TASK_INIT(&info->task, 0, 0, 0);
186        }
187
188        rval = bspExtInstallSharedISR((int)r, (void (*)(void*))filter, arg, 0);
189
190        if ( rval ) {
191                free(info, M_DEVBUF);
192                return rval;
193        }
194
195        if ( cookiep )
196                *cookiep = info;
197        return rval;
198}
199
200int
201bus_teardown_intr(device_t dev, struct resource *r, void *cookiep)
202{
203int rval;
204struct irq_cookie *info = cookiep;
205        rval = bspExtRemoveSharedISR((int)r, (void (*)(void*))info->handler, info->arg);
206        if ( 0 == rval ) {
207                if ( info->task.ta_fn ) {
208                        taskqueue_drain(taskqueue_fast, &info->task);
209                }
210                free(info, M_DEVBUF);
211        }
212        return rval;
213}
214
215bus_space_handle_t
216rman_get_bushandle(struct resource *r)
217{
218bus_space_handle_t h = (bus_space_handle_t)r;
219bus_space_handle_t msk = (PCI_BASE_ADDRESS_SPACE_IO & h) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK;
220        return h & msk;
221}
222
223bus_space_tag_t
224rman_get_bustag(struct resource *r)
225{
226bus_space_handle_t h = (bus_space_handle_t)r;
227        return (PCI_BASE_ADDRESS_SPACE_IO & h) ? bus_space_io : bus_space_mem;
228}
229
230int
231bus_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)
232{
233bus_dma_tag_t tag;
234        if ( filter || lockfunc )
235                return ENOTSUP;
236        if ( ! (tag = malloc(sizeof(*tag), M_DEVBUF, M_NOWAIT)) )
237                return ENOMEM;
238        /* save some information */
239        tag->alignment = alignment;
240        tag->maxsize   = maxsize;
241        tag->maxsegs   = nsegs;
242        *ptag          = tag;
243        return 0;
244}
245
246void
247bus_dma_tag_destroy(bus_dma_tag_t tag)
248{
249        free(tag, M_DEVBUF);
250}
251
252int
253bus_dmamem_alloc(bus_dma_tag_t tag, void **p_vaddr, unsigned flags, bus_dmamap_t *p_map)
254{
255uintptr_t a;
256        if ( ! (*p_map = malloc(tag->maxsize + tag->alignment, M_DEVBUF, M_NOWAIT)) )
257                return ENOMEM;
258        a = ((uintptr_t)*p_map + tag->alignment - 1 ) & ~(tag->alignment - 1);
259        *p_vaddr = (void*)a;
260        return 0;
261}
262
263void
264bus_dmamem_free(bus_dma_tag_t tag, void *vaddr, bus_dmamap_t map)
265{
266        free(map, M_DEVBUF);
267}
Note: See TracBrowser for help on using the repository browser.