ps3bus.c revision 331722
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: stable/11/sys/powerpc/ps3/ps3bus.c 331722 2018-03-29 02:50:57Z eadler $");
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
53static void	ps3bus_identify(driver_t *, device_t);
54static int	ps3bus_probe(device_t);
55static int	ps3bus_attach(device_t);
56static int	ps3bus_print_child(device_t dev, device_t child);
57static int	ps3bus_read_ivar(device_t bus, device_t child, int which,
58		    uintptr_t *result);
59static 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);
62static int	ps3bus_activate_resource(device_t bus, device_t child, int type,
63		    int rid, struct resource *res);
64static bus_dma_tag_t ps3bus_get_dma_tag(device_t dev, device_t child);
65static 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);
67static int	ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs,
68		    int nsegs, void *cookie);
69static int	ps3_gettime(device_t dev, struct timespec *ts);
70static int	ps3_settime(device_t dev, struct timespec *ts);
71
72struct 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
87static MALLOC_DEFINE(M_PS3BUS, "ps3bus", "PS3 system bus device information");
88
89enum ps3bus_irq_type {
90	SB_IRQ = 2,
91	OHCI_IRQ = 3,
92	EHCI_IRQ = 4,
93};
94
95enum ps3bus_reg_type {
96	OHCI_REG = 3,
97	EHCI_REG = 4,
98};
99
100static 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
127struct ps3bus_softc {
128	struct rman sc_mem_rman;
129	struct rman sc_intr_rman;
130	struct mem_region *regions;
131	int rcount;
132};
133
134static driver_t ps3bus_driver = {
135	"ps3bus",
136	ps3bus_methods,
137	sizeof(struct ps3bus_softc)
138};
139
140static devclass_t ps3bus_devclass;
141
142DRIVER_MODULE(ps3bus, nexus, ps3bus_driver, ps3bus_devclass, 0, 0);
143
144static void
145ps3bus_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
154static int
155ps3bus_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
164static void
165ps3bus_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
246static void
247ps3bus_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
317static int
318ps3bus_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
475static int
476ps3bus_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, "%#jx");
484	retval += resource_list_print_type(&dinfo->resources, "irq",
485	    SYS_RES_IRQ, "%jd");
486
487	retval += bus_print_child_footer(dev, child);
488
489	return (retval);
490}
491
492static int
493ps3bus_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
523static struct resource *
524ps3bus_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
607static int
608ps3bus_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
636static bus_dma_tag_t
637ps3bus_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
698fail:
699	mtx_unlock(&dinfo->iommu_mtx);
700
701	if (err)
702		return (NULL);
703
704	return (dinfo->dma_tag);
705}
706
707static int
708ps3_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
734static int
735ps3_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
743static int
744ps3_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
758static int
759ps3_settime(device_t dev, struct timespec *ts)
760{
761	return (-1);
762}
763
764