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