]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/platforms/pseries/phyp_dump.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[karo-tx-linux.git] / arch / powerpc / platforms / pseries / phyp_dump.c
index df4870ec90d8d91c088a0b9b9b666c9e3548897e..edbc012c2ebca1cff90c13d713d2e442e3ac52a1 100644 (file)
@@ -182,6 +182,18 @@ static void print_dump_header(const struct phyp_dump_header *ph)
 #endif
 }
 
+static ssize_t show_phyp_dump_active(struct kobject *kobj,
+                       struct kobj_attribute *attr, char *buf)
+{
+
+       /* create filesystem entry so kdump is phyp-dump aware */
+       return sprintf(buf, "%lx\n", phyp_dump_info->phyp_dump_at_boot);
+}
+
+static struct kobj_attribute pdl = __ATTR(phyp_dump_active, 0600,
+                                       show_phyp_dump_active,
+                                       NULL);
+
 static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr)
 {
        int rc;
@@ -204,7 +216,13 @@ static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr)
                printk(KERN_ERR "phyp-dump: unexpected error (%d) on "
                                                "register\n", rc);
                print_dump_header(ph);
+               return;
        }
+
+       rc = sysfs_create_file(kernel_kobj, &pdl.attr);
+       if (rc)
+               printk(KERN_ERR "phyp-dump: unable to create sysfs"
+                               " file (%d)\n", rc);
 }
 
 static
@@ -261,6 +279,39 @@ static void release_memory_range(unsigned long start_pfn,
        }
 }
 
+/**
+ * track_freed_range -- Counts the range being freed.
+ * Once the counter goes to zero, it re-registers dump for
+ * future use.
+ */
+static void
+track_freed_range(unsigned long addr, unsigned long length)
+{
+       static unsigned long scratch_area_size, reserved_area_size;
+
+       if (addr < phyp_dump_info->init_reserve_start)
+               return;
+
+       if ((addr >= phyp_dump_info->init_reserve_start) &&
+           (addr <= phyp_dump_info->init_reserve_start +
+            phyp_dump_info->init_reserve_size))
+               reserved_area_size += length;
+
+       if ((addr >= phyp_dump_info->reserved_scratch_addr) &&
+           (addr <= phyp_dump_info->reserved_scratch_addr +
+            phyp_dump_info->reserved_scratch_size))
+               scratch_area_size += length;
+
+       if ((reserved_area_size == phyp_dump_info->init_reserve_size) &&
+           (scratch_area_size == phyp_dump_info->reserved_scratch_size)) {
+
+               invalidate_last_dump(&phdr,
+                               phyp_dump_info->reserved_scratch_addr);
+               register_dump_area(&phdr,
+                               phyp_dump_info->reserved_scratch_addr);
+       }
+}
+
 /* ------------------------------------------------- */
 /**
  * sysfs_release_region -- sysfs interface to release memory range.
@@ -285,6 +336,8 @@ static ssize_t store_release_region(struct kobject *kobj,
        if (ret != 2)
                return -EINVAL;
 
+       track_freed_range(start_addr, length);
+
        /* Range-check - don't free any reserved memory that
         * wasn't reserved for phyp-dump */
        if (start_addr < phyp_dump_info->init_reserve_start)
@@ -425,3 +478,30 @@ int __init early_init_dt_scan_phyp_dump(unsigned long node,
                                                *((unsigned long *)&sizes[4]);
        return 1;
 }
+
+/* Look for phyp_dump= cmdline option */
+static int __init early_phyp_dump_enabled(char *p)
+{
+       phyp_dump_info->phyp_dump_at_boot = 1;
+
+        if (!p)
+                return 0;
+
+        if (strncmp(p, "1", 1) == 0)
+               phyp_dump_info->phyp_dump_at_boot = 1;
+        else if (strncmp(p, "0", 1) == 0)
+               phyp_dump_info->phyp_dump_at_boot = 0;
+
+        return 0;
+}
+early_param("phyp_dump", early_phyp_dump_enabled);
+
+/* Look for phyp_dump_reserve_size= cmdline option */
+static int __init early_phyp_dump_reserve_size(char *p)
+{
+        if (p)
+               phyp_dump_info->reserve_bootvar = memparse(p, &p);
+
+        return 0;
+}
+early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size);