aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorGeoff Levand <geoffrey.levand@am.sony.com>2006-11-22 18:46:51 -0500
committerPaul Mackerras <paulus@samba.org>2006-12-04 04:40:42 -0500
commitf58a9d171a346afb1b09190427e6c28c6118703e (patch)
treec58029f610ba1e7a8680d09a8cdbdb737dbc166b /arch/powerpc/platforms
parenta985239bdf017e00e985c3a31149d6ae128fdc5f (diff)
[POWERPC] ps3: add support for ps3 platform
Adds the core platform support for the PS3 game console and other devices using the PS3 hypervisor. Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/Makefile1
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig32
-rw-r--r--arch/powerpc/platforms/ps3/Makefile2
-rw-r--r--arch/powerpc/platforms/ps3/mm.c827
-rw-r--r--arch/powerpc/platforms/ps3/platform.h60
-rw-r--r--arch/powerpc/platforms/ps3/setup.c173
-rw-r--r--arch/powerpc/platforms/ps3/smp.c158
-rw-r--r--arch/powerpc/platforms/ps3/time.c104
8 files changed, 1357 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 7ad2673d0aa5..56caf4fbd730 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -16,4 +16,5 @@ obj-$(CONFIG_PPC_ISERIES) += iseries/
16obj-$(CONFIG_PPC_MAPLE) += maple/ 16obj-$(CONFIG_PPC_MAPLE) += maple/
17obj-$(CONFIG_PPC_PASEMI) += pasemi/ 17obj-$(CONFIG_PPC_PASEMI) += pasemi/
18obj-$(CONFIG_PPC_CELL) += cell/ 18obj-$(CONFIG_PPC_CELL) += cell/
19obj-$(CONFIG_PS3) += ps3/
19obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ 20obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
new file mode 100644
index 000000000000..f023719f6459
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -0,0 +1,32 @@
1menu "PS3 Platform Options"
2 depends on PPC_PS3
3
4config PS3_HTAB_SIZE
5 depends on PPC_PS3
6 int "PS3 Platform pagetable size"
7 range 18 20
8 default 20
9 help
10 This option is only for experts who may have the desire to fine
11 tune the pagetable size on their system. The value here is
12 expressed as the log2 of the page table size. Valid values are
13 18, 19, and 20, corresponding to 256KB, 512KB and 1MB respectively.
14
15 If unsure, choose the default (20) with the confidence that your
16 system will have optimal runtime performance.
17
18config PS3_DYNAMIC_DMA
19 depends on PPC_PS3 && EXPERIMENTAL
20 bool "PS3 Platform dynamic DMA page table management"
21 default n
22 help
23 This option will enable kernel support to take advantage of the
24 per device dynamic DMA page table management provided by the Cell
25 processor's IO Controller. This support incurs some runtime
26 overhead and also slightly increases kernel memory usage. The
27 current implementation should be considered experimental.
28
29 This support is mainly for Linux kernel development. If unsure,
30 say N.
31
32endmenu
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile
new file mode 100644
index 000000000000..8d6c72c6ea7a
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/Makefile
@@ -0,0 +1,2 @@
1obj-y += setup.o mm.o smp.o time.o hvcall.o htab.o repository.o
2obj-y += interrupt.o exports.o
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
new file mode 100644
index 000000000000..a57f7036dd1f
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -0,0 +1,827 @@
1/*
2 * PS3 address space management.
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 Sony Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/memory_hotplug.h>
24
25#include <asm/lmb.h>
26#include <asm/udbg.h>
27#include <asm/ps3.h>
28#include <asm/lv1call.h>
29
30#include "platform.h"
31
32#if defined(DEBUG)
33#define DBG(fmt...) udbg_printf(fmt)
34#else
35#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
36#endif
37
38enum {
39#if defined(CONFIG_PS3_USE_LPAR_ADDR)
40 USE_LPAR_ADDR = 1,
41#else
42 USE_LPAR_ADDR = 0,
43#endif
44#if defined(CONFIG_PS3_DYNAMIC_DMA)
45 USE_DYNAMIC_DMA = 1,
46#else
47 USE_DYNAMIC_DMA = 0,
48#endif
49};
50
51enum {
52 PAGE_SHIFT_4K = 12U,
53 PAGE_SHIFT_64K = 16U,
54 PAGE_SHIFT_16M = 24U,
55};
56
57static unsigned long make_page_sizes(unsigned long a, unsigned long b)
58{
59 return (a << 56) | (b << 48);
60}
61
62enum {
63 ALLOCATE_MEMORY_TRY_ALT_UNIT = 0X04,
64 ALLOCATE_MEMORY_ADDR_ZERO = 0X08,
65};
66
67/* valid htab sizes are {18,19,20} = 256K, 512K, 1M */
68
69enum {
70 HTAB_SIZE_MAX = 20U, /* HV limit of 1MB */
71 HTAB_SIZE_MIN = 18U, /* CPU limit of 256KB */
72};
73
74/*============================================================================*/
75/* virtual address space routines */
76/*============================================================================*/
77
78/**
79 * struct mem_region - memory region structure
80 * @base: base address
81 * @size: size in bytes
82 * @offset: difference between base and rm.size
83 */
84
85struct mem_region {
86 unsigned long base;
87 unsigned long size;
88 unsigned long offset;
89};
90
91/**
92 * struct map - address space state variables holder
93 * @total: total memory available as reported by HV
94 * @vas_id - HV virtual address space id
95 * @htab_size: htab size in bytes
96 *
97 * The HV virtual address space (vas) allows for hotplug memory regions.
98 * Memory regions can be created and destroyed in the vas at runtime.
99 * @rm: real mode (bootmem) region
100 * @r1: hotplug memory region(s)
101 *
102 * ps3 addresses
103 * virt_addr: a cpu 'translated' effective address
104 * phys_addr: an address in what Linux thinks is the physical address space
105 * lpar_addr: an address in the HV virtual address space
106 * bus_addr: an io controller 'translated' address on a device bus
107 */
108
109struct map {
110 unsigned long total;
111 unsigned long vas_id;
112 unsigned long htab_size;
113 struct mem_region rm;
114 struct mem_region r1;
115};
116
117#define debug_dump_map(x) _debug_dump_map(x, __func__, __LINE__)
118static void _debug_dump_map(const struct map* m, const char* func, int line)
119{
120 DBG("%s:%d: map.total = %lxh\n", func, line, m->total);
121 DBG("%s:%d: map.rm.size = %lxh\n", func, line, m->rm.size);
122 DBG("%s:%d: map.vas_id = %lu\n", func, line, m->vas_id);
123 DBG("%s:%d: map.htab_size = %lxh\n", func, line, m->htab_size);
124 DBG("%s:%d: map.r1.base = %lxh\n", func, line, m->r1.base);
125 DBG("%s:%d: map.r1.offset = %lxh\n", func, line, m->r1.offset);
126 DBG("%s:%d: map.r1.size = %lxh\n", func, line, m->r1.size);
127}
128
129static struct map map;
130
131/**
132 * ps3_mm_phys_to_lpar - translate a linux physical address to lpar address
133 * @phys_addr: linux physical address
134 */
135
136unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr)
137{
138 BUG_ON(is_kernel_addr(phys_addr));
139 if (USE_LPAR_ADDR)
140 return phys_addr;
141 else
142 return (phys_addr < map.rm.size || phys_addr >= map.total)
143 ? phys_addr : phys_addr + map.r1.offset;
144}
145
146EXPORT_SYMBOL(ps3_mm_phys_to_lpar);
147
148/**
149 * ps3_mm_vas_create - create the virtual address space
150 */
151
152void __init ps3_mm_vas_create(unsigned long* htab_size)
153{
154 int result;
155 unsigned long start_address;
156 unsigned long size;
157 unsigned long access_right;
158 unsigned long max_page_size;
159 unsigned long flags;
160
161 result = lv1_query_logical_partition_address_region_info(0,
162 &start_address, &size, &access_right, &max_page_size,
163 &flags);
164
165 if (result) {
166 DBG("%s:%d: lv1_query_logical_partition_address_region_info "
167 "failed: %s\n", __func__, __LINE__,
168 ps3_result(result));
169 goto fail;
170 }
171
172 if (max_page_size < PAGE_SHIFT_16M) {
173 DBG("%s:%d: bad max_page_size %lxh\n", __func__, __LINE__,
174 max_page_size);
175 goto fail;
176 }
177
178 BUILD_BUG_ON(CONFIG_PS3_HTAB_SIZE > HTAB_SIZE_MAX);
179 BUILD_BUG_ON(CONFIG_PS3_HTAB_SIZE < HTAB_SIZE_MIN);
180
181 result = lv1_construct_virtual_address_space(CONFIG_PS3_HTAB_SIZE,
182 2, make_page_sizes(PAGE_SHIFT_16M, PAGE_SHIFT_64K),
183 &map.vas_id, &map.htab_size);
184
185 if (result) {
186 DBG("%s:%d: lv1_construct_virtual_address_space failed: %s\n",
187 __func__, __LINE__, ps3_result(result));
188 goto fail;
189 }
190
191 result = lv1_select_virtual_address_space(map.vas_id);
192
193 if (result) {
194 DBG("%s:%d: lv1_select_virtual_address_space failed: %s\n",
195 __func__, __LINE__, ps3_result(result));
196 goto fail;
197 }
198
199 *htab_size = map.htab_size;
200
201 debug_dump_map(&map);
202
203 return;
204
205fail:
206 panic("ps3_mm_vas_create failed");
207}
208
209/**
210 * ps3_mm_vas_destroy -
211 */
212
213void ps3_mm_vas_destroy(void)
214{
215 if (map.vas_id) {
216 lv1_select_virtual_address_space(0);
217 lv1_destruct_virtual_address_space(map.vas_id);
218 map.vas_id = 0;
219 }
220}
221
222/*============================================================================*/
223/* memory hotplug routines */
224/*============================================================================*/
225
226/**
227 * ps3_mm_region_create - create a memory region in the vas
228 * @r: pointer to a struct mem_region to accept initialized values
229 * @size: requested region size
230 *
231 * This implementation creates the region with the vas large page size.
232 * @size is rounded down to a multiple of the vas large page size.
233 */
234
235int ps3_mm_region_create(struct mem_region *r, unsigned long size)
236{
237 int result;
238 unsigned long muid;
239
240 r->size = _ALIGN_DOWN(size, 1 << PAGE_SHIFT_16M);
241
242 DBG("%s:%d requested %lxh\n", __func__, __LINE__, size);
243 DBG("%s:%d actual %lxh\n", __func__, __LINE__, r->size);
244 DBG("%s:%d difference %lxh (%luMB)\n", __func__, __LINE__,
245 (unsigned long)(size - r->size),
246 (size - r->size) / 1024 / 1024);
247
248 if (r->size == 0) {
249 DBG("%s:%d: size == 0\n", __func__, __LINE__);
250 result = -1;
251 goto zero_region;
252 }
253
254 result = lv1_allocate_memory(r->size, PAGE_SHIFT_16M, 0,
255 ALLOCATE_MEMORY_TRY_ALT_UNIT, &r->base, &muid);
256
257 if (result || r->base < map.rm.size) {
258 DBG("%s:%d: lv1_allocate_memory failed: %s\n",
259 __func__, __LINE__, ps3_result(result));
260 goto zero_region;
261 }
262
263 r->offset = r->base - map.rm.size;
264 return result;
265
266zero_region:
267 r->size = r->base = r->offset = 0;
268 return result;
269}
270
271/**
272 * ps3_mm_region_destroy - destroy a memory region
273 * @r: pointer to struct mem_region
274 */
275
276void ps3_mm_region_destroy(struct mem_region *r)
277{
278 if (r->base) {
279 lv1_release_memory(r->base);
280 r->size = r->base = r->offset = 0;
281 map.total = map.rm.size;
282 }
283}
284
285/**
286 * ps3_mm_add_memory - hot add memory
287 */
288
289static int __init ps3_mm_add_memory(void)
290{
291 int result;
292 unsigned long start_addr;
293 unsigned long start_pfn;
294 unsigned long nr_pages;
295
296 BUG_ON(!mem_init_done);
297
298 start_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size;
299 start_pfn = start_addr >> PAGE_SHIFT;
300 nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT;
301
302 DBG("%s:%d: start_addr %lxh, start_pfn %lxh, nr_pages %lxh\n",
303 __func__, __LINE__, start_addr, start_pfn, nr_pages);
304
305 result = add_memory(0, start_addr, map.r1.size);
306
307 if (result) {
308 DBG("%s:%d: add_memory failed: (%d)\n",
309 __func__, __LINE__, result);
310 return result;
311 }
312
313 result = online_pages(start_pfn, nr_pages);
314
315 if (result)
316 DBG("%s:%d: online_pages failed: (%d)\n",
317 __func__, __LINE__, result);
318
319 return result;
320}
321
322core_initcall(ps3_mm_add_memory);
323
324/*============================================================================*/
325/* dma routines */
326/*============================================================================*/
327
328/**
329 * dma_lpar_to_bus - Translate an lpar address to ioc mapped bus address.
330 * @r: pointer to dma region structure
331 * @lpar_addr: HV lpar address
332 */
333
334static unsigned long dma_lpar_to_bus(struct ps3_dma_region *r,
335 unsigned long lpar_addr)
336{
337 BUG_ON(lpar_addr >= map.r1.base + map.r1.size);
338 return r->bus_addr + (lpar_addr <= map.rm.size ? lpar_addr
339 : lpar_addr - map.r1.offset);
340}
341
342#define dma_dump_region(_a) _dma_dump_region(_a, __func__, __LINE__)
343static void _dma_dump_region(const struct ps3_dma_region *r, const char* func,
344 int line)
345{
346 DBG("%s:%d: dev %u:%u\n", func, line, r->did.bus_id,
347 r->did.dev_id);
348 DBG("%s:%d: page_size %u\n", func, line, r->page_size);
349 DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr);
350 DBG("%s:%d: len %lxh\n", func, line, r->len);
351}
352
353/**
354 * dma_chunk - A chunk of dma pages mapped by the io controller.
355 * @region - The dma region that owns this chunk.
356 * @lpar_addr: Starting lpar address of the area to map.
357 * @bus_addr: Starting ioc bus address of the area to map.
358 * @len: Length in bytes of the area to map.
359 * @link: A struct list_head used with struct ps3_dma_region.chunk_list, the
360 * list of all chuncks owned by the region.
361 *
362 * This implementation uses a very simple dma page manager
363 * based on the dma_chunk structure. This scheme assumes
364 * that all drivers use very well behaved dma ops.
365 */
366
367struct dma_chunk {
368 struct ps3_dma_region *region;
369 unsigned long lpar_addr;
370 unsigned long bus_addr;
371 unsigned long len;
372 struct list_head link;
373 unsigned int usage_count;
374};
375
376#define dma_dump_chunk(_a) _dma_dump_chunk(_a, __func__, __LINE__)
377static void _dma_dump_chunk (const struct dma_chunk* c, const char* func,
378 int line)
379{
380 DBG("%s:%d: r.dev %u:%u\n", func, line,
381 c->region->did.bus_id, c->region->did.dev_id);
382 DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr);
383 DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size);
384 DBG("%s:%d: r.len %lxh\n", func, line, c->region->len);
385 DBG("%s:%d: c.lpar_addr %lxh\n", func, line, c->lpar_addr);
386 DBG("%s:%d: c.bus_addr %lxh\n", func, line, c->bus_addr);
387 DBG("%s:%d: c.len %lxh\n", func, line, c->len);
388}
389
390static struct dma_chunk * dma_find_chunk(struct ps3_dma_region *r,
391 unsigned long bus_addr, unsigned long len)
392{
393 struct dma_chunk *c;
394 unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size);
395 unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size);
396
397 list_for_each_entry(c, &r->chunk_list.head, link) {
398 /* intersection */
399 if (aligned_bus >= c->bus_addr
400 && aligned_bus < c->bus_addr + c->len
401 && aligned_bus + aligned_len <= c->bus_addr + c->len) {
402 return c;
403 }
404 /* below */
405 if (aligned_bus + aligned_len <= c->bus_addr) {
406 continue;
407 }
408 /* above */
409 if (aligned_bus >= c->bus_addr + c->len) {
410 continue;
411 }
412
413 /* we don't handle the multi-chunk case for now */
414
415 dma_dump_chunk(c);
416 BUG();
417 }
418 return NULL;
419}
420
421static int dma_free_chunk(struct dma_chunk *c)
422{
423 int result = 0;
424
425 if (c->bus_addr) {
426 result = lv1_unmap_device_dma_region(c->region->did.bus_id,
427 c->region->did.dev_id, c->bus_addr, c->len);
428 BUG_ON(result);
429 }
430
431 kfree(c);
432 return result;
433}
434
435/**
436 * dma_map_pages - Maps dma pages into the io controller bus address space.
437 * @r: Pointer to a struct ps3_dma_region.
438 * @phys_addr: Starting physical address of the area to map.
439 * @len: Length in bytes of the area to map.
440 * c_out: A pointer to receive an allocated struct dma_chunk for this area.
441 *
442 * This is the lowest level dma mapping routine, and is the one that will
443 * make the HV call to add the pages into the io controller address space.
444 */
445
446static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
447 unsigned long len, struct dma_chunk **c_out)
448{
449 int result;
450 struct dma_chunk *c;
451
452 c = kzalloc(sizeof(struct dma_chunk), GFP_ATOMIC);
453
454 if (!c) {
455 result = -ENOMEM;
456 goto fail_alloc;
457 }
458
459 c->region = r;
460 c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
461 c->bus_addr = dma_lpar_to_bus(r, c->lpar_addr);
462 c->len = len;
463
464 result = lv1_map_device_dma_region(c->region->did.bus_id,
465 c->region->did.dev_id, c->lpar_addr, c->bus_addr, c->len,
466 0xf800000000000000UL);
467
468 if (result) {
469 DBG("%s:%d: lv1_map_device_dma_region failed: %s\n",
470 __func__, __LINE__, ps3_result(result));
471 goto fail_map;
472 }
473
474 list_add(&c->link, &r->chunk_list.head);
475
476 *c_out = c;
477 return 0;
478
479fail_map:
480 kfree(c);
481fail_alloc:
482 *c_out = NULL;
483 DBG(" <- %s:%d\n", __func__, __LINE__);
484 return result;
485}
486
487/**
488 * dma_region_create - Create a device dma region.
489 * @r: Pointer to a struct ps3_dma_region.
490 *
491 * This is the lowest level dma region create routine, and is the one that
492 * will make the HV call to create the region.
493 */
494
495static int dma_region_create(struct ps3_dma_region* r)
496{
497 int result;
498
499 r->len = _ALIGN_UP(map.total, 1 << r->page_size);
500 INIT_LIST_HEAD(&r->chunk_list.head);
501 spin_lock_init(&r->chunk_list.lock);
502
503 result = lv1_allocate_device_dma_region(r->did.bus_id, r->did.dev_id,
504 r->len, r->page_size, r->region_type, &r->bus_addr);
505
506 dma_dump_region(r);
507
508 if (result) {
509 DBG("%s:%d: lv1_allocate_device_dma_region failed: %s\n",
510 __func__, __LINE__, ps3_result(result));
511 r->len = r->bus_addr = 0;
512 }
513
514 return result;
515}
516
517/**
518 * dma_region_free - Free a device dma region.
519 * @r: Pointer to a struct ps3_dma_region.
520 *
521 * This is the lowest level dma region free routine, and is the one that
522 * will make the HV call to free the region.
523 */
524
525static int dma_region_free(struct ps3_dma_region* r)
526{
527 int result;
528 struct dma_chunk *c;
529 struct dma_chunk *tmp;
530
531 list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) {
532 list_del(&c->link);
533 dma_free_chunk(c);
534 }
535
536 result = lv1_free_device_dma_region(r->did.bus_id, r->did.dev_id,
537 r->bus_addr);
538
539 if (result)
540 DBG("%s:%d: lv1_free_device_dma_region failed: %s\n",
541 __func__, __LINE__, ps3_result(result));
542
543 r->len = r->bus_addr = 0;
544
545 return result;
546}
547
548/**
549 * dma_map_area - Map an area of memory into a device dma region.
550 * @r: Pointer to a struct ps3_dma_region.
551 * @virt_addr: Starting virtual address of the area to map.
552 * @len: Length in bytes of the area to map.
553 * @bus_addr: A pointer to return the starting ioc bus address of the area to
554 * map.
555 *
556 * This is the common dma mapping routine.
557 */
558
559static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
560 unsigned long len, unsigned long *bus_addr)
561{
562 int result;
563 unsigned long flags;
564 struct dma_chunk *c;
565 unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
566 : virt_addr;
567
568 *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
569
570 if (!USE_DYNAMIC_DMA) {
571 unsigned long lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
572 DBG(" -> %s:%d\n", __func__, __LINE__);
573 DBG("%s:%d virt_addr %lxh\n", __func__, __LINE__,
574 virt_addr);
575 DBG("%s:%d phys_addr %lxh\n", __func__, __LINE__,
576 phys_addr);
577 DBG("%s:%d lpar_addr %lxh\n", __func__, __LINE__,
578 lpar_addr);
579 DBG("%s:%d len %lxh\n", __func__, __LINE__, len);
580 DBG("%s:%d bus_addr %lxh (%lxh)\n", __func__, __LINE__,
581 *bus_addr, len);
582 }
583
584 spin_lock_irqsave(&r->chunk_list.lock, flags);
585 c = dma_find_chunk(r, *bus_addr, len);
586
587 if (c) {
588 c->usage_count++;
589 spin_unlock_irqrestore(&r->chunk_list.lock, flags);
590 return 0;
591 }
592
593 result = dma_map_pages(r, _ALIGN_DOWN(phys_addr, 1 << r->page_size),
594 _ALIGN_UP(len, 1 << r->page_size), &c);
595
596 if (result) {
597 *bus_addr = 0;
598 DBG("%s:%d: dma_map_pages failed (%d)\n",
599 __func__, __LINE__, result);
600 spin_unlock_irqrestore(&r->chunk_list.lock, flags);
601 return result;
602 }
603
604 c->usage_count = 1;
605
606 spin_unlock_irqrestore(&r->chunk_list.lock, flags);
607 return result;
608}
609
610/**
611 * dma_unmap_area - Unmap an area of memory from a device dma region.
612 * @r: Pointer to a struct ps3_dma_region.
613 * @bus_addr: The starting ioc bus address of the area to unmap.
614 * @len: Length in bytes of the area to unmap.
615 *
616 * This is the common dma unmap routine.
617 */
618
619int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
620 unsigned long len)
621{
622 unsigned long flags;
623 struct dma_chunk *c;
624
625 spin_lock_irqsave(&r->chunk_list.lock, flags);
626 c = dma_find_chunk(r, bus_addr, len);
627
628 if (!c) {
629 unsigned long aligned_bus = _ALIGN_DOWN(bus_addr,
630 1 << r->page_size);
631 unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size);
632 DBG("%s:%d: not found: bus_addr %lxh\n",
633 __func__, __LINE__, bus_addr);
634 DBG("%s:%d: not found: len %lxh\n",
635 __func__, __LINE__, len);
636 DBG("%s:%d: not found: aligned_bus %lxh\n",
637 __func__, __LINE__, aligned_bus);
638 DBG("%s:%d: not found: aligned_len %lxh\n",
639 __func__, __LINE__, aligned_len);
640 BUG();
641 }
642
643 c->usage_count--;
644
645 if (!c->usage_count) {
646 list_del(&c->link);
647 dma_free_chunk(c);
648 }
649
650 spin_unlock_irqrestore(&r->chunk_list.lock, flags);
651 return 0;
652}
653
654/**
655 * dma_region_create_linear - Setup a linear dma maping for a device.
656 * @r: Pointer to a struct ps3_dma_region.
657 *
658 * This routine creates an HV dma region for the device and maps all available
659 * ram into the io controller bus address space.
660 */
661
662static int dma_region_create_linear(struct ps3_dma_region *r)
663{
664 int result;
665 unsigned long tmp;
666
667 /* force 16M dma pages for linear mapping */
668
669 if (r->page_size != PS3_DMA_16M) {
670 pr_info("%s:%d: forcing 16M pages for linear map\n",
671 __func__, __LINE__);
672 r->page_size = PS3_DMA_16M;
673 }
674
675 result = dma_region_create(r);
676 BUG_ON(result);
677
678 result = dma_map_area(r, map.rm.base, map.rm.size, &tmp);
679 BUG_ON(result);
680
681 if (USE_LPAR_ADDR)
682 result = dma_map_area(r, map.r1.base, map.r1.size,
683 &tmp);
684 else
685 result = dma_map_area(r, map.rm.size, map.r1.size,
686 &tmp);
687
688 BUG_ON(result);
689
690 return result;
691}
692
693/**
694 * dma_region_free_linear - Free a linear dma mapping for a device.
695 * @r: Pointer to a struct ps3_dma_region.
696 *
697 * This routine will unmap all mapped areas and free the HV dma region.
698 */
699
700static int dma_region_free_linear(struct ps3_dma_region *r)
701{
702 int result;
703
704 result = dma_unmap_area(r, dma_lpar_to_bus(r, 0), map.rm.size);
705 BUG_ON(result);
706
707 result = dma_unmap_area(r, dma_lpar_to_bus(r, map.r1.base),
708 map.r1.size);
709 BUG_ON(result);
710
711 result = dma_region_free(r);
712 BUG_ON(result);
713
714 return result;
715}
716
717/**
718 * dma_map_area_linear - Map an area of memory into a device dma region.
719 * @r: Pointer to a struct ps3_dma_region.
720 * @virt_addr: Starting virtual address of the area to map.
721 * @len: Length in bytes of the area to map.
722 * @bus_addr: A pointer to return the starting ioc bus address of the area to
723 * map.
724 *
725 * This routine just returns the coresponding bus address. Actual mapping
726 * occurs in dma_region_create_linear().
727 */
728
729static int dma_map_area_linear(struct ps3_dma_region *r,
730 unsigned long virt_addr, unsigned long len, unsigned long *bus_addr)
731{
732 unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
733 : virt_addr;
734 *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
735 return 0;
736}
737
738/**
739 * dma_unmap_area_linear - Unmap an area of memory from a device dma region.
740 * @r: Pointer to a struct ps3_dma_region.
741 * @bus_addr: The starting ioc bus address of the area to unmap.
742 * @len: Length in bytes of the area to unmap.
743 *
744 * This routine does nothing. Unmapping occurs in dma_region_free_linear().
745 */
746
747static int dma_unmap_area_linear(struct ps3_dma_region *r,
748 unsigned long bus_addr, unsigned long len)
749{
750 return 0;
751}
752
753int ps3_dma_region_create(struct ps3_dma_region *r)
754{
755 return (USE_DYNAMIC_DMA)
756 ? dma_region_create(r)
757 : dma_region_create_linear(r);
758}
759
760int ps3_dma_region_free(struct ps3_dma_region *r)
761{
762 return (USE_DYNAMIC_DMA)
763 ? dma_region_free(r)
764 : dma_region_free_linear(r);
765}
766
767int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr,
768 unsigned long len, unsigned long *bus_addr)
769{
770 return (USE_DYNAMIC_DMA)
771 ? dma_map_area(r, virt_addr, len, bus_addr)
772 : dma_map_area_linear(r, virt_addr, len, bus_addr);
773}
774
775int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr,
776 unsigned long len)
777{
778 return (USE_DYNAMIC_DMA) ? dma_unmap_area(r, bus_addr, len)
779 : dma_unmap_area_linear(r, bus_addr, len);
780}
781
782/*============================================================================*/
783/* system startup routines */
784/*============================================================================*/
785
786/**
787 * ps3_mm_init - initialize the address space state variables
788 */
789
790void __init ps3_mm_init(void)
791{
792 int result;
793
794 DBG(" -> %s:%d\n", __func__, __LINE__);
795
796 result = ps3_repository_read_mm_info(&map.rm.base, &map.rm.size,
797 &map.total);
798
799 if (result)
800 panic("ps3_repository_read_mm_info() failed");
801
802 map.rm.offset = map.rm.base;
803 map.vas_id = map.htab_size = 0;
804
805 /* this implementation assumes map.rm.base is zero */
806
807 BUG_ON(map.rm.base);
808 BUG_ON(!map.rm.size);
809
810 lmb_add(map.rm.base, map.rm.size);
811 lmb_analyze();
812
813 /* arrange to do this in ps3_mm_add_memory */
814 ps3_mm_region_create(&map.r1, map.total - map.rm.size);
815
816 DBG(" <- %s:%d\n", __func__, __LINE__);
817}
818
819/**
820 * ps3_mm_shutdown - final cleanup of address space
821 */
822
823void ps3_mm_shutdown(void)
824{
825 ps3_mm_region_destroy(&map.r1);
826 map.total = map.rm.size;
827}
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
new file mode 100644
index 000000000000..d9948df6ccd4
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -0,0 +1,60 @@
1/*
2 * PS3 platform declarations.
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 Sony Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#if !defined(_PS3_PLATFORM_H)
22#define _PS3_PLATFORM_H
23
24#include <linux/rtc.h>
25
26/* htab */
27
28void __init ps3_hpte_init(unsigned long htab_size);
29void __init ps3_map_htab(void);
30
31/* mm */
32
33void __init ps3_mm_init(void);
34void __init ps3_mm_vas_create(unsigned long* htab_size);
35void ps3_mm_vas_destroy(void);
36void ps3_mm_shutdown(void);
37
38/* irq */
39
40void ps3_init_IRQ(void);
41void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq);
42
43/* smp */
44
45void smp_init_ps3(void);
46void ps3_smp_cleanup_cpu(int cpu);
47
48/* time */
49
50void __init ps3_calibrate_decr(void);
51unsigned long __init ps3_get_boot_time(void);
52void ps3_get_rtc_time(struct rtc_time *time);
53int ps3_set_rtc_time(struct rtc_time *time);
54
55/* os area */
56
57int __init ps3_os_area_init(void);
58u64 ps3_os_area_rtc_diff(void);
59
60#endif
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
new file mode 100644
index 000000000000..c1f6de50654d
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -0,0 +1,173 @@
1/*
2 * PS3 platform setup routines.
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 Sony Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/delay.h>
23#include <linux/fs.h>
24#include <linux/root_dev.h>
25#include <linux/console.h>
26#include <linux/kexec.h>
27
28#include <asm/machdep.h>
29#include <asm/firmware.h>
30#include <asm/time.h>
31#include <asm/iommu.h>
32#include <asm/udbg.h>
33#include <asm/prom.h>
34#include <asm/lv1call.h>
35
36#include "platform.h"
37
38#if defined(DEBUG)
39#define DBG(fmt...) udbg_printf(fmt)
40#else
41#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
42#endif
43
44static void ps3_show_cpuinfo(struct seq_file *m)
45{
46 seq_printf(m, "machine\t\t: %s\n", ppc_md.name);
47}
48
49static void ps3_power_save(void)
50{
51 /*
52 * lv1_pause() puts the PPE thread into inactive state until an
53 * irq on an unmasked plug exists. MSR[EE] has no effect.
54 * flags: 0 = wake on DEC interrupt, 1 = ignore DEC interrupt.
55 */
56
57 lv1_pause(0);
58}
59
60static void ps3_panic(char *str)
61{
62 DBG("%s:%d %s\n", __func__, __LINE__, str);
63
64#ifdef CONFIG_SMP
65 smp_send_stop();
66#endif
67 printk("\n");
68 printk(" System does not reboot automatically.\n");
69 printk(" Please press POWER button.\n");
70 printk("\n");
71
72 for (;;) ;
73}
74
75static void __init ps3_setup_arch(void)
76{
77 DBG(" -> %s:%d\n", __func__, __LINE__);
78
79 ps3_spu_set_platform();
80 ps3_map_htab();
81
82#ifdef CONFIG_SMP
83 smp_init_ps3();
84#endif
85
86#ifdef CONFIG_DUMMY_CONSOLE
87 conswitchp = &dummy_con;
88#endif
89
90 ppc_md.power_save = ps3_power_save;
91
92 DBG(" <- %s:%d\n", __func__, __LINE__);
93}
94
95static void __init ps3_progress(char *s, unsigned short hex)
96{
97 printk("*** %04x : %s\n", hex, s ? s : "");
98}
99
100static int __init ps3_probe(void)
101{
102 unsigned long htab_size;
103 unsigned long dt_root;
104
105 DBG(" -> %s:%d\n", __func__, __LINE__);
106
107 dt_root = of_get_flat_dt_root();
108 if (!of_flat_dt_is_compatible(dt_root, "PS3"))
109 return 0;
110
111 powerpc_firmware_features |= FW_FEATURE_LPAR;
112
113 ps3_os_area_init();
114 ps3_mm_init();
115 ps3_mm_vas_create(&htab_size);
116 ps3_hpte_init(htab_size);
117
118 DBG(" <- %s:%d\n", __func__, __LINE__);
119 return 1;
120}
121
122#if defined(CONFIG_KEXEC)
123static void ps3_kexec_cpu_down(int crash_shutdown, int secondary)
124{
125 DBG(" -> %s:%d\n", __func__, __LINE__);
126
127 if (secondary) {
128 int cpu;
129 for_each_online_cpu(cpu)
130 if (cpu)
131 ps3_smp_cleanup_cpu(cpu);
132 } else
133 ps3_smp_cleanup_cpu(0);
134
135 DBG(" <- %s:%d\n", __func__, __LINE__);
136}
137
138static void ps3_machine_kexec(struct kimage *image)
139{
140 unsigned long ppe_id;
141
142 DBG(" -> %s:%d\n", __func__, __LINE__);
143
144 lv1_get_logical_ppe_id(&ppe_id);
145 lv1_configure_irq_state_bitmap(ppe_id, 0, 0);
146 ps3_mm_shutdown();
147 ps3_mm_vas_destroy();
148
149 default_machine_kexec(image);
150
151 DBG(" <- %s:%d\n", __func__, __LINE__);
152}
153#endif
154
155define_machine(ps3) {
156 .name = "PS3",
157 .probe = ps3_probe,
158 .setup_arch = ps3_setup_arch,
159 .show_cpuinfo = ps3_show_cpuinfo,
160 .init_IRQ = ps3_init_IRQ,
161 .panic = ps3_panic,
162 .get_boot_time = ps3_get_boot_time,
163 .set_rtc_time = ps3_set_rtc_time,
164 .get_rtc_time = ps3_get_rtc_time,
165 .calibrate_decr = ps3_calibrate_decr,
166 .progress = ps3_progress,
167#if defined(CONFIG_KEXEC)
168 .kexec_cpu_down = ps3_kexec_cpu_down,
169 .machine_kexec = ps3_machine_kexec,
170 .machine_kexec_prepare = default_machine_kexec_prepare,
171 .machine_crash_shutdown = default_machine_crash_shutdown,
172#endif
173};
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
new file mode 100644
index 000000000000..11d2080607ed
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -0,0 +1,158 @@
1/*
2 * PS3 SMP routines.
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 Sony Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/smp.h>
23
24#include <asm/machdep.h>
25#include <asm/udbg.h>
26#include <asm/ps3.h>
27
28#include "platform.h"
29
30#if defined(DEBUG)
31#define DBG(fmt...) udbg_printf(fmt)
32#else
33#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
34#endif
35
36static irqreturn_t ipi_function_handler(int irq, void *msg)
37{
38 smp_message_recv((int)(long)msg);
39 return IRQ_HANDLED;
40}
41
42/**
43 * virqs - a per cpu array of virqs for ipi use
44 */
45
46#define MSG_COUNT 4
47static DEFINE_PER_CPU(unsigned int, virqs[MSG_COUNT]);
48
49static const char *names[MSG_COUNT] = {
50 "ipi call",
51 "ipi reschedule",
52 "ipi migrate",
53 "ipi debug brk"
54};
55
56static void do_message_pass(int target, int msg)
57{
58 int result;
59 unsigned int virq;
60
61 if (msg >= MSG_COUNT) {
62 DBG("%s:%d: bad msg: %d\n", __func__, __LINE__, msg);
63 return;
64 }
65
66 virq = per_cpu(virqs, target)[msg];
67 result = ps3_send_event_locally(virq);
68
69 if (result)
70 DBG("%s:%d: ps3_send_event_locally(%d, %d) failed"
71 " (%d)\n", __func__, __LINE__, target, msg, result);
72}
73
74static void ps3_smp_message_pass(int target, int msg)
75{
76 int cpu;
77
78 if (target < NR_CPUS)
79 do_message_pass(target, msg);
80 else if (target == MSG_ALL_BUT_SELF) {
81 for_each_online_cpu(cpu)
82 if (cpu != smp_processor_id())
83 do_message_pass(cpu, msg);
84 } else {
85 for_each_online_cpu(cpu)
86 do_message_pass(cpu, msg);
87 }
88}
89
90static int ps3_smp_probe(void)
91{
92 return 2;
93}
94
95static void __init ps3_smp_setup_cpu(int cpu)
96{
97 int result;
98 unsigned int *virqs = per_cpu(virqs, cpu);
99 int i;
100
101 DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
102
103 /*
104 * Check assumptions on virqs[] indexing. If this
105 * check fails, then a different mapping of PPC_MSG_
106 * to index needs to be setup.
107 */
108
109 BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION != 0);
110 BUILD_BUG_ON(PPC_MSG_RESCHEDULE != 1);
111 BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
112
113 for (i = 0; i < MSG_COUNT; i++) {
114 result = ps3_alloc_event_irq(&virqs[i]);
115
116 if (result)
117 continue;
118
119 DBG("%s:%d: (%d, %d) => virq %u\n",
120 __func__, __LINE__, cpu, i, virqs[i]);
121
122
123 request_irq(virqs[i], ipi_function_handler, IRQF_DISABLED,
124 names[i], (void*)(long)i);
125 }
126
127 ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]);
128
129 DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
130}
131
132void ps3_smp_cleanup_cpu(int cpu)
133{
134 unsigned int *virqs = per_cpu(virqs, cpu);
135 int i;
136
137 DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
138 for (i = 0; i < MSG_COUNT; i++) {
139 ps3_free_event_irq(virqs[i]);
140 free_irq(virqs[i], (void*)(long)i);
141 virqs[i] = NO_IRQ;
142 }
143 DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
144}
145
146static struct smp_ops_t ps3_smp_ops = {
147 .probe = ps3_smp_probe,
148 .message_pass = ps3_smp_message_pass,
149 .kick_cpu = smp_generic_kick_cpu,
150 .setup_cpu = ps3_smp_setup_cpu,
151};
152
153void smp_init_ps3(void)
154{
155 DBG(" -> %s\n", __func__);
156 smp_ops = &ps3_smp_ops;
157 DBG(" <- %s\n", __func__);
158}
diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c
new file mode 100644
index 000000000000..1bae8b19b363
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/time.c
@@ -0,0 +1,104 @@
1/*
2 * PS3 time and rtc routines.
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 Sony Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22
23#include <asm/rtc.h>
24#include <asm/lv1call.h>
25#include <asm/ps3.h>
26
27#include "platform.h"
28
29#define dump_tm(_a) _dump_tm(_a, __func__, __LINE__)
30static void _dump_tm(const struct rtc_time *tm, const char* func, int line)
31{
32 pr_debug("%s:%d tm_sec %d\n", func, line, tm->tm_sec);
33 pr_debug("%s:%d tm_min %d\n", func, line, tm->tm_min);
34 pr_debug("%s:%d tm_hour %d\n", func, line, tm->tm_hour);
35 pr_debug("%s:%d tm_mday %d\n", func, line, tm->tm_mday);
36 pr_debug("%s:%d tm_mon %d\n", func, line, tm->tm_mon);
37 pr_debug("%s:%d tm_year %d\n", func, line, tm->tm_year);
38 pr_debug("%s:%d tm_wday %d\n", func, line, tm->tm_wday);
39}
40
41#define dump_time(_a) _dump_time(_a, __func__, __LINE__)
42static void __attribute__ ((unused)) _dump_time(int time, const char* func,
43 int line)
44{
45 struct rtc_time tm;
46
47 to_tm(time, &tm);
48
49 pr_debug("%s:%d time %d\n", func, line, time);
50 _dump_tm(&tm, func, line);
51}
52
53/**
54 * rtc_shift - Difference in seconds between 1970 and the ps3 rtc value.
55 */
56
57static s64 rtc_shift;
58
59void __init ps3_calibrate_decr(void)
60{
61 int result;
62 u64 tmp;
63
64 result = ps3_repository_read_be_tb_freq(0, &tmp);
65 BUG_ON(result);
66
67 ppc_tb_freq = tmp;
68 ppc_proc_freq = ppc_tb_freq * 40;
69
70 rtc_shift = ps3_os_area_rtc_diff();
71}
72
73static u64 read_rtc(void)
74{
75 int result;
76 u64 rtc_val;
77 u64 tb_val;
78
79 result = lv1_get_rtc(&rtc_val, &tb_val);
80 BUG_ON(result);
81
82 return rtc_val;
83}
84
85int ps3_set_rtc_time(struct rtc_time *tm)
86{
87 u64 now = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
88 tm->tm_hour, tm->tm_min, tm->tm_sec);
89
90 rtc_shift = now - read_rtc();
91 return 0;
92}
93
94void ps3_get_rtc_time(struct rtc_time *tm)
95{
96 to_tm(read_rtc() + rtc_shift, tm);
97 tm->tm_year -= 1900;
98 tm->tm_mon -= 1;
99}
100
101unsigned long __init ps3_get_boot_time(void)
102{
103 return read_rtc() + rtc_shift;
104}