]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/powerpc/kernel/prom.c
powerpc: Make the 64-bit kernel as a position-independent executable
[linux-2.6-omap-h63xx.git] / arch / powerpc / kernel / prom.c
index 8a9359ae471853688e509d42bd2999b78d1a87ca..3a2dc7e6586a392292ccf3ccbfacb39151a3f675 100644 (file)
@@ -53,6 +53,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/phyp_dump.h>
 #include <asm/kexec.h>
+#include <mm/mmu_decl.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) printk(KERN_ERR fmt)
@@ -608,6 +609,10 @@ static struct feature_property {
        {"altivec", 0, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC},
        {"ibm,vmx", 1, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC},
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_VSX
+       /* Yes, this _really_ is ibm,vmx == 2 to enable VSX */
+       {"ibm,vmx", 2, CPU_FTR_VSX, PPC_FEATURE_HAS_VSX},
+#endif /* CONFIG_VSX */
 #ifdef CONFIG_PPC64
        {"ibm,dfp", 1, 0, PPC_FEATURE_HAS_DFP},
        {"ibm,purr", 1, CPU_FTR_PURR, 0},
@@ -883,9 +888,10 @@ static u64 __init dt_mem_next_cell(int s, cell_t **cellp)
  */
 static int __init early_init_dt_scan_drconf_memory(unsigned long node)
 {
-       cell_t *dm, *ls;
+       cell_t *dm, *ls, *usm;
        unsigned long l, n, flags;
        u64 base, size, lmb_size;
+       unsigned int is_kexec_kdump = 0, rngs;
 
        ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
        if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
@@ -900,6 +906,12 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
        if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
                return 0;
 
+       /* check if this is a kexec/kdump kernel. */
+       usm = (cell_t *)of_get_flat_dt_prop(node, "linux,drconf-usable-memory",
+                                                &l);
+       if (usm != NULL)
+               is_kexec_kdump = 1;
+
        for (; n != 0; --n) {
                base = dt_mem_next_cell(dt_root_addr_cells, &dm);
                flags = dm[3];
@@ -910,13 +922,34 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
                if ((flags & 0x80) || !(flags & 0x8))
                        continue;
                size = lmb_size;
-               if (iommu_is_off) {
-                       if (base >= 0x80000000ul)
+               rngs = 1;
+               if (is_kexec_kdump) {
+                       /*
+                        * For each lmb in ibm,dynamic-memory, a corresponding
+                        * entry in linux,drconf-usable-memory property contains
+                        * a counter 'p' followed by 'p' (base, size) duple.
+                        * Now read the counter from
+                        * linux,drconf-usable-memory property
+                        */
+                       rngs = dt_mem_next_cell(dt_root_size_cells, &usm);
+                       if (!rngs) /* there are no (base, size) duple */
                                continue;
-                       if ((base + size) > 0x80000000ul)
-                               size = 0x80000000ul - base;
                }
-               lmb_add(base, size);
+               do {
+                       if (is_kexec_kdump) {
+                               base = dt_mem_next_cell(dt_root_addr_cells,
+                                                        &usm);
+                               size = dt_mem_next_cell(dt_root_size_cells,
+                                                        &usm);
+                       }
+                       if (iommu_is_off) {
+                               if (base >= 0x80000000ul)
+                                       continue;
+                               if ((base + size) > 0x80000000ul)
+                                       size = 0x80000000ul - base;
+                       }
+                       lmb_add(base, size);
+               } while (--rngs);
        }
        lmb_dump_all();
        return 0;
@@ -978,7 +1011,10 @@ static int __init early_init_dt_scan_memory(unsigned long node,
                }
 #endif
                lmb_add(base, size);
+
+               memstart_addr = min((u64)memstart_addr, base);
        }
+
        return 0;
 }
 
@@ -1156,6 +1192,9 @@ void __init early_init_devtree(void *params)
 
        /* Reserve LMB regions used by kernel, initrd, dt, etc... */
        lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
+       /* If relocatable, reserve first 32k for interrupt vectors etc. */
+       if (PHYSICAL_START > MEMORY_START)
+               lmb_reserve(MEMORY_START, 0x8000);
        reserve_kdump_trampoline();
        reserve_crashkernel();
        early_reserve_mem();
@@ -1332,12 +1371,14 @@ EXPORT_SYMBOL(of_node_put);
  */
 void of_attach_node(struct device_node *np)
 {
-       write_lock(&devtree_lock);
+       unsigned long flags;
+
+       write_lock_irqsave(&devtree_lock, flags);
        np->sibling = np->parent->child;
        np->allnext = allnodes;
        np->parent->child = np;
        allnodes = np;
-       write_unlock(&devtree_lock);
+       write_unlock_irqrestore(&devtree_lock, flags);
 }
 
 /*
@@ -1348,8 +1389,9 @@ void of_attach_node(struct device_node *np)
 void of_detach_node(struct device_node *np)
 {
        struct device_node *parent;
+       unsigned long flags;
 
-       write_lock(&devtree_lock);
+       write_lock_irqsave(&devtree_lock, flags);
 
        parent = np->parent;
        if (!parent)
@@ -1380,7 +1422,7 @@ void of_detach_node(struct device_node *np)
        of_node_set_flag(np, OF_DETACHED);
 
 out_unlock:
-       write_unlock(&devtree_lock);
+       write_unlock_irqrestore(&devtree_lock, flags);
 }
 
 #ifdef CONFIG_PPC_PSERIES
@@ -1461,20 +1503,21 @@ __initcall(prom_reconfig_setup);
 int prom_add_property(struct device_node* np, struct property* prop)
 {
        struct property **next;
+       unsigned long flags;
 
        prop->next = NULL;      
-       write_lock(&devtree_lock);
+       write_lock_irqsave(&devtree_lock, flags);
        next = &np->properties;
        while (*next) {
                if (strcmp(prop->name, (*next)->name) == 0) {
                        /* duplicate ! don't insert it */
-                       write_unlock(&devtree_lock);
+                       write_unlock_irqrestore(&devtree_lock, flags);
                        return -1;
                }
                next = &(*next)->next;
        }
        *next = prop;
