source: rtems-libbsd/rtemsbsd/rtems/rtems-bsd-nexus.c @ 36a16f5c

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 36a16f5c was 36a16f5c, checked in by Sebastian Huber <sebastian.huber@…>, on 09/30/15 at 12:52:57

i386: Quick and dirty hack to get PCI working

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bsd_rtems
5 *
6 * @brief TODO.
7 */
8
9/*
10 * Copyright (c) 2009-2015 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40#include <machine/rtems-bsd-kernel-space.h>
41#include <machine/rtems-bsd-thread.h>
42
43#include <rtems/bsd/sys/param.h>
44#include <rtems/bsd/sys/types.h>
45#include <sys/systm.h>
46#include <sys/bus.h>
47#include <sys/kernel.h>
48#include <sys/module.h>
49#include <sys/rman.h>
50#include <sys/malloc.h>
51#include <machine/bus.h>
52
53#include <rtems/bsd/bsd.h>
54#include <rtems/irq-extension.h>
55
56/* #define DISABLE_INTERRUPT_EXTENSION */
57
58RTEMS_BSD_DECLARE_SET(nexus, rtems_bsd_device);
59
60RTEMS_BSD_DEFINE_SET(nexus, rtems_bsd_device);
61
62RTEMS_STATIC_ASSERT(SYS_RES_MEMORY == RTEMS_BSD_RES_MEMORY, RTEMS_BSD_RES_MEMORY);
63
64RTEMS_STATIC_ASSERT(SYS_RES_IRQ == RTEMS_BSD_RES_IRQ, RTEMS_BSD_RES_IRQ);
65
66static struct rman mem_rman;
67
68static struct rman irq_rman;
69
70#ifdef __i386__
71static struct rman port_rman;
72#endif
73
74static int
75nexus_probe(device_t dev)
76{
77        static const char name[] = "IRQS";
78        rtems_status_code status;
79        int err;
80        const rtems_bsd_device *nd;
81
82        device_set_desc(dev, "RTEMS Nexus device");
83
84#ifndef DISABLE_INTERRUPT_EXTENSION
85        status = rtems_interrupt_server_initialize(
86                rtems_bsd_get_task_priority(name),
87                rtems_bsd_get_task_stack_size(name),
88                RTEMS_DEFAULT_MODES,
89                RTEMS_DEFAULT_ATTRIBUTES,
90                NULL
91        );
92        BSD_ASSERT(status == RTEMS_SUCCESSFUL);
93#endif
94
95        mem_rman.rm_start = 0;
96        mem_rman.rm_end = ~0UL;
97        mem_rman.rm_type = RMAN_ARRAY;
98        mem_rman.rm_descr = "I/O memory addresses";
99        err = rman_init(&mem_rman) != 0;
100        BSD_ASSERT(err == 0);
101        err = rman_manage_region(&mem_rman, mem_rman.rm_start, mem_rman.rm_end);
102        BSD_ASSERT(err == 0);
103
104        irq_rman.rm_start = 0;
105        irq_rman.rm_end = ~0UL;
106        irq_rman.rm_type = RMAN_ARRAY;
107        irq_rman.rm_descr = "Interrupt vectors";
108        err = rman_init(&irq_rman) != 0;
109        BSD_ASSERT(err == 0);
110        err = rman_manage_region(&irq_rman, irq_rman.rm_start, irq_rman.rm_end);
111        BSD_ASSERT(err == 0);
112
113#ifdef __i386__
114        port_rman.rm_start = 0;
115        port_rman.rm_end = 0xffff;
116        port_rman.rm_type = RMAN_ARRAY;
117        port_rman.rm_descr = "I/O ports";
118        err = rman_init(&port_rman) != 0;
119        BSD_ASSERT(err == 0);
120        err = rman_manage_region(&port_rman, port_rman.rm_start,
121            port_rman.rm_end);
122        BSD_ASSERT(err == 0);
123#endif
124
125        SET_FOREACH(nd, nexus) {
126                device_add_child(dev, nd->name, nd->unit);
127        }
128
129        return (0);
130}
131
132static bool
133nexus_get_start(const rtems_bsd_device *nd, int type, u_long *start)
134{
135        u_long sr = *start;
136        size_t i;
137
138        for (i = 0; i < nd->resource_count; ++i) {
139                const rtems_bsd_device_resource *dr = &nd->resources[i];
140
141                if (dr->type == type && dr->start_request == sr) {
142                        *start = dr->start_actual;
143
144                        return (true);
145                }
146        }
147
148        return (false);
149}
150
151static struct resource *
152nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
153    u_long start, u_long end, u_long count, u_int flags)
154{
155        struct resource *res = NULL;
156        struct rman *rm;
157        const rtems_bsd_device *nd;
158
159        switch (type) {
160        case SYS_RES_MEMORY:
161                rm = &mem_rman;
162                break;
163        case SYS_RES_IRQ:
164                rm = &irq_rman;
165                break;
166#ifdef __i386__
167        case SYS_RES_IOPORT:
168                rm = &port_rman;
169                break;
170#endif
171        default:
172                return (res);
173        }
174
175        SET_FOREACH(nd, nexus) {
176                if (strcmp(device_get_name(child), nd->name) == 0
177                    && device_get_unit(child) == nd->unit) {
178                        if (nexus_get_start(nd, type, &start)) {
179                                res = rman_reserve_resource(rm, start, end,
180                                    count, flags, child);
181                                if (res != NULL) {
182                                        rman_set_rid(res, *rid);
183                                        rman_set_bushandle(res,
184                                            rman_get_start(res));
185                                }
186                        };
187
188                        return (res);
189                }
190        }
191
192#ifdef __i386__
193        /*
194         * FIXME: This is a quick and dirty hack.  Simply reserve resources of
195         * this kind.  See also pci_reserve_map().
196         */
197        if (start + count - end <= 1UL) {
198                res = rman_reserve_resource(rm, start, end, count, flags,
199                    child);
200                if (res != NULL) {
201                        rman_set_rid(res, *rid);
202                        rman_set_bushandle(res, rman_get_start(res));
203                }
204        }
205#endif
206
207        return (res);
208}
209
210static int
211nexus_release_resource(device_t bus, device_t child, int type, int rid,
212    struct resource *res)
213{
214        return (rman_release_resource(res));
215}
216
217#ifdef __i386__
218static int
219nexus_activate_resource(device_t bus, device_t child, int type, int rid,
220    struct resource *res)
221{
222        switch (type) {
223        case SYS_RES_IOPORT:
224                rman_set_bustag(res, X86_BUS_SPACE_IO);
225                break;
226        case SYS_RES_MEMORY:
227                rman_set_bustag(res, X86_BUS_SPACE_MEM);
228                break;
229        }
230        return (rman_activate_resource(res));
231}
232
233static int
234nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
235    struct resource *res)
236{
237
238        return (rman_deactivate_resource(res));
239}
240#endif
241
242struct nexus_intr {
243        driver_filter_t *filt;
244        driver_intr_t *intr;
245        void *arg;
246};
247
248static void
249nexus_intr_with_filter(void *arg)
250{
251        struct nexus_intr *ni;
252        int status;
253
254        ni = arg;
255
256        status = (*ni->filt)(ni->arg);
257        if ((status & FILTER_SCHEDULE_THREAD) != 0) {
258                (*ni->intr)(ni->arg);
259        }
260}
261
262static int
263nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
264    driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
265{
266        int err;
267#ifndef DISABLE_INTERRUPT_EXTENSION
268        struct nexus_intr *ni;
269
270        ni = malloc(sizeof(*ni), M_TEMP, M_WAITOK);
271        if (ni != NULL) {
272                rtems_status_code sc;
273                rtems_interrupt_handler rh;
274                void *ra;
275
276                ni->filt = filt;
277                ni->intr = intr;
278                ni->arg = arg;
279
280                *cookiep = ni;
281
282                if (filt == NULL) {
283                        rh = intr;
284                        ra = arg;
285                } else {
286                        rh = nexus_intr_with_filter;
287                        ra = ni;
288                }
289
290                sc = rtems_interrupt_server_handler_install(RTEMS_ID_NONE,
291                    rman_get_start(res), device_get_nameunit(child),
292                    RTEMS_INTERRUPT_UNIQUE, rh, ra);
293                if (sc == RTEMS_SUCCESSFUL) {
294                        err = 0;
295                } else {
296                        free(ni, M_TEMP);
297
298                        err = EINVAL;
299                }
300        } else {
301                err = ENOMEM;
302        }
303#else
304        err = EINVAL;
305#endif
306
307        return (err);
308}
309
310static int
311nexus_teardown_intr(device_t dev, device_t child, struct resource *res,
312    void *cookie)
313{
314        int err;
315#ifndef DISABLE_INTERRUPT_EXTENSION
316        struct nexus_intr *ni;
317        rtems_status_code sc;
318        rtems_interrupt_handler rh;
319        void *ra;
320
321        ni = cookie;
322
323        if (ni->filt == NULL) {
324                rh = ni->intr;
325                ra = ni->arg;
326        } else {
327                rh = nexus_intr_with_filter;
328                ra = ni->arg;
329        }
330
331        sc = rtems_interrupt_server_handler_install(RTEMS_ID_NONE,
332            rman_get_start(res), device_get_nameunit(child),
333            RTEMS_INTERRUPT_UNIQUE, rh, ra);
334        err = sc == RTEMS_SUCCESSFUL ? 0 : EINVAL;
335#else
336        err = EINVAL;
337#endif
338
339        return (err);
340}
341
342static device_method_t nexus_methods[] = {
343        /* Device interface */
344        DEVMETHOD(device_probe, nexus_probe),
345        DEVMETHOD(device_attach, bus_generic_attach),
346        DEVMETHOD(device_detach, bus_generic_detach),
347        DEVMETHOD(device_shutdown, bus_generic_shutdown),
348        DEVMETHOD(device_suspend, bus_generic_suspend),
349        DEVMETHOD(device_resume, bus_generic_resume),
350
351        /* Bus interface */
352        DEVMETHOD(bus_print_child, bus_generic_print_child),
353        DEVMETHOD(bus_add_child, bus_generic_add_child),
354        DEVMETHOD(bus_alloc_resource, nexus_alloc_resource),
355        DEVMETHOD(bus_release_resource, nexus_release_resource),
356#ifdef __i386__
357        DEVMETHOD(bus_activate_resource, nexus_activate_resource),
358        DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
359#endif
360        DEVMETHOD(bus_setup_intr, nexus_setup_intr),
361        DEVMETHOD(bus_teardown_intr, nexus_teardown_intr),
362
363        { 0, 0 }
364};
365
366static driver_t nexus_driver = {
367        .name = "nexus",
368        .methods = nexus_methods,
369        .size = 0
370};
371
372static devclass_t nexus_devclass;
373
374DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);
Note: See TracBrowser for help on using the repository browser.