xref: /freebsd/sys/powerpc/ps3/ps3bus.c (revision d43fa8ef534ac87a16843d45264f56cf11e0fcbc)
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