xref: /freebsd/sys/powerpc/ps3/ps3bus.c (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
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,
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,
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", DEVICE_UNIT_ANY);
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", DEVICE_UNIT_ANY);
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, DEVICE_UNIT_ANY);
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 	bus_attach_children(self);
483 	return (0);
484 }
485 
486 static int
487 ps3bus_print_child(device_t dev, device_t child)
488 {
489 	struct ps3bus_devinfo *dinfo = device_get_ivars(child);
490 	int retval = 0;
491 
492 	retval += bus_print_child_header(dev, child);
493 	retval += resource_list_print_type(&dinfo->resources, "mem",
494 	    SYS_RES_MEMORY, "%#jx");
495 	retval += resource_list_print_type(&dinfo->resources, "irq",
496 	    SYS_RES_IRQ, "%jd");
497 
498 	retval += bus_print_child_footer(dev, child);
499 
500 	return (retval);
501 }
502 
503 static int
504 ps3bus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
505 {
506 	struct ps3bus_devinfo *dinfo = device_get_ivars(child);
507 
508 	switch (which) {
509 	case PS3BUS_IVAR_BUS:
510 		*result = dinfo->bus;
511 		break;
512 	case PS3BUS_IVAR_DEVICE:
513 		*result = dinfo->dev;
514 		break;
515 	case PS3BUS_IVAR_BUSTYPE:
516 		*result = dinfo->bustype;
517 		break;
518 	case PS3BUS_IVAR_DEVTYPE:
519 		*result = dinfo->devtype;
520 		break;
521 	case PS3BUS_IVAR_BUSIDX:
522 		*result = dinfo->busidx;
523 		break;
524 	case PS3BUS_IVAR_DEVIDX:
525 		*result = dinfo->devidx;
526 		break;
527 	default:
528 		return (EINVAL);
529 	}
530 
531 	return (0);
532 }
533 
534 static struct rman *
535 ps3bus_get_rman(device_t bus, int type, u_int flags)
536 {
537 	struct	ps3bus_softc *sc;
538 
539 	sc = device_get_softc(bus);
540 	switch (type) {
541 	case SYS_RES_MEMORY:
542 		return (&sc->sc_mem_rman);
543 	case SYS_RES_IRQ:
544 		return (&sc->sc_intr_rman);
545 	default:
546 		return (NULL);
547 	}
548 }
549 
550 static struct resource *
551 ps3bus_alloc_resource(device_t bus, device_t child, int type, int *rid,
552     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
553 {
554 	struct	ps3bus_devinfo *dinfo;
555         rman_res_t	adjstart, adjend, adjcount;
556         struct	resource_list_entry *rle;
557 
558 	dinfo = device_get_ivars(child);
559 
560 	switch (type) {
561 	case SYS_RES_MEMORY:
562 		rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
563 		    *rid);
564 		if (rle == NULL) {
565 			device_printf(bus, "no rle for %s memory %d\n",
566 				      device_get_nameunit(child), *rid);
567 			return (NULL);
568 		}
569 
570 		if (start < rle->start)
571 			adjstart = rle->start;
572 		else if (start > rle->end)
573 			adjstart = rle->end;
574 		else
575 			adjstart = start;
576 
577 		if (end < rle->start)
578 			adjend = rle->start;
579 		else if (end > rle->end)
580 			adjend = rle->end;
581 		else
582 			adjend = end;
583 
584 		adjcount = adjend - adjstart;
585 		break;
586 	case SYS_RES_IRQ:
587 		rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ,
588 		    *rid);
589 		adjstart = rle->start;
590 		adjcount = ulmax(count, rle->count);
591 		adjend = ulmax(rle->end, rle->start + adjcount - 1);
592 		break;
593 	default:
594 		device_printf(bus, "unknown resource request from %s\n",
595 			      device_get_nameunit(child));
596 		return (NULL);
597         }
598 
599 	return (bus_generic_rman_alloc_resource(bus, child, type, rid, adjstart,
600 	    adjend, adjcount, flags));
601 }
602 
603 static int
604 ps3bus_map_resource(device_t bus, device_t child, struct resource *r,
605     struct resource_map_request *argsp, struct resource_map *map)
606 {
607 	struct resource_map_request args;
608 	rman_res_t length, start;
609 	int error;
610 
611 	/* Resources must be active to be mapped. */
612 	if (!(rman_get_flags(r) & RF_ACTIVE))
613 		return (ENXIO);
614 
615 	/* Mappings are only supported on memory resources. */
616 	switch (rman_get_type(r)) {
617 	case SYS_RES_MEMORY:
618 		break;
619 	default:
620 		return (EINVAL);
621 	}
622 
623 	resource_init_map_request(&args);
624 	error = resource_validate_map_request(r, argsp, &args, &start, &length);
625 	if (error)
626 		return (error);
627 
628 	if (bootverbose)
629 		printf("ps3 mapdev: start %jx, len %jd\n", start, length);
630 
631 	map->r_vaddr = pmap_mapdev_attr(start, length, args.memattr);
632 	if (map->r_vaddr == NULL)
633 		return (ENOMEM);
634 	map->r_bustag = &bs_be_tag;
635 	map->r_bushandle = (vm_offset_t)map->r_vaddr;
636 	map->r_size = length;
637 	return (0);
638 }
639 
640 static int
641 ps3bus_unmap_resource(device_t bus, device_t child, struct resource *r,
642     struct resource_map *map)
643 {
644 
645 	switch (rman_get_type(r)) {
646 	case SYS_RES_MEMORY:
647 		pmap_unmapdev(map->r_vaddr, map->r_size);
648 		return (0);
649 	default:
650 		return (EINVAL);
651 	}
652 }
653 
654 static bus_dma_tag_t
655 ps3bus_get_dma_tag(device_t dev, device_t child)
656 {
657 	struct ps3bus_devinfo *dinfo = device_get_ivars(child);
658 	struct ps3bus_softc *sc = device_get_softc(dev);
659 	int i, err, flags, pagesize;
660 
661 	if (dinfo->bustype != PS3_BUSTYPE_SYSBUS &&
662 	    dinfo->bustype != PS3_BUSTYPE_STORAGE)
663 		return (bus_get_dma_tag(dev));
664 
665 	mtx_lock(&dinfo->iommu_mtx);
666 	if (dinfo->dma_tag != NULL) {
667 		mtx_unlock(&dinfo->iommu_mtx);
668 		return (dinfo->dma_tag);
669 	}
670 
671 	flags = 0; /* 32-bit mode */
672 	if (dinfo->bustype == PS3_BUSTYPE_SYSBUS &&
673 	    dinfo->devtype == PS3_DEVTYPE_USB)
674 		flags = 2; /* 8-bit mode */
675 
676 	pagesize = 24; /* log_2(16 MB) */
677 	if (dinfo->bustype == PS3_BUSTYPE_STORAGE)
678 		pagesize = 12; /* 4 KB */
679 
680 	for (i = 0; i < sc->rcount; i++) {
681 		err = lv1_allocate_device_dma_region(dinfo->bus, dinfo->dev,
682 		    sc->regions[i].mr_size, pagesize, flags,
683 		    &dinfo->dma_base[i]);
684 		if (err != 0) {
685 			device_printf(child,
686 			    "could not allocate DMA region %d: %d\n", i, err);
687 			goto fail;
688 		}
689 
690 		err = lv1_map_device_dma_region(dinfo->bus, dinfo->dev,
691 		    sc->regions[i].mr_start, dinfo->dma_base[i],
692 		    sc->regions[i].mr_size,
693 		    0xf800000000000800UL /* Cell Handbook Figure 7.3.4.1 */);
694 		if (err != 0) {
695 			device_printf(child,
696 			    "could not map DMA region %d: %d\n", i, err);
697 			goto fail;
698 		}
699 	}
700 
701 	err = bus_dma_tag_create(bus_get_dma_tag(dev),
702 	    1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
703 	    NULL, NULL, BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE,
704 	    0, NULL, NULL, &dinfo->dma_tag);
705 
706 	/*
707 	 * Note: storage devices have IOMMU mappings set up by the hypervisor,
708 	 * but use physical, non-translated addresses. The above IOMMU
709 	 * initialization is necessary for the hypervisor to be able to set up
710 	 * the mappings, but actual DMA mappings should not use the IOMMU
711 	 * routines.
712 	 */
713 	if (dinfo->bustype != PS3_BUSTYPE_STORAGE)
714 		bus_dma_tag_set_iommu(dinfo->dma_tag, dev, dinfo);
715 
716 fail:
717 	mtx_unlock(&dinfo->iommu_mtx);
718 
719 	if (err)
720 		return (NULL);
721 
722 	return (dinfo->dma_tag);
723 }
724 
725 static int
726 ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs,
727     bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_addr_t boundary,
728     void *cookie)
729 {
730 	struct ps3bus_devinfo *dinfo = cookie;
731 	struct ps3bus_softc *sc = device_get_softc(dev);
732 	int i, j;
733 
734 	for (i = 0; i < *nsegs; i++) {
735 		for (j = 0; j < sc->rcount; j++) {
736 			if (segs[i].ds_addr >= sc->regions[j].mr_start &&
737 			    segs[i].ds_addr < sc->regions[j].mr_start +
738 			      sc->regions[j].mr_size)
739 				break;
740 		}
741 		KASSERT(j < sc->rcount,
742 		    ("Trying to map address %#lx not in physical memory",
743 		    segs[i].ds_addr));
744 
745 		segs[i].ds_addr = dinfo->dma_base[j] +
746 		    (segs[i].ds_addr - sc->regions[j].mr_start);
747 	}
748 
749 	return (0);
750 }
751 
752 static int
753 ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, void *cookie)
754 {
755 
756 	return (0);
757 }
758 
759 #define Y2K 946684800
760 
761 static int
762 ps3_gettime(device_t dev, struct timespec *ts)
763 {
764 	uint64_t rtc, tb;
765 	int result;
766 
767 	result = lv1_get_rtc(&rtc, &tb);
768 	if (result)
769 		return (result);
770 
771 	ts->tv_sec = rtc + Y2K;
772 	ts->tv_nsec = 0;
773 	return (0);
774 }
775 
776 static int
777 ps3_settime(device_t dev, struct timespec *ts)
778 {
779 	return (-1);
780 }
781