diff options
Diffstat (limited to 'arch/powerpc/platforms/iseries')
-rw-r--r-- | arch/powerpc/platforms/iseries/Kconfig | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/exception.S | 62 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/irq.c | 13 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/setup.c | 9 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/smp.c | 45 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/smp.h | 6 |
6 files changed, 60 insertions, 79 deletions
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig index e5bc9f75d474..b57cda3a0817 100644 --- a/arch/powerpc/platforms/iseries/Kconfig +++ b/arch/powerpc/platforms/iseries/Kconfig | |||
@@ -1,7 +1,9 @@ | |||
1 | config PPC_ISERIES | 1 | config PPC_ISERIES |
2 | bool "IBM Legacy iSeries" | 2 | bool "IBM Legacy iSeries" |
3 | depends on PPC64 && PPC_BOOK3S | 3 | depends on PPC64 && PPC_BOOK3S |
4 | select PPC_INDIRECT_IO | 4 | select PPC_SMP_MUXED_IPI |
5 | select PPC_INDIRECT_PIO | ||
6 | select PPC_INDIRECT_MMIO | ||
5 | select PPC_PCI_CHOICE if EXPERT | 7 | select PPC_PCI_CHOICE if EXPERT |
6 | 8 | ||
7 | menu "iSeries device drivers" | 9 | menu "iSeries device drivers" |
diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index 32a56c6dfa72..29c02f36b32f 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <asm/thread_info.h> | 31 | #include <asm/thread_info.h> |
32 | #include <asm/ptrace.h> | 32 | #include <asm/ptrace.h> |
33 | #include <asm/cputable.h> | 33 | #include <asm/cputable.h> |
34 | #include <asm/mmu.h> | ||
34 | 35 | ||
35 | #include "exception.h" | 36 | #include "exception.h" |
36 | 37 | ||
@@ -60,29 +61,31 @@ system_reset_iSeries: | |||
60 | /* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */ | 61 | /* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */ |
61 | /* In the UP case we'll yield() later, and we will not access the paca anyway */ | 62 | /* In the UP case we'll yield() later, and we will not access the paca anyway */ |
62 | #ifdef CONFIG_SMP | 63 | #ifdef CONFIG_SMP |
63 | 1: | 64 | iSeries_secondary_wait_paca: |
64 | HMT_LOW | 65 | HMT_LOW |
65 | LOAD_REG_ADDR(r23, __secondary_hold_spinloop) | 66 | LOAD_REG_ADDR(r23, __secondary_hold_spinloop) |
66 | ld r23,0(r23) | 67 | ld r23,0(r23) |
67 | sync | ||
68 | LOAD_REG_ADDR(r3,current_set) | ||
69 | sldi r28,r24,3 /* get current_set[cpu#] */ | ||
70 | ldx r3,r3,r28 | ||
71 | addi r1,r3,THREAD_SIZE | ||
72 | subi r1,r1,STACK_FRAME_OVERHEAD | ||
73 | 68 | ||
74 | cmpwi 0,r23,0 /* Keep poking the Hypervisor until */ | 69 | cmpdi 0,r23,0 |
75 | bne 2f /* we're released */ | 70 | bne 2f /* go on when the master is ready */ |
76 | /* Let the Hypervisor know we are alive */ | 71 | |
72 | /* Keep poking the Hypervisor until we're released */ | ||
77 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ | 73 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ |
78 | lis r3,0x8002 | 74 | lis r3,0x8002 |
79 | rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ | 75 | rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ |
80 | li r0,-1 /* r0=-1 indicates a Hypervisor call */ | 76 | li r0,-1 /* r0=-1 indicates a Hypervisor call */ |
81 | sc /* Invoke the hypervisor via a system call */ | 77 | sc /* Invoke the hypervisor via a system call */ |
82 | b 1b | 78 | b iSeries_secondary_wait_paca |
83 | #endif | ||
84 | 79 | ||
85 | 2: | 80 | 2: |
81 | HMT_MEDIUM | ||
82 | sync | ||
83 | |||
84 | LOAD_REG_ADDR(r3, nr_cpu_ids) /* get number of pacas allocated */ | ||
85 | lwz r3,0(r3) /* nr_cpus= or NR_CPUS can limit */ | ||
86 | cmpld 0,r24,r3 /* is our cpu number allocated? */ | ||
87 | bge iSeries_secondary_yield /* no, yield forever */ | ||
88 | |||
86 | /* Load our paca now that it's been allocated */ | 89 | /* Load our paca now that it's been allocated */ |
87 | LOAD_REG_ADDR(r13, paca) | 90 | LOAD_REG_ADDR(r13, paca) |
88 | ld r13,0(r13) | 91 | ld r13,0(r13) |
@@ -93,10 +96,24 @@ system_reset_iSeries: | |||
93 | ori r23,r23,MSR_RI | 96 | ori r23,r23,MSR_RI |
94 | mtmsrd r23 /* RI on */ | 97 | mtmsrd r23 /* RI on */ |
95 | 98 | ||
96 | HMT_LOW | 99 | iSeries_secondary_smp_loop: |
97 | #ifdef CONFIG_SMP | ||
98 | lbz r23,PACAPROCSTART(r13) /* Test if this processor | 100 | lbz r23,PACAPROCSTART(r13) /* Test if this processor |
99 | * should start */ | 101 | * should start */ |
102 | cmpwi 0,r23,0 | ||
103 | bne 3f /* go on when we are told */ | ||
104 | |||
105 | HMT_LOW | ||
106 | /* Let the Hypervisor know we are alive */ | ||
107 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ | ||
108 | lis r3,0x8002 | ||
109 | rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ | ||
110 | li r0,-1 /* r0=-1 indicates a Hypervisor call */ | ||
111 | sc /* Invoke the hypervisor via a system call */ | ||
112 | mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ | ||
113 | b iSeries_secondary_smp_loop /* wait for signal to start */ | ||
114 | |||
115 | 3: | ||
116 | HMT_MEDIUM | ||
100 | sync | 117 | sync |
101 | LOAD_REG_ADDR(r3,current_set) | 118 | LOAD_REG_ADDR(r3,current_set) |
102 | sldi r28,r24,3 /* get current_set[cpu#] */ | 119 | sldi r28,r24,3 /* get current_set[cpu#] */ |
@@ -104,27 +121,22 @@ system_reset_iSeries: | |||
104 | addi r1,r3,THREAD_SIZE | 121 | addi r1,r3,THREAD_SIZE |
105 | subi r1,r1,STACK_FRAME_OVERHEAD | 122 | subi r1,r1,STACK_FRAME_OVERHEAD |
106 | 123 | ||
107 | cmpwi 0,r23,0 | ||
108 | beq iSeries_secondary_smp_loop /* Loop until told to go */ | ||
109 | b __secondary_start /* Loop until told to go */ | 124 | b __secondary_start /* Loop until told to go */ |
110 | iSeries_secondary_smp_loop: | 125 | #endif /* CONFIG_SMP */ |
111 | /* Let the Hypervisor know we are alive */ | 126 | |
112 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ | 127 | iSeries_secondary_yield: |
113 | lis r3,0x8002 | ||
114 | rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ | ||
115 | #else /* CONFIG_SMP */ | ||
116 | /* Yield the processor. This is required for non-SMP kernels | 128 | /* Yield the processor. This is required for non-SMP kernels |
117 | which are running on multi-threaded machines. */ | 129 | which are running on multi-threaded machines. */ |
130 | HMT_LOW | ||
118 | lis r3,0x8000 | 131 | lis r3,0x8000 |
119 | rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ | 132 | rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ |
120 | addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ | 133 | addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ |
121 | li r4,0 /* "yield timed" */ | 134 | li r4,0 /* "yield timed" */ |
122 | li r5,-1 /* "yield forever" */ | 135 | li r5,-1 /* "yield forever" */ |
123 | #endif /* CONFIG_SMP */ | ||
124 | li r0,-1 /* r0=-1 indicates a Hypervisor call */ | 136 | li r0,-1 /* r0=-1 indicates a Hypervisor call */ |
125 | sc /* Invoke the hypervisor via a system call */ | 137 | sc /* Invoke the hypervisor via a system call */ |
126 | mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ | 138 | mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ |
127 | b 2b /* If SMP not configured, secondaries | 139 | b iSeries_secondary_yield /* If SMP not configured, secondaries |
128 | * loop forever */ | 140 | * loop forever */ |
129 | 141 | ||
130 | /*** ISeries-LPAR interrupt handlers ***/ | 142 | /*** ISeries-LPAR interrupt handlers ***/ |
@@ -157,7 +169,7 @@ BEGIN_FTR_SECTION | |||
157 | FTR_SECTION_ELSE | 169 | FTR_SECTION_ELSE |
158 | EXCEPTION_PROLOG_1(PACA_EXGEN) | 170 | EXCEPTION_PROLOG_1(PACA_EXGEN) |
159 | EXCEPTION_PROLOG_ISERIES_1 | 171 | EXCEPTION_PROLOG_ISERIES_1 |
160 | ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) | 172 | ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) |
161 | b data_access_common | 173 | b data_access_common |
162 | 174 | ||
163 | .do_stab_bolted_iSeries: | 175 | .do_stab_bolted_iSeries: |
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 52a6889832c7..b2103453eb01 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c | |||
@@ -42,7 +42,6 @@ | |||
42 | #include "irq.h" | 42 | #include "irq.h" |
43 | #include "pci.h" | 43 | #include "pci.h" |
44 | #include "call_pci.h" | 44 | #include "call_pci.h" |
45 | #include "smp.h" | ||
46 | 45 | ||
47 | #ifdef CONFIG_PCI | 46 | #ifdef CONFIG_PCI |
48 | 47 | ||
@@ -171,7 +170,7 @@ static void iseries_enable_IRQ(struct irq_data *d) | |||
171 | { | 170 | { |
172 | u32 bus, dev_id, function, mask; | 171 | u32 bus, dev_id, function, mask; |
173 | const u32 sub_bus = 0; | 172 | const u32 sub_bus = 0; |
174 | unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; | 173 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); |
175 | 174 | ||
176 | /* The IRQ has already been locked by the caller */ | 175 | /* The IRQ has already been locked by the caller */ |
177 | bus = REAL_IRQ_TO_BUS(rirq); | 176 | bus = REAL_IRQ_TO_BUS(rirq); |
@@ -188,7 +187,7 @@ static unsigned int iseries_startup_IRQ(struct irq_data *d) | |||
188 | { | 187 | { |
189 | u32 bus, dev_id, function, mask; | 188 | u32 bus, dev_id, function, mask; |
190 | const u32 sub_bus = 0; | 189 | const u32 sub_bus = 0; |
191 | unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; | 190 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); |
192 | 191 | ||
193 | bus = REAL_IRQ_TO_BUS(rirq); | 192 | bus = REAL_IRQ_TO_BUS(rirq); |
194 | function = REAL_IRQ_TO_FUNC(rirq); | 193 | function = REAL_IRQ_TO_FUNC(rirq); |
@@ -234,7 +233,7 @@ static void iseries_shutdown_IRQ(struct irq_data *d) | |||
234 | { | 233 | { |
235 | u32 bus, dev_id, function, mask; | 234 | u32 bus, dev_id, function, mask; |
236 | const u32 sub_bus = 0; | 235 | const u32 sub_bus = 0; |
237 | unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; | 236 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); |
238 | 237 | ||
239 | /* irq should be locked by the caller */ | 238 | /* irq should be locked by the caller */ |
240 | bus = REAL_IRQ_TO_BUS(rirq); | 239 | bus = REAL_IRQ_TO_BUS(rirq); |
@@ -257,7 +256,7 @@ static void iseries_disable_IRQ(struct irq_data *d) | |||
257 | { | 256 | { |
258 | u32 bus, dev_id, function, mask; | 257 | u32 bus, dev_id, function, mask; |
259 | const u32 sub_bus = 0; | 258 | const u32 sub_bus = 0; |
260 | unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; | 259 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); |
261 | 260 | ||
262 | /* The IRQ has already been locked by the caller */ | 261 | /* The IRQ has already been locked by the caller */ |
263 | bus = REAL_IRQ_TO_BUS(rirq); | 262 | bus = REAL_IRQ_TO_BUS(rirq); |
@@ -271,7 +270,7 @@ static void iseries_disable_IRQ(struct irq_data *d) | |||
271 | 270 | ||
272 | static void iseries_end_IRQ(struct irq_data *d) | 271 | static void iseries_end_IRQ(struct irq_data *d) |
273 | { | 272 | { |
274 | unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; | 273 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); |
275 | 274 | ||
276 | HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), | 275 | HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), |
277 | (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); | 276 | (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); |
@@ -316,7 +315,7 @@ unsigned int iSeries_get_irq(void) | |||
316 | #ifdef CONFIG_SMP | 315 | #ifdef CONFIG_SMP |
317 | if (get_lppaca()->int_dword.fields.ipi_cnt) { | 316 | if (get_lppaca()->int_dword.fields.ipi_cnt) { |
318 | get_lppaca()->int_dword.fields.ipi_cnt = 0; | 317 | get_lppaca()->int_dword.fields.ipi_cnt = 0; |
319 | iSeries_smp_message_recv(); | 318 | smp_ipi_demux(); |
320 | } | 319 | } |
321 | #endif /* CONFIG_SMP */ | 320 | #endif /* CONFIG_SMP */ |
322 | if (hvlpevent_is_pending()) | 321 | if (hvlpevent_is_pending()) |
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 2946ae10fbfd..c25a0815c26b 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c | |||
@@ -249,7 +249,7 @@ static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, | |||
249 | unsigned long i; | 249 | unsigned long i; |
250 | unsigned long mem_blocks = 0; | 250 | unsigned long mem_blocks = 0; |
251 | 251 | ||
252 | if (cpu_has_feature(CPU_FTR_SLB)) | 252 | if (mmu_has_feature(MMU_FTR_SLB)) |
253 | mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, | 253 | mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, |
254 | max_entries); | 254 | max_entries); |
255 | else | 255 | else |
@@ -634,7 +634,7 @@ static int __init iseries_probe(void) | |||
634 | 634 | ||
635 | hpte_init_iSeries(); | 635 | hpte_init_iSeries(); |
636 | /* iSeries does not support 16M pages */ | 636 | /* iSeries does not support 16M pages */ |
637 | cur_cpu_spec->cpu_features &= ~CPU_FTR_16M_PAGE; | 637 | cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE; |
638 | 638 | ||
639 | return 1; | 639 | return 1; |
640 | } | 640 | } |
@@ -685,6 +685,11 @@ void * __init iSeries_early_setup(void) | |||
685 | powerpc_firmware_features |= FW_FEATURE_ISERIES; | 685 | powerpc_firmware_features |= FW_FEATURE_ISERIES; |
686 | powerpc_firmware_features |= FW_FEATURE_LPAR; | 686 | powerpc_firmware_features |= FW_FEATURE_LPAR; |
687 | 687 | ||
688 | #ifdef CONFIG_SMP | ||
689 | /* On iSeries we know we can never have more than 64 cpus */ | ||
690 | nr_cpu_ids = max(nr_cpu_ids, 64); | ||
691 | #endif | ||
692 | |||
688 | iSeries_fixup_klimit(); | 693 | iSeries_fixup_klimit(); |
689 | 694 | ||
690 | /* | 695 | /* |
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c index 6c6029914dbc..e3265adde5d3 100644 --- a/arch/powerpc/platforms/iseries/smp.c +++ b/arch/powerpc/platforms/iseries/smp.c | |||
@@ -42,57 +42,23 @@ | |||
42 | #include <asm/cputable.h> | 42 | #include <asm/cputable.h> |
43 | #include <asm/system.h> | 43 | #include <asm/system.h> |
44 | 44 | ||
45 | #include "smp.h" | 45 | static void smp_iSeries_cause_ipi(int cpu, unsigned long data) |
46 | |||
47 | static unsigned long iSeries_smp_message[NR_CPUS]; | ||
48 | |||
49 | void iSeries_smp_message_recv(void) | ||
50 | { | ||
51 | int cpu = smp_processor_id(); | ||
52 | int msg; | ||
53 | |||
54 | if (num_online_cpus() < 2) | ||
55 | return; | ||
56 | |||
57 | for (msg = 0; msg < 4; msg++) | ||
58 | if (test_and_clear_bit(msg, &iSeries_smp_message[cpu])) | ||
59 | smp_message_recv(msg); | ||
60 | } | ||
61 | |||
62 | static inline void smp_iSeries_do_message(int cpu, int msg) | ||
63 | { | 46 | { |
64 | set_bit(msg, &iSeries_smp_message[cpu]); | ||
65 | HvCall_sendIPI(&(paca[cpu])); | 47 | HvCall_sendIPI(&(paca[cpu])); |
66 | } | 48 | } |
67 | 49 | ||
68 | static void smp_iSeries_message_pass(int target, int msg) | ||
69 | { | ||
70 | int i; | ||
71 | |||
72 | if (target < NR_CPUS) | ||
73 | smp_iSeries_do_message(target, msg); | ||
74 | else { | ||
75 | for_each_online_cpu(i) { | ||
76 | if ((target == MSG_ALL_BUT_SELF) && | ||
77 | (i == smp_processor_id())) | ||
78 | continue; | ||
79 | smp_iSeries_do_message(i, msg); | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | static int smp_iSeries_probe(void) | 50 | static int smp_iSeries_probe(void) |
85 | { | 51 | { |
86 | return cpumask_weight(cpu_possible_mask); | 52 | return cpumask_weight(cpu_possible_mask); |
87 | } | 53 | } |
88 | 54 | ||
89 | static void smp_iSeries_kick_cpu(int nr) | 55 | static int smp_iSeries_kick_cpu(int nr) |
90 | { | 56 | { |
91 | BUG_ON((nr < 0) || (nr >= NR_CPUS)); | 57 | BUG_ON((nr < 0) || (nr >= NR_CPUS)); |
92 | 58 | ||
93 | /* Verify that our partition has a processor nr */ | 59 | /* Verify that our partition has a processor nr */ |
94 | if (lppaca_of(nr).dyn_proc_status >= 2) | 60 | if (lppaca_of(nr).dyn_proc_status >= 2) |
95 | return; | 61 | return -ENOENT; |
96 | 62 | ||
97 | /* The processor is currently spinning, waiting | 63 | /* The processor is currently spinning, waiting |
98 | * for the cpu_start field to become non-zero | 64 | * for the cpu_start field to become non-zero |
@@ -100,6 +66,8 @@ static void smp_iSeries_kick_cpu(int nr) | |||
100 | * continue on to secondary_start in iSeries_head.S | 66 | * continue on to secondary_start in iSeries_head.S |
101 | */ | 67 | */ |
102 | paca[nr].cpu_start = 1; | 68 | paca[nr].cpu_start = 1; |
69 | |||
70 | return 0; | ||
103 | } | 71 | } |
104 | 72 | ||
105 | static void __devinit smp_iSeries_setup_cpu(int nr) | 73 | static void __devinit smp_iSeries_setup_cpu(int nr) |
@@ -107,7 +75,8 @@ static void __devinit smp_iSeries_setup_cpu(int nr) | |||
107 | } | 75 | } |
108 | 76 | ||
109 | static struct smp_ops_t iSeries_smp_ops = { | 77 | static struct smp_ops_t iSeries_smp_ops = { |
110 | .message_pass = smp_iSeries_message_pass, | 78 | .message_pass = smp_muxed_ipi_message_pass, |
79 | .cause_ipi = smp_iSeries_cause_ipi, | ||
111 | .probe = smp_iSeries_probe, | 80 | .probe = smp_iSeries_probe, |
112 | .kick_cpu = smp_iSeries_kick_cpu, | 81 | .kick_cpu = smp_iSeries_kick_cpu, |
113 | .setup_cpu = smp_iSeries_setup_cpu, | 82 | .setup_cpu = smp_iSeries_setup_cpu, |
diff --git a/arch/powerpc/platforms/iseries/smp.h b/arch/powerpc/platforms/iseries/smp.h deleted file mode 100644 index d501f7de01e7..000000000000 --- a/arch/powerpc/platforms/iseries/smp.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef _PLATFORMS_ISERIES_SMP_H | ||
2 | #define _PLATFORMS_ISERIES_SMP_H | ||
3 | |||
4 | extern void iSeries_smp_message_recv(void); | ||
5 | |||
6 | #endif /* _PLATFORMS_ISERIES_SMP_H */ | ||