2 * xen_acpi_memhotplug.c - interface to notify Xen on memory device hotadd
4 * Copyright (C) 2008, Intel corporation
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 #include <xen/interface/platform.h>
25 #include <asm/hypervisor.h>
27 struct xen_hotmem_entry {
28 struct list_head hotmem_list;
35 struct xen_hotmem_list {
36 struct list_head list;
37 unsigned int entry_nr;
40 static struct xen_hotmem_list xen_hotmem = {
41 .list = LIST_HEAD_INIT(xen_hotmem.list)
43 static DEFINE_SPINLOCK(xen_hotmem_lock);
45 static int xen_hyper_addmem(struct xen_hotmem_entry *entry)
49 op.cmd = XENPF_mem_hotadd;
50 op.u.mem_add.spfn = entry->start >> PAGE_SHIFT;
51 op.u.mem_add.epfn = entry->end >> PAGE_SHIFT;
52 op.u.mem_add.flags = entry->flags;
53 op.u.mem_add.pxm = entry->pxm;
55 return HYPERVISOR_platform_op(&op);
58 static int add_hotmem_entry(int pxm, uint64_t start,
59 uint64_t length, uint32_t flags)
61 struct xen_hotmem_entry *entry;
63 if (pxm < 0 || !length)
66 entry = kzalloc(sizeof(struct xen_hotmem_entry), GFP_ATOMIC);
70 INIT_LIST_HEAD(&entry->hotmem_list);
72 entry->end = start + length;
76 spin_lock(&xen_hotmem_lock);
78 list_add_tail(&entry->hotmem_list, &xen_hotmem.list);
79 xen_hotmem.entry_nr++;
81 spin_unlock(&xen_hotmem_lock);
86 static int free_hotmem_entry(struct xen_hotmem_entry *entry)
88 list_del(&entry->hotmem_list);
94 static void xen_hotadd_mem_dpc(struct work_struct *work)
96 struct list_head *elem, *tmp;
97 struct xen_hotmem_entry *entry;
101 spin_lock_irqsave(&xen_hotmem_lock, flags);
102 list_for_each_safe(elem, tmp, &xen_hotmem.list) {
103 entry = list_entry(elem, struct xen_hotmem_entry, hotmem_list);
104 ret = xen_hyper_addmem(entry);
106 pr_warn("xen addmem failed with %x\n", ret);
107 free_hotmem_entry(entry);
108 xen_hotmem.entry_nr--;
110 spin_unlock_irqrestore(&xen_hotmem_lock, flags);
113 static DECLARE_WORK(xen_hotadd_mem_work, xen_hotadd_mem_dpc);
115 static int xen_acpi_get_pxm(acpi_handle h)
117 unsigned long long pxm;
120 acpi_handle phandle = h;
124 status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
125 if (ACPI_SUCCESS(status))
127 status = acpi_get_parent(handle, &phandle);
128 } while (ACPI_SUCCESS(status));
133 static int xen_hotadd_memory(struct acpi_memory_device *mem_device)
137 struct acpi_memory_info *info;
142 pxm = xen_acpi_get_pxm(mem_device->device->handle);
148 * Always return success to ACPI driver, and notify hypervisor later
149 * because hypervisor will utilize the memory in memory hotadd hypercall
151 list_for_each_entry(info, &mem_device->res_list, list) {
152 if (info->enabled) { /* just sanity check...*/
157 * If the memory block size is zero, please ignore it.
158 * Don't try to do the following memory hotplug flowchart.
163 result = add_hotmem_entry(pxm, info->start_addr,
174 schedule_work(&xen_hotadd_mem_work);
179 static int xen_hotadd_mem_init(void)
181 if (!is_initial_xendomain())
187 static void xen_hotadd_mem_exit(void)
189 flush_scheduled_work();