Commit 0f4ac132365e56802cbe377313491aa84086371c

Authored by Jim Keniston
Committed by Benjamin Herrenschmidt
1 parent 6dd2270029

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>

Showing 3 changed files with 113 additions and 64 deletions Side-by-side Diff

arch/powerpc/include/asm/nvram.h
... ... @@ -51,7 +51,8 @@
51 51 extern int __init nvram_scan_partitions(void);
52 52 extern loff_t nvram_create_partition(const char *name, int sig,
53 53 int req_size, int min_size);
54   -extern int nvram_remove_partition(const char *name, int sig);
  54 +extern int nvram_remove_partition(const char *name, int sig,
  55 + const char *exceptions[]);
55 56 extern int nvram_get_partition_size(loff_t data_index);
56 57 extern loff_t nvram_find_partition(const char *name, int sig, int *out_size);
57 58  
arch/powerpc/kernel/nvram_64.c
... ... @@ -237,22 +237,45 @@
237 237 return c_sum;
238 238 }
239 239  
  240 +/*
  241 + * Per the criteria passed via nvram_remove_partition(), should this
  242 + * partition be removed? 1=remove, 0=keep
  243 + */
  244 +static int nvram_can_remove_partition(struct nvram_partition *part,
  245 + const char *name, int sig, const char *exceptions[])
  246 +{
  247 + if (part->header.signature != sig)
  248 + return 0;
  249 + if (name) {
  250 + if (strncmp(name, part->header.name, 12))
  251 + return 0;
  252 + } else if (exceptions) {
  253 + const char **except;
  254 + for (except = exceptions; *except; except++) {
  255 + if (!strncmp(*except, part->header.name, 12))
  256 + return 0;
  257 + }
  258 + }
  259 + return 1;
  260 +}
  261 +
240 262 /**
241 263 * nvram_remove_partition - Remove one or more partitions in nvram
242 264 * @name: name of the partition to remove, or NULL for a
243 265 * signature only match
244 266 * @sig: signature of the partition(s) to remove
  267 + * @exceptions: When removing all partitions with a matching signature,
  268 + * leave these alone.
245 269 */
246 270  
247   -int __init nvram_remove_partition(const char *name, int sig)
  271 +int __init nvram_remove_partition(const char *name, int sig,
  272 + const char *exceptions[])
248 273 {
249 274 struct nvram_partition *part, *prev, *tmp;
250 275 int rc;
251 276  
252 277 list_for_each_entry(part, &nvram_partitions, partition) {
253   - if (part->header.signature != sig)
254   - continue;
255   - if (name && strncmp(name, part->header.name, 12))
  278 + if (!nvram_can_remove_partition(part, name, sig, exceptions))
256 279 continue;
257 280  
258 281 /* Make partition a free partition */
arch/powerpc/platforms/pseries/nvram.c
... ... @@ -30,18 +30,31 @@
30 30 static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
31 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 33 struct err_log_info {
37 34 int error_type;
38 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 +};
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 +};
  57 +
45 58 static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
46 59 {
47 60 unsigned int i;
... ... @@ -134,7 +147,7 @@
134 147 }
135 148  
136 149  
137   -/* nvram_write_error_log
  150 +/* nvram_write_os_partition, nvram_write_error_log
138 151 *
139 152 * We need to buffer the error logs into nvram to ensure that we have
140 153 * the failure information to decode. If we have a severe error there
141 154  
142 155  
143 156  
144 157  
145 158  
146 159  
147 160  
... ... @@ -156,48 +169,55 @@
156 169 * The 'data' section would look like (in bytes):
157 170 * +--------------+------------+-----------------------------------+
158 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 175 * event_logged: 0 if event has not been logged to syslog, 1 if it has
163 176 * sequence #: The unique sequence # for each event. (until it wraps)
164 177 * error log: The error log from event_scan
165 178 */
166   -int nvram_write_error_log(char * buff, int length,
167   - unsigned int err_type, unsigned int error_log_cnt)
  179 +int nvram_write_os_partition(struct nvram_os_partition *part, char * buff,
  180 + int length, unsigned int err_type, unsigned int error_log_cnt)
168 181 {
169 182 int rc;
170 183 loff_t tmp_index;
171 184 struct err_log_info info;
172 185  
173   - if (nvram_error_log_index == -1) {
  186 + if (part->index == -1) {
174 187 return -ESPIPE;
175 188 }
176 189  
177   - if (length > nvram_error_log_size) {
178   - length = nvram_error_log_size;
  190 + if (length > part->size) {
  191 + length = part->size;
179 192 }
180 193  
181 194 info.error_type = err_type;
182 195 info.seq_num = error_log_cnt;
183 196  
184   - tmp_index = nvram_error_log_index;
  197 + tmp_index = part->index;
185 198  
186 199 rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
187 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 202 return rc;
190 203 }
191 204  
192 205 rc = ppc_md.nvram_write(buff, length, &tmp_index);
193 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 208 return rc;
196 209 }
197 210  
198 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 221 /* nvram_read_error_log
202 222 *
203 223 * Reads nvram for error log for at most 'length'
204 224  
205 225  
... ... @@ -209,13 +229,13 @@
209 229 loff_t tmp_index;
210 230 struct err_log_info info;
211 231  
212   - if (nvram_error_log_index == -1)
  232 + if (rtas_log_partition.index == -1)
213 233 return -1;
214 234  
215   - if (length > nvram_error_log_size)
216   - length = nvram_error_log_size;
  235 + if (length > rtas_log_partition.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 240 rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
221 241 if (rc <= 0) {
222 242  
... ... @@ -244,10 +264,10 @@
244 264 int clear_word = ERR_FLAG_ALREADY_LOGGED;
245 265 int rc;
246 266  
247   - if (nvram_error_log_index == -1)
  267 + if (rtas_log_partition.index == -1)
248 268 return -1;
249 269  
250   - tmp_index = nvram_error_log_index;
  270 + tmp_index = rtas_log_partition.index;
251 271  
252 272 rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
253 273 if (rc <= 0) {
254 274  
255 275  
256 276  
... ... @@ -258,23 +278,25 @@
258 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
264   - * error logs and cleanup partitions if needed.
  283 + * This sets up a partition with an "OS" signature.
265 284 *
266 285 * The general strategy is the following:
267   - * 1.) If there is log partition large enough then use it.
268   - * 2.) If there is none large enough, search
269   - * for a free partition that is large enough.
270   - * 3.) If there is not a free partition large enough remove
271   - * _all_ OS partitions and consolidate the space.
272   - * 4.) Will first try getting a chunk that will satisfy the maximum
273   - * error log size (NVRAM_MAX_REQ).
274   - * 5.) If the max chunk cannot be allocated then try finding a chunk
275   - * that will satisfy the minum needed (NVRAM_MIN_REQ).
  286 + * 1.) If a partition with the indicated name already exists...
  287 + * - If it's large enough, use it.
  288 + * - Otherwise, recycle it and keep going.
  289 + * 2.) Search for a free partition that is large enough.
  290 + * 3.) If there's not a free partition large enough, recycle any obsolete
  291 + * OS partitions and try again.
  292 + * 4.) Will first try getting a chunk that will satisfy the requested size.
  293 + * 5.) If a chunk of the requested size cannot be allocated, then try finding
  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 301 loff_t p;
280 302 int size;
281 303  
282 304  
283 305  
284 306  
285 307  
286 308  
... ... @@ -282,47 +304,50 @@
282 304 /* Scan nvram for partitions */
283 305 nvram_scan_partitions();
284 306  
285   - /* Lookg for ours */
286   - p = nvram_find_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, &size);
  307 + /* Look for ours */
  308 + p = nvram_find_partition(part->name, NVRAM_SIG_OS, &size);
287 309  
288 310 /* Found one but too small, remove it */
289   - if (p && size < NVRAM_MIN_REQ) {
290   - pr_info("nvram: Found too small "NVRAM_LOG_PART_NAME" partition"
291   - ",removing it...");
292   - nvram_remove_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS);
  311 + if (p && size < part->min_size) {
  312 + pr_info("nvram: Found too small %s partition,"
  313 + " removing it...\n", part->name);
  314 + nvram_remove_partition(part->name, NVRAM_SIG_OS, NULL);
293 315 p = 0;
294 316 }
295 317  
296 318 /* Create one if we didn't find */
297 319 if (!p) {
298   - p = nvram_create_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS,
299   - NVRAM_MAX_REQ, NVRAM_MIN_REQ);
300   - /* No room for it, try to get rid of any OS partition
301   - * and try again
302   - */
  320 + p = nvram_create_partition(part->name, NVRAM_SIG_OS,
  321 + part->req_size, part->min_size);
303 322 if (p == -ENOSPC) {
304   - pr_info("nvram: No room to create "NVRAM_LOG_PART_NAME
305   - " partition, deleting all OS partitions...");
306   - nvram_remove_partition(NULL, NVRAM_SIG_OS);
307   - p = nvram_create_partition(NVRAM_LOG_PART_NAME,
308   - NVRAM_SIG_OS, NVRAM_MAX_REQ,
309   - NVRAM_MIN_REQ);
  323 + pr_info("nvram: No room to create %s partition, "
  324 + "deleting any obsolete OS partitions...\n",
  325 + part->name);
  326 + nvram_remove_partition(NULL, NVRAM_SIG_OS,
  327 + pseries_nvram_os_partitions);
  328 + p = nvram_create_partition(part->name, NVRAM_SIG_OS,
  329 + part->req_size, part->min_size);
310 330 }
311 331 }
312 332  
313 333 if (p <= 0) {
314   - pr_err("nvram: Failed to find or create "NVRAM_LOG_PART_NAME
315   - " partition, err %d\n", (int)p);
316   - return 0;
  334 + pr_err("nvram: Failed to find or create %s"
  335 + " partition, err %d\n", part->name, (int)p);
  336 + return -1;
317 337 }
318 338  
319   - nvram_error_log_index = p;
320   - nvram_error_log_size = nvram_get_partition_size(p) -
321   - sizeof(struct err_log_info);
  339 + part->index = p;
  340 + part->size = nvram_get_partition_size(p) - sizeof(struct err_log_info);
322 341  
323 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 352 int __init pSeries_nvram_init(void)
328 353 {