
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>


---

 memhotplug-dave/arch/ppc64/Kconfig     |    4 
 memhotplug-dave/drivers/base/memory.c  |  140 +++++++++++++++++++++------------
 memhotplug-dave/include/linux/memory.h |    1 
 3 files changed, 95 insertions(+), 50 deletions(-)

diff -puN drivers/base/memory.c~N-sysfs-memory-class-work drivers/base/memory.c
--- memhotplug/drivers/base/memory.c~N-sysfs-memory-class-work	Thu Aug  5 09:41:18 2004
+++ memhotplug-dave/drivers/base/memory.c	Thu Aug  5 09:41:18 2004
@@ -11,6 +11,7 @@
 #include <linux/memory.h>
 #include <linux/kobject.h>
 #include <asm/atomic.h>
+#include <asm/uaccess.h>
 
 struct sysdev_class memory_sysdev_class = {
 	set_kset_name("memory"),
@@ -31,7 +32,7 @@ static int memory_hotplug_filter(struct 
 static char *memory_hotplug_name(struct kset *kset, struct kobject *kobj)
 {
 	printk("Hit %s\n", __func__);
-        return "-no_name_implemented";
+	return "memory";
 }
 
 static int memory_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
@@ -91,8 +92,85 @@ static ssize_t show_mem_state(struct sys
 {
 	struct memory_block *mem =
 		container_of(dev, struct memory_block, sysdev);
-	return sprintf(buf, "%d\n", mem->state);
+	ssize_t len = 0;
+
+	/*
+	 * We can probably put these states in a nice little array
+	 * so that they're not open-coded
+	 */
+	switch (mem->state) {
+		case MEM_ONLINE:
+			len = sprintf(buf, "online\n");
+			break;
+		case MEM_OFFLINE:
+			len = sprintf(buf, "offline\n");
+			break;
+		case MEM_GOING_OFFLINE:
+			len = sprintf(buf, "going-offline\n");
+			break;
+		case MEM_INVALID:
+			len = sprintf(buf, "invalid\n");
+			break;
+		default:
+			len = sprintf(buf, "ERROR\n");
+			break;
+	}
+
+	return len;
+}
+
+#define update_memdevice(...) 	do {} while(0);
+
+static int online_memory_block(struct memory_block *mem)
+{
+	int ret = 0;
+	down(&mem->state_sem);
+
+	if (mem->state != MEM_OFFLINE)
+		return -EINVAL;
+
+	ret = __online_memory_block(mem);
+	if (!ret)
+		mem->state = MEM_ONLINE;
+
+	up(&mem->state_sem);
+
+	return ret;
+}
+
+static ssize_t
+store_mem_state(struct sys_device *dev, const char *buf, size_t count)
+{
+	struct memory_block *mem =
+		container_of(dev, struct memory_block, sysdev);
+	unsigned int phys_section_nr = mem->phys_index;
+	unsigned int section = phys_section[phys_section_nr];
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (mem_section[section].phys_section == INVALID_SECTION) {
+		printk("%s: Ummm.. this section (%d) is not currently mapped!\n",
+			__func__, section);
+		return -EINVAL;
+	}
+
+	if (!strncmp(buf, "online", min((int)count,6))) {
+		online_memory_block(mem);
+	} else if(!strncmp(buf, "offline", min((int)count,7)))
+		return -ENOSYS;
+	else
+		return -EINVAL;
+
+	/*
+	 * Now that the memory has been truly onlined, update the
+	 * appropriate entry in sysfs
+	 */
+	update_memdevice();
+
+	return count;
 }
+
 /*
  * phys_device is a bad name for this.  What I really want
  * is a way to differentiate between memory ranges that
@@ -110,7 +188,7 @@ static ssize_t show_phys_device(struct s
 }
 
 SYSDEV_ATTR(phys_index, 0444, show_mem_phys_index, NULL);
-SYSDEV_ATTR(state, 0444, show_mem_state, NULL);
+SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state);
 SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL);
 
 #define mem_create_simple_file(mem, attr_name)	\
@@ -142,21 +220,23 @@ static int block_size_init(void)
 /* define this off in some header somewhere ... */
 #ifdef CONFIG_ARCH_MEMORY_PROBE
 static ssize_t
-memory_probe_store(struct class *class, const char *buf, size_t count)
+memory_probe_store(struct class *class, const char __user *buf, size_t count)
 {
+	u64 phys_addr;
 	/*
 	 * Hmmm... what do we really want this to do?
 	 */
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	printk("Hit %s!\n", __func__);
-
-	/* make call into arch code */
-	//static int num; /* hehe. no locking */
+	phys_addr = simple_strtoull(buf, NULL, 0);
 
-	//add_memory_block(num++, 0x100*num, MEM_OFFLINE, 4);
+	/*
+	if (!ram_present(phys_addr, PAGES_PER_SECTION))
+		return -EINVAL;
+	*/
 
+	add_pages(phys_addr, (PAGES_PER_SECTION << PAGE_SHIFT), 0);
 	return count;
 }
 static CLASS_ATTR(probe, 0700, NULL, memory_probe_store);
@@ -194,6 +274,7 @@ int add_memory_block(unsigned long node_
 
 	mem->phys_index = phys_index;
 	mem->state = state;
+	init_MUTEX(&mem->state_sem);
 	mem->phys_device = phys_device;
 
 #if 0
@@ -212,46 +293,6 @@ int add_memory_block(unsigned long node_
 	return 0;
 }
 
-#define update_memdevice(...) 	do {} while(0)
-#define online_section(...) 	do {} while(0)
-
-static ssize_t
-online_store(struct class *class, const char *buf, size_t count)
-{
-	unsigned int section = simple_strtoul(buf, NULL, 10);
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	if (mem_section[section].phys_section == INVALID_SECTION) {
-		printk("%s: Ummm.. this section is not currently mapped!\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	/*
-	 * Crude section based onlining; probably need random
-	 * address onlining...
-	 */
-	online_section(section);
-
-	/*
-	 * Now that the memory has been truly onlined, update the
-	 * appropriate entry in sysfs
-	 */
-	update_memdevice();
-
-	return count;
-}
-static CLASS_ATTR(online, 0700, NULL, online_store);
-
-static int online_init(void)
-{
-	sysfs_create_file(&memory_sysdev_class.kset.kobj,
-		&class_attr_online.attr);
-	return 0;
-}
-
 /*
  * need an interface for the VM to add new memory regions,
  * but without onlining it.
@@ -294,7 +335,6 @@ int __init memory_dev_init(void)
 
 	memory_probe_init();
 	block_size_init();
-	online_init();
 
 	return ret;
 }
diff -puN include/linux/memory.h~N-sysfs-memory-class-work include/linux/memory.h
--- memhotplug/include/linux/memory.h~N-sysfs-memory-class-work	Thu Aug  5 09:41:18 2004
+++ memhotplug-dave/include/linux/memory.h	Thu Aug  5 09:41:18 2004
@@ -45,6 +45,7 @@ enum memory_state {
 struct memory_block {
 	unsigned long phys_index;
 	enum memory_state state; 	/* just filler for now */
+	struct semaphore state_sem;
 	int phys_device;		/* to which fru does this belong? */
 	void *hw;			/* optional pointer to fw/hw data */
 	int (*phys_callback)(struct memory_block *);
diff -puN arch/ppc64/Kconfig~N-sysfs-memory-class-work arch/ppc64/Kconfig
--- memhotplug/arch/ppc64/Kconfig~N-sysfs-memory-class-work	Thu Aug  5 09:41:18 2004
+++ memhotplug-dave/arch/ppc64/Kconfig	Thu Aug  5 09:41:18 2004
@@ -185,6 +185,10 @@ config NONLINEAR
 config MEMORY_HOTPLUG
 	bool "Allow memory hotplug"
 
+config MEMORY_HOTPLUG
+	bool "Allow for memory hotplug"
+	depends on NONLINEAR
+
 config DISCONTIGMEM
 	bool "Discontiguous Memory Support"
 	depends on SMP && PPC_PSERIES

_
