aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorJim Keniston <jkenisto@linux.vnet.ibm.com>2011-02-09 07:43:13 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-03-04 02:19:04 -0500
commit0f4ac132365e56802cbe377313491aa84086371c (patch)
tree447b5da68f7c3160bbe9c9262f0ed337a2008d57 /arch/powerpc/platforms
parent6dd227002972be910c6191f38f8641e01796557f (diff)
powerpc/nvram: Generalize code for OS partitions in NVRAM
Adapt the functions used to create and write to the RTAS-log partition to work with any OS-type partition. Signed-off-by: Jim Keniston <jkenisto@us.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c143
1 files changed, 84 insertions, 59 deletions
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 7e828ba29bc..befb41bc4d3 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -30,17 +30,30 @@ static int nvram_fetch, nvram_store;
30static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ 30static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
31static DEFINE_SPINLOCK(nvram_lock); 31static DEFINE_SPINLOCK(nvram_lock);
32 32
33static long nvram_error_log_index = -1;
34static long nvram_error_log_size = 0;
35
36struct err_log_info { 33struct err_log_info {
37 int error_type; 34 int error_type;
38 unsigned int seq_num; 35 unsigned int seq_num;
39}; 36};
40#define NVRAM_MAX_REQ 2079
41#define NVRAM_MIN_REQ 1055
42 37
43#define NVRAM_LOG_PART_NAME "ibm,rtas-log" 38struct nvram_os_partition {
39 const char *name;
40 int req_size; /* desired size, in bytes */
41 int min_size; /* minimum acceptable size (0 means req_size) */
42 long size; /* size of data portion of partition */
43 long index; /* offset of data portion of partition */
44};
45
46static struct nvram_os_partition rtas_log_partition = {
47 .name = "ibm,rtas-log",
48 .req_size = 2079,
49 .min_size = 1055,
50 .index = -1
51};
52
53static const char *pseries_nvram_os_partitions[] = {
54 "ibm,rtas-log",
55 NULL
56};
44 57
45static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) 58static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
46{ 59{
@@ -134,7 +147,7 @@ static ssize_t pSeries_nvram_get_size(void)
134} 147}
135 148
136 149
137/* nvram_write_error_log 150/* nvram_write_os_partition, nvram_write_error_log
138 * 151 *
139 * We need to buffer the error logs into nvram to ensure that we have 152 * We need to buffer the error logs into nvram to ensure that we have
140 * the failure information to decode. If we have a severe error there 153 * the failure information to decode. If we have a severe error there
@@ -156,48 +169,55 @@ static ssize_t pSeries_nvram_get_size(void)
156 * The 'data' section would look like (in bytes): 169 * The 'data' section would look like (in bytes):
157 * +--------------+------------+-----------------------------------+ 170 * +--------------+------------+-----------------------------------+
158 * | event_logged | sequence # | error log | 171 * | event_logged | sequence # | error log |
159 * |0 3|4 7|8 nvram_error_log_size-1| 172 * |0 3|4 7|8 error_log_size-1|
160 * +--------------+------------+-----------------------------------+ 173 * +--------------+------------+-----------------------------------+
161 * 174 *
162 * event_logged: 0 if event has not been logged to syslog, 1 if it has 175 * event_logged: 0 if event has not been logged to syslog, 1 if it has
163 * sequence #: The unique sequence # for each event. (until it wraps) 176 * sequence #: The unique sequence # for each event. (until it wraps)
164 * error log: The error log from event_scan 177 * error log: The error log from event_scan
165 */ 178 */
166int nvram_write_error_log(char * buff, int length, 179int nvram_write_os_partition(struct nvram_os_partition *part, char * buff,
167 unsigned int err_type, unsigned int error_log_cnt) 180 int length, unsigned int err_type, unsigned int error_log_cnt)
168{ 181{
169 int rc; 182 int rc;
170 loff_t tmp_index; 183 loff_t tmp_index;
171 struct err_log_info info; 184 struct err_log_info info;
172 185
173 if (nvram_error_log_index == -1) { 186 if (part->index == -1) {
174 return -ESPIPE; 187 return -ESPIPE;
175 } 188 }
176 189
177 if (length > nvram_error_log_size) { 190 if (length > part->size) {
178 length = nvram_error_log_size; 191 length = part->size;
179 } 192 }
180 193
181 info.error_type = err_type; 194 info.error_type = err_type;
182 info.seq_num = error_log_cnt; 195 info.seq_num = error_log_cnt;
183 196
184 tmp_index = nvram_error_log_index; 197 tmp_index = part->index;
185 198
186 rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index); 199 rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
187 if (rc <= 0) { 200 if (rc <= 0) {
188 printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); 201 pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);
189 return rc; 202 return rc;
190 } 203 }
191 204
192 rc = ppc_md.nvram_write(buff, length, &tmp_index); 205 rc = ppc_md.nvram_write(buff, length, &tmp_index);
193 if (rc <= 0) { 206 if (rc <= 0) {
194 printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); 207 pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);
195 return rc; 208 return rc;
196 } 209 }
197 210
198 return 0; 211 return 0;
199} 212}
200 213
214int nvram_write_error_log(char * buff, int length,
215 unsigned int err_type, unsigned int error_log_cnt)
216{
217 return nvram_write_os_partition(&rtas_log_partition, buff, length,
218 err_type, error_log_cnt);
219}
220
201/* nvram_read_error_log 221/* nvram_read_error_log
202 * 222 *
203 * Reads nvram for error log for at most 'length' 223 * Reads nvram for error log for at most 'length'
@@ -209,13 +229,13 @@ int nvram_read_error_log(char * buff, int length,
209 loff_t tmp_index; 229 loff_t tmp_index;
210 struct err_log_info info; 230 struct err_log_info info;
211 231
212 if (nvram_error_log_index == -1) 232 if (rtas_log_partition.index == -1)
213 return -1; 233 return -1;
214 234
215 if (length > nvram_error_log_size) 235 if (length > rtas_log_partition.size)
216 length = nvram_error_log_size; 236 length = rtas_log_partition.size;
217 237
218 tmp_index = nvram_error_log_index; 238 tmp_index = rtas_log_partition.index;
219 239
220 rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index); 240 rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
221 if (rc <= 0) { 241 if (rc <= 0) {
@@ -244,10 +264,10 @@ int nvram_clear_error_log(void)
244 int clear_word = ERR_FLAG_ALREADY_LOGGED; 264 int clear_word = ERR_FLAG_ALREADY_LOGGED;
245 int rc; 265 int rc;
246 266
247 if (nvram_error_log_index == -1) 267 if (rtas_log_partition.index == -1)
248 return -1; 268 return -1;
249 269
250 tmp_index = nvram_error_log_index; 270 tmp_index = rtas_log_partition.index;
251 271
252 rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index); 272 rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
253 if (rc <= 0) { 273 if (rc <= 0) {
@@ -258,23 +278,25 @@ int nvram_clear_error_log(void)
258 return 0; 278 return 0;
259} 279}
260 280
261/* pseries_nvram_init_log_partition 281/* pseries_nvram_init_os_partition
262 * 282 *
263 * This will setup the partition we need for buffering the 283 * This sets up a partition with an "OS" signature.
264 * error logs and cleanup partitions if needed.
265 * 284 *
266 * The general strategy is the following: 285 * The general strategy is the following:
267 * 1.) If there is log partition large enough then use it. 286 * 1.) If a partition with the indicated name already exists...
268 * 2.) If there is none large enough, search 287 * - If it's large enough, use it.
269 * for a free partition that is large enough. 288 * - Otherwise, recycle it and keep going.
270 * 3.) If there is not a free partition large enough remove 289 * 2.) Search for a free partition that is large enough.
271 * _all_ OS partitions and consolidate the space. 290 * 3.) If there's not a free partition large enough, recycle any obsolete
272 * 4.) Will first try getting a chunk that will satisfy the maximum 291 * OS partitions and try again.
273 * error log size (NVRAM_MAX_REQ). 292 * 4.) Will first try getting a chunk that will satisfy the requested size.
274 * 5.) If the max chunk cannot be allocated then try finding a chunk 293 * 5.) If a chunk of the requested size cannot be allocated, then try finding
275 * that will satisfy the minum needed (NVRAM_MIN_REQ). 294 * a chunk that will satisfy the minum needed.
295 *
296 * Returns 0 on success, else -1.
276 */ 297 */
277static int __init pseries_nvram_init_log_partition(void) 298static int __init pseries_nvram_init_os_partition(struct nvram_os_partition
299 *part)
278{ 300{
279 loff_t p; 301 loff_t p;
280 int size; 302 int size;
@@ -282,47 +304,50 @@ static int __init pseries_nvram_init_log_partition(void)
282 /* Scan nvram for partitions */ 304 /* Scan nvram for partitions */
283 nvram_scan_partitions(); 305 nvram_scan_partitions();
284 306
285 /* Lookg for ours */ 307 /* Look for ours */
286 p = nvram_find_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, &size); 308 p = nvram_find_partition(part->name, NVRAM_SIG_OS, &size);
287 309
288 /* Found one but too small, remove it */ 310 /* Found one but too small, remove it */
289 if (p && size < NVRAM_MIN_REQ) { 311 if (p && size < part->min_size) {
290 pr_info("nvram: Found too small "NVRAM_LOG_PART_NAME" partition" 312 pr_info("nvram: Found too small %s partition,"
291 ",removing it..."); 313 " removing it...\n", part->name);
292 nvram_remove_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS); 314 nvram_remove_partition(part->name, NVRAM_SIG_OS, NULL);
293 p = 0; 315 p = 0;
294 } 316 }
295 317
296 /* Create one if we didn't find */ 318 /* Create one if we didn't find */
297 if (!p) { 319 if (!p) {
298 p = nvram_create_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, 320 p = nvram_create_partition(part->name, NVRAM_SIG_OS,
299 NVRAM_MAX_REQ, NVRAM_MIN_REQ); 321 part->req_size, part->min_size);
300 /* No room for it, try to get rid of any OS partition
301 * and try again
302 */
303 if (p == -ENOSPC) { 322 if (p == -ENOSPC) {
304 pr_info("nvram: No room to create "NVRAM_LOG_PART_NAME 323 pr_info("nvram: No room to create %s partition, "
305 " partition, deleting all OS partitions..."); 324 "deleting any obsolete OS partitions...\n",
306 nvram_remove_partition(NULL, NVRAM_SIG_OS); 325 part->name);
307 p = nvram_create_partition(NVRAM_LOG_PART_NAME, 326 nvram_remove_partition(NULL, NVRAM_SIG_OS,
308 NVRAM_SIG_OS, NVRAM_MAX_REQ, 327 pseries_nvram_os_partitions);
309 NVRAM_MIN_REQ); 328 p = nvram_create_partition(part->name, NVRAM_SIG_OS,
329 part->req_size, part->min_size);
310 } 330 }
311 } 331 }
312 332
313 if (p <= 0) { 333 if (p <= 0) {
314 pr_err("nvram: Failed to find or create "NVRAM_LOG_PART_NAME 334 pr_err("nvram: Failed to find or create %s"
315 " partition, err %d\n", (int)p); 335 " partition, err %d\n", part->name, (int)p);
316 return 0; 336 return -1;
317 } 337 }
318 338
319 nvram_error_log_index = p; 339 part->index = p;
320 nvram_error_log_size = nvram_get_partition_size(p) - 340 part->size = nvram_get_partition_size(p) - sizeof(struct err_log_info);
321 sizeof(struct err_log_info);
322 341
323 return 0; 342 return 0;
324} 343}
325machine_arch_initcall(pseries, pseries_nvram_init_log_partition); 344
345static int __init pseries_nvram_init_log_partitions(void)
346{
347 (void) pseries_nvram_init_os_partition(&rtas_log_partition);
348 return 0;
349}
350machine_arch_initcall(pseries, pseries_nvram_init_log_partitions);
326 351
327int __init pSeries_nvram_init(void) 352int __init pSeries_nvram_init(void)
328{ 353{