]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/mips/mips/nexus.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / mips / mips / nexus.c
1 /*-
2  * Copyright 1998 Massachusetts Institute of Technology
3  *
4  * Permission to use, copy, modify, and distribute this software and
5  * its documentation for any purpose and without fee is hereby
6  * granted, provided that both the above copyright notice and this
7  * permission notice appear in all copies, that both the above
8  * copyright notice and this permission notice appear in all
9  * supporting documentation, and that the name of M.I.T. not be used
10  * in advertising or publicity pertaining to distribution of the
11  * software without specific, written prior permission.  M.I.T. makes
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied
14  * warranty.
15  *
16  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30
31 /*
32  * This code implements a `root nexus' for MIPS Architecture
33  * machines.  The function of the root nexus is to serve as an
34  * attachment point for both processors and buses, and to manage
35  * resources which are common to all of them.  In particular,
36  * this code implements the core resource managers for interrupt
37  * requests and memory address space.
38  */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/bus.h>
46 #include <sys/kernel.h>
47 #include <sys/malloc.h>
48 #include <sys/module.h>
49 #include <sys/rman.h>
50 #include <sys/interrupt.h>
51
52 #include <vm/vm.h>
53 #include <vm/pmap.h>
54
55 #include <machine/bus.h>
56 #include <machine/intr_machdep.h>
57 #include <machine/pmap.h>
58 #include <machine/resource.h>
59 #include <machine/vmparam.h>
60
61 #ifdef NEXUS_DEBUG
62 #define dprintf printf
63 #else 
64 #define dprintf(x, arg...)
65 #endif  /* NEXUS_DEBUG */
66
67 static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device");
68
69 struct nexus_device {
70         struct resource_list    nx_resources;
71 };
72
73 #define DEVTONX(dev)    ((struct nexus_device *)device_get_ivars(dev))
74 #define NUM_MIPS_IRQS   6
75 #define MIPS_MEM_RID    0x20
76
77 static struct rman irq_rman;
78 static struct rman mem_rman;
79
80 #ifdef notyet
81 /*
82  * XXX: TODO: Implement bus space barrier functions.
83  * Currently tag and handle are set when memory resources
84  * are activated.
85  */
86 struct bus_space_tag nexus_bustag = {
87         NULL,                   /* cookie */
88         NULL,                   /* parent bus tag */
89         NEXUS_BUS_SPACE,        /* type */
90         nexus_bus_barrier,      /* bus_space_barrier */
91 };
92 #endif
93
94 static struct resource *
95                 nexus_alloc_resource(device_t, device_t, int, int *, u_long,
96                     u_long, u_long, u_int);
97 static int      nexus_activate_resource(device_t, device_t, int, int,
98                     struct resource *);
99 static device_t nexus_add_child(device_t, int, const char *, int);
100 static int      nexus_attach(device_t);
101 static int      nexus_deactivate_resource(device_t, device_t, int, int,
102                     struct resource *);
103 static void     nexus_delete_resource(device_t, device_t, int, int);
104 static struct resource_list *
105                 nexus_get_reslist(device_t, device_t);
106 static int      nexus_get_resource(device_t, device_t, int, int, u_long *,
107                     u_long *);
108 static void     nexus_hinted_child(device_t, const char *, int);
109 static int      nexus_print_child(device_t, device_t);
110 static int      nexus_print_all_resources(device_t dev);
111 static int      nexus_probe(device_t);
112 static int      nexus_release_resource(device_t, device_t, int, int,
113                     struct resource *);
114 static int      nexus_set_resource(device_t, device_t, int, int, u_long,
115                     u_long);
116 static int      nexus_setup_intr(device_t dev, device_t child,
117                     struct resource *res, int flags, driver_filter_t *filt,
118                     driver_intr_t *intr, void *arg, void **cookiep);
119 static int      nexus_teardown_intr(device_t, device_t, struct resource *,
120                     void *);
121
122 static device_method_t nexus_methods[] = {
123         /* Device interface */
124         DEVMETHOD(device_probe,         nexus_probe),
125         DEVMETHOD(device_attach,        nexus_attach),
126
127         /* Bus interface */
128         DEVMETHOD(bus_add_child,        nexus_add_child),
129         DEVMETHOD(bus_activate_resource,nexus_activate_resource),
130         DEVMETHOD(bus_alloc_resource,   nexus_alloc_resource),
131         DEVMETHOD(bus_deactivate_resource,      nexus_deactivate_resource),
132         DEVMETHOD(bus_delete_resource,  nexus_delete_resource),
133         DEVMETHOD(bus_get_resource,     nexus_get_resource),
134         DEVMETHOD(bus_get_resource_list,        nexus_get_reslist),
135         DEVMETHOD(bus_hinted_child,     nexus_hinted_child),
136         DEVMETHOD(bus_print_child,      nexus_print_child),
137         DEVMETHOD(bus_release_resource, nexus_release_resource),
138         DEVMETHOD(bus_set_resource,     nexus_set_resource),
139         DEVMETHOD(bus_setup_intr,       nexus_setup_intr),
140         DEVMETHOD(bus_teardown_intr,    nexus_teardown_intr),
141
142         { 0, 0 }
143 };
144
145 static driver_t nexus_driver = {
146         "nexus",
147         nexus_methods,
148         1                       /* no softc */
149 };
150 static devclass_t nexus_devclass;
151
152 static int
153 nexus_probe(device_t dev)
154 {
155
156         device_set_desc(dev, "MIPS32 root nexus");
157
158         irq_rman.rm_start = 0;
159         irq_rman.rm_end = NUM_MIPS_IRQS - 1;
160         irq_rman.rm_type = RMAN_ARRAY;
161         irq_rman.rm_descr = "Hardware IRQs";
162         if (rman_init(&irq_rman) != 0 ||
163             rman_manage_region(&irq_rman, 0, NUM_MIPS_IRQS - 1) != 0) {
164                 panic("%s: irq_rman", __func__);
165         }
166
167         mem_rman.rm_start = 0;
168         mem_rman.rm_end = ~0u;
169         mem_rman.rm_type = RMAN_ARRAY;
170         mem_rman.rm_descr = "Memory addresses";
171         if (rman_init(&mem_rman) != 0 ||
172             rman_manage_region(&mem_rman, 0, ~0) != 0) {
173                 panic("%s: mem_rman", __func__);
174         }
175
176         return (0);
177 }
178
179 static int
180 nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
181     driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
182 {
183         int irq;
184
185         register_t sr = intr_disable();
186         irq = rman_get_start(res);
187         if (irq >= NUM_MIPS_IRQS)
188                 return (0);
189
190         cpu_establish_hardintr(device_get_nameunit(child), filt, intr, arg,
191             irq, flags, cookiep);
192         intr_restore(sr);
193         return (0);
194 }
195
196 static int
197 nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
198 {
199
200         printf("Unimplemented %s at %s:%d\n", __func__, __FILE__, __LINE__);
201         return (0);
202 }
203
204 static int
205 nexus_attach(device_t dev)
206 {
207
208         bus_generic_probe(dev);
209         bus_enumerate_hinted_children(dev);
210         bus_generic_attach(dev);
211
212         return (0);
213 }
214
215 static int
216 nexus_print_child(device_t bus, device_t child)
217 {
218         int retval = 0;
219
220         retval += bus_print_child_header(bus, child);
221         retval += nexus_print_all_resources(child);
222         if (device_get_flags(child))
223                 retval += printf(" flags %#x", device_get_flags(child));
224         retval += printf(" on %s\n", device_get_nameunit(bus));
225
226         return (retval);
227 }
228
229 static int
230 nexus_print_all_resources(device_t dev)
231 {
232         struct nexus_device *ndev = DEVTONX(dev);
233         struct resource_list *rl = &ndev->nx_resources;
234         int retval = 0;
235
236         if (STAILQ_FIRST(rl))
237                 retval += printf(" at");
238
239         retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
240         retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
241
242         return (retval);
243 }
244
245 static void
246 nexus_hinted_child(device_t bus, const char *dname, int dunit)
247 {
248         device_t child;
249         long    maddr;
250         int     msize;
251         int     result;
252
253         child = BUS_ADD_CHILD(bus, 0, dname, dunit);
254
255         /*
256          * Set hard-wired resources for hinted child using
257          * specific RIDs.
258          */
259         resource_long_value(dname, dunit, "maddr", &maddr);
260         resource_int_value(dname, dunit, "msize", &msize);
261
262         dprintf("%s: discovered hinted child %s at maddr %p(%d)\n",
263             __func__, device_get_nameunit(child),
264             (void *)(intptr_t)maddr, msize);
265
266         result = bus_set_resource(child, SYS_RES_MEMORY, MIPS_MEM_RID,
267             maddr, msize);
268         if (result != 0) {
269                 device_printf(bus, "warning: bus_set_resource() failed\n");
270         }
271 }
272
273 static device_t
274 nexus_add_child(device_t bus, int order, const char *name, int unit)
275 {
276         device_t        child;
277         struct nexus_device *ndev;
278
279         ndev = malloc(sizeof(struct nexus_device), M_NEXUSDEV, M_NOWAIT|M_ZERO);
280         if (!ndev)
281                 return (0);
282         resource_list_init(&ndev->nx_resources);
283
284         child = device_add_child_ordered(bus, order, name, unit);
285
286         /* should we free this in nexus_child_detached? */
287         device_set_ivars(child, ndev);
288
289         return (child);
290 }
291
292 /*
293  * Allocate a resource on behalf of child.  NB: child is usually going to be a
294  * child of one of our descendants, not a direct child of nexus0.
295  * (Exceptions include footbridge.)
296  */
297 static struct resource *
298 nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
299         u_long start, u_long end, u_long count, u_int flags)
300 {
301         struct nexus_device             *ndev = DEVTONX(child);
302         struct resource                 *rv;
303         struct resource_list_entry      *rle;
304         struct rman                     *rm;
305         int                              isdefault, needactivate, passthrough;
306
307         dprintf("%s: entry (%p, %p, %d, %p, %p, %p, %ld, %d)\n",
308             __func__, bus, child, type, rid, (void *)(intptr_t)start,
309             (void *)(intptr_t)end, count, flags);
310         dprintf("%s: requested rid is %d\n", __func__, *rid);
311
312         isdefault = (start == 0UL && end == ~0UL && count == 1);
313         needactivate = flags & RF_ACTIVE;
314         passthrough = (device_get_parent(child) != bus);
315         rle = NULL;
316
317         /*
318          * If this is an allocation of the "default" range for a given RID,
319          * and we know what the resources for this device are (ie. they aren't
320          * maintained by a child bus), then work out the start/end values.
321          */
322         if (isdefault) {
323                 rle = resource_list_find(&ndev->nx_resources, type, *rid);
324                 if (rle == NULL)
325                         return (NULL);
326                 if (rle->res != NULL) {
327                         panic("%s: resource entry is busy", __func__);
328                 }
329                 start = rle->start;
330                 end = rle->end;
331                 count = rle->count;
332         }
333
334         switch (type) {
335         case SYS_RES_IRQ:
336                 rm = &irq_rman;
337                 break;
338         case SYS_RES_MEMORY:
339                 rm = &mem_rman;
340                 break;
341         default:
342                 printf("%s: unknown resource type %d\n", __func__, type);
343                 return (0);
344         }
345
346         rv = rman_reserve_resource(rm, start, end, count, flags, child);
347         if (rv == 0) {
348                 printf("%s: could not reserve resource\n", __func__);
349                 return (0);
350         }
351
352         rman_set_rid(rv, *rid);
353
354         if (needactivate) {
355                 if (bus_activate_resource(child, type, *rid, rv)) {
356                         printf("%s: could not activate resource\n", __func__);
357                         rman_release_resource(rv);
358                         return (0);
359                 }
360         }
361
362         return (rv);
363 }
364
365 static int
366 nexus_activate_resource(device_t bus, device_t child, int type, int rid,
367     struct resource *r)
368 {
369 #ifdef TARGET_OCTEON
370         uint64_t temp;
371 #endif          
372         /*
373          * If this is a memory resource, track the direct mapping
374          * in the uncached MIPS KSEG1 segment.
375          */
376         if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
377                 caddr_t vaddr = 0;
378                 u_int32_t paddr;
379                 u_int32_t psize;
380                 u_int32_t poffs;
381                 
382                 paddr = rman_get_start(r);
383                 psize = rman_get_size(r);
384                 poffs = paddr - trunc_page(paddr);
385                 vaddr = (caddr_t) pmap_mapdev(paddr-poffs, psize+poffs) + poffs;
386
387                 rman_set_virtual(r, vaddr);
388                 rman_set_bustag(r, MIPS_BUS_SPACE_MEM);
389 #ifdef TARGET_OCTEON
390                 temp = 0x0000000000000000;
391                 temp |= (uint32_t)vaddr;
392                 rman_set_bushandle(r, (bus_space_handle_t)temp);
393 #else           
394                 rman_set_bushandle(r, (bus_space_handle_t)vaddr);
395 #endif          
396         }
397
398         return (rman_activate_resource(r));
399 }
400
401 static struct resource_list *
402 nexus_get_reslist(device_t dev, device_t child)
403 {
404         struct nexus_device *ndev = DEVTONX(child);
405
406         return (&ndev->nx_resources);
407 }
408
409 static int
410 nexus_set_resource(device_t dev, device_t child, int type, int rid,
411     u_long start, u_long count)
412 {
413         struct nexus_device             *ndev = DEVTONX(child);
414         struct resource_list            *rl = &ndev->nx_resources;
415         struct resource_list_entry      *rle;
416
417         dprintf("%s: entry (%p, %p, %d, %d, %p, %ld)\n",
418             __func__, dev, child, type, rid, (void *)(intptr_t)start, count);
419
420         rle = resource_list_add(rl, type, rid, start, start + count - 1,
421             count);
422         if (rle == NULL)
423                 return (ENXIO);
424
425         return (0);
426 }
427
428 static int
429 nexus_get_resource(device_t dev, device_t child, int type, int rid,
430     u_long *startp, u_long *countp)
431 {
432         struct nexus_device             *ndev = DEVTONX(child);
433         struct resource_list            *rl = &ndev->nx_resources;
434         struct resource_list_entry      *rle;
435
436         rle = resource_list_find(rl, type, rid);
437         if (!rle)
438                 return(ENOENT);
439         if (startp)
440                 *startp = rle->start;
441         if (countp)
442                 *countp = rle->count;
443         return (0);
444 }
445
446 static void
447 nexus_delete_resource(device_t dev, device_t child, int type, int rid)
448 {
449         struct nexus_device     *ndev = DEVTONX(child);
450         struct resource_list    *rl = &ndev->nx_resources;
451
452         dprintf("%s: entry\n", __func__);
453
454         resource_list_delete(rl, type, rid);
455 }
456
457 static int
458 nexus_release_resource(device_t bus, device_t child, int type, int rid,
459                        struct resource *r)
460 {
461         dprintf("%s: entry\n", __func__);
462
463         if (rman_get_flags(r) & RF_ACTIVE) {
464                 int error = bus_deactivate_resource(child, type, rid, r);
465                 if (error)
466                         return error;
467         }
468
469         return (rman_release_resource(r));
470 }
471
472 static int
473 nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
474                           struct resource *r)
475 {
476
477         return (rman_deactivate_resource(r));
478 }
479
480 DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);