1254885Sdumbbell/*-
2254885Sdumbbell * SPDX-License-Identifier: BSD-2-Clause
3254885Sdumbbell *
4254885Sdumbbell * Copyright (C) 2010 Nathan Whitehorn
5254885Sdumbbell * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru)
6254885Sdumbbell * All rights reserved.
7254885Sdumbbell *
8254885Sdumbbell * Redistribution and use in source and binary forms, with or without
9254885Sdumbbell * modification, are permitted provided that the following conditions
10254885Sdumbbell * are met:
11254885Sdumbbell * 1. Redistributions of source code must retain the above copyright
12254885Sdumbbell *    notice, this list of conditions and the following disclaimer.
13254885Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright
14254885Sdumbbell *    notice, this list of conditions and the following disclaimer in the
15254885Sdumbbell *    documentation and/or other materials provided with the distribution.
16254885Sdumbbell *
17254885Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18254885Sdumbbell * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19254885Sdumbbell * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20254885Sdumbbell * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21254885Sdumbbell * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22254885Sdumbbell * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23254885Sdumbbell * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24254885Sdumbbell * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25254885Sdumbbell * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26254885Sdumbbell * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27254885Sdumbbell */
28254885Sdumbbell
29254885Sdumbbell#include <sys/param.h>
30254885Sdumbbell#include <sys/systm.h>
31254885Sdumbbell#include <sys/kernel.h>
32254885Sdumbbell#include <sys/module.h>
33254885Sdumbbell#include <sys/malloc.h>
34254885Sdumbbell#include <sys/bus.h>
35254885Sdumbbell#include <sys/clock.h>
36254885Sdumbbell#include <sys/cpu.h>
37254885Sdumbbell#include <sys/lock.h>
38254885Sdumbbell#include <sys/mutex.h>
39254885Sdumbbell#include <sys/resource.h>
40254885Sdumbbell#include <sys/rman.h>
41254885Sdumbbell
42254885Sdumbbell#include <vm/vm.h>
43254885Sdumbbell#include <vm/pmap.h>
44254885Sdumbbell
45254885Sdumbbell#include <machine/bus.h>
46254885Sdumbbell#include <machine/platform.h>
47254885Sdumbbell#include <machine/resource.h>
48254885Sdumbbell
49254885Sdumbbell#include "ps3bus.h"
50254885Sdumbbell#include "ps3-hvcall.h"
51254885Sdumbbell#include "iommu_if.h"
52254885Sdumbbell#include "clock_if.h"
53254885Sdumbbell
54254885Sdumbbellstatic void	ps3bus_identify(driver_t *, device_t);
55254885Sdumbbellstatic int	ps3bus_probe(device_t);
56254885Sdumbbellstatic int	ps3bus_attach(device_t);
57254885Sdumbbellstatic int	ps3bus_print_child(device_t dev, device_t child);
58254885Sdumbbellstatic int	ps3bus_read_ivar(device_t bus, device_t child, int which,
59254885Sdumbbell		    uintptr_t *result);
60254885Sdumbbellstatic struct rman *ps3bus_get_rman(device_t bus, int type, u_int flags);
61254885Sdumbbellstatic struct resource *ps3bus_alloc_resource(device_t bus, device_t child,
62254885Sdumbbell		    int type, int *rid, rman_res_t start, rman_res_t end,
63254885Sdumbbell		    rman_res_t count, u_int flags);
64254885Sdumbbellstatic int	ps3bus_map_resource(device_t bus, device_t child,
65254885Sdumbbell		    struct resource *r, struct resource_map_request *argsp,
66254885Sdumbbell		    struct resource_map *map);
67254885Sdumbbellstatic int	ps3bus_unmap_resource(device_t bus, device_t child,
68254885Sdumbbell		    struct resource *r, struct resource_map *map);
69254885Sdumbbellstatic bus_dma_tag_t ps3bus_get_dma_tag(device_t dev, device_t child);
70254885Sdumbbellstatic int	ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs,
71254885Sdumbbell		    bus_addr_t min, bus_addr_t max, bus_size_t alignment,
72254885Sdumbbell		    bus_addr_t boundary, void *cookie);
73254885Sdumbbellstatic int	ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs,
74254885Sdumbbell		    int nsegs, void *cookie);
75254885Sdumbbellstatic int	ps3_gettime(device_t dev, struct timespec *ts);
76254885Sdumbbellstatic int	ps3_settime(device_t dev, struct timespec *ts);
77254885Sdumbbell
78254885Sdumbbellstruct ps3bus_devinfo {
79254885Sdumbbell	int bus;
80254885Sdumbbell	int dev;
81254885Sdumbbell	uint64_t bustype;
82254885Sdumbbell	uint64_t devtype;
83254885Sdumbbell	int busidx;
84254885Sdumbbell	int devidx;
85254885Sdumbbell
86254885Sdumbbell	struct resource_list resources;
87254885Sdumbbell	bus_dma_tag_t dma_tag;
88254885Sdumbbell
89254885Sdumbbell	struct mtx iommu_mtx;
90254885Sdumbbell	bus_addr_t dma_base[4];
91254885Sdumbbell};
92254885Sdumbbell
93254885Sdumbbellstatic MALLOC_DEFINE(M_PS3BUS, "ps3bus", "PS3 system bus device information");
94254885Sdumbbell
95254885Sdumbbellenum ps3bus_irq_type {
96254885Sdumbbell	SB_IRQ = 2,
97254885Sdumbbell	OHCI_IRQ = 3,
98254885Sdumbbell	EHCI_IRQ = 4,
99254885Sdumbbell};
100254885Sdumbbell
101254885Sdumbbellenum ps3bus_reg_type {
102254885Sdumbbell	OHCI_REG = 3,
103254885Sdumbbell	EHCI_REG = 4,
104};
105
106static 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
139struct ps3bus_softc {
140	struct rman sc_mem_rman;
141	struct rman sc_intr_rman;
142	struct mem_region *regions;
143	int rcount;
144};
145
146static driver_t ps3bus_driver = {
147	"ps3bus",
148	ps3bus_methods,
149	sizeof(struct ps3bus_softc)
150};
151
152DRIVER_MODULE(ps3bus, nexus, ps3bus_driver, 0, 0);
153
154static void
155ps3bus_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
164static int
165ps3bus_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
174static void
175ps3bus_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
256static void
257ps3bus_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
327static int
328ps3bus_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", -1);
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", -1);
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, -1);
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	return (bus_generic_attach(self));
483}
484
485static int
486ps3bus_print_child(device_t dev, device_t child)
487{
488	struct ps3bus_devinfo *dinfo = device_get_ivars(child);
489	int retval = 0;
490
491	retval += bus_print_child_header(dev, child);
492	retval += resource_list_print_type(&dinfo->resources, "mem",
493	    SYS_RES_MEMORY, "%#jx");
494	retval += resource_list_print_type(&dinfo->resources, "irq",
495	    SYS_RES_IRQ, "%jd");
496
497	retval += bus_print_child_footer(dev, child);
498
499	return (retval);
500}
501
502static int
503ps3bus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
504{
505	struct ps3bus_devinfo *dinfo = device_get_ivars(child);
506
507	switch (which) {
508	case PS3BUS_IVAR_BUS:
509		*result = dinfo->bus;
510		break;
511	case PS3BUS_IVAR_DEVICE:
512		*result = dinfo->dev;
513		break;
514	case PS3BUS_IVAR_BUSTYPE:
515		*result = dinfo->bustype;
516		break;
517	case PS3BUS_IVAR_DEVTYPE:
518		*result = dinfo->devtype;
519		break;
520	case PS3BUS_IVAR_BUSIDX:
521		*result = dinfo->busidx;
522		break;
523	case PS3BUS_IVAR_DEVIDX:
524		*result = dinfo->devidx;
525		break;
526	default:
527		return (EINVAL);
528	}
529
530	return (0);
531}
532
533static struct rman *
534ps3bus_get_rman(device_t bus, int type, u_int flags)
535{
536	struct	ps3bus_softc *sc;
537
538	sc = device_get_softc(bus);
539	switch (type) {
540	case SYS_RES_MEMORY:
541		return (&sc->sc_mem_rman);
542	case SYS_RES_IRQ:
543		return (&sc->sc_intr_rman);
544	default:
545		return (NULL);
546	}
547}
548
549static struct resource *
550ps3bus_alloc_resource(device_t bus, device_t child, int type, int *rid,
551    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
552{
553	struct	ps3bus_devinfo *dinfo;
554        rman_res_t	adjstart, adjend, adjcount;
555        struct	resource_list_entry *rle;
556
557	dinfo = device_get_ivars(child);
558
559	switch (type) {
560	case SYS_RES_MEMORY:
561		rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
562		    *rid);
563		if (rle == NULL) {
564			device_printf(bus, "no rle for %s memory %d\n",
565				      device_get_nameunit(child), *rid);
566			return (NULL);
567		}
568
569		if (start < rle->start)
570			adjstart = rle->start;
571		else if (start > rle->end)
572			adjstart = rle->end;
573		else
574			adjstart = start;
575
576		if (end < rle->start)
577			adjend = rle->start;
578		else if (end > rle->end)
579			adjend = rle->end;
580		else
581			adjend = end;
582
583		adjcount = adjend - adjstart;
584		break;
585	case SYS_RES_IRQ:
586		rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ,
587		    *rid);
588		adjstart = rle->start;
589		adjcount = ulmax(count, rle->count);
590		adjend = ulmax(rle->end, rle->start + adjcount - 1);
591		break;
592	default:
593		device_printf(bus, "unknown resource request from %s\n",
594			      device_get_nameunit(child));
595		return (NULL);
596        }
597
598	return (bus_generic_rman_alloc_resource(bus, child, type, rid, adjstart,
599	    adjend, adjcount, flags));
600}
601
602static int
603ps3bus_map_resource(device_t bus, device_t child, struct resource *r,
604    struct resource_map_request *argsp, struct resource_map *map)
605{
606	struct resource_map_request args;
607	rman_res_t length, start;
608	int error;
609
610	/* Resources must be active to be mapped. */
611	if (!(rman_get_flags(r) & RF_ACTIVE))
612		return (ENXIO);
613
614	/* Mappings are only supported on memory resources. */
615	switch (rman_get_type(r)) {
616	case SYS_RES_MEMORY:
617		break;
618	default:
619		return (EINVAL);
620	}
621
622	resource_init_map_request(&args);
623	error = resource_validate_map_request(r, argsp, &args, &start, &length);
624	if (error)
625		return (error);
626
627	if (bootverbose)
628		printf("ps3 mapdev: start %jx, len %jd\n", start, length);
629
630	map->r_vaddr = pmap_mapdev_attr(start, length, args.memattr);
631	if (map->r_vaddr == NULL)
632		return (ENOMEM);
633	map->r_bustag = &bs_be_tag;
634	map->r_bushandle = (vm_offset_t)map->r_vaddr;
635	map->r_size = length;
636	return (0);
637}
638
639static int
640ps3bus_unmap_resource(device_t bus, device_t child, struct resource *r,
641    struct resource_map *map)
642{
643
644	switch (rman_get_type(r)) {
645	case SYS_RES_MEMORY:
646		pmap_unmapdev(map->r_vaddr, map->r_size);
647		return (0);
648	default:
649		return (EINVAL);
650	}
651}
652
653static bus_dma_tag_t
654ps3bus_get_dma_tag(device_t dev, device_t child)
655{
656	struct ps3bus_devinfo *dinfo = device_get_ivars(child);
657	struct ps3bus_softc *sc = device_get_softc(dev);
658	int i, err, flags, pagesize;
659
660	if (dinfo->bustype != PS3_BUSTYPE_SYSBUS &&
661	    dinfo->bustype != PS3_BUSTYPE_STORAGE)
662		return (bus_get_dma_tag(dev));
663
664	mtx_lock(&dinfo->iommu_mtx);
665	if (dinfo->dma_tag != NULL) {
666		mtx_unlock(&dinfo->iommu_mtx);
667		return (dinfo->dma_tag);
668	}
669
670	flags = 0; /* 32-bit mode */
671	if (dinfo->bustype == PS3_BUSTYPE_SYSBUS &&
672	    dinfo->devtype == PS3_DEVTYPE_USB)
673		flags = 2; /* 8-bit mode */
674
675	pagesize = 24; /* log_2(16 MB) */
676	if (dinfo->bustype == PS3_BUSTYPE_STORAGE)
677		pagesize = 12; /* 4 KB */
678
679	for (i = 0; i < sc->rcount; i++) {
680		err = lv1_allocate_device_dma_region(dinfo->bus, dinfo->dev,
681		    sc->regions[i].mr_size, pagesize, flags,
682		    &dinfo->dma_base[i]);
683		if (err != 0) {
684			device_printf(child,
685			    "could not allocate DMA region %d: %d\n", i, err);
686			goto fail;
687		}
688
689		err = lv1_map_device_dma_region(dinfo->bus, dinfo->dev,
690		    sc->regions[i].mr_start, dinfo->dma_base[i],
691		    sc->regions[i].mr_size,
692		    0xf800000000000800UL /* Cell Handbook Figure 7.3.4.1 */);
693		if (err != 0) {
694			device_printf(child,
695			    "could not map DMA region %d: %d\n", i, err);
696			goto fail;
697		}
698	}
699
700	err = bus_dma_tag_create(bus_get_dma_tag(dev),
701	    1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
702	    NULL, NULL, BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE,
703	    0, NULL, NULL, &dinfo->dma_tag);
704
705	/*
706	 * Note: storage devices have IOMMU mappings set up by the hypervisor,
707	 * but use physical, non-translated addresses. The above IOMMU
708	 * initialization is necessary for the hypervisor to be able to set up
709	 * the mappings, but actual DMA mappings should not use the IOMMU
710	 * routines.
711	 */
712	if (dinfo->bustype != PS3_BUSTYPE_STORAGE)
713		bus_dma_tag_set_iommu(dinfo->dma_tag, dev, dinfo);
714
715fail:
716	mtx_unlock(&dinfo->iommu_mtx);
717
718	if (err)
719		return (NULL);
720
721	return (dinfo->dma_tag);
722}
723
724static int
725ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs,
726    bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_addr_t boundary,
727    void *cookie)
728{
729	struct ps3bus_devinfo *dinfo = cookie;
730	struct ps3bus_softc *sc = device_get_softc(dev);
731	int i, j;
732
733	for (i = 0; i < *nsegs; i++) {
734		for (j = 0; j < sc->rcount; j++) {
735			if (segs[i].ds_addr >= sc->regions[j].mr_start &&
736			    segs[i].ds_addr < sc->regions[j].mr_start +
737			      sc->regions[j].mr_size)
738				break;
739		}
740		KASSERT(j < sc->rcount,
741		    ("Trying to map address %#lx not in physical memory",
742		    segs[i].ds_addr));
743
744		segs[i].ds_addr = dinfo->dma_base[j] +
745		    (segs[i].ds_addr - sc->regions[j].mr_start);
746	}
747
748	return (0);
749}
750
751static int
752ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, void *cookie)
753{
754
755	return (0);
756}
757
758#define Y2K 946684800
759
760static int
761ps3_gettime(device_t dev, struct timespec *ts)
762{
763	uint64_t rtc, tb;
764	int result;
765
766	result = lv1_get_rtc(&rtc, &tb);
767	if (result)
768		return (result);
769
770	ts->tv_sec = rtc + Y2K;
771	ts->tv_nsec = 0;
772	return (0);
773}
774
775static int
776ps3_settime(device_t dev, struct timespec *ts)
777{
778	return (-1);
779}
780