Blame view

drivers/acpi/acpi_memhotplug.c 14.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /*
   * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
   *
   * All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or (at
   * your option) any later version.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
   * NON INFRINGEMENT.  See the GNU General Public License for more
   * details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   *
   *
   * ACPI based HotPlug driver that supports Memory Hotplug
c7060d9e9   Nick Andrew   trivial: Fix miss...
23
   * This driver fields notifications from firmware for memory add
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
30
31
32
   * and remove operations and alerts the VM of the affected memory
   * ranges.
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/types.h>
  #include <linux/memory_hotplug.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
33
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <acpi/acpi_drivers.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  #define ACPI_MEMORY_DEVICE_CLASS		"memory"
  #define ACPI_MEMORY_DEVICE_HID			"PNP0C80"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
  #define ACPI_MEMORY_DEVICE_NAME			"Hotplug Mem Device"
  
  #define _COMPONENT		ACPI_MEMORY_DEVICE_COMPONENT
aa7b2b2e9   Zhao Yakui   ACPI: Don't treat...
40
41
  #undef PREFIX
  #define 	PREFIX		"ACPI:memory_hp:"
f52fd66d2   Len Brown   ACPI: clean up AC...
42
43
  ACPI_MODULE_NAME("acpi_memhotplug");
  MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
7cda93e00   Len Brown   ACPI: delete extr...
44
  MODULE_DESCRIPTION("Hotplug Mem Driver");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  MODULE_LICENSE("GPL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
  /* Memory Device States */
  #define MEMORY_INVALID_STATE	0
  #define MEMORY_POWER_ON_STATE	1
  #define MEMORY_POWER_OFF_STATE	2
