diff options
author | Joel H Schopp <jschopp@us.ibm.com> | 2006-05-01 15:16:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-01 21:17:46 -0400 |
commit | bed120c64eb07b6838bb758109811484af8cebba (patch) | |
tree | 884231ab38d01a2b19c6d062f5230ea8b9f5ecb3 | |
parent | 46a66eecdf7bc12562ecb492297447ed0e1ecf59 (diff) |
[PATCH] spufs: fix for CONFIG_NUMA
Based on an older patch from Mike Kravetz <kravetz@us.ibm.com>
We need to have a mem_map for high addresses in order to make fops->no_page
work on spufs mem and register files. So far, we have used the
memory_present() function during early bootup, but that did not work when
CONFIG_NUMA was enabled.
We now use the __add_pages() function to add the mem_map when loading the
spufs module, which is a lot nicer.
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Cc: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/powerpc/platforms/cell/Kconfig | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/setup.c | 78 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 72 | ||||
-rw-r--r-- | mm/memory_hotplug.c | 6 |
4 files changed, 70 insertions, 89 deletions
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index c2a3db8edb0c..6a02d51086c8 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig | |||
@@ -12,7 +12,8 @@ config SPU_FS | |||
12 | 12 | ||
13 | config SPUFS_MMAP | 13 | config SPUFS_MMAP |
14 | bool | 14 | bool |
15 | depends on SPU_FS && SPARSEMEM && !PPC_64K_PAGES | 15 | depends on SPU_FS && SPARSEMEM |
16 | select MEMORY_HOTPLUG | ||
16 | default y | 17 | default y |
17 | 18 | ||
18 | endmenu | 19 | endmenu |
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index dac5d0365fde..6574b22b3cf3 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
30 | #include <linux/root_dev.h> | 30 | #include <linux/root_dev.h> |
31 | #include <linux/console.h> | 31 | #include <linux/console.h> |
32 | #include <linux/mutex.h> | ||
33 | #include <linux/memory_hotplug.h> | ||
32 | 34 | ||
33 | #include <asm/mmu.h> | 35 | #include <asm/mmu.h> |
34 | #include <asm/processor.h> | 36 | #include <asm/processor.h> |
@@ -46,6 +48,7 @@ | |||
46 | #include <asm/cputable.h> | 48 | #include <asm/cputable.h> |
47 | #include <asm/ppc-pci.h> | 49 | #include <asm/ppc-pci.h> |
48 | #include <asm/irq.h> | 50 | #include <asm/irq.h> |
51 | #include <asm/spu.h> | ||
49 | 52 | ||
50 | #include "interrupt.h" | 53 | #include "interrupt.h" |
51 | #include "iommu.h" | 54 | #include "iommu.h" |
@@ -69,77 +72,6 @@ static void cell_show_cpuinfo(struct seq_file *m) | |||
69 | of_node_put(root); | 72 | of_node_put(root); |
70 | } | 73 | } |
71 | 74 | ||
72 | #ifdef CONFIG_SPARSEMEM | ||
73 | static int __init find_spu_node_id(struct device_node *spe) | ||
74 | { | ||
75 | unsigned int *id; | ||
76 | #ifdef CONFIG_NUMA | ||
77 | struct device_node *cpu; | ||
78 | cpu = spe->parent->parent; | ||
79 | id = (unsigned int *)get_property(cpu, "node-id", NULL); | ||
80 | #else | ||
81 | id = NULL; | ||
82 | #endif | ||
83 | return id ? *id : 0; | ||
84 | } | ||
85 | |||
86 | static void __init cell_spuprop_present(struct device_node *spe, | ||
87 | const char *prop, int early) | ||
88 | { | ||
89 | struct address_prop { | ||
90 | unsigned long address; | ||
91 | unsigned int len; | ||
92 | } __attribute__((packed)) *p; | ||
93 | int proplen; | ||
94 | |||
95 | unsigned long start_pfn, end_pfn, pfn; | ||
96 | int node_id; | ||
97 | |||
98 | p = (void*)get_property(spe, prop, &proplen); | ||
99 | WARN_ON(proplen != sizeof (*p)); | ||
100 | |||
101 | node_id = find_spu_node_id(spe); | ||
102 | |||
103 | start_pfn = p->address >> PAGE_SHIFT; | ||
104 | end_pfn = (p->address + p->len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
105 | |||
106 | /* We need to call memory_present *before* the call to sparse_init, | ||
107 | but we can initialize the page structs only *after* that call. | ||
108 | Thus, we're being called twice. */ | ||
109 | if (early) | ||
110 | memory_present(node_id, start_pfn, end_pfn); | ||
111 | else { | ||
112 | /* As the pages backing SPU LS and I/O are outside the range | ||
113 | of regular memory, their page structs were not initialized | ||
114 | by free_area_init. Do it here instead. */ | ||
115 | for (pfn = start_pfn; pfn < end_pfn; pfn++) { | ||
116 | struct page *page = pfn_to_page(pfn); | ||
117 | set_page_links(page, ZONE_DMA, node_id, pfn); | ||
118 | init_page_count(page); | ||
119 | reset_page_mapcount(page); | ||
120 | SetPageReserved(page); | ||
121 | INIT_LIST_HEAD(&page->lru); | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static void __init cell_spumem_init(int early) | ||
127 | { | ||
128 | struct device_node *node; | ||
129 | for (node = of_find_node_by_type(NULL, "spe"); | ||
130 | node; node = of_find_node_by_type(node, "spe")) { | ||
131 | cell_spuprop_present(node, "local-store", early); | ||
132 | cell_spuprop_present(node, "problem", early); | ||
133 | cell_spuprop_present(node, "priv1", early); | ||
134 | cell_spuprop_present(node, "priv2", early); | ||
135 | } | ||
136 | } | ||
137 | #else | ||
138 | static void __init cell_spumem_init(int early) | ||
139 | { | ||
140 | } | ||
141 | #endif | ||
142 | |||
143 | static void cell_progress(char *s, unsigned short hex) | 75 | static void cell_progress(char *s, unsigned short hex) |
144 | { | 76 | { |
145 | printk("*** %04x : %s\n", hex, s ? s : ""); | 77 | printk("*** %04x : %s\n", hex, s ? s : ""); |
@@ -172,8 +104,6 @@ static void __init cell_setup_arch(void) | |||
172 | #endif | 104 | #endif |
173 | 105 | ||
174 | mmio_nvram_init(); | 106 | mmio_nvram_init(); |
175 | |||
176 | cell_spumem_init(0); | ||
177 | } | 107 | } |
178 | 108 | ||
179 | /* | 109 | /* |
@@ -189,8 +119,6 @@ static void __init cell_init_early(void) | |||
189 | 119 | ||
190 | ppc64_interrupt_controller = IC_CELL_PIC; | 120 | ppc64_interrupt_controller = IC_CELL_PIC; |
191 | 121 | ||
192 | cell_spumem_init(1); | ||
193 | |||
194 | DBG(" <- cell_init_early()\n"); | 122 | DBG(" <- cell_init_early()\n"); |
195 | } | 123 | } |
196 | 124 | ||
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index ef47a6239d48..b788e165c557 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -520,6 +520,56 @@ void spu_irq_setaffinity(struct spu *spu, int cpu) | |||
520 | } | 520 | } |
521 | EXPORT_SYMBOL_GPL(spu_irq_setaffinity); | 521 | EXPORT_SYMBOL_GPL(spu_irq_setaffinity); |
522 | 522 | ||
523 | static int __init find_spu_node_id(struct device_node *spe) | ||
524 | { | ||
525 | unsigned int *id; | ||
526 | struct device_node *cpu; | ||
527 | cpu = spe->parent->parent; | ||
528 | id = (unsigned int *)get_property(cpu, "node-id", NULL); | ||
529 | return id ? *id : 0; | ||
530 | } | ||
531 | |||
532 | static int __init cell_spuprop_present(struct device_node *spe, | ||
533 | const char *prop) | ||
534 | { | ||
535 | static DEFINE_MUTEX(add_spumem_mutex); | ||
536 | |||
537 | struct address_prop { | ||
538 | unsigned long address; | ||
539 | unsigned int len; | ||
540 | } __attribute__((packed)) *p; | ||
541 | int proplen; | ||
542 | |||
543 | unsigned long start_pfn, nr_pages; | ||
544 | int node_id; | ||
545 | struct pglist_data *pgdata; | ||
546 | struct zone *zone; | ||
547 | int ret; | ||
548 | |||
549 | p = (void*)get_property(spe, prop, &proplen); | ||
550 | WARN_ON(proplen != sizeof (*p)); | ||
551 | |||
552 | start_pfn = p->address >> PAGE_SHIFT; | ||
553 | nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
554 | |||
555 | /* | ||
556 | * XXX need to get the correct NUMA node in here. This may | ||
557 | * be different from the spe::node_id property, e.g. when | ||
558 | * the host firmware is not NUMA aware. | ||
559 | */ | ||
560 | node_id = 0; | ||
561 | |||
562 | pgdata = NODE_DATA(node_id); | ||
563 | zone = pgdata->node_zones; | ||
564 | |||
565 | /* XXX rethink locking here */ | ||
566 | mutex_lock(&add_spumem_mutex); | ||
567 | ret = __add_pages(zone, start_pfn, nr_pages); | ||
568 | mutex_unlock(&add_spumem_mutex); | ||
569 | |||
570 | return ret; | ||
571 | } | ||
572 | |||
523 | static void __iomem * __init map_spe_prop(struct device_node *n, | 573 | static void __iomem * __init map_spe_prop(struct device_node *n, |
524 | const char *name) | 574 | const char *name) |
525 | { | 575 | { |
@@ -530,6 +580,8 @@ static void __iomem * __init map_spe_prop(struct device_node *n, | |||
530 | 580 | ||
531 | void *p; | 581 | void *p; |
532 | int proplen; | 582 | int proplen; |
583 | void* ret = NULL; | ||
584 | int err = 0; | ||
533 | 585 | ||
534 | p = get_property(n, name, &proplen); | 586 | p = get_property(n, name, &proplen); |
535 | if (proplen != sizeof (struct address_prop)) | 587 | if (proplen != sizeof (struct address_prop)) |
@@ -537,7 +589,14 @@ static void __iomem * __init map_spe_prop(struct device_node *n, | |||
537 | 589 | ||
538 | prop = p; | 590 | prop = p; |
539 | 591 | ||
540 | return ioremap(prop->address, prop->len); | 592 | err = cell_spuprop_present(n, name); |
593 | if (err && (err != -EEXIST)) | ||
594 | goto out; | ||
595 | |||
596 | ret = ioremap(prop->address, prop->len); | ||
597 | |||
598 | out: | ||
599 | return ret; | ||
541 | } | 600 | } |
542 | 601 | ||
543 | static void spu_unmap(struct spu *spu) | 602 | static void spu_unmap(struct spu *spu) |
@@ -597,17 +656,6 @@ out: | |||
597 | return ret; | 656 | return ret; |
598 | } | 657 | } |
599 | 658 | ||
600 | static int __init find_spu_node_id(struct device_node *spe) | ||
601 | { | ||
602 | unsigned int *id; | ||
603 | struct device_node *cpu; | ||
604 | |||
605 | cpu = spe->parent->parent; | ||
606 | id = (unsigned int *)get_property(cpu, "node-id", NULL); | ||
607 | |||
608 | return id ? *id : 0; | ||
609 | } | ||
610 | |||
611 | static int __init create_spu(struct device_node *spe) | 659 | static int __init create_spu(struct device_node *spe) |
612 | { | 660 | { |
613 | struct spu *spu; | 661 | struct spu *spu; |
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 1fe76d963ac2..1ae2b2cc3a54 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -69,12 +69,16 @@ int __add_pages(struct zone *zone, unsigned long phys_start_pfn, | |||
69 | for (i = 0; i < nr_pages; i += PAGES_PER_SECTION) { | 69 | for (i = 0; i < nr_pages; i += PAGES_PER_SECTION) { |
70 | err = __add_section(zone, phys_start_pfn + i); | 70 | err = __add_section(zone, phys_start_pfn + i); |
71 | 71 | ||
72 | if (err) | 72 | /* We want to keep adding the rest of the |
73 | * sections if the first ones already exist | ||
74 | */ | ||
75 | if (err && (err != -EEXIST)) | ||
73 | break; | 76 | break; |
74 | } | 77 | } |
75 | 78 | ||
76 | return err; | 79 | return err; |
77 | } | 80 | } |
81 | EXPORT_SYMBOL_GPL(__add_pages); | ||
78 | 82 | ||
79 | static void grow_zone_span(struct zone *zone, | 83 | static void grow_zone_span(struct zone *zone, |
80 | unsigned long start_pfn, unsigned long end_pfn) | 84 | unsigned long start_pfn, unsigned long end_pfn) |