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