]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/ps3/ps3bus.c
Upgrade Unbound to 1.9.2.
[FreeBSD/FreeBSD.git] / sys / powerpc / ps3 / ps3bus.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2010 Nathan Whitehorn
5  * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru)
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/malloc.h>
37 #include <sys/bus.h>
38 #include <sys/clock.h>
39 #include <sys/cpu.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42 #include <sys/resource.h>
43 #include <sys/rman.h>
44
45 #include <vm/vm.h>
46 #include <vm/pmap.h>
47
48 #include <machine/bus.h>
49 #include <machine/platform.h>
50 #include <machine/resource.h>
51
52 #include "ps3bus.h"
53 #include "ps3-hvcall.h"
54 #include "iommu_if.h"
55 #include "clock_if.h"
56
57 static void     ps3bus_identify(driver_t *, device_t);
58 static int      ps3bus_probe(device_t);
59 static int      ps3bus_attach(device_t);
60 static int      ps3bus_print_child(device_t dev, device_t child);
61 static int      ps3bus_read_ivar(device_t bus, device_t child, int which,
62                     uintptr_t *result);
63 static struct resource *ps3bus_alloc_resource(device_t bus, device_t child,
64                     int type, int *rid, rman_res_t start, rman_res_t end,
65                     rman_res_t count, u_int flags);
66 static int      ps3bus_activate_resource(device_t bus, device_t child, int type,
67                     int rid, struct resource *res);
68 static bus_dma_tag_t ps3bus_get_dma_tag(device_t dev, device_t child);
69 static int      ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs,                    bus_addr_t min, bus_addr_t max, bus_size_t alignment,
70                     bus_addr_t boundary, void *cookie);
71 static int      ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs,
72                     int nsegs, void *cookie);
73 static int      ps3_gettime(device_t dev, struct timespec *ts);
74 static int      ps3_settime(device_t dev, struct timespec *ts);
75
76 struct ps3bus_devinfo {
77         int bus;
78         int dev;
79         uint64_t bustype;
80         uint64_t devtype;
81         int busidx;
82         int devidx;
83
84         struct resource_list resources;
85         bus_dma_tag_t dma_tag;
86
87         struct mtx iommu_mtx;
88         bus_addr_t dma_base[4];
89 };
90
91 static MALLOC_DEFINE(M_PS3BUS, "ps3bus", "PS3 system bus device information");
92
93 enum ps3bus_irq_type {
94         SB_IRQ = 2,
95         OHCI_IRQ = 3,
96         EHCI_IRQ = 4,
97 };
98
99 enum ps3bus_reg_type {
100         OHCI_REG = 3,
101         EHCI_REG = 4,
102 };
103
104 static device_method_t ps3bus_methods[] = {
105         /* Device interface */
106         DEVMETHOD(device_identify,      ps3bus_identify),
107         DEVMETHOD(device_probe,         ps3bus_probe),
108         DEVMETHOD(device_attach,        ps3bus_attach),
109
110         /* Bus interface */
111         DEVMETHOD(bus_add_child,        bus_generic_add_child),
112         DEVMETHOD(bus_get_dma_tag,      ps3bus_get_dma_tag),
113         DEVMETHOD(bus_print_child,      ps3bus_print_child),
114         DEVMETHOD(bus_read_ivar,        ps3bus_read_ivar),
115         DEVMETHOD(bus_alloc_resource,   ps3bus_alloc_resource),
116         DEVMETHOD(bus_activate_resource, ps3bus_activate_resource),
117         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
118         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
119
120         /* IOMMU interface */
121         DEVMETHOD(iommu_map,            ps3_iommu_map),
122         DEVMETHOD(iommu_unmap,          ps3_iommu_unmap),
123
124         /* Clock interface */
125         DEVMETHOD(clock_gettime,        ps3_gettime),
126         DEVMETHOD(clock_settime,        ps3_settime),
127
128         DEVMETHOD_END
129 };
130
131 struct ps3bus_softc {
132         struct rman sc_mem_rman;
133         struct rman sc_intr_rman;
134         struct mem_region *regions;
135         int rcount;
136 };
137
138 static driver_t ps3bus_driver = {
139         "ps3bus",
140         ps3bus_methods,
141         sizeof(struct ps3bus_softc)
142 };
143
144 static devclass_t ps3bus_devclass;
145
146 DRIVER_MODULE(ps3bus, nexus, ps3bus_driver, ps3bus_devclass, 0, 0);
147
148 static void
149 ps3bus_identify(driver_t *driver, device_t parent)
150 {
151         if (strcmp(installed_platform(), "ps3") != 0)
152                 return;
153
154         if (device_find_child(parent, "ps3bus", -1) == NULL)
155                 BUS_ADD_CHILD(parent, 0, "ps3bus", 0);
156 }
157
158 static int 
159 ps3bus_probe(device_t dev) 
160 {
161         /* Do not attach to any OF nodes that may be present */
162         
163         device_set_desc(dev, "Playstation 3 System Bus");
164
165         return (BUS_PROBE_NOWILDCARD);
166 }
167
168 static void
169 ps3bus_resources_init(struct rman *rm, int bus_index, int dev_index,
170     struct ps3bus_devinfo *dinfo)
171 {
172         uint64_t irq_type, irq, outlet;
173         uint64_t reg_type, paddr, len;
174         uint64_t ppe, junk;
175         int i, result;
176         int thread;
177
178         resource_list_init(&dinfo->resources);
179
180         lv1_get_logical_ppe_id(&ppe);
181         thread = 32 - fls(mfctrl());
182
183         /* Scan for interrupts */
184         for (i = 0; i < 10; i++) {
185                 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
186                     (lv1_repository_string("bus") >> 32) | bus_index,
187                     lv1_repository_string("dev") | dev_index,
188                     lv1_repository_string("intr") | i, 0, &irq_type, &irq);
189
190                 if (result != 0)
191                         break;
192
193                 switch (irq_type) {
194                 case SB_IRQ:
195                         lv1_construct_event_receive_port(&outlet);
196                         lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet,
197                             0);
198                         lv1_connect_interrupt_event_receive_port(dinfo->bus,
199                             dinfo->dev, outlet, irq);
200                         break;
201                 case OHCI_IRQ:
202                 case EHCI_IRQ:
203                         lv1_construct_io_irq_outlet(irq, &outlet);
204                         lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet,
205                             0);
206                         break;
207                 default:
208                         printf("Unknown IRQ type %ld for device %d.%d\n",
209                             irq_type, dinfo->bus, dinfo->dev);
210                         break;
211                 }
212
213                 resource_list_add(&dinfo->resources, SYS_RES_IRQ, i,
214                     outlet, outlet, 1);
215         }
216
217         /* Scan for registers */
218         for (i = 0; i < 10; i++) {
219                 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
220                     (lv1_repository_string("bus") >> 32) | bus_index,
221                     lv1_repository_string("dev") | dev_index,
222                     lv1_repository_string("reg") | i, 
223                     lv1_repository_string("type"), &reg_type, &junk);
224
225                 if (result != 0)
226                         break;
227
228                 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
229                     (lv1_repository_string("bus") >> 32) | bus_index,
230                     lv1_repository_string("dev") | dev_index,
231                     lv1_repository_string("reg") | i, 
232                     lv1_repository_string("data"), &paddr, &len);
233
234                 result = lv1_map_device_mmio_region(dinfo->bus, dinfo->dev,
235                     paddr, len, 12 /* log_2(4 KB) */, &paddr);
236
237                 if (result != 0) {
238                         printf("Mapping registers failed for device "
239                             "%d.%d (%ld.%ld): %d\n", dinfo->bus, dinfo->dev,
240                             dinfo->bustype, dinfo->devtype, result);
241                         continue;
242                 }
243
244                 rman_manage_region(rm, paddr, paddr + len - 1);
245                 resource_list_add(&dinfo->resources, SYS_RES_MEMORY, i,
246                     paddr, paddr + len, len);
247         }
248 }
249
250 static void
251 ps3bus_resources_init_by_type(struct rman *rm, int bus_index, int dev_index,
252     uint64_t irq_type, uint64_t reg_type, struct ps3bus_devinfo *dinfo)
253 {
254         uint64_t _irq_type, irq, outlet;
255         uint64_t _reg_type, paddr, len;
256         uint64_t ppe, junk;
257         int i, result;
258         int thread;
259
260         resource_list_init(&dinfo->resources);
261
262         lv1_get_logical_ppe_id(&ppe);
263         thread = 32 - fls(mfctrl());
264
265         /* Scan for interrupts */
266         for (i = 0; i < 10; i++) {
267                 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
268                     (lv1_repository_string("bus") >> 32) | bus_index,
269                     lv1_repository_string("dev") | dev_index,
270                     lv1_repository_string("intr") | i, 0, &_irq_type, &irq);
271
272                 if (result != 0)
273                         break;
274
275                 if (_irq_type != irq_type)
276                         continue;
277
278                 lv1_construct_io_irq_outlet(irq, &outlet);
279                 lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet,
280                     0);
281                 resource_list_add(&dinfo->resources, SYS_RES_IRQ, i,
282                     outlet, outlet, 1);
283         }
284
285         /* Scan for registers */
286         for (i = 0; i < 10; i++) {
287                 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
288                     (lv1_repository_string("bus") >> 32) | bus_index,
289                     lv1_repository_string("dev") | dev_index,
290                     lv1_repository_string("reg") | i, 
291                     lv1_repository_string("type"), &_reg_type, &junk);
292
293                 if (result != 0)
294                         break;
295
296                 if (_reg_type != reg_type)
297                         continue;
298
299                 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
300                     (lv1_repository_string("bus") >> 32) | bus_index,
301                     lv1_repository_string("dev") | dev_index,
302                     lv1_repository_string("reg") | i, 
303                     lv1_repository_string("data"), &paddr, &len);
304
305                 result = lv1_map_device_mmio_region(dinfo->bus, dinfo->dev,
306                     paddr, len, 12 /* log_2(4 KB) */, &paddr);
307
308                 if (result != 0) {
309                         printf("Mapping registers failed for device "
310                             "%d.%d (%ld.%ld): %d\n", dinfo->bus, dinfo->dev,
311                             dinfo->bustype, dinfo->devtype, result);
312                         break;
313                 }
314
315                 rman_manage_region(rm, paddr, paddr + len - 1);
316                 resource_list_add(&dinfo->resources, SYS_RES_MEMORY, i,
317                     paddr, paddr + len, len);
318         }
319 }
320
321 static int 
322 ps3bus_attach(device_t self) 
323 {
324         struct ps3bus_softc *sc;
325         struct ps3bus_devinfo *dinfo;
326         int bus_index, dev_index, result;
327         uint64_t bustype, bus, devs;
328         uint64_t dev, devtype;
329         uint64_t junk;
330         device_t cdev;
331
332         sc = device_get_softc(self);
333         sc->sc_mem_rman.rm_type = RMAN_ARRAY;
334         sc->sc_mem_rman.rm_descr = "PS3Bus Memory Mapped I/O";
335         sc->sc_intr_rman.rm_type = RMAN_ARRAY;
336         sc->sc_intr_rman.rm_descr = "PS3Bus Interrupts";
337         rman_init(&sc->sc_mem_rman);
338         rman_init(&sc->sc_intr_rman);
339         rman_manage_region(&sc->sc_intr_rman, 0, ~0);
340
341         /* Get memory regions for DMA */
342         mem_regions(&sc->regions, &sc->rcount, NULL, NULL);
343
344         /*
345          * Probe all the PS3's buses.
346          */
347
348         for (bus_index = 0; bus_index < 5; bus_index++) {
349                 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
350                     (lv1_repository_string("bus") >> 32) | bus_index,
351                     lv1_repository_string("type"), 0, 0, &bustype, &junk);
352
353                 if (result != 0)
354                         continue;
355
356                 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
357                     (lv1_repository_string("bus") >> 32) | bus_index,
358                     lv1_repository_string("id"), 0, 0, &bus, &junk);
359
360                 if (result != 0)
361                         continue;
362
363                 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
364                     (lv1_repository_string("bus") >> 32) | bus_index,
365                     lv1_repository_string("num_dev"), 0, 0, &devs, &junk);
366
367                 for (dev_index = 0; dev_index < devs; dev_index++) {
368                         result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
369                             (lv1_repository_string("bus") >> 32) | bus_index,
370                             lv1_repository_string("dev") | dev_index,
371                             lv1_repository_string("type"), 0, &devtype, &junk);
372
373                         if (result != 0)
374                                 continue;
375
376                         result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
377                             (lv1_repository_string("bus") >> 32) | bus_index,
378                             lv1_repository_string("dev") | dev_index,
379                             lv1_repository_string("id"), 0, &dev, &junk);
380
381                         if (result != 0)
382                                 continue;
383                         
384                         switch (devtype) {
385                         case PS3_DEVTYPE_USB:
386                                 /* USB device has OHCI and EHCI USB host controllers */
387
388                                 lv1_open_device(bus, dev, 0);
389
390                                 /* OHCI host controller */
391
392                                 dinfo = malloc(sizeof(*dinfo), M_PS3BUS,
393                                     M_WAITOK | M_ZERO);
394
395                                 dinfo->bus = bus;
396                                 dinfo->dev = dev;
397                                 dinfo->bustype = bustype;
398                                 dinfo->devtype = devtype;
399                                 dinfo->busidx = bus_index;
400                                 dinfo->devidx = dev_index;
401
402                                 ps3bus_resources_init_by_type(&sc->sc_mem_rman, bus_index,
403                                     dev_index, OHCI_IRQ, OHCI_REG, dinfo);
404
405                                 cdev = device_add_child(self, "ohci", -1);
406                                 if (cdev == NULL) {
407                                         device_printf(self,
408                                             "device_add_child failed\n");
409                                         free(dinfo, M_PS3BUS);
410                                         continue;
411                                 }
412
413                                 mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
414                                 device_set_ivars(cdev, dinfo);
415
416                                 /* EHCI host controller */
417
418                                 dinfo = malloc(sizeof(*dinfo), M_PS3BUS,
419                                     M_WAITOK | M_ZERO);
420
421                                 dinfo->bus = bus;
422                                 dinfo->dev = dev;
423                                 dinfo->bustype = bustype;
424                                 dinfo->devtype = devtype;
425                                 dinfo->busidx = bus_index;
426                                 dinfo->devidx = dev_index;
427
428                                 ps3bus_resources_init_by_type(&sc->sc_mem_rman, bus_index,
429                                     dev_index, EHCI_IRQ, EHCI_REG, dinfo);
430
431                                 cdev = device_add_child(self, "ehci", -1);
432                                 if (cdev == NULL) {
433                                         device_printf(self,
434                                             "device_add_child failed\n");
435                                         free(dinfo, M_PS3BUS);
436                                         continue;
437                                 }
438
439                                 mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
440                                 device_set_ivars(cdev, dinfo);
441                                 break;
442                         default:
443                                 dinfo = malloc(sizeof(*dinfo), M_PS3BUS,
444                                     M_WAITOK | M_ZERO);
445
446                                 dinfo->bus = bus;
447                                 dinfo->dev = dev;
448                                 dinfo->bustype = bustype;
449                                 dinfo->devtype = devtype;
450                                 dinfo->busidx = bus_index;
451                                 dinfo->devidx = dev_index;
452
453                                 if (dinfo->bustype == PS3_BUSTYPE_SYSBUS ||
454                                     dinfo->bustype == PS3_BUSTYPE_STORAGE)
455                                         lv1_open_device(bus, dev, 0);
456
457                                 ps3bus_resources_init(&sc->sc_mem_rman, bus_index,
458                                     dev_index, dinfo);
459
460                                 cdev = device_add_child(self, NULL, -1);
461                                 if (cdev == NULL) {
462                                         device_printf(self,
463                                             "device_add_child failed\n");
464                                         free(dinfo, M_PS3BUS);
465                                         continue;
466                                 }
467
468                                 mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
469                                 device_set_ivars(cdev, dinfo);
470                         }
471                 }
472         }
473         
474         clock_register(self, 1000);
475
476         return (bus_generic_attach(self));
477 }
478
479 static int
480 ps3bus_print_child(device_t dev, device_t child)
481 {
482         struct ps3bus_devinfo *dinfo = device_get_ivars(child);
483         int retval = 0;
484
485         retval += bus_print_child_header(dev, child);
486         retval += resource_list_print_type(&dinfo->resources, "mem",
487             SYS_RES_MEMORY, "%#jx");
488         retval += resource_list_print_type(&dinfo->resources, "irq",
489             SYS_RES_IRQ, "%jd");
490
491         retval += bus_print_child_footer(dev, child);
492
493         return (retval);
494 }
495
496 static int
497 ps3bus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
498 {
499         struct ps3bus_devinfo *dinfo = device_get_ivars(child);
500
501         switch (which) {
502         case PS3BUS_IVAR_BUS:
503                 *result = dinfo->bus;
504                 break;
505         case PS3BUS_IVAR_DEVICE:
506                 *result = dinfo->dev;
507                 break;
508         case PS3BUS_IVAR_BUSTYPE:
509                 *result = dinfo->bustype;
510                 break;
511         case PS3BUS_IVAR_DEVTYPE:
512                 *result = dinfo->devtype;
513                 break;
514         case PS3BUS_IVAR_BUSIDX:
515                 *result = dinfo->busidx;
516                 break;
517         case PS3BUS_IVAR_DEVIDX:
518                 *result = dinfo->devidx;
519                 break;
520         default:
521                 return (EINVAL);
522         }
523
524         return (0);
525 }
526
527 static struct resource *
528 ps3bus_alloc_resource(device_t bus, device_t child, int type, int *rid,
529     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
530 {
531         struct  ps3bus_devinfo *dinfo;
532         struct  ps3bus_softc *sc;
533         int     needactivate;
534         struct  resource *rv;
535         struct  rman *rm;
536         rman_res_t      adjstart, adjend, adjcount;
537         struct  resource_list_entry *rle;
538
539         sc = device_get_softc(bus);
540         dinfo = device_get_ivars(child);
541         needactivate = flags & RF_ACTIVE;
542         flags &= ~RF_ACTIVE;
543
544         switch (type) {
545         case SYS_RES_MEMORY:
546                 rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
547                     *rid);
548                 if (rle == NULL) {
549                         device_printf(bus, "no rle for %s memory %d\n",
550                                       device_get_nameunit(child), *rid);
551                         return (NULL);
552                 }
553
554                 if (start < rle->start)
555                         adjstart = rle->start;
556                 else if (start > rle->end)
557                         adjstart = rle->end;
558                 else
559                         adjstart = start;
560
561                 if (end < rle->start)
562                         adjend = rle->start;
563                 else if (end > rle->end)
564                         adjend = rle->end;
565                 else
566                         adjend = end;
567
568                 adjcount = adjend - adjstart;
569
570                 rm = &sc->sc_mem_rman;
571                 break;
572         case SYS_RES_IRQ:
573                 rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ,
574                     *rid);
575                 rm = &sc->sc_intr_rman;
576                 adjstart = rle->start;
577                 adjcount = ulmax(count, rle->count);
578                 adjend = ulmax(rle->end, rle->start + adjcount - 1);
579                 break;
580         default:
581                 device_printf(bus, "unknown resource request from %s\n",
582                               device_get_nameunit(child));
583                 return (NULL);
584         }
585
586         rv = rman_reserve_resource(rm, adjstart, adjend, adjcount, flags,
587             child);
588         if (rv == NULL) {
589                 device_printf(bus,
590                         "failed to reserve resource %#lx - %#lx (%#lx)"
591                         " for %s\n", adjstart, adjend, adjcount,
592                         device_get_nameunit(child));
593                 return (NULL);
594         }
595
596         rman_set_rid(rv, *rid);
597
598         if (needactivate) {
599                 if (bus_activate_resource(child, type, *rid, rv) != 0) {
600                         device_printf(bus,
601                                 "failed to activate resource for %s\n",
602                                 device_get_nameunit(child));
603                                 rman_release_resource(rv);
604                         return (NULL);
605                 }
606         }
607
608         return (rv);
609 }
610
611 static int
612 ps3bus_activate_resource(device_t bus, device_t child, int type, int rid,
613     struct resource *res)
614 {
615         void *p;
616
617         if (type == SYS_RES_IRQ)
618                 return (bus_activate_resource(bus, type, rid, res));
619
620         if (type == SYS_RES_MEMORY) {
621                 vm_offset_t start;
622
623                 start = (vm_offset_t) rman_get_start(res);
624
625                 if (bootverbose)
626                         printf("ps3 mapdev: start %zx, len %ld\n", start,
627                                rman_get_size(res));
628
629                 p = pmap_mapdev(start, (vm_size_t) rman_get_size(res));
630                 if (p == NULL)
631                         return (ENOMEM);
632                 rman_set_virtual(res, p);
633                 rman_set_bustag(res, &bs_be_tag);
634                 rman_set_bushandle(res, (rman_res_t)p);
635         }
636
637         return (rman_activate_resource(res));
638 }
639
640 static bus_dma_tag_t
641 ps3bus_get_dma_tag(device_t dev, device_t child)
642 {
643         struct ps3bus_devinfo *dinfo = device_get_ivars(child);
644         struct ps3bus_softc *sc = device_get_softc(dev);
645         int i, err, flags, pagesize;
646
647         if (dinfo->bustype != PS3_BUSTYPE_SYSBUS &&
648             dinfo->bustype != PS3_BUSTYPE_STORAGE)
649                 return (bus_get_dma_tag(dev));
650
651         mtx_lock(&dinfo->iommu_mtx);
652         if (dinfo->dma_tag != NULL) {
653                 mtx_unlock(&dinfo->iommu_mtx);
654                 return (dinfo->dma_tag);
655         }
656
657         flags = 0; /* 32-bit mode */
658         if (dinfo->bustype == PS3_BUSTYPE_SYSBUS &&
659             dinfo->devtype == PS3_DEVTYPE_USB)
660                 flags = 2; /* 8-bit mode */
661
662         pagesize = 24; /* log_2(16 MB) */
663         if (dinfo->bustype == PS3_BUSTYPE_STORAGE)
664                 pagesize = 12; /* 4 KB */
665
666         for (i = 0; i < sc->rcount; i++) {
667                 err = lv1_allocate_device_dma_region(dinfo->bus, dinfo->dev,
668                     sc->regions[i].mr_size, pagesize, flags,
669                     &dinfo->dma_base[i]);
670                 if (err != 0) {
671                         device_printf(child,
672                             "could not allocate DMA region %d: %d\n", i, err);
673                         goto fail;
674                 }
675
676                 err = lv1_map_device_dma_region(dinfo->bus, dinfo->dev,
677                     sc->regions[i].mr_start, dinfo->dma_base[i],
678                     sc->regions[i].mr_size,
679                     0xf800000000000800UL /* Cell Handbook Figure 7.3.4.1 */);
680                 if (err != 0) {
681                         device_printf(child,
682                             "could not map DMA region %d: %d\n", i, err);
683                         goto fail;
684                 }
685         }
686
687         err = bus_dma_tag_create(bus_get_dma_tag(dev),
688             1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
689             NULL, NULL, BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE,
690             0, NULL, NULL, &dinfo->dma_tag);
691
692         /*
693          * Note: storage devices have IOMMU mappings set up by the hypervisor,
694          * but use physical, non-translated addresses. The above IOMMU
695          * initialization is necessary for the hypervisor to be able to set up
696          * the mappings, but actual DMA mappings should not use the IOMMU
697          * routines.
698          */
699         if (dinfo->bustype != PS3_BUSTYPE_STORAGE)
700                 bus_dma_tag_set_iommu(dinfo->dma_tag, dev, dinfo);
701
702 fail:
703         mtx_unlock(&dinfo->iommu_mtx);
704
705         if (err)
706                 return (NULL);
707
708         return (dinfo->dma_tag);
709 }
710
711 static int
712 ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs,
713     bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_addr_t boundary,
714     void *cookie)
715 {
716         struct ps3bus_devinfo *dinfo = cookie;
717         struct ps3bus_softc *sc = device_get_softc(dev);
718         int i, j;
719
720         for (i = 0; i < *nsegs; i++) {
721                 for (j = 0; j < sc->rcount; j++) {
722                         if (segs[i].ds_addr >= sc->regions[j].mr_start &&
723                             segs[i].ds_addr < sc->regions[j].mr_start +
724                               sc->regions[j].mr_size)
725                                 break;
726                 }
727                 KASSERT(j < sc->rcount,
728                     ("Trying to map address %#lx not in physical memory",
729                     segs[i].ds_addr));
730
731                 segs[i].ds_addr = dinfo->dma_base[j] +
732                     (segs[i].ds_addr - sc->regions[j].mr_start);
733         }
734
735         return (0);
736 }
737
738 static int
739 ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, void *cookie)
740 {
741
742         return (0);
743 }
744
745 #define Y2K 946684800
746
747 static int
748 ps3_gettime(device_t dev, struct timespec *ts)
749 {
750         uint64_t rtc, tb;
751         int result;
752
753         result = lv1_get_rtc(&rtc, &tb);
754         if (result)
755                 return (result);
756
757         ts->tv_sec = rtc + Y2K;
758         ts->tv_nsec = 0;
759         return (0);
760 }
761         
762 static int
763 ps3_settime(device_t dev, struct timespec *ts)
764 {
765         return (-1);
766 }
767