-       write_unlock(&devtree_lock);
+       write_unlock_irqrestore(&devtree_lock, flags);
 
 #ifdef CONFIG_PROC_DEVICETREE
        /* try to add to proc as well if it was initialized */
@@ -1494,9 +1537,10 @@ int prom_add_property(struct device_node* np, struct property* prop)
 int prom_remove_property(struct device_node *np, struct property *prop)
 {
        struct property **next;
+       unsigned long flags;
        int found = 0;
 
-       write_lock(&devtree_lock);
+       write_lock_irqsave(&devtree_lock, flags);
        next = &np->properties;
        while (*next) {
                if (*next == prop) {
@@ -1509,7 +1553,7 @@ int prom_remove_property(struct device_node *np, struct property *prop)
                }
                next = &(*next)->next;
        }
-       write_unlock(&devtree_lock);
+       write_unlock_irqrestore(&devtree_lock, flags);
 
        if (!found)
                return -ENODEV;
@@ -1535,9 +1579,10 @@ int prom_update_property(struct device_node *np,
                         struct property *oldprop)
 {
        struct property **next;
+       unsigned long flags;
        int found = 0;
 
-       write_lock(&devtree_lock);
+       write_lock_irqsave(&devtree_lock, flags);
        next = &np->properties;
        while (*next) {
                if (*next == oldprop) {
@@ -1551,7 +1596,7 @@ int prom_update_property(struct device_node *np,
                }
                next = &(*next)->next;
        }
-       write_unlock(&devtree_lock);
+       write_unlock_irqrestore(&devtree_lock, flags);
 
        if (!found)
                return -ENODEV;