diff options
author | Jim Keniston <jkenisto@linux.vnet.ibm.com> | 2011-02-09 07:43:13 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-03-04 02:19:04 -0500 |
commit | 0f4ac132365e56802cbe377313491aa84086371c (patch) | |
tree | 447b5da68f7c3160bbe9c9262f0ed337a2008d57 /arch/powerpc/platforms | |
parent | 6dd227002972be910c6191f38f8641e01796557f (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.c | 143 |
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; | |||
30 | static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ | 30 | static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ |
31 | static DEFINE_SPINLOCK(nvram_lock); | 31 | static DEFINE_SPINLOCK(nvram_lock); |
32 | 32 | ||
33 | static long nvram_error_log_index = -1; | ||
34 | static long nvram_error_log_size = 0; | ||
35 | |||
36 | struct err_log_info { | 33 | struct 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" | 38 | struct 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 | |||
46 | static 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 | |||
53 | static const char *pseries_nvram_os_partitions[] = { | ||
54 | "ibm,rtas-log", | ||
55 | NULL | ||
56 | }; | ||
44 | 57 | ||
45 | static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) | 58 | static 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 | */ |
166 | int nvram_write_error_log(char * buff, int length, | 179 | int 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 | ||
214 | int 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 | */ |
277 | static int __init pseries_nvram_init_log_partition(void) | 298 | static 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 | } |
325 | machine_arch_initcall(pseries, pseries_nvram_init_log_partition); | 344 | |
345 | static int __init pseries_nvram_init_log_partitions(void) | ||
346 | { | ||
347 | (void) pseries_nvram_init_os_partition(&rtas_log_partition); | ||
348 | return 0; | ||
349 | } | ||
350 | machine_arch_initcall(pseries, pseries_nvram_init_log_partitions); | ||
326 | 351 | ||
327 | int __init pSeries_nvram_init(void) | 352 | int __init pSeries_nvram_init(void) |
328 | { | 353 | { |