aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/ps3
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/ps3')
-rw-r--r--arch/powerpc/platforms/ps3/device-init.c24
-rw-r--r--arch/powerpc/platforms/ps3/htab.c14
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c9
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c646
-rw-r--r--arch/powerpc/platforms/ps3/platform.h10
-rw-r--r--arch/powerpc/platforms/ps3/setup.c3
-rw-r--r--arch/powerpc/platforms/ps3/time.c14
7 files changed, 644 insertions, 76 deletions
diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c
index ce15cada88d4..fd063fe0c9b3 100644
--- a/arch/powerpc/platforms/ps3/device-init.c
+++ b/arch/powerpc/platforms/ps3/device-init.c
@@ -297,8 +297,8 @@ static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo)
297 u64 dev_port; 297 u64 dev_port;
298 } *notify_event; 298 } *notify_event;
299 299
300 pr_debug(" -> %s:%u: bus_id %u, dev_id %u, dev_type %u\n", __func__, 300 pr_debug(" -> %s:%u: (%u:%u:%u)\n", __func__, __LINE__, repo->bus_id,
301 __LINE__, repo->bus_id, repo->dev_id, repo->dev_type); 301 repo->dev_id, repo->dev_type);
302 302
303 buf = kzalloc(512, GFP_KERNEL); 303 buf = kzalloc(512, GFP_KERNEL);
304 if (!buf) 304 if (!buf)
@@ -359,6 +359,11 @@ static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo)
359 break; 359 break;
360 } 360 }
361 361
362 pr_debug("%s:%d: notify event (%u:%u:%u): event_type 0x%lx, "
363 "port %lu\n", __func__, __LINE__, repo->bus_index,
364 repo->dev_index, repo->dev_type,
365 notify_event->event_type, notify_event->dev_port);
366
362 if (notify_event->event_type != notify_region_probe || 367 if (notify_event->event_type != notify_region_probe ||
363 notify_event->bus_id != repo->bus_id) { 368 notify_event->bus_id != repo->bus_id) {
364 pr_debug("%s:%u: bad notify_event: event %lu, " 369 pr_debug("%s:%u: bad notify_event: event %lu, "
@@ -370,8 +375,9 @@ static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo)
370 375
371 if (notify_event->dev_id == repo->dev_id && 376 if (notify_event->dev_id == repo->dev_id &&
372 notify_event->dev_type == repo->dev_type) { 377 notify_event->dev_type == repo->dev_type) {
373 pr_debug("%s:%u: device ready: dev_id %u\n", __func__, 378 pr_debug("%s:%u: device ready (%u:%u:%u)\n", __func__,
374 __LINE__, repo->dev_id); 379 __LINE__, repo->bus_index, repo->dev_index,
380 repo->dev_type);
375 error = 0; 381 error = 0;
376 break; 382 break;
377 } 383 }
@@ -412,9 +418,10 @@ static int ps3_setup_storage_dev(const struct ps3_repository_device *repo,
412 return -ENODEV; 418 return -ENODEV;
413 } 419 }
414 420
415 pr_debug("%s:%u: index %u:%u: port %lu blk_size %lu num_blocks %lu " 421 pr_debug("%s:%u: (%u:%u:%u): port %lu blk_size %lu num_blocks %lu "
416 "num_regions %u\n", __func__, __LINE__, repo->bus_index, 422 "num_regions %u\n", __func__, __LINE__, repo->bus_index,
417 repo->dev_index, port, blk_size, num_blocks, num_regions); 423 repo->dev_index, repo->dev_type, port, blk_size, num_blocks,
424 num_regions);
418 425
419 p = kzalloc(sizeof(struct ps3_storage_device) + 426 p = kzalloc(sizeof(struct ps3_storage_device) +
420 num_regions * sizeof(struct ps3_storage_region), 427 num_regions * sizeof(struct ps3_storage_region),
@@ -681,8 +688,9 @@ static int ps3_probe_thread(void *data)
681 pr_debug("%s:%u: find device error.\n", 688 pr_debug("%s:%u: find device error.\n",
682 __func__, __LINE__); 689 __func__, __LINE__);
683 else { 690 else {
684 pr_debug("%s:%u: found device\n", __func__, 691 pr_debug("%s:%u: found device (%u:%u:%u)\n",
685 __LINE__); 692 __func__, __LINE__, repo->bus_index,
693 repo->dev_index, repo->dev_type);
686 ps3_register_repository_device(repo); 694 ps3_register_repository_device(repo);
687 ps3_repository_bump_device(repo); 695 ps3_repository_bump_device(repo);
688 ms = 250; 696 ms = 250;
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index 5d2e176a1b18..7382f195c4f8 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -60,7 +60,8 @@ static void _debug_dump_hpte(unsigned long pa, unsigned long va,
60} 60}
61 61
62static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, 62static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va,
63 unsigned long pa, unsigned long rflags, unsigned long vflags, int psize) 63 unsigned long pa, unsigned long rflags, unsigned long vflags,
64 int psize, int ssize)
64{ 65{
65 unsigned long slot; 66 unsigned long slot;
66 struct hash_pte lhpte; 67 struct hash_pte lhpte;
@@ -72,7 +73,8 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va,
72 73
73 vflags &= ~HPTE_V_SECONDARY; /* this bit is ignored */ 74 vflags &= ~HPTE_V_SECONDARY; /* this bit is ignored */
74 75
75 lhpte.v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; 76 lhpte.v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) |
77 vflags | HPTE_V_VALID;
76 lhpte.r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags; 78 lhpte.r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags;
77 79
78 p_pteg = hpte_group / HPTES_PER_GROUP; 80 p_pteg = hpte_group / HPTES_PER_GROUP;
@@ -167,14 +169,14 @@ static long ps3_hpte_remove(unsigned long hpte_group)
167} 169}
168 170
169static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, 171static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
170 unsigned long va, int psize, int local) 172 unsigned long va, int psize, int ssize, int local)
171{ 173{
172 unsigned long flags; 174 unsigned long flags;
173 unsigned long result; 175 unsigned long result;
174 unsigned long pteg, bit; 176 unsigned long pteg, bit;
175 unsigned long hpte_v, want_v; 177 unsigned long hpte_v, want_v;
176 178
177 want_v = hpte_encode_v(va, psize); 179 want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M);
178 180
179 spin_lock_irqsave(&ps3_bolttab_lock, flags); 181 spin_lock_irqsave(&ps3_bolttab_lock, flags);
180 182
@@ -205,13 +207,13 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
205} 207}
206 208
207static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, 209static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
208 int psize) 210 int psize, int ssize)
209{ 211{
210 panic("ps3_hpte_updateboltedpp() not implemented"); 212 panic("ps3_hpte_updateboltedpp() not implemented");
211} 213}
212 214
213static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, 215static void ps3_hpte_invalidate(unsigned long slot, unsigned long va,
214 int psize, int local) 216 int psize, int ssize, int local)
215{ 217{
216 unsigned long flags; 218 unsigned long flags;
217 unsigned long result; 219 unsigned long result;
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 67e32ec9b37e..3a6db04aa940 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -673,9 +673,16 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq,
673 return 0; 673 return 0;
674} 674}
675 675
676static int ps3_host_match(struct irq_host *h, struct device_node *np)
677{
678 /* Match all */
679 return 1;
680}
681
676static struct irq_host_ops ps3_host_ops = { 682static struct irq_host_ops ps3_host_ops = {
677 .map = ps3_host_map, 683 .map = ps3_host_map,
678 .unmap = ps3_host_unmap, 684 .unmap = ps3_host_unmap,
685 .match = ps3_host_match,
679}; 686};
680 687
681void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) 688void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
@@ -726,7 +733,7 @@ void __init ps3_init_IRQ(void)
726 unsigned cpu; 733 unsigned cpu;
727 struct irq_host *host; 734 struct irq_host *host;
728 735
729 host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, 736 host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops,
730 PS3_INVALID_OUTLET); 737 PS3_INVALID_OUTLET);
731 irq_set_default_host(host); 738 irq_set_default_host(host);
732 irq_set_virq_count(PS3_PLUG_MAX + 1); 739 irq_set_virq_count(PS3_PLUG_MAX + 1);
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
index b70e474014f0..766685ab26f8 100644
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * PS3 'Other OS' area data. 2 * PS3 flash memory os area.
3 * 3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc. 4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 Sony Corp. 5 * Copyright 2006 Sony Corp.
@@ -20,6 +20,9 @@
20 20
21#include <linux/kernel.h> 21#include <linux/kernel.h>
22#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/workqueue.h>
24#include <linux/fs.h>
25#include <linux/syscalls.h>
23 26
24#include <asm/lmb.h> 27#include <asm/lmb.h>
25 28
@@ -29,7 +32,7 @@ enum {
29 OS_AREA_SEGMENT_SIZE = 0X200, 32 OS_AREA_SEGMENT_SIZE = 0X200,
30}; 33};
31 34
32enum { 35enum os_area_ldr_format {
33 HEADER_LDR_FORMAT_RAW = 0, 36 HEADER_LDR_FORMAT_RAW = 0,
34 HEADER_LDR_FORMAT_GZIP = 1, 37 HEADER_LDR_FORMAT_GZIP = 1,
35}; 38};
@@ -38,7 +41,7 @@ enum {
38 * struct os_area_header - os area header segment. 41 * struct os_area_header - os area header segment.
39 * @magic_num: Always 'cell_ext_os_area'. 42 * @magic_num: Always 'cell_ext_os_area'.
40 * @hdr_version: Header format version number. 43 * @hdr_version: Header format version number.
41 * @os_area_offset: Starting segment number of os image area. 44 * @db_area_offset: Starting segment number of other os database area.
42 * @ldr_area_offset: Starting segment number of bootloader image area. 45 * @ldr_area_offset: Starting segment number of bootloader image area.
43 * @ldr_format: HEADER_LDR_FORMAT flag. 46 * @ldr_format: HEADER_LDR_FORMAT flag.
44 * @ldr_size: Size of bootloader image in bytes. 47 * @ldr_size: Size of bootloader image in bytes.
@@ -50,9 +53,9 @@ enum {
50 */ 53 */
51 54
52struct os_area_header { 55struct os_area_header {
53 s8 magic_num[16]; 56 u8 magic_num[16];
54 u32 hdr_version; 57 u32 hdr_version;
55 u32 os_area_offset; 58 u32 db_area_offset;
56 u32 ldr_area_offset; 59 u32 ldr_area_offset;
57 u32 _reserved_1; 60 u32 _reserved_1;
58 u32 ldr_format; 61 u32 ldr_format;
@@ -60,12 +63,12 @@ struct os_area_header {
60 u32 _reserved_2[6]; 63 u32 _reserved_2[6];
61}; 64};
62 65
63enum { 66enum os_area_boot_flag {
64 PARAM_BOOT_FLAG_GAME_OS = 0, 67 PARAM_BOOT_FLAG_GAME_OS = 0,
65 PARAM_BOOT_FLAG_OTHER_OS = 1, 68 PARAM_BOOT_FLAG_OTHER_OS = 1,
66}; 69};
67 70
68enum { 71enum os_area_ctrl_button {
69 PARAM_CTRL_BUTTON_O_IS_YES = 0, 72 PARAM_CTRL_BUTTON_O_IS_YES = 0,
70 PARAM_CTRL_BUTTON_X_IS_YES = 1, 73 PARAM_CTRL_BUTTON_X_IS_YES = 1,
71}; 74};
@@ -84,6 +87,9 @@ enum {
84 * @dns_primary: User preference of static primary dns server. 87 * @dns_primary: User preference of static primary dns server.
85 * @dns_secondary: User preference of static secondary dns server. 88 * @dns_secondary: User preference of static secondary dns server.
86 * 89 *
90 * The ps3 rtc maintains a read-only value that approximates seconds since
91 * 2000-01-01 00:00:00 UTC.
92 *
87 * User preference of zero for static_ip_addr means use dhcp. 93 * User preference of zero for static_ip_addr means use dhcp.
88 */ 94 */
89 95
@@ -108,45 +114,172 @@ struct os_area_params {
108 u8 _reserved_5[8]; 114 u8 _reserved_5[8];
109}; 115};
110 116
117enum {
118 OS_AREA_DB_MAGIC_NUM = 0x2d64622dU,
119};
120
111/** 121/**
112 * struct saved_params - Static working copies of data from the 'Other OS' area. 122 * struct os_area_db - Shared flash memory database.
123 * @magic_num: Always '-db-' = 0x2d64622d.
124 * @version: os_area_db format version number.
125 * @index_64: byte offset of the database id index for 64 bit variables.
126 * @count_64: number of usable 64 bit index entries
127 * @index_32: byte offset of the database id index for 32 bit variables.
128 * @count_32: number of usable 32 bit index entries
129 * @index_16: byte offset of the database id index for 16 bit variables.
130 * @count_16: number of usable 16 bit index entries
113 * 131 *
114 * For the convinience of the guest, the HV makes a copy of the 'Other OS' area 132 * Flash rom storage for exclusive use by guests running in the other os lpar.
115 * in flash to a high address in the boot memory region and then puts that RAM 133 * The current system configuration allocates 1K (two segments) for other os
116 * address and the byte count into the repository for retreval by the guest. 134 * use.
117 * We copy the data we want into a static variable and allow the memory setup 135 */
118 * by the HV to be claimed by the lmb manager. 136
137struct os_area_db {
138 u32 magic_num;
139 u16 version;
140 u16 _reserved_1;
141 u16 index_64;
142 u16 count_64;
143 u16 index_32;
144 u16 count_32;
145 u16 index_16;
146 u16 count_16;
147 u32 _reserved_2;
148 u8 _db_data[1000];
149};
150
151/**
152 * enum os_area_db_owner - Data owners.
153 */
154
155enum os_area_db_owner {
156 OS_AREA_DB_OWNER_ANY = -1,
157 OS_AREA_DB_OWNER_NONE = 0,
158 OS_AREA_DB_OWNER_PROTOTYPE = 1,
159 OS_AREA_DB_OWNER_LINUX = 2,
160 OS_AREA_DB_OWNER_PETITBOOT = 3,
161 OS_AREA_DB_OWNER_MAX = 32,
162};
163
164enum os_area_db_key {
165 OS_AREA_DB_KEY_ANY = -1,
166 OS_AREA_DB_KEY_NONE = 0,
167 OS_AREA_DB_KEY_RTC_DIFF = 1,
168 OS_AREA_DB_KEY_VIDEO_MODE = 2,
169 OS_AREA_DB_KEY_MAX = 8,
170};
171
172struct os_area_db_id {
173 int owner;
174 int key;
175};
176
177static const struct os_area_db_id os_area_db_id_empty = {
178 .owner = OS_AREA_DB_OWNER_NONE,
179 .key = OS_AREA_DB_KEY_NONE
180};
181
182static const struct os_area_db_id os_area_db_id_any = {
183 .owner = OS_AREA_DB_OWNER_ANY,
184 .key = OS_AREA_DB_KEY_ANY
185};
186
187static const struct os_area_db_id os_area_db_id_rtc_diff = {
188 .owner = OS_AREA_DB_OWNER_LINUX,
189 .key = OS_AREA_DB_KEY_RTC_DIFF
190};
191
192static const struct os_area_db_id os_area_db_id_video_mode = {
193 .owner = OS_AREA_DB_OWNER_LINUX,
194 .key = OS_AREA_DB_KEY_VIDEO_MODE
195};
196
197#define SECONDS_FROM_1970_TO_2000 946684800LL
198
199/**
200 * struct saved_params - Static working copies of data from the PS3 'os area'.
201 *
202 * The order of preference we use for the rtc_diff source:
203 * 1) The database value.
204 * 2) The game os value.
205 * 3) The number of seconds from 1970 to 2000.
119 */ 206 */
120 207
121struct saved_params { 208struct saved_params {
122 /* param 0 */ 209 unsigned int valid;
123 s64 rtc_diff; 210 s64 rtc_diff;
124 unsigned int av_multi_out; 211 unsigned int av_multi_out;
125 unsigned int ctrl_button;
126 /* param 1 */
127 u8 static_ip_addr[4];
128 u8 network_mask[4];
129 u8 default_gateway[4];
130 /* param 2 */
131 u8 dns_primary[4];
132 u8 dns_secondary[4];
133} static saved_params; 212} static saved_params;
134 213
214static struct property property_rtc_diff = {
215 .name = "linux,rtc_diff",
216 .length = sizeof(saved_params.rtc_diff),
217 .value = &saved_params.rtc_diff,
218};
219
220static struct property property_av_multi_out = {
221 .name = "linux,av_multi_out",
222 .length = sizeof(saved_params.av_multi_out),
223 .value = &saved_params.av_multi_out,
224};
225
226/**
227 * os_area_set_property - Add or overwrite a saved_params value to the device tree.
228 *
229 * Overwrites an existing property.
230 */
231
232static void os_area_set_property(struct device_node *node,
233 struct property *prop)
234{
235 int result;
236 struct property *tmp = of_find_property(node, prop->name, NULL);
237
238 if (tmp) {
239 pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name);
240 prom_remove_property(node, tmp);
241 }
242
243 result = prom_add_property(node, prop);
244
245 if (result)
246 pr_debug("%s:%d prom_set_property failed\n", __func__,
247 __LINE__);
248}
249
250/**
251 * os_area_get_property - Get a saved_params value from the device tree.
252 *
253 */
254
255static void __init os_area_get_property(struct device_node *node,
256 struct property *prop)
257{
258 const struct property *tmp = of_find_property(node, prop->name, NULL);
259
260 if (tmp) {
261 BUG_ON(prop->length != tmp->length);
262 memcpy(prop->value, tmp->value, prop->length);
263 } else
264 pr_debug("%s:%d not found %s\n", __func__, __LINE__,
265 prop->name);
266}
267
135#define dump_header(_a) _dump_header(_a, __func__, __LINE__) 268#define dump_header(_a) _dump_header(_a, __func__, __LINE__)
136static void _dump_header(const struct os_area_header *h, const char *func, 269static void _dump_header(const struct os_area_header *h, const char *func,
137 int line) 270 int line)
138{ 271{
139 pr_debug("%s:%d: h.magic_num: '%s'\n", func, line, 272 pr_debug("%s:%d: h.magic_num: '%s'\n", func, line,
140 h->magic_num); 273 h->magic_num);
141 pr_debug("%s:%d: h.hdr_version: %u\n", func, line, 274 pr_debug("%s:%d: h.hdr_version: %u\n", func, line,
142 h->hdr_version); 275 h->hdr_version);
143 pr_debug("%s:%d: h.os_area_offset: %u\n", func, line, 276 pr_debug("%s:%d: h.db_area_offset: %u\n", func, line,
144 h->os_area_offset); 277 h->db_area_offset);
145 pr_debug("%s:%d: h.ldr_area_offset: %u\n", func, line, 278 pr_debug("%s:%d: h.ldr_area_offset: %u\n", func, line,
146 h->ldr_area_offset); 279 h->ldr_area_offset);
147 pr_debug("%s:%d: h.ldr_format: %u\n", func, line, 280 pr_debug("%s:%d: h.ldr_format: %u\n", func, line,
148 h->ldr_format); 281 h->ldr_format);
149 pr_debug("%s:%d: h.ldr_size: %xh\n", func, line, 282 pr_debug("%s:%d: h.ldr_size: %xh\n", func, line,
150 h->ldr_size); 283 h->ldr_size);
151} 284}
152 285
@@ -176,7 +309,7 @@ static void _dump_params(const struct os_area_params *p, const char *func,
176 p->dns_secondary[2], p->dns_secondary[3]); 309 p->dns_secondary[2], p->dns_secondary[3]);
177} 310}
178 311
179static int __init verify_header(const struct os_area_header *header) 312static int verify_header(const struct os_area_header *header)
180{ 313{
181 if (memcmp(header->magic_num, "cell_ext_os_area", 16)) { 314 if (memcmp(header->magic_num, "cell_ext_os_area", 16)) {
182 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); 315 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
@@ -188,7 +321,7 @@ static int __init verify_header(const struct os_area_header *header)
188 return -1; 321 return -1;
189 } 322 }
190 323
191 if (header->os_area_offset > header->ldr_area_offset) { 324 if (header->db_area_offset > header->ldr_area_offset) {
192 pr_debug("%s:%d offsets failed\n", __func__, __LINE__); 325 pr_debug("%s:%d offsets failed\n", __func__, __LINE__);
193 return -1; 326 return -1;
194 } 327 }
@@ -196,58 +329,477 @@ static int __init verify_header(const struct os_area_header *header)
196 return 0; 329 return 0;
197} 330}
198 331
199int __init ps3_os_area_init(void) 332static int db_verify(const struct os_area_db *db)
333{
334 if (db->magic_num != OS_AREA_DB_MAGIC_NUM) {
335 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
336 return -1;
337 }
338
339 if (db->version != 1) {
340 pr_debug("%s:%d version failed\n", __func__, __LINE__);
341 return -1;
342 }
343
344 return 0;
345}
346
347struct db_index {
348 uint8_t owner:5;
349 uint8_t key:3;
350};
351
352struct db_iterator {
353 const struct os_area_db *db;
354 struct os_area_db_id match_id;
355 struct db_index *idx;
356 struct db_index *last_idx;
357 union {
358 uint64_t *value_64;
359 uint32_t *value_32;
360 uint16_t *value_16;
361 };
362};
363
364static unsigned int db_align_up(unsigned int val, unsigned int size)
365{
366 return (val + (size - 1)) & (~(size - 1));
367}
368
369/**
370 * db_for_each_64 - Iterator for 64 bit entries.
371 *
372 * A NULL value for id can be used to match all entries.
373 * OS_AREA_DB_OWNER_ANY and OS_AREA_DB_KEY_ANY can be used to match all.
374 */
375
376static int db_for_each_64(const struct os_area_db *db,
377 const struct os_area_db_id *match_id, struct db_iterator *i)
378{
379next:
380 if (!i->db) {
381 i->db = db;
382 i->match_id = match_id ? *match_id : os_area_db_id_any;
383 i->idx = (void *)db + db->index_64;
384 i->last_idx = i->idx + db->count_64;
385 i->value_64 = (void *)db + db->index_64
386 + db_align_up(db->count_64, 8);
387 } else {
388 i->idx++;
389 i->value_64++;
390 }
391
392 if (i->idx >= i->last_idx) {
393 pr_debug("%s:%d: reached end\n", __func__, __LINE__);
394 return 0;
395 }
396
397 if (i->match_id.owner != OS_AREA_DB_OWNER_ANY
398 && i->match_id.owner != (int)i->idx->owner)
399 goto next;
400 if (i->match_id.key != OS_AREA_DB_KEY_ANY
401 && i->match_id.key != (int)i->idx->key)
402 goto next;
403
404 return 1;
405}
406
407static int db_delete_64(struct os_area_db *db, const struct os_area_db_id *id)
408{
409 struct db_iterator i;
410
411 for (i.db = NULL; db_for_each_64(db, id, &i); ) {
412
413 pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__,
414 i.idx->owner, i.idx->key,
415 (unsigned long long)*i.value_64);
416
417 i.idx->owner = 0;
418 i.idx->key = 0;
419 *i.value_64 = 0;
420 }
421 return 0;
422}
423
424static int db_set_64(struct os_area_db *db, const struct os_area_db_id *id,
425 uint64_t value)
426{
427 struct db_iterator i;
428
429 pr_debug("%s:%d: (%d:%d) <= %llxh\n", __func__, __LINE__,
430 id->owner, id->key, (unsigned long long)value);
431
432 if (!id->owner || id->owner == OS_AREA_DB_OWNER_ANY
433 || id->key == OS_AREA_DB_KEY_ANY) {
434 pr_debug("%s:%d: bad id: (%d:%d)\n", __func__,
435 __LINE__, id->owner, id->key);
436 return -1;
437 }
438
439 db_delete_64(db, id);
440
441 i.db = NULL;
442 if (db_for_each_64(db, &os_area_db_id_empty, &i)) {
443
444 pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__,
445 i.idx->owner, i.idx->key,
446 (unsigned long long)*i.value_64);
447
448 i.idx->owner = id->owner;
449 i.idx->key = id->key;
450 *i.value_64 = value;
451
452 pr_debug("%s:%d: set (%d:%d) <= %llxh\n", __func__, __LINE__,
453 i.idx->owner, i.idx->key,
454 (unsigned long long)*i.value_64);
455 return 0;
456 }
457 pr_debug("%s:%d: database full.\n",
458 __func__, __LINE__);
459 return -1;
460}
461
462static int db_get_64(const struct os_area_db *db,
463 const struct os_area_db_id *id, uint64_t *value)
464{
465 struct db_iterator i;
466
467 i.db = NULL;
468 if (db_for_each_64(db, id, &i)) {
469 *value = *i.value_64;
470 pr_debug("%s:%d: found %lld\n", __func__, __LINE__,
471 (long long int)*i.value_64);
472 return 0;
473 }
474 pr_debug("%s:%d: not found\n", __func__, __LINE__);
475 return -1;
476}
477
478static int db_get_rtc_diff(const struct os_area_db *db, int64_t *rtc_diff)
479{
480 return db_get_64(db, &os_area_db_id_rtc_diff, (uint64_t*)rtc_diff);
481}
482
483#define dump_db(a) _dump_db(a, __func__, __LINE__)
484static void _dump_db(const struct os_area_db *db, const char *func,
485 int line)
486{
487 pr_debug("%s:%d: db.magic_num: '%s'\n", func, line,
488 (const char*)&db->magic_num);
489 pr_debug("%s:%d: db.version: %u\n", func, line,
490 db->version);
491 pr_debug("%s:%d: db.index_64: %u\n", func, line,
492 db->index_64);
493 pr_debug("%s:%d: db.count_64: %u\n", func, line,
494 db->count_64);
495 pr_debug("%s:%d: db.index_32: %u\n", func, line,
496 db->index_32);
497 pr_debug("%s:%d: db.count_32: %u\n", func, line,
498 db->count_32);
499 pr_debug("%s:%d: db.index_16: %u\n", func, line,
500 db->index_16);
501 pr_debug("%s:%d: db.count_16: %u\n", func, line,
502 db->count_16);
503}
504
505static void os_area_db_init(struct os_area_db *db)
506{
507 enum {
508 HEADER_SIZE = offsetof(struct os_area_db, _db_data),
509 INDEX_64_COUNT = 64,
510 VALUES_64_COUNT = 57,
511 INDEX_32_COUNT = 64,
512 VALUES_32_COUNT = 57,
513 INDEX_16_COUNT = 64,
514 VALUES_16_COUNT = 57,
515 };
516
517 memset(db, 0, sizeof(struct os_area_db));
518
519 db->magic_num = OS_AREA_DB_MAGIC_NUM;
520 db->version = 1;
521 db->index_64 = HEADER_SIZE;
522 db->count_64 = VALUES_64_COUNT;
523 db->index_32 = HEADER_SIZE
524 + INDEX_64_COUNT * sizeof(struct db_index)
525 + VALUES_64_COUNT * sizeof(u64);
526 db->count_32 = VALUES_32_COUNT;
527 db->index_16 = HEADER_SIZE
528 + INDEX_64_COUNT * sizeof(struct db_index)
529 + VALUES_64_COUNT * sizeof(u64)
530 + INDEX_32_COUNT * sizeof(struct db_index)
531 + VALUES_32_COUNT * sizeof(u32);
532 db->count_16 = VALUES_16_COUNT;
533
534 /* Rules to check db layout. */
535
536 BUILD_BUG_ON(sizeof(struct db_index) != 1);
537 BUILD_BUG_ON(sizeof(struct os_area_db) != 2 * OS_AREA_SEGMENT_SIZE);
538 BUILD_BUG_ON(INDEX_64_COUNT & 0x7);
539 BUILD_BUG_ON(VALUES_64_COUNT > INDEX_64_COUNT);
540 BUILD_BUG_ON(INDEX_32_COUNT & 0x7);
541 BUILD_BUG_ON(VALUES_32_COUNT > INDEX_32_COUNT);
542 BUILD_BUG_ON(INDEX_16_COUNT & 0x7);
543 BUILD_BUG_ON(VALUES_16_COUNT > INDEX_16_COUNT);
544 BUILD_BUG_ON(HEADER_SIZE
545 + INDEX_64_COUNT * sizeof(struct db_index)
546 + VALUES_64_COUNT * sizeof(u64)
547 + INDEX_32_COUNT * sizeof(struct db_index)
548 + VALUES_32_COUNT * sizeof(u32)
549 + INDEX_16_COUNT * sizeof(struct db_index)
550 + VALUES_16_COUNT * sizeof(u16)
551 > sizeof(struct os_area_db));
552}
553
554/**
555 * update_flash_db - Helper for os_area_queue_work_handler.
556 *
557 */
558
559static void update_flash_db(void)
560{
561 int result;
562 int file;
563 off_t offset;
564 ssize_t count;
565 static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
566 const struct os_area_header *header;
567 struct os_area_db* db;
568
569 /* Read in header and db from flash. */
570
571 file = sys_open("/dev/ps3flash", O_RDWR, 0);
572
573 if (file < 0) {
574 pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
575 goto fail_open;
576 }
577
578 header = kmalloc(buf_len, GFP_KERNEL);
579
580 if (!header) {
581 pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__);
582 goto fail_malloc;
583 }
584
585 offset = sys_lseek(file, 0, SEEK_SET);
586
587 if (offset != 0) {
588 pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
589 goto fail_header_seek;
590 }
591
592 count = sys_read(file, (char __user *)header, buf_len);
593
594 result = count < OS_AREA_SEGMENT_SIZE || verify_header(header)
595 || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE;
596
597 if (result) {
598 pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
599 dump_header(header);
600 goto fail_header;
601 }
602
603 /* Now got a good db offset and some maybe good db data. */
604
605 db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE;
606
607 result = db_verify(db);
608
609 if (result) {
610 printk(KERN_NOTICE "%s:%d: Verify of flash database failed, "
611 "formatting.\n", __func__, __LINE__);
612 dump_db(db);
613 os_area_db_init(db);
614 }
615
616 /* Now got good db data. */
617
618 db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
619
620 offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE,
621 SEEK_SET);
622
623 if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) {
624 pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
625 goto fail_db_seek;
626 }
627
628 count = sys_write(file, (const char __user *)db,
629 sizeof(struct os_area_db));
630
631 if (count < sizeof(struct os_area_db)) {
632 pr_debug("%s:%d sys_write failed\n", __func__, __LINE__);
633 }
634
635fail_db_seek:
636fail_header:
637fail_header_seek:
638 kfree(header);
639fail_malloc:
640 sys_close(file);
641fail_open:
642 return;
643}
644
645/**
646 * os_area_queue_work_handler - Asynchronous write handler.
647 *
648 * An asynchronous write for flash memory and the device tree. Do not
649 * call directly, use os_area_queue_work().
650 */
651
652static void os_area_queue_work_handler(struct work_struct *work)
653{
654 struct device_node *node;
655
656 pr_debug(" -> %s:%d\n", __func__, __LINE__);
657
658 node = of_find_node_by_path("/");
659
660 if (node) {
661 os_area_set_property(node, &property_rtc_diff);
662 of_node_put(node);
663 } else
664 pr_debug("%s:%d of_find_node_by_path failed\n",
665 __func__, __LINE__);
666
667#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
668 update_flash_db();
669#else
670 printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n",
671 __func__, __LINE__);
672#endif
673 pr_debug(" <- %s:%d\n", __func__, __LINE__);
674}
675
676static void os_area_queue_work(void)
677{
678 static DECLARE_WORK(q, os_area_queue_work_handler);
679
680 wmb();
681 schedule_work(&q);
682}
683
684/**
685 * ps3_os_area_save_params - Copy data from os area mirror to @saved_params.
686 *
687 * For the convenience of the guest the HV makes a copy of the os area in
688 * flash to a high address in the boot memory region and then puts that RAM
689 * address and the byte count into the repository for retrieval by the guest.
690 * We copy the data we want into a static variable and allow the memory setup
691 * by the HV to be claimed by the lmb manager.
692 *
693 * The os area mirror will not be available to a second stage kernel, and
694 * the header verify will fail. In this case, the saved_params values will
695 * be set from flash memory or the passed in device tree in ps3_os_area_init().
696 */
697
698void __init ps3_os_area_save_params(void)
200{ 699{
201 int result; 700 int result;
202 u64 lpar_addr; 701 u64 lpar_addr;
203 unsigned int size; 702 unsigned int size;
204 struct os_area_header *header; 703 struct os_area_header *header;
205 struct os_area_params *params; 704 struct os_area_params *params;
705 struct os_area_db *db;
706
707 pr_debug(" -> %s:%d\n", __func__, __LINE__);
206 708
207 result = ps3_repository_read_boot_dat_info(&lpar_addr, &size); 709 result = ps3_repository_read_boot_dat_info(&lpar_addr, &size);
208 710
209 if (result) { 711 if (result) {
210 pr_debug("%s:%d ps3_repository_read_boot_dat_info failed\n", 712 pr_debug("%s:%d ps3_repository_read_boot_dat_info failed\n",
211 __func__, __LINE__); 713 __func__, __LINE__);
212 return result; 714 return;
213 } 715 }
214 716
215 header = (struct os_area_header *)__va(lpar_addr); 717 header = (struct os_area_header *)__va(lpar_addr);
216 params = (struct os_area_params *)__va(lpar_addr + OS_AREA_SEGMENT_SIZE); 718 params = (struct os_area_params *)__va(lpar_addr
719 + OS_AREA_SEGMENT_SIZE);
217 720
218 result = verify_header(header); 721 result = verify_header(header);
219 722
220 if (result) { 723 if (result) {
724 /* Second stage kernels exit here. */
221 pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); 725 pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
222 dump_header(header); 726 dump_header(header);
223 return -EIO; 727 return;
224 } 728 }
225 729
730 db = (struct os_area_db *)__va(lpar_addr
731 + header->db_area_offset * OS_AREA_SEGMENT_SIZE);
732
226 dump_header(header); 733 dump_header(header);
227 dump_params(params); 734 dump_params(params);
735 dump_db(db);
228 736
229 saved_params.rtc_diff = params->rtc_diff; 737 result = db_verify(db) || db_get_rtc_diff(db, &saved_params.rtc_diff);
738 if (result)
739 saved_params.rtc_diff = params->rtc_diff ? params->rtc_diff
740 : SECONDS_FROM_1970_TO_2000;
230 saved_params.av_multi_out = params->av_multi_out; 741 saved_params.av_multi_out = params->av_multi_out;
231 saved_params.ctrl_button = params->ctrl_button; 742 saved_params.valid = 1;
232 memcpy(saved_params.static_ip_addr, params->static_ip_addr, 4); 743
233 memcpy(saved_params.network_mask, params->network_mask, 4); 744 memset(header, 0, sizeof(*header));
234 memcpy(saved_params.default_gateway, params->default_gateway, 4);
235 memcpy(saved_params.dns_secondary, params->dns_secondary, 4);
236 745
237 return result; 746 pr_debug(" <- %s:%d\n", __func__, __LINE__);
238} 747}
239 748
240/** 749/**
241 * ps3_os_area_rtc_diff - Returns the ps3 rtc diff value. 750 * ps3_os_area_init - Setup os area device tree properties as needed.
751 */
752
753void __init ps3_os_area_init(void)
754{
755 struct device_node *node;
756
757 pr_debug(" -> %s:%d\n", __func__, __LINE__);
758
759 node = of_find_node_by_path("/");
760
761 if (!saved_params.valid && node) {
762 /* Second stage kernels should have a dt entry. */
763 os_area_get_property(node, &property_rtc_diff);
764 os_area_get_property(node, &property_av_multi_out);
765 }
766
767 if(!saved_params.rtc_diff)
768 saved_params.rtc_diff = SECONDS_FROM_1970_TO_2000;
769
770 if (node) {
771 os_area_set_property(node, &property_rtc_diff);
772 os_area_set_property(node, &property_av_multi_out);
773 of_node_put(node);
774 } else
775 pr_debug("%s:%d of_find_node_by_path failed\n",
776 __func__, __LINE__);
777
778 pr_debug(" <- %s:%d\n", __func__, __LINE__);
779}
780
781/**
782 * ps3_os_area_get_rtc_diff - Returns the rtc diff value.
783 */
784
785u64 ps3_os_area_get_rtc_diff(void)
786{
787 return saved_params.rtc_diff;
788}
789
790/**
791 * ps3_os_area_set_rtc_diff - Set the rtc diff value.
242 * 792 *
243 * The ps3 rtc maintains a value that approximates seconds since 793 * An asynchronous write is needed to support writing updates from
244 * 2000-01-01 00:00:00 UTC. Returns the exact number of seconds from 1970 to 794 * the timer interrupt context.
245 * 2000 when saved_params.rtc_diff has not been properly set up.
246 */ 795 */
247 796
248u64 ps3_os_area_rtc_diff(void) 797void ps3_os_area_set_rtc_diff(u64 rtc_diff)
249{ 798{
250 return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL; 799 if (saved_params.rtc_diff != rtc_diff) {
800 saved_params.rtc_diff = rtc_diff;
801 os_area_queue_work();
802 }
251} 803}
252 804
253/** 805/**
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 2eb8f92704b4..01f0c9506e11 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -47,7 +47,11 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq);
47/* smp */ 47/* smp */
48 48
49void smp_init_ps3(void); 49void smp_init_ps3(void);
50#ifdef CONFIG_SMP
50void ps3_smp_cleanup_cpu(int cpu); 51void ps3_smp_cleanup_cpu(int cpu);
52#else
53static inline void ps3_smp_cleanup_cpu(int cpu) { }
54#endif
51 55
52/* time */ 56/* time */
53 57
@@ -58,8 +62,10 @@ int ps3_set_rtc_time(struct rtc_time *time);
58 62
59/* os area */ 63/* os area */
60 64
61int __init ps3_os_area_init(void); 65void __init ps3_os_area_save_params(void);
62u64 ps3_os_area_rtc_diff(void); 66void __init ps3_os_area_init(void);
67u64 ps3_os_area_get_rtc_diff(void);
68void ps3_os_area_set_rtc_diff(u64 rtc_diff);
63 69
64/* spu */ 70/* spu */
65 71
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index 609945dbe394..5c2cbb08eb52 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -206,6 +206,7 @@ static void __init ps3_setup_arch(void)
206 prealloc_ps3flash_bounce_buffer(); 206 prealloc_ps3flash_bounce_buffer();
207 207
208 ppc_md.power_save = ps3_power_save; 208 ppc_md.power_save = ps3_power_save;
209 ps3_os_area_init();
209 210
210 DBG(" <- %s:%d\n", __func__, __LINE__); 211 DBG(" <- %s:%d\n", __func__, __LINE__);
211} 212}
@@ -228,7 +229,7 @@ static int __init ps3_probe(void)
228 229
229 powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE; 230 powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE;
230 231
231 ps3_os_area_init(); 232 ps3_os_area_save_params();
232 ps3_mm_init(); 233 ps3_mm_init();
233 ps3_mm_vas_create(&htab_size); 234 ps3_mm_vas_create(&htab_size);
234 ps3_hpte_init(htab_size); 235 ps3_hpte_init(htab_size);
diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c
index 802a9ccacb5e..d0daf7d6d3b2 100644
--- a/arch/powerpc/platforms/ps3/time.c
+++ b/arch/powerpc/platforms/ps3/time.c
@@ -50,12 +50,6 @@ static void __maybe_unused _dump_time(int time, const char *func,
50 _dump_tm(&tm, func, line); 50 _dump_tm(&tm, func, line);
51} 51}
52 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) 53void __init ps3_calibrate_decr(void)
60{ 54{
61 int result; 55 int result;
@@ -66,8 +60,6 @@ void __init ps3_calibrate_decr(void)
66 60
67 ppc_tb_freq = tmp; 61 ppc_tb_freq = tmp;
68 ppc_proc_freq = ppc_tb_freq * 40; 62 ppc_proc_freq = ppc_tb_freq * 40;
69
70 rtc_shift = ps3_os_area_rtc_diff();
71} 63}
72 64
73static u64 read_rtc(void) 65static u64 read_rtc(void)
@@ -87,18 +79,18 @@ int ps3_set_rtc_time(struct rtc_time *tm)
87 u64 now = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 79 u64 now = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
88 tm->tm_hour, tm->tm_min, tm->tm_sec); 80 tm->tm_hour, tm->tm_min, tm->tm_sec);
89 81
90 rtc_shift = now - read_rtc(); 82 ps3_os_area_set_rtc_diff(now - read_rtc());
91 return 0; 83 return 0;
92} 84}
93 85
94void ps3_get_rtc_time(struct rtc_time *tm) 86void ps3_get_rtc_time(struct rtc_time *tm)
95{ 87{
96 to_tm(read_rtc() + rtc_shift, tm); 88 to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm);
97 tm->tm_year -= 1900; 89 tm->tm_year -= 1900;
98 tm->tm_mon -= 1; 90 tm->tm_mon -= 1;
99} 91}
100 92
101unsigned long __init ps3_get_boot_time(void) 93unsigned long __init ps3_get_boot_time(void)
102{ 94{
103 return read_rtc() + rtc_shift; 95 return read_rtc() + ps3_os_area_get_rtc_diff();
104} 96}