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