blob: 0062a43a2e0d8e96698cf0cb090adce0170b4581 [file] [log] [blame]
Benjamin Herrenschmidt55190f82011-09-19 17:44:52 +00001/*
2 * SMP support for PowerNV machines.
3 *
4 * Copyright 2011 IBM Corp.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/interrupt.h>
17#include <linux/delay.h>
18#include <linux/init.h>
19#include <linux/spinlock.h>
20#include <linux/cpu.h>
21
22#include <asm/irq.h>
23#include <asm/smp.h>
24#include <asm/paca.h>
25#include <asm/machdep.h>
26#include <asm/cputable.h>
27#include <asm/firmware.h>
Benjamin Herrenschmidt55190f82011-09-19 17:44:52 +000028#include <asm/rtas.h>
29#include <asm/vdso_datapage.h>
30#include <asm/cputhreads.h>
31#include <asm/xics.h>
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +000032#include <asm/opal.h>
Preeti U Murthyf2038912014-04-11 16:01:48 +053033#include <asm/runlatch.h>
Anton Blanchard2751b622014-03-11 11:54:06 +110034#include <asm/code-patching.h>
Benjamin Herrenschmidt55190f82011-09-19 17:44:52 +000035
36#include "powernv.h"
37
Benjamin Herrenschmidt344eb012011-09-19 17:44:54 +000038#ifdef DEBUG
39#include <asm/udbg.h>
40#define DBG(fmt...) udbg_printf(fmt)
41#else
42#define DBG(fmt...)
43#endif
44
Paul Gortmaker061d19f2013-06-24 15:30:09 -040045static void pnv_smp_setup_cpu(int cpu)
Benjamin Herrenschmidt55190f82011-09-19 17:44:52 +000046{
47 if (cpu != boot_cpuid)
48 xics_setup_cpu();
49}
50
Greg Kroah-Hartmancad5cef2012-12-21 14:04:10 -080051int pnv_smp_kick_cpu(int nr)
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +000052{
53 unsigned int pcpu = get_hard_smp_processor_id(nr);
Anton Blanchard2751b622014-03-11 11:54:06 +110054 unsigned long start_here =
55 __pa(ppc_function_entry(generic_secondary_smp_init));
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +000056 long rc;
57
58 BUG_ON(nr < 0 || nr >= NR_CPUS);
59
Benjamin Herrenschmidtb2b48582013-05-14 15:12:31 +100060 /*
61 * If we already started or OPALv2 is not supported, we just
62 * kick the CPU via the PACA
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +000063 */
Benjamin Herrenschmidtb2b48582013-05-14 15:12:31 +100064 if (paca[nr].cpu_start || !firmware_has_feature(FW_FEATURE_OPALv2))
65 goto kick;
66
67 /*
68 * At this point, the CPU can either be spinning on the way in
69 * from kexec or be inside OPAL waiting to be started for the
70 * first time. OPAL v3 allows us to query OPAL to know if it
71 * has the CPUs, so we do that
72 */
73 if (firmware_has_feature(FW_FEATURE_OPALv3)) {
74 uint8_t status;
75
76 rc = opal_query_cpu_status(pcpu, &status);
Benjamin Herrenschmidt4ea90082013-05-03 17:21:00 +000077 if (rc != OPAL_SUCCESS) {
Benjamin Herrenschmidtb2b48582013-05-14 15:12:31 +100078 pr_warn("OPAL Error %ld querying CPU %d state\n",
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +000079 rc, nr);
Benjamin Herrenschmidt4ea90082013-05-03 17:21:00 +000080 return -ENODEV;
81 }
Benjamin Herrenschmidtb2b48582013-05-14 15:12:31 +100082
83 /*
84 * Already started, just kick it, probably coming from
85 * kexec and spinning
86 */
87 if (status == OPAL_THREAD_STARTED)
88 goto kick;
89
90 /*
91 * Available/inactive, let's kick it
92 */
93 if (status == OPAL_THREAD_INACTIVE) {
94 pr_devel("OPAL: Starting CPU %d (HW 0x%x)...\n",
95 nr, pcpu);
96 rc = opal_start_cpu(pcpu, start_here);
97 if (rc != OPAL_SUCCESS) {
98 pr_warn("OPAL Error %ld starting CPU %d\n",
99 rc, nr);
100 return -ENODEV;
101 }
102 } else {
103 /*
104 * An unavailable CPU (or any other unknown status)
105 * shouldn't be started. It should also
106 * not be in the possible map but currently it can
107 * happen
108 */
109 pr_devel("OPAL: CPU %d (HW 0x%x) is unavailable"
110 " (status %d)...\n", nr, pcpu, status);
111 return -ENODEV;
112 }
113 } else {
114 /*
115 * On OPAL v2, we just kick it and hope for the best,
116 * we must not test the error from opal_start_cpu() or
117 * we would fail to get CPUs from kexec.
118 */
119 opal_start_cpu(pcpu, start_here);
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +0000120 }
Benjamin Herrenschmidtb2b48582013-05-14 15:12:31 +1000121 kick:
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +0000122 return smp_generic_kick_cpu(nr);
123}
124
Benjamin Herrenschmidt344eb012011-09-19 17:44:54 +0000125#ifdef CONFIG_HOTPLUG_CPU
126
127static int pnv_smp_cpu_disable(void)
128{
129 int cpu = smp_processor_id();
130
131 /* This is identical to pSeries... might consolidate by
132 * moving migrate_irqs_away to a ppc_md with default to
133 * the generic fixup_irqs. --BenH.
134 */
135 set_cpu_online(cpu, false);
136 vdso_data->processorCount--;
137 if (cpu == boot_cpuid)
138 boot_cpuid = cpumask_any(cpu_online_mask);
139 xics_migrate_irqs_away();
140 return 0;
141}
142
143static void pnv_smp_cpu_kill_self(void)
144{
145 unsigned int cpu;
146
Benjamin Herrenschmidt344eb012011-09-19 17:44:54 +0000147 /* Standard hot unplug procedure */
148 local_irq_disable();
149 idle_task_exit();
150 current->active_mm = NULL; /* for sanity */
151 cpu = smp_processor_id();
152 DBG("CPU%d offline\n", cpu);
153 generic_set_cpu_dead(cpu);
154 smp_wmb();
155
156 /* We don't want to take decrementer interrupts while we are offline,
157 * so clear LPCR:PECE1. We keep PECE2 enabled.
158 */
159 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);
160 while (!generic_check_cpu_restart(cpu)) {
Preeti U Murthyf2038912014-04-11 16:01:48 +0530161 ppc64_runlatch_off();
Michael Ellerman8d6f7c52014-05-23 18:15:26 +1000162 power7_nap(1);
Preeti U Murthyf2038912014-04-11 16:01:48 +0530163 ppc64_runlatch_on();
Michael Ellermane2186022014-05-23 18:15:30 +1000164
165 /* Reenable IRQs briefly to clear the IPI that woke us */
166 local_irq_enable();
167 local_irq_disable();
168 mb();
169
170 if (cpu_core_split_required())
171 continue;
172
173 if (!generic_check_cpu_restart(cpu))
Benjamin Herrenschmidt344eb012011-09-19 17:44:54 +0000174 DBG("CPU%d Unexpected exit while offline !\n", cpu);
Benjamin Herrenschmidt344eb012011-09-19 17:44:54 +0000175 }
176 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1);
177 DBG("CPU%d coming online...\n", cpu);
178}
179
180#endif /* CONFIG_HOTPLUG_CPU */
181
Benjamin Herrenschmidt55190f82011-09-19 17:44:52 +0000182static struct smp_ops_t pnv_smp_ops = {
183 .message_pass = smp_muxed_ipi_message_pass,
184 .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */
185 .probe = xics_smp_probe,
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +0000186 .kick_cpu = pnv_smp_kick_cpu,
Benjamin Herrenschmidt55190f82011-09-19 17:44:52 +0000187 .setup_cpu = pnv_smp_setup_cpu,
Andy Fleming39fd4022013-08-05 14:58:35 -0500188 .cpu_bootable = smp_generic_cpu_bootable,
Benjamin Herrenschmidt344eb012011-09-19 17:44:54 +0000189#ifdef CONFIG_HOTPLUG_CPU
190 .cpu_disable = pnv_smp_cpu_disable,
191 .cpu_die = generic_cpu_die,
192#endif /* CONFIG_HOTPLUG_CPU */
Benjamin Herrenschmidt55190f82011-09-19 17:44:52 +0000193};
194
195/* This is called very early during platform setup_arch */
196void __init pnv_smp_init(void)
197{
198 smp_ops = &pnv_smp_ops;
199
200 /* XXX We don't yet have a proper entry point from HAL, for
201 * now we rely on kexec-style entry from BML
202 */
203
204#ifdef CONFIG_PPC_RTAS
205 /* Non-lpar has additional take/give timebase */
206 if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
207 smp_ops->give_timebase = rtas_give_timebase;
208 smp_ops->take_timebase = rtas_take_timebase;
209 }
210#endif /* CONFIG_PPC_RTAS */
Benjamin Herrenschmidt344eb012011-09-19 17:44:54 +0000211
212#ifdef CONFIG_HOTPLUG_CPU
213 ppc_md.cpu_die = pnv_smp_cpu_kill_self;
214#endif
Benjamin Herrenschmidt55190f82011-09-19 17:44:52 +0000215}