|
@@ -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 */
|