[PATCH] memory hotplug: ppc64 specific hot-add functions
[pandora-kernel.git] / arch / ppc64 / mm / init.c
index 975b26d..e2bd777 100644 (file)
@@ -871,3 +871,80 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
        return vma_prot;
 }
 EXPORT_SYMBOL(phys_mem_access_prot);
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+
+void online_page(struct page *page)
+{
+       ClearPageReserved(page);
+       free_cold_page(page);
+       totalram_pages++;
+       num_physpages++;
+}
+
+/*
+ * This works only for the non-NUMA case.  Later, we'll need a lookup
+ * to convert from real physical addresses to nid, that doesn't use
+ * pfn_to_nid().
+ */
+int __devinit add_memory(u64 start, u64 size)
+{
+       struct pglist_data *pgdata = NODE_DATA(0);
+       struct zone *zone;
+       unsigned long start_pfn = start >> PAGE_SHIFT;
+       unsigned long nr_pages = size >> PAGE_SHIFT;
+
+       /* this should work for most non-highmem platforms */
+       zone = pgdata->node_zones;
+
+       return __add_pages(zone, start_pfn, nr_pages);
+
+       return 0;
+}
+
+/*
+ * First pass at this code will check to determine if the remove
+ * request is within the RMO.  Do not allow removal within the RMO.
+ */
+int __devinit remove_memory(u64 start, u64 size)
+{
+       struct zone *zone;
+       unsigned long start_pfn, end_pfn, nr_pages;
+
+       start_pfn = start >> PAGE_SHIFT;
+       nr_pages = size >> PAGE_SHIFT;
+       end_pfn = start_pfn + nr_pages;
+
+       printk("%s(): Attempting to remove memoy in range "
+                       "%lx to %lx\n", __func__, start, start+size);
+       /*
+        * check for range within RMO
+        */
+       zone = page_zone(pfn_to_page(start_pfn));
+
+       printk("%s(): memory will be removed from "
+                       "the %s zone\n", __func__, zone->name);
+
+       /*
+        * not handling removing memory ranges that
+        * overlap multiple zones yet
+        */
+       if (end_pfn > (zone->zone_start_pfn + zone->spanned_pages))
+               goto overlap;
+
+       /* make sure it is NOT in RMO */
+       if ((start < lmb.rmo_size) || ((start+size) < lmb.rmo_size)) {
+               printk("%s(): range to be removed must NOT be in RMO!\n",
+                       __func__);
+               goto in_rmo;
+       }
+
+       return __remove_pages(zone, start_pfn, nr_pages);
+
+overlap:
+       printk("%s(): memory range to be removed overlaps "
+               "multiple zones!!!\n", __func__);
+in_rmo:
+       return -1;
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */