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