Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/powerpc/ps3/ps3bus.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (C) 2010 Nathan Whitehorn
5
* Copyright (C) 2011 glevand ([email protected])
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", DEVICE_UNIT_ANY) == 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
782