4be44fcd3   Len Brown   [ACPI] Lindent al...
50
51
  static int acpi_memory_device_add(struct acpi_device *device);
  static int acpi_memory_device_remove(struct acpi_device *device, int type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
53
54
55
56
57
  static const struct acpi_device_id memory_device_ids[] = {
  	{ACPI_MEMORY_DEVICE_HID, 0},
  	{"", 0},
  };
  MODULE_DEVICE_TABLE(acpi, memory_device_ids);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  static struct acpi_driver acpi_memory_device_driver = {
c2b6705b7   Len Brown   ACPI: fix acpi_dr...
59
  	.name = "acpi_memhotplug",
4be44fcd3   Len Brown   [ACPI] Lindent al...
60
  	.class = ACPI_MEMORY_DEVICE_CLASS,
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
61
  	.ids = memory_device_ids,
4be44fcd3   Len Brown   [ACPI] Lindent al...
62
63
64
65
  	.ops = {
  		.add = acpi_memory_device_add,
  		.remove = acpi_memory_device_remove,
  		},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  };
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
67
68
69
70
71
72
73
74
  struct acpi_memory_info {
  	struct list_head list;
  	u64 start_addr;		/* Memory Range start physical addr */
  	u64 length;		/* Memory Range length */
  	unsigned short caching;	/* memory cache attribute */
  	unsigned short write_protect;	/* memory read/write attribute */
  	unsigned int enabled:1;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  struct acpi_memory_device {
3b74863df   Patrick Mochel   ACPI: acpi_memhot...
76
  	struct acpi_device * device;
4be44fcd3   Len Brown   [ACPI] Lindent al...
77
  	unsigned int state;	/* State of the memory device */
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
78
  	struct list_head res_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  };
887b95931   Yasunori Goto   [PATCH] acpi memo...
80
  static int acpi_hotmem_initialized;
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  static acpi_status
  acpi_memory_get_resource(struct acpi_resource *resource, void *context)
  {
  	struct acpi_memory_device *mem_device = context;
  	struct acpi_resource_address64 address64;
  	struct acpi_memory_info *info, *new;
  	acpi_status status;
  
  	status = acpi_resource_to_address64(resource, &address64);
  	if (ACPI_FAILURE(status) ||
  	    (address64.resource_type != ACPI_MEMORY_RANGE))
  		return AE_OK;
  
  	list_for_each_entry(info, &mem_device->res_list, list) {
  		/* Can we combine the resource range information? */
  		if ((info->caching == address64.info.mem.caching) &&
  		    (info->write_protect == address64.info.mem.write_protect) &&
  		    (info->start_addr + info->length == address64.minimum)) {
  			info->length += address64.address_length;
  			return AE_OK;
  		}
  	}
  
  	new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
  	if (!new)
  		return AE_ERROR;
  
  	INIT_LIST_HEAD(&new->list);
  	new->caching = address64.info.mem.caching;
  	new->write_protect = address64.info.mem.write_protect;
  	new->start_addr = address64.minimum;
  	new->length = address64.address_length;
  	list_add_tail(&new->list, &mem_device->res_list);
  
  	return AE_OK;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
  static int
  acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
  {
  	acpi_status status;
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
121
  	struct acpi_memory_info *info, *n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123

5d2870faa   KAMEZAWA Hiroyuki   [PATCH] memory ho...
124
125
  	if (!list_empty(&mem_device->res_list))
  		return 0;
b86327852   Patrick Mochel   ACPI: acpi_memhot...
126
  	status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
127
128
129
130
  				     acpi_memory_get_resource, mem_device);
  	if (ACPI_FAILURE(status)) {
  		list_for_each_entry_safe(info, n, &mem_device->res_list, list)
  			kfree(info);
5d2870faa   KAMEZAWA Hiroyuki   [PATCH] memory ho...
131
  		INIT_LIST_HEAD(&mem_device->res_list);
d550d98d3   Patrick Mochel   ACPI: delete trac...
132
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  	}
d550d98d3   Patrick Mochel   ACPI: delete trac...
134
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
  }
  
  static int
  acpi_memory_get_device(acpi_handle handle,
4be44fcd3   Len Brown   [ACPI] Lindent al...
139
  		       struct acpi_memory_device **mem_device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
  {
  	acpi_status status;
  	acpi_handle phandle;
  	struct acpi_device *device = NULL;
  	struct acpi_device *pdevice = NULL;
aa7b2b2e9   Zhao Yakui   ACPI: Don't treat...
145
  	int result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
  
  	if (!acpi_bus_get_device(handle, &device) && device)
  		goto end;
  
  	status = acpi_get_parent(handle, &phandle);
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
153
  		ACPI_EXCEPTION((AE_INFO, status, "Cannot find acpi parent"));
d550d98d3   Patrick Mochel   ACPI: delete trac...
154
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
  	}
  
  	/* Get the parent device */
aa7b2b2e9   Zhao Yakui   ACPI: Don't treat...
158
159
160
  	result = acpi_bus_get_device(phandle, &pdevice);
  	if (result) {
  		printk(KERN_WARNING PREFIX "Cannot get acpi bus device");
d550d98d3   Patrick Mochel   ACPI: delete trac...
161
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
166
167
  	}
  
  	/*
  	 * Now add the notified device.  This creates the acpi_device
  	 * and invokes .add function
  	 */
aa7b2b2e9   Zhao Yakui   ACPI: Don't treat...
168
169
170
  	result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
  	if (result) {
  		printk(KERN_WARNING PREFIX "Cannot add acpi bus");
d550d98d3   Patrick Mochel   ACPI: delete trac...
171
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
173
        end:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
  	*mem_device = acpi_driver_data(device);
  	if (!(*mem_device)) {
4be44fcd3   Len Brown   [ACPI] Lindent al...
176
177
  		printk(KERN_ERR "
   driver data not found");
d550d98d3   Patrick Mochel   ACPI: delete trac...
178
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  	}
d550d98d3   Patrick Mochel   ACPI: delete trac...
180
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
182
  static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  {
27663c585   Matthew Wilcox   ACPI: Change acpi...
184
  	unsigned long long current_status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
  
  	/* Get device present/absent information from the _STA */
b86327852   Patrick Mochel   ACPI: acpi_memhot...
187
  	if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA",
4be44fcd3   Len Brown   [ACPI] Lindent al...
188
  					       NULL, &current_status)))
d550d98d3   Patrick Mochel   ACPI: delete trac...
189
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
  	/*
  	 * Check for device status. Device should be
  	 * present/enabled/functioning.
  	 */
a0bd4ac49   Bjorn Helgaas   ACPI: Remove dupl...
194
195
196
  	if (!((current_status & ACPI_STA_DEVICE_PRESENT)
  	      && (current_status & ACPI_STA_DEVICE_ENABLED)
  	      && (current_status & ACPI_STA_DEVICE_FUNCTIONING)))
d550d98d3   Patrick Mochel   ACPI: delete trac...
197
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198

d550d98d3   Patrick Mochel   ACPI: delete trac...
199
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
201
  static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
  {
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
203
204
  	int result, num_enabled = 0;
  	struct acpi_memory_info *info;
1e3590e2e   Yasunori Goto   [PATCH] pgdat all...
205
  	int node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
  
  	/* Get the range from the _CRS */
  	result = acpi_memory_get_device_resources(mem_device);
  	if (result) {
6468463ab   Len Brown   ACPI: un-export A...
211
212
  		printk(KERN_ERR PREFIX "get_device_resources failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
  		mem_device->state = MEMORY_INVALID_STATE;
  		return result;
  	}
b86327852   Patrick Mochel   ACPI: acpi_memhot...
216
  	node = acpi_get_node(mem_device->device->handle);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
  	/*
  	 * Tell the VM there is more memory here...
  	 * Note: Assume that this function returns zero on success
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
220
221
  	 * We don't have memory-hot-add rollback function,now.
  	 * (i.e. memory-hot-remove function)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  	 */
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
223
  	list_for_each_entry(info, &mem_device->res_list, list) {
fa25d8d6d   KAMEZAWA Hiroyuki   [PATCH] memory ho...
224
  		if (info->enabled) { /* just sanity check...*/
dd56a8e36   Yasunori Goto   [PATCH] Catch not...
225
226
227
  			num_enabled++;
  			continue;
  		}
5d2619fca   Zhao Yakui   ACPI: Ingore the ...
228
229
230
231
232
233
  		/*
  		 * If the memory block size is zero, please ignore it.
  		 * Don't try to do the following memory hotplug flowchart.
  		 */
  		if (!info->length)
  			continue;
8c2676a58   Keith Mannthey   [PATCH] hot-add-m...
234
235
  		if (node < 0)
  			node = memory_add_physaddr_to_nid(info->start_addr);
bc02af93d   Yasunori Goto   [PATCH] pgdat all...
236
  		result = add_memory(node, info->start_addr, info->length);
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
237
238
239
240
241
242
  		if (result)
  			continue;
  		info->enabled = 1;
  		num_enabled++;
  	}
  	if (!num_enabled) {
0a1f1ab8d   Andrew Morton   ACPI: fixup memho...
243
244
  		printk(KERN_ERR PREFIX "add_memory failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  		mem_device->state = MEMORY_INVALID_STATE;
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
246
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  	}
5d2619fca   Zhao Yakui   ACPI: Ingore the ...
248
249
250
251
252
253
254
255
256
  	/*
  	 * Sometimes the memory device will contain several memory blocks.
  	 * When one memory block is hot-added to the system memory, it will
  	 * be regarded as a success.
  	 * Otherwise if the last memory block can't be hot-added to the system
  	 * memory, it will be failure and the memory device can't be bound with
  	 * driver.
  	 */
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
258
  static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
  {
  	acpi_status status;
4be44fcd3   Len Brown   [ACPI] Lindent al...
261
  	struct acpi_object_list arg_list;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  	union acpi_object arg;
27663c585   Matthew Wilcox   ACPI: Change acpi...
263
  	unsigned long long current_status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
269
270
  
  	/* Issue the _EJ0 command */
  	arg_list.count = 1;
  	arg_list.pointer = &arg;
  	arg.type = ACPI_TYPE_INTEGER;
  	arg.integer.value = 1;
b86327852   Patrick Mochel   ACPI: acpi_memhot...
271
  	status = acpi_evaluate_object(mem_device->device->handle,
4be44fcd3   Len Brown   [ACPI] Lindent al...
272
  				      "_EJ0", &arg_list, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
  	/* Return on _EJ0 failure */
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
275
  		ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed"));
d550d98d3   Patrick Mochel   ACPI: delete trac...
276
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
  	}
  
  	/* Evalute _STA to check if the device is disabled */
b86327852   Patrick Mochel   ACPI: acpi_memhot...
280
  	status = acpi_evaluate_integer(mem_device->device->handle, "_STA",
4be44fcd3   Len Brown   [ACPI] Lindent al...
281
  				       NULL, &current_status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  	if (ACPI_FAILURE(status))
d550d98d3   Patrick Mochel   ACPI: delete trac...
283
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  
  	/* Check for device status.  Device should be disabled */
a0bd4ac49   Bjorn Helgaas   ACPI: Remove dupl...
286
  	if (current_status & ACPI_STA_DEVICE_ENABLED)
d550d98d3   Patrick Mochel   ACPI: delete trac...
287
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288

d550d98d3   Patrick Mochel   ACPI: delete trac...
289
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
291
  static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  {
  	int result;
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
294
  	struct acpi_memory_info *info, *n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
  
  	/*
  	 * Ask the VM to offline this memory range.
  	 * Note: Assume that this function returns zero on success
  	 */
9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
301
302
303
304
305
306
307
  	list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
  		if (info->enabled) {
  			result = remove_memory(info->start_addr, info->length);
  			if (result)
  				return result;
  		}
  		kfree(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
311
312
  	}
  
  	/* Power-off and eject the device */
  	result = acpi_memory_powerdown_device(mem_device);
  	if (result) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
316
317
318
319
320
  		/* Set the status of the device to invalid */
  		mem_device->state = MEMORY_INVALID_STATE;
  		return result;
  	}
  
  	mem_device->state = MEMORY_POWER_OFF_STATE;
  	return result;
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
321
  static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
  {
  	struct acpi_memory_device *mem_device;
  	struct acpi_device *device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
328
  
  	switch (event) {
  	case ACPI_NOTIFY_BUS_CHECK:
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
329
330
331
  				  "
  Received BUS CHECK notification for device
  "));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
  		/* Fall Through */
  	case ACPI_NOTIFY_DEVICE_CHECK:
  		if (event == ACPI_NOTIFY_DEVICE_CHECK)
  			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
336
337
338
  					  "
  Received DEVICE CHECK notification for device
  "));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  		if (acpi_memory_get_device(handle, &mem_device)) {
6468463ab   Len Brown   ACPI: un-export A...
340
341
  			printk(KERN_ERR PREFIX "Cannot find driver data
  ");
d550d98d3   Patrick Mochel   ACPI: delete trac...
342
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
  		}
  
  		if (!acpi_memory_check_device(mem_device)) {
  			if (acpi_memory_enable_device(mem_device))
6468463ab   Len Brown   ACPI: un-export A...
347
348
349
  				printk(KERN_ERR PREFIX
  					    "Cannot enable memory device
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
  		}
  		break;
  	case ACPI_NOTIFY_EJECT_REQUEST:
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
354
355
356
  				  "
  Received EJECT REQUEST notification for device
  "));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
  
  		if (acpi_bus_get_device(handle, &device)) {
6468463ab   Len Brown   ACPI: un-export A...
359
360
  			printk(KERN_ERR PREFIX "Device doesn't exist
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
364
  			break;
  		}
  		mem_device = acpi_driver_data(device);
  		if (!mem_device) {
6468463ab   Len Brown   ACPI: un-export A...
365
366
  			printk(KERN_ERR PREFIX "Driver Data is NULL
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
  			break;
  		}
  
  		/*
  		 * Currently disabling memory device from kernel mode
  		 * TBD: Can also be disabled from user mode scripts
  		 * TBD: Can also be disabled by Callback registration
4be44fcd3   Len Brown   [ACPI] Lindent al...
374
  		 *      with generic sysfs driver
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
  		 */
  		if (acpi_memory_disable_device(mem_device))
6468463ab   Len Brown   ACPI: un-export A...
377
378
379
  			printk(KERN_ERR PREFIX
  				    "Disable memory device
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
  		/*
  		 * TBD: Invoke acpi_bus_remove to cleanup data structures
  		 */
  		break;
  	default:
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
386
387
  				  "Unsupported event [0x%x]
  ", event));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
  		break;
  	}
d550d98d3   Patrick Mochel   ACPI: delete trac...
390
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
392
  static int acpi_memory_device_add(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
  {
  	int result;
  	struct acpi_memory_device *mem_device = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
  
  	if (!device)
d550d98d3   Patrick Mochel   ACPI: delete trac...
398
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399

36bcbec7c   Burman Yan   ACPI: replace kma...
400
  	mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  	if (!mem_device)
d550d98d3   Patrick Mochel   ACPI: delete trac...
402
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403

9ac023989   KAMEZAWA Hiroyuki   [PATCH] acpi memo...
404
  	INIT_LIST_HEAD(&mem_device->res_list);
3b74863df   Patrick Mochel   ACPI: acpi_memhot...
405
  	mem_device->device = device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
  	sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
  	sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
db89b4f0d   Pavel Machek   ACPI: catch calls...
408
  	device->driver_data = mem_device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
413
  
  	/* Get the range from the _CRS */
  	result = acpi_memory_get_device_resources(mem_device);
  	if (result) {
  		kfree(mem_device);
d550d98d3   Patrick Mochel   ACPI: delete trac...
414
  		return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
  	}
  
  	/* Set the device state */
  	mem_device->state = MEMORY_POWER_ON_STATE;
6cbe44cd8   Yasunori Goto   [PATCH] Change lo...
419
420
  	printk(KERN_DEBUG "%s 
  ", acpi_device_name(device));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

887b95931   Yasunori Goto   [PATCH] acpi memo...
422
423
424
425
426
427
428
429
  	/*
  	 * Early boot code has recognized memory area by EFI/E820.
  	 * If DSDT shows these memory devices on boot, hotplug is not necessary
  	 * for them. So, it just returns until completion of this driver's
  	 * start up.
  	 */
  	if (!acpi_hotmem_initialized)
  		return 0;
1f425994f   Yasunori Goto   [PATCH] Catch not...
430
431
432
433
  	if (!acpi_memory_check_device(mem_device)) {
  		/* call add_memory func */
  		result = acpi_memory_enable_device(mem_device);
  		if (result)
55ac9a018   Lin Ming   ACPI: replace ACP...
434
435
436
  			printk(KERN_ERR PREFIX
  				"Error in acpi_memory_enable_device
  ");
1f425994f   Yasunori Goto   [PATCH] Catch not...
437
  	}
d120cfb54   Len Brown   merge linus into ...
438
  	return result;
1f425994f   Yasunori Goto   [PATCH] Catch not...
439
  }
80f20fef6   Bjorn Helgaas   ACPI: memory hotp...
440
441
442
443
444
445
446
447
448
449
450
451
452
  static int acpi_memory_device_remove(struct acpi_device *device, int type)
  {
  	struct acpi_memory_device *mem_device = NULL;
  
  
  	if (!device || !acpi_driver_data(device))
  		return -EINVAL;
  
  	mem_device = acpi_driver_data(device);
  	kfree(mem_device);
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
  /*
   * Helper function to check for memory device
   */
4be44fcd3   Len Brown   [ACPI] Lindent al...
456
  static acpi_status is_memory_device(acpi_handle handle)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
  {
  	char *hardware_id;
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  	struct acpi_device_info *info;
15b8dd53f   Bob Moore   ACPICA: Major upd...
461
  	status = acpi_get_object_info(handle, &info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  	if (ACPI_FAILURE(status))
d550d98d3   Patrick Mochel   ACPI: delete trac...
463
  		return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  	if (!(info->valid & ACPI_VALID_HID)) {
15b8dd53f   Bob Moore   ACPICA: Major upd...
466
  		kfree(info);
d550d98d3   Patrick Mochel   ACPI: delete trac...
467
  		return AE_ERROR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  	}
15b8dd53f   Bob Moore   ACPICA: Major upd...
469
  	hardware_id = info->hardware_id.string;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	if ((hardware_id == NULL) ||
4be44fcd3   Len Brown   [ACPI] Lindent al...
471
  	    (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  		status = AE_ERROR;
15b8dd53f   Bob Moore   ACPICA: Major upd...
473
  	kfree(info);
d550d98d3   Patrick Mochel   ACPI: delete trac...
474
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
  }
  
  static acpi_status
4be44fcd3   Len Brown   [ACPI] Lindent al...
478
479
  acpi_memory_register_notify_handler(acpi_handle handle,
  				    u32 level, void *ctxt, void **retv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
  {
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  
  	status = is_memory_device(handle);
07dd4855e   Yasunori Goto   ACPI: memory hotp...
484
  	if (ACPI_FAILURE(status))
d550d98d3   Patrick Mochel   ACPI: delete trac...
485
  		return AE_OK;	/* continue */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
  
  	status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
4be44fcd3   Len Brown   [ACPI] Lindent al...
488
  					     acpi_memory_device_notify, NULL);
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
489
  	/* continue */
d550d98d3   Patrick Mochel   ACPI: delete trac...
490
  	return AE_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
  }
  
  static acpi_status
4be44fcd3   Len Brown   [ACPI] Lindent al...
494
495
  acpi_memory_deregister_notify_handler(acpi_handle handle,
  				      u32 level, void *ctxt, void **retv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
  {
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
  
  	status = is_memory_device(handle);
07dd4855e   Yasunori Goto   ACPI: memory hotp...
500
  	if (ACPI_FAILURE(status))
d550d98d3   Patrick Mochel   ACPI: delete trac...
501
  		return AE_OK;	/* continue */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
  
  	status = acpi_remove_notify_handler(handle,
4be44fcd3   Len Brown   [ACPI] Lindent al...
504
505
  					    ACPI_SYSTEM_NOTIFY,
  					    acpi_memory_device_notify);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506

d550d98d3   Patrick Mochel   ACPI: delete trac...
507
  	return AE_OK;	/* continue */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
509
  static int __init acpi_memory_device_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
  {
  	int result;
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
516
  
  	result = acpi_bus_register_driver(&acpi_memory_device_driver);
  
  	if (result < 0)
d550d98d3   Patrick Mochel   ACPI: delete trac...
517
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
  
  	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
4be44fcd3   Len Brown   [ACPI] Lindent al...
520
  				     ACPI_UINT32_MAX,
2263576cf   Lin Ming   ACPICA: Add post-...
521
  				     acpi_memory_register_notify_handler, NULL,
4be44fcd3   Len Brown   [ACPI] Lindent al...
522
  				     NULL, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523

4be44fcd3   Len Brown   [ACPI] Lindent al...
524
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
525
  		ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
  		acpi_bus_unregister_driver(&acpi_memory_device_driver);
d550d98d3   Patrick Mochel   ACPI: delete trac...
527
  		return -ENODEV;
4be44fcd3   Len Brown   [ACPI] Lindent al...
528
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529

887b95931   Yasunori Goto   [PATCH] acpi memo...
530
  	acpi_hotmem_initialized = 1;
d550d98d3   Patrick Mochel   ACPI: delete trac...
531
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
533
  static void __exit acpi_memory_device_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
  {
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
540
541
  
  	/*
  	 * Adding this to un-install notification handlers for all the device
  	 * handles.
  	 */
  	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
4be44fcd3   Len Brown   [ACPI] Lindent al...
542
  				     ACPI_UINT32_MAX,
2263576cf   Lin Ming   ACPICA: Add post-...
543
  				     acpi_memory_deregister_notify_handler, NULL,
4be44fcd3   Len Brown   [ACPI] Lindent al...
544
  				     NULL, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545

4be44fcd3   Len Brown   [ACPI] Lindent al...
546
  	if (ACPI_FAILURE(status))
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
547
  		ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
  
  	acpi_bus_unregister_driver(&acpi_memory_device_driver);
d550d98d3   Patrick Mochel   ACPI: delete trac...
550
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
  }
  
  module_init(acpi_memory_device_init);
  module_exit(acpi_memory_device_exit);