]> 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 3bfe7837e8207978062b0d8426a0f50b04b6c448..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();