aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/cpu.c46
-rw-r--r--drivers/base/iommu.c100
-rw-r--r--drivers/base/memory.c19
-rw-r--r--drivers/base/node.c107
-rw-r--r--drivers/base/topology.c4
6 files changed, 266 insertions, 11 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index c66637392bbc..b5b8ba512b28 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_FW_LOADER) += firmware_class.o
11obj-$(CONFIG_NUMA) += node.o 11obj-$(CONFIG_NUMA) += node.o
12obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o 12obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
13obj-$(CONFIG_SMP) += topology.o 13obj-$(CONFIG_SMP) += topology.o
14obj-$(CONFIG_IOMMU_API) += iommu.o
14ifeq ($(CONFIG_SYSFS),y) 15ifeq ($(CONFIG_SYSFS),y)
15obj-$(CONFIG_MODULES) += module.o 16obj-$(CONFIG_MODULES) += module.o
16endif 17endif
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 64f5d54f7edc..719ee5c1c8d9 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -109,7 +109,7 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
109 */ 109 */
110static ssize_t print_cpus_map(char *buf, cpumask_t *map) 110static ssize_t print_cpus_map(char *buf, cpumask_t *map)
111{ 111{
112 int n = cpulist_scnprintf(buf, PAGE_SIZE-2, *map); 112 int n = cpulist_scnprintf(buf, PAGE_SIZE-2, map);
113 113
114 buf[n++] = '\n'; 114 buf[n++] = '\n';
115 buf[n] = '\0'; 115 buf[n] = '\0';
@@ -128,10 +128,54 @@ print_cpus_func(online);
128print_cpus_func(possible); 128print_cpus_func(possible);
129print_cpus_func(present); 129print_cpus_func(present);
130 130
131/*
132 * Print values for NR_CPUS and offlined cpus
133 */
134static ssize_t print_cpus_kernel_max(struct sysdev_class *class, char *buf)
135{
136 int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1);
137 return n;
138}
139static SYSDEV_CLASS_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
140
141/* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */
142unsigned int total_cpus;
143
144static ssize_t print_cpus_offline(struct sysdev_class *class, char *buf)
145{
146 int n = 0, len = PAGE_SIZE-2;
147 cpumask_var_t offline;
148
149 /* display offline cpus < nr_cpu_ids */
150 if (!alloc_cpumask_var(&offline, GFP_KERNEL))
151 return -ENOMEM;
152 cpumask_complement(offline, cpu_online_mask);
153 n = cpulist_scnprintf(buf, len, offline);
154 free_cpumask_var(offline);
155
156 /* display offline cpus >= nr_cpu_ids */
157 if (total_cpus && nr_cpu_ids < total_cpus) {
158 if (n && n < len)
159 buf[n++] = ',';
160
161 if (nr_cpu_ids == total_cpus-1)
162 n += snprintf(&buf[n], len - n, "%d", nr_cpu_ids);
163 else
164 n += snprintf(&buf[n], len - n, "%d-%d",
165 nr_cpu_ids, total_cpus-1);
166 }
167
168 n += snprintf(&buf[n], len - n, "\n");
169 return n;
170}
171static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL);
172
131static struct sysdev_class_attribute *cpu_state_attr[] = { 173static struct sysdev_class_attribute *cpu_state_attr[] = {
132 &attr_online_map, 174 &attr_online_map,
133 &attr_possible_map, 175 &attr_possible_map,
134 &attr_present_map, 176 &attr_present_map,
177 &attr_kernel_max,
178 &attr_offline,
135}; 179};
136 180
137static int cpu_states_init(void) 181static int cpu_states_init(void)
diff --git a/drivers/base/iommu.c b/drivers/base/iommu.c
new file mode 100644
index 000000000000..5e039d4f877c
--- /dev/null
+++ b/drivers/base/iommu.c
@@ -0,0 +1,100 @@
1/*
2 * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
3 * Author: Joerg Roedel <joerg.roedel@amd.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published
7 * by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#include <linux/bug.h>
20#include <linux/types.h>
21#include <linux/errno.h>
22#include <linux/iommu.h>
23
24static struct iommu_ops *iommu_ops;
25
26void register_iommu(struct iommu_ops *ops)
27{
28 if (iommu_ops)
29 BUG();
30
31 iommu_ops = ops;
32}
33
34bool iommu_found()
35{
36 return iommu_ops != NULL;
37}
38EXPORT_SYMBOL_GPL(iommu_found);
39
40struct iommu_domain *iommu_domain_alloc(void)
41{
42 struct iommu_domain *domain;
43 int ret;
44
45 domain = kmalloc(sizeof(*domain), GFP_KERNEL);
46 if (!domain)
47 return NULL;
48
49 ret = iommu_ops->domain_init(domain);
50 if (ret)
51 goto out_free;
52
53 return domain;
54
55out_free:
56 kfree(domain);
57
58 return NULL;
59}
60EXPORT_SYMBOL_GPL(iommu_domain_alloc);
61
62void iommu_domain_free(struct iommu_domain *domain)
63{
64 iommu_ops->domain_destroy(domain);
65 kfree(domain);
66}
67EXPORT_SYMBOL_GPL(iommu_domain_free);
68
69int iommu_attach_device(struct iommu_domain *domain, struct device *dev)
70{
71 return iommu_ops->attach_dev(domain, dev);
72}
73EXPORT_SYMBOL_GPL(iommu_attach_device);
74
75void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
76{
77 iommu_ops->detach_dev(domain, dev);
78}
79EXPORT_SYMBOL_GPL(iommu_detach_device);
80
81int iommu_map_range(struct iommu_domain *domain, unsigned long iova,
82 phys_addr_t paddr, size_t size, int prot)
83{
84 return iommu_ops->map(domain, iova, paddr, size, prot);
85}
86EXPORT_SYMBOL_GPL(iommu_map_range);
87
88void iommu_unmap_range(struct iommu_domain *domain, unsigned long iova,
89 size_t size)
90{
91 iommu_ops->unmap(domain, iova, size);
92}
93EXPORT_SYMBOL_GPL(iommu_unmap_range);
94
95phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
96 unsigned long iova)
97{
98 return iommu_ops->iova_to_phys(domain, iova);
99}
100EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 5260e9e0df48..989429cfed88 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -347,8 +347,9 @@ static inline int memory_probe_init(void)
347 * section belongs to... 347 * section belongs to...
348 */ 348 */
349 349
350static int add_memory_block(unsigned long node_id, struct mem_section *section, 350static int add_memory_block(int nid, struct mem_section *section,
351 unsigned long state, int phys_device) 351 unsigned long state, int phys_device,
352 enum mem_add_context context)
352{ 353{
353 struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL); 354 struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL);
354 int ret = 0; 355 int ret = 0;
@@ -370,6 +371,10 @@ static int add_memory_block(unsigned long node_id, struct mem_section *section,
370 ret = mem_create_simple_file(mem, phys_device); 371 ret = mem_create_simple_file(mem, phys_device);
371 if (!ret) 372 if (!ret)
372 ret = mem_create_simple_file(mem, removable); 373 ret = mem_create_simple_file(mem, removable);
374 if (!ret) {
375 if (context == HOTPLUG)
376 ret = register_mem_sect_under_node(mem, nid);
377 }
373 378
374 return ret; 379 return ret;
375} 380}
@@ -382,7 +387,7 @@ static int add_memory_block(unsigned long node_id, struct mem_section *section,
382 * 387 *
383 * This could be made generic for all sysdev classes. 388 * This could be made generic for all sysdev classes.
384 */ 389 */
385static struct memory_block *find_memory_block(struct mem_section *section) 390struct memory_block *find_memory_block(struct mem_section *section)
386{ 391{
387 struct kobject *kobj; 392 struct kobject *kobj;
388 struct sys_device *sysdev; 393 struct sys_device *sysdev;
@@ -411,6 +416,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
411 struct memory_block *mem; 416 struct memory_block *mem;
412 417
413 mem = find_memory_block(section); 418 mem = find_memory_block(section);
419 unregister_mem_sect_under_nodes(mem);
414 mem_remove_simple_file(mem, phys_index); 420 mem_remove_simple_file(mem, phys_index);
415 mem_remove_simple_file(mem, state); 421 mem_remove_simple_file(mem, state);
416 mem_remove_simple_file(mem, phys_device); 422 mem_remove_simple_file(mem, phys_device);
@@ -424,9 +430,9 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
424 * need an interface for the VM to add new memory regions, 430 * need an interface for the VM to add new memory regions,
425 * but without onlining it. 431 * but without onlining it.
426 */ 432 */
427int register_new_memory(struct mem_section *section) 433int register_new_memory(int nid, struct mem_section *section)
428{ 434{
429 return add_memory_block(0, section, MEM_OFFLINE, 0); 435 return add_memory_block(nid, section, MEM_OFFLINE, 0, HOTPLUG);
430} 436}
431 437
432int unregister_memory_section(struct mem_section *section) 438int unregister_memory_section(struct mem_section *section)
@@ -458,7 +464,8 @@ int __init memory_dev_init(void)
458 for (i = 0; i < NR_MEM_SECTIONS; i++) { 464 for (i = 0; i < NR_MEM_SECTIONS; i++) {
459 if (!present_section_nr(i)) 465 if (!present_section_nr(i))
460 continue; 466 continue;
461 err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0); 467 err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE,
468 0, BOOT);
462 if (!ret) 469 if (!ret)
463 ret = err; 470 ret = err;
464 } 471 }
diff --git a/drivers/base/node.c b/drivers/base/node.c
index f5207090885a..43fa90b837ee 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -6,6 +6,7 @@
6#include <linux/module.h> 6#include <linux/module.h>
7#include <linux/init.h> 7#include <linux/init.h>
8#include <linux/mm.h> 8#include <linux/mm.h>
9#include <linux/memory.h>
9#include <linux/node.h> 10#include <linux/node.h>
10#include <linux/hugetlb.h> 11#include <linux/hugetlb.h>
11#include <linux/cpumask.h> 12#include <linux/cpumask.h>
@@ -30,8 +31,8 @@ static ssize_t node_read_cpumap(struct sys_device *dev, int type, char *buf)
30 BUILD_BUG_ON((NR_CPUS/32 * 9) > (PAGE_SIZE-1)); 31 BUILD_BUG_ON((NR_CPUS/32 * 9) > (PAGE_SIZE-1));
31 32
32 len = type? 33 len = type?
33 cpulist_scnprintf(buf, PAGE_SIZE-2, *mask): 34 cpulist_scnprintf(buf, PAGE_SIZE-2, mask) :
34 cpumask_scnprintf(buf, PAGE_SIZE-2, *mask); 35 cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
35 buf[len++] = '\n'; 36 buf[len++] = '\n';
36 buf[len] = '\0'; 37 buf[len] = '\0';
37 return len; 38 return len;
@@ -248,6 +249,105 @@ int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
248 return 0; 249 return 0;
249} 250}
250 251
252#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
253#define page_initialized(page) (page->lru.next)
254
255static int get_nid_for_pfn(unsigned long pfn)
256{
257 struct page *page;
258
259 if (!pfn_valid_within(pfn))
260 return -1;
261 page = pfn_to_page(pfn);
262 if (!page_initialized(page))
263 return -1;
264 return pfn_to_nid(pfn);
265}
266
267/* register memory section under specified node if it spans that node */
268int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
269{
270 unsigned long pfn, sect_start_pfn, sect_end_pfn;
271
272 if (!mem_blk)
273 return -EFAULT;
274 if (!node_online(nid))
275 return 0;
276 sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
277 sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
278 for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
279 int page_nid;
280
281 page_nid = get_nid_for_pfn(pfn);
282 if (page_nid < 0)
283 continue;
284 if (page_nid != nid)
285 continue;
286 return sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj,
287 &mem_blk->sysdev.kobj,
288 kobject_name(&mem_blk->sysdev.kobj));
289 }
290 /* mem section does not span the specified node */
291 return 0;
292}
293
294/* unregister memory section under all nodes that it spans */
295int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
296{
297 nodemask_t unlinked_nodes;
298 unsigned long pfn, sect_start_pfn, sect_end_pfn;
299
300 if (!mem_blk)
301 return -EFAULT;
302 nodes_clear(unlinked_nodes);
303 sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
304 sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
305 for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
306 unsigned int nid;
307
308 nid = get_nid_for_pfn(pfn);
309 if (nid < 0)
310 continue;
311 if (!node_online(nid))
312 continue;
313 if (node_test_and_set(nid, unlinked_nodes))
314 continue;
315 sysfs_remove_link(&node_devices[nid].sysdev.kobj,
316 kobject_name(&mem_blk->sysdev.kobj));
317 }
318 return 0;
319}
320
321static int link_mem_sections(int nid)
322{
323 unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
324 unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
325 unsigned long pfn;
326 int err = 0;
327
328 for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
329 unsigned long section_nr = pfn_to_section_nr(pfn);
330 struct mem_section *mem_sect;
331 struct memory_block *mem_blk;
332 int ret;
333
334 if (!present_section_nr(section_nr))
335 continue;
336 mem_sect = __nr_to_section(section_nr);
337 mem_blk = find_memory_block(mem_sect);
338 ret = register_mem_sect_under_node(mem_blk, nid);
339 if (!err)
340 err = ret;
341
342 /* discard ref obtained in find_memory_block() */
343 kobject_put(&mem_blk->sysdev.kobj);
344 }
345 return err;
346}
347#else
348static int link_mem_sections(int nid) { return 0; }
349#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
350
251int register_one_node(int nid) 351int register_one_node(int nid)
252{ 352{
253 int error = 0; 353 int error = 0;
@@ -267,6 +367,9 @@ int register_one_node(int nid)
267 if (cpu_to_node(cpu) == nid) 367 if (cpu_to_node(cpu) == nid)
268 register_cpu_under_node(cpu, nid); 368 register_cpu_under_node(cpu, nid);
269 } 369 }
370
371 /* link memory sections under this node */
372 error = link_mem_sections(nid);
270 } 373 }
271 374
272 return error; 375 return error;
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 199cd97e32e6..a8bc1cbcfa7c 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -49,8 +49,8 @@ static ssize_t show_cpumap(int type, cpumask_t *mask, char *buf)
49 49
50 if (len > 1) { 50 if (len > 1) {
51 n = type? 51 n = type?
52 cpulist_scnprintf(buf, len-2, *mask): 52 cpulist_scnprintf(buf, len-2, mask) :
53 cpumask_scnprintf(buf, len-2, *mask); 53 cpumask_scnprintf(buf, len-2, mask);
54 buf[n++] = '\n'; 54 buf[n++] = '\n';
55 buf[n] = '\0'; 55 buf[n] = '\0';
56 } 56 }