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