Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6
[cascardo/linux.git] / arch / powerpc / kernel / nvram_64.c
index 6dd2700..bb12b32 100644 (file)
 
 #define NVRAM_HEADER_LEN       sizeof(struct nvram_header)
 #define NVRAM_BLOCK_LEN                NVRAM_HEADER_LEN
-#define NVRAM_MAX_REQ          2079
-#define NVRAM_MIN_REQ          1055
 
 /* If change this size, then change the size of NVNAME_LEN */
 struct nvram_header {
        unsigned char signature;
        unsigned char checksum;
        unsigned short length;
+       /* Terminating null required only for names < 12 chars. */
        char name[12];
 };
 
@@ -53,14 +52,7 @@ struct nvram_partition {
        unsigned int index;
 };
 
-static struct nvram_partition * nvram_part;
-static long nvram_error_log_index = -1;
-static long nvram_error_log_size = 0;
-
-struct err_log_info {
-       int error_type;
-       unsigned int seq_num;
-};
+static LIST_HEAD(nvram_partitions);
 
 static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
 {
@@ -205,14 +197,12 @@ static struct miscdevice nvram_dev = {
 #ifdef DEBUG_NVRAM
 static void __init nvram_print_partitions(char * label)
 {
-       struct list_head * p;
        struct nvram_partition * tmp_part;
        
        printk(KERN_WARNING "--------%s---------\n", label);
        printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
-       list_for_each(p, &nvram_part->partition) {
-               tmp_part = list_entry(p, struct nvram_partition, partition);
-               printk(KERN_WARNING "%4d    \t%02x\t%02x\t%d\t%s\n",
+       list_for_each_entry(tmp_part, &nvram_partitions, partition) {
+               printk(KERN_WARNING "%4d    \t%02x\t%02x\t%d\t%12s\n",
                       tmp_part->index, tmp_part->header.signature,
                       tmp_part->header.checksum, tmp_part->header.length,
                       tmp_part->header.name);
@@ -254,12 +244,12 @@ static unsigned char __init nvram_checksum(struct nvram_header *p)
  * @sig: signature of the partition(s) to remove
  */
 
-static int __init nvram_remove_partition(const char *name, int sig)
+int __init nvram_remove_partition(const char *name, int sig)
 {
        struct nvram_partition *part, *prev, *tmp;
        int rc;
 
-       list_for_each_entry(part, &nvram_part->partition, partition) {
+       list_for_each_entry(part, &nvram_partitions, partition) {
                if (part->header.signature != sig)
                        continue;
                if (name && strncmp(name, part->header.name, 12))
@@ -267,7 +257,7 @@ static int __init nvram_remove_partition(const char *name, int sig)
 
                /* Make partition a free partition */
                part->header.signature = NVRAM_SIG_FREE;
-               sprintf(part->header.name, "wwwwwwwwwwww");
+               strncpy(part->header.name, "wwwwwwwwwwww", 12);
                part->header.checksum = nvram_checksum(&part->header);
                rc = nvram_write_header(part);
                if (rc <= 0) {
@@ -278,7 +268,7 @@ static int __init nvram_remove_partition(const char *name, int sig)
 
        /* Merge contiguous ones */
        prev = NULL;
-       list_for_each_entry_safe(part, tmp, &nvram_part->partition, partition) {
+       list_for_each_entry_safe(part, tmp, &nvram_partitions, partition) {
                if (part->header.signature != NVRAM_SIG_FREE) {
                        prev = NULL;
                        continue;
@@ -313,8 +303,8 @@ static int __init nvram_remove_partition(const char *name, int sig)
  * you need to query for the actual size yourself after the
  * call using nvram_partition_get_size().
  */
-static loff_t __init nvram_create_partition(const char *name, int sig,
-                                           int req_size, int min_size)
+loff_t __init nvram_create_partition(const char *name, int sig,
+                                    int req_size, int min_size)
 {
        struct nvram_partition *part;
        struct nvram_partition *new_part;
@@ -342,7 +332,7 @@ static loff_t __init nvram_create_partition(const char *name, int sig,
 
        /* Find a free partition that will give us the maximum needed size 
           If can't find one that will give us the minimum size needed */
-       list_for_each_entry(part, &nvram_part->partition, partition) {
+       list_for_each_entry(part, &nvram_partitions, partition) {
                if (part->header.signature != NVRAM_SIG_FREE)
                        continue;
 
@@ -417,11 +407,11 @@ static loff_t __init nvram_create_partition(const char *name, int sig,
  *              the partition. The same value that is returned by
  *              nvram_create_partition().
  */
-static int nvram_get_partition_size(loff_t data_index)
+int nvram_get_partition_size(loff_t data_index)
 {
        struct nvram_partition *part;
        
-       list_for_each_entry(part, &nvram_part->partition, partition) {
+       list_for_each_entry(part, &nvram_partitions, partition) {
                if (part->index + NVRAM_HEADER_LEN == data_index)
                        return (part->header.length - 1) * NVRAM_BLOCK_LEN;
        }
@@ -429,82 +419,29 @@ static int nvram_get_partition_size(loff_t data_index)
 }
 
 
-/* nvram_setup_partition
- *
- * This will setup the partition we need for buffering the
- * error logs and cleanup partitions if needed.
- *
- * The general strategy is the following:
- * 1.) If there is ppc64,linux partition large enough then use it.
- * 2.) If there is not a ppc64,linux partition large enough, search
- * for a free partition that is large enough.
- * 3.) If there is not a free partition large enough remove 
- * _all_ OS partitions and consolidate the space.
- * 4.) Will first try getting a chunk that will satisfy the maximum
- * error log size (NVRAM_MAX_REQ).
- * 5.) If the max chunk cannot be allocated then try finding a chunk
- * that will satisfy the minum needed (NVRAM_MIN_REQ).
+/**
+ * nvram_find_partition - Find an nvram partition by signature and name
+ * @name: Name of the partition or NULL for any name
+ * @sig: Signature to test against
+ * @out_size: if non-NULL, returns the size of the data part of the partition
  */
-static int __init nvram_setup_partition(void)
+loff_t nvram_find_partition(const char *name, int sig, int *out_size)
 {
-       struct list_head * p;
-       struct nvram_partition * part;
-       int rc;
-
-       /* For now, we don't do any of this on pmac, until I
-        * have figured out if it's worth killing some unused stuffs
-        * in our nvram, as Apple defined partitions use pretty much
-        * all of the space
-        */
-       if (machine_is(powermac))
-               return -ENOSPC;
-
-       /* see if we have an OS partition that meets our needs.
-          will try getting the max we need.  If not we'll delete
-          partitions and try again. */
-       list_for_each(p, &nvram_part->partition) {
-               part = list_entry(p, struct nvram_partition, partition);
-               if (part->header.signature != NVRAM_SIG_OS)
-                       continue;
-
-               if (strcmp(part->header.name, "ppc64,linux"))
-                       continue;
-
-               if ((part->header.length - 1) * NVRAM_BLOCK_LEN >= NVRAM_MIN_REQ) {
-                       /* found our partition */
-                       nvram_error_log_index = part->index + NVRAM_HEADER_LEN;
-                       nvram_error_log_size = ((part->header.length - 1) *
-                                               NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
-                       return 0;
-               }
-
-               /* Found one but it's too small, remove it */
-               nvram_remove_partition("ppc64,linux", NVRAM_SIG_OS);
-       }
-       
-       /* try creating a partition with the free space we have */
-       rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
-                                      NVRAM_MAX_REQ, NVRAM_MIN_REQ);
-       if (rc < 0) {
-               /* need to free up some space, remove any "OS" partition */
-               nvram_remove_partition(NULL, NVRAM_SIG_OS);
-       
-               /* Try again */
-               rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
-                                           NVRAM_MAX_REQ, NVRAM_MIN_REQ);
-               if (rc < 0) {
-                       pr_err("nvram_create_partition: Could not find"
-                              " enough space in NVRAM for partition\n");
-                       return rc;
+       struct nvram_partition *p;
+
+       list_for_each_entry(p, &nvram_partitions, partition) {
+               if (p->header.signature == sig &&
+                   (!name || !strncmp(p->header.name, name, 12))) {
+                       if (out_size)
+                               *out_size = (p->header.length - 1) *
+                                       NVRAM_BLOCK_LEN;
+                       return p->index + NVRAM_HEADER_LEN;
                }
        }
-       
-       nvram_error_log_index = rc;     
-       nvram_error_log_size = nvram_get_partition_size(rc) - sizeof(struct err_log_info);      
        return 0;
 }
 
-static int __init nvram_scan_partitions(void)
+int __init nvram_scan_partitions(void)
 {
        loff_t cur_index = 0;
        struct nvram_header phead;
@@ -514,7 +451,7 @@ static int __init nvram_scan_partitions(void)
        int total_size;
        int err;
 
-       if (ppc_md.nvram_size == NULL)
+       if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
                return -ENODEV;
        total_size = ppc_md.nvram_size();
        
@@ -561,12 +498,16 @@ static int __init nvram_scan_partitions(void)
                
                memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
                tmp_part->index = cur_index;
-               list_add_tail(&tmp_part->partition, &nvram_part->partition);
+               list_add_tail(&tmp_part->partition, &nvram_partitions);
                
                cur_index += phead.length * NVRAM_BLOCK_LEN;
        }
        err = 0;
 
+#ifdef DEBUG_NVRAM
+       nvram_print_partitions("NVRAM Partitions");
+#endif
+
  out:
        kfree(header);
        return err;
@@ -574,7 +515,6 @@ static int __init nvram_scan_partitions(void)
 
 static int __init nvram_init(void)
 {
-       int error;
        int rc;
        
        BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16);
@@ -588,29 +528,6 @@ static int __init nvram_init(void)
                return rc;
        }
        
-       /* initialize our anchor for the nvram partition list */
-       nvram_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
-       if (!nvram_part) {
-               printk(KERN_ERR "nvram_init: Failed kmalloc\n");
-               return -ENOMEM;
-       }
-       INIT_LIST_HEAD(&nvram_part->partition);
-  
-       /* Get all the NVRAM partitions */
-       error = nvram_scan_partitions();
-       if (error) {
-               printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n");
-               return error;
-       }
-               
-       if(nvram_setup_partition()) 
-               printk(KERN_WARNING "nvram_init: Could not find nvram partition"
-                      " for nvram buffered error logging.\n");
-  
-#ifdef DEBUG_NVRAM
-       nvram_print_partitions("NVRAM Partitions");
-#endif
-
        return rc;
 }
 
@@ -619,135 +536,6 @@ void __exit nvram_cleanup(void)
         misc_deregister( &nvram_dev );
 }
 
-
-#ifdef CONFIG_PPC_PSERIES
-
-/* nvram_write_error_log
- *
- * We need to buffer the error logs into nvram to ensure that we have
- * the failure information to decode.  If we have a severe error there
- * is no way to guarantee that the OS or the machine is in a state to
- * get back to user land and write the error to disk.  For example if
- * the SCSI device driver causes a Machine Check by writing to a bad
- * IO address, there is no way of guaranteeing that the device driver
- * is in any state that is would also be able to write the error data
- * captured to disk, thus we buffer it in NVRAM for analysis on the
- * next boot.
- *
- * In NVRAM the partition containing the error log buffer will looks like:
- * Header (in bytes):
- * +-----------+----------+--------+------------+------------------+
- * | signature | checksum | length | name       | data             |
- * |0          |1         |2      3|4         15|16        length-1|
- * +-----------+----------+--------+------------+------------------+
- *
- * The 'data' section would look like (in bytes):
- * +--------------+------------+-----------------------------------+
- * | event_logged | sequence # | error log                         |
- * |0            3|4          7|8            nvram_error_log_size-1|
- * +--------------+------------+-----------------------------------+
- *
- * event_logged: 0 if event has not been logged to syslog, 1 if it has
- * sequence #: The unique sequence # for each event. (until it wraps)
- * error log: The error log from event_scan
- */
-int nvram_write_error_log(char * buff, int length,
-                          unsigned int err_type, unsigned int error_log_cnt)
-{
-       int rc;
-       loff_t tmp_index;
-       struct err_log_info info;
-       
-       if (nvram_error_log_index == -1) {
-               return -ESPIPE;
-       }
-
-       if (length > nvram_error_log_size) {
-               length = nvram_error_log_size;
-       }
-
-       info.error_type = err_type;
-       info.seq_num = error_log_cnt;
-
-       tmp_index = nvram_error_log_index;
-
-       rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
-       if (rc <= 0) {
-               printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
-               return rc;
-       }
-
-       rc = ppc_md.nvram_write(buff, length, &tmp_index);
-       if (rc <= 0) {
-               printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
-               return rc;
-       }
-       
-       return 0;
-}
-
-/* nvram_read_error_log
- *
- * Reads nvram for error log for at most 'length'
- */
-int nvram_read_error_log(char * buff, int length,
-                         unsigned int * err_type, unsigned int * error_log_cnt)
-{
-       int rc;
-       loff_t tmp_index;
-       struct err_log_info info;
-       
-       if (nvram_error_log_index == -1)
-               return -1;
-
-       if (length > nvram_error_log_size)
-               length = nvram_error_log_size;
-
-       tmp_index = nvram_error_log_index;
-
-       rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
-       if (rc <= 0) {
-               printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
-               return rc;
-       }
-
-       rc = ppc_md.nvram_read(buff, length, &tmp_index);
-       if (rc <= 0) {
-               printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
-               return rc;
-       }
-
-       *error_log_cnt = info.seq_num;
-       *err_type = info.error_type;
-
-       return 0;
-}
-
-/* This doesn't actually zero anything, but it sets the event_logged
- * word to tell that this event is safely in syslog.
- */
-int nvram_clear_error_log(void)
-{
-       loff_t tmp_index;
-       int clear_word = ERR_FLAG_ALREADY_LOGGED;
-       int rc;
-
-       if (nvram_error_log_index == -1)
-               return -1;
-
-       tmp_index = nvram_error_log_index;
-       
-       rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
-       if (rc <= 0) {
-               printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc);
-               return rc;
-       }
-
-       return 0;
-}
-
-#endif /* CONFIG_PPC_PSERIES */
-
 module_init(nvram_init);
 module_exit(nvram_cleanup);
 MODULE_LICENSE("GPL");