aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-19 15:57:45 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-19 15:57:45 -0500
commit34b85e3574424beb30e4cd163e6da2e2282d2683 (patch)
tree8962201bcfb406db85796f2690f92bcc051373f4 /arch/powerpc
parentd5e80b4b1857d5175bc6815aeefbb0e19b1a2c9b (diff)
parentd70a54e2d08510a99b1f10eceeae6f2f7086e226 (diff)
Merge tag 'powerpc-3.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux
Pull second batch of powerpc updates from Michael Ellerman: "The highlight is the series that reworks the idle management on powernv, which allows us to use deeper idle states on those machines. There's the fix from Anton for the "BUG at kernel/smpboot.c:134!" problem. An i2c driver for powernv. This is acked by Wolfram Sang, and he asked that we take it through the powerpc tree. A fix for audit from rgb at Red Hat, acked by Paul Moore who is one of the audit maintainers. A patch from Ben to export the symbol map of our OPAL firmware as a sysfs file, so that tools can use it. Also some CXL fixes, a couple of powerpc perf fixes, a fix for smt-enabled, and the patch to add __force to get_user() so we can use bitwise types" * tag 'powerpc-3.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux: powerpc/powernv: Ignore smt-enabled on Power8 and later powerpc/uaccess: Allow get_user() with bitwise types powerpc/powernv: Expose OPAL firmware symbol map powernv/powerpc: Add winkle support for offline cpus powernv/cpuidle: Redesign idle states management powerpc/powernv: Enable Offline CPUs to enter deep idle states powerpc/powernv: Switch off MMU before entering nap/sleep/rvwinkle mode i2c: Driver to expose PowerNV platform i2c busses powerpc: add little endian flag to syscall_get_arch() power/perf/hv-24x7: Use kmem_cache_free() instead of kfree powerpc/perf/hv-24x7: Use per-cpu page buffer cxl: Unmap MMIO regions when detaching a context cxl: Add timeout to process element commands cxl: Change contexts_lock to a mutex to fix sleep while atomic bug powerpc: Secondary CPUs must set cpu_callin_map after setting active and online
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/cpuidle.h20
-rw-r--r--arch/powerpc/include/asm/opal.h42
-rw-r--r--arch/powerpc/include/asm/paca.h10
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h2
-rw-r--r--arch/powerpc/include/asm/processor.h3
-rw-r--r--arch/powerpc/include/asm/reg.h4
-rw-r--r--arch/powerpc/include/asm/syscall.h6
-rw-r--r--arch/powerpc/include/asm/uaccess.h6
-rw-r--r--arch/powerpc/kernel/asm-offsets.c11
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S35
-rw-r--r--arch/powerpc/kernel/idle_power7.S344
-rw-r--r--arch/powerpc/kernel/smp.c9
-rw-r--r--arch/powerpc/perf/hv-24x7.c23
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S39
-rw-r--r--arch/powerpc/platforms/powernv/opal.c50
-rw-r--r--arch/powerpc/platforms/powernv/powernv.h2
-rw-r--r--arch/powerpc/platforms/powernv/setup.c166
-rw-r--r--arch/powerpc/platforms/powernv/smp.c29
-rw-r--r--arch/powerpc/platforms/powernv/subcore.c34
-rw-r--r--arch/powerpc/platforms/powernv/subcore.h9
20 files changed, 766 insertions, 78 deletions
diff --git a/arch/powerpc/include/asm/cpuidle.h b/arch/powerpc/include/asm/cpuidle.h
new file mode 100644
index 000000000000..d2f99ca1e3a6
--- /dev/null
+++ b/arch/powerpc/include/asm/cpuidle.h
@@ -0,0 +1,20 @@
1#ifndef _ASM_POWERPC_CPUIDLE_H
2#define _ASM_POWERPC_CPUIDLE_H
3
4#ifdef CONFIG_PPC_POWERNV
5/* Used in powernv idle state management */
6#define PNV_THREAD_RUNNING 0
7#define PNV_THREAD_NAP 1
8#define PNV_THREAD_SLEEP 2
9#define PNV_THREAD_WINKLE 3
10#define PNV_CORE_IDLE_LOCK_BIT 0x100
11#define PNV_CORE_IDLE_THREAD_BITS 0x0FF
12
13#ifndef __ASSEMBLY__
14extern u32 pnv_fastsleep_workaround_at_entry[];
15extern u32 pnv_fastsleep_workaround_at_exit[];
16#endif
17
18#endif
19
20#endif
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 5cd8d2fddba9..eb95b675109b 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -56,6 +56,14 @@ struct opal_sg_list {
56#define OPAL_HARDWARE_FROZEN -13 56#define OPAL_HARDWARE_FROZEN -13
57#define OPAL_WRONG_STATE -14 57#define OPAL_WRONG_STATE -14
58#define OPAL_ASYNC_COMPLETION -15 58#define OPAL_ASYNC_COMPLETION -15
59#define OPAL_I2C_TIMEOUT -17
60#define OPAL_I2C_INVALID_CMD -18
61#define OPAL_I2C_LBUS_PARITY -19
62#define OPAL_I2C_BKEND_OVERRUN -20
63#define OPAL_I2C_BKEND_ACCESS -21
64#define OPAL_I2C_ARBT_LOST -22
65#define OPAL_I2C_NACK_RCVD -23
66#define OPAL_I2C_STOP_ERR -24
59 67
60/* API Tokens (in r0) */ 68/* API Tokens (in r0) */
61#define OPAL_INVALID_CALL -1 69#define OPAL_INVALID_CALL -1
@@ -152,12 +160,25 @@ struct opal_sg_list {
152#define OPAL_PCI_ERR_INJECT 96 160#define OPAL_PCI_ERR_INJECT 96
153#define OPAL_PCI_EEH_FREEZE_SET 97 161#define OPAL_PCI_EEH_FREEZE_SET 97
154#define OPAL_HANDLE_HMI 98 162#define OPAL_HANDLE_HMI 98
163#define OPAL_CONFIG_CPU_IDLE_STATE 99
164#define OPAL_SLW_SET_REG 100
155#define OPAL_REGISTER_DUMP_REGION 101 165#define OPAL_REGISTER_DUMP_REGION 101
156#define OPAL_UNREGISTER_DUMP_REGION 102 166#define OPAL_UNREGISTER_DUMP_REGION 102
157#define OPAL_WRITE_TPO 103 167#define OPAL_WRITE_TPO 103
158#define OPAL_READ_TPO 104 168#define OPAL_READ_TPO 104
159#define OPAL_IPMI_SEND 107 169#define OPAL_IPMI_SEND 107
160#define OPAL_IPMI_RECV 108 170#define OPAL_IPMI_RECV 108
171#define OPAL_I2C_REQUEST 109
172
173/* Device tree flags */
174
175/* Flags set in power-mgmt nodes in device tree if
176 * respective idle states are supported in the platform.
177 */
178#define OPAL_PM_NAP_ENABLED 0x00010000
179#define OPAL_PM_SLEEP_ENABLED 0x00020000
180#define OPAL_PM_WINKLE_ENABLED 0x00040000
181#define OPAL_PM_SLEEP_ENABLED_ER1 0x00080000
161 182
162#ifndef __ASSEMBLY__ 183#ifndef __ASSEMBLY__
163 184
@@ -712,6 +733,24 @@ typedef struct oppanel_line {
712 uint64_t line_len; 733 uint64_t line_len;
713} oppanel_line_t; 734} oppanel_line_t;
714 735
736/* OPAL I2C request */
737struct opal_i2c_request {
738 uint8_t type;
739#define OPAL_I2C_RAW_READ 0
740#define OPAL_I2C_RAW_WRITE 1
741#define OPAL_I2C_SM_READ 2
742#define OPAL_I2C_SM_WRITE 3
743 uint8_t flags;
744#define OPAL_I2C_ADDR_10 0x01 /* Not supported yet */
745 uint8_t subaddr_sz; /* Max 4 */
746 uint8_t reserved;
747 __be16 addr; /* 7 or 10 bit address */
748 __be16 reserved2;
749 __be32 subaddr; /* Sub-address if any */
750 __be32 size; /* Data size */
751 __be64 buffer_ra; /* Buffer real address */
752};
753
715/* /sys/firmware/opal */ 754/* /sys/firmware/opal */
716extern struct kobject *opal_kobj; 755extern struct kobject *opal_kobj;
717 756
@@ -876,11 +915,14 @@ int64_t opal_sensor_read(uint32_t sensor_hndl, int token, __be32 *sensor_data);
876int64_t opal_handle_hmi(void); 915int64_t opal_handle_hmi(void);
877int64_t opal_register_dump_region(uint32_t id, uint64_t start, uint64_t end); 916int64_t opal_register_dump_region(uint32_t id, uint64_t start, uint64_t end);
878int64_t opal_unregister_dump_region(uint32_t id); 917int64_t opal_unregister_dump_region(uint32_t id);
918int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);
879int64_t opal_pci_set_phb_cxl_mode(uint64_t phb_id, uint64_t mode, uint64_t pe_number); 919int64_t opal_pci_set_phb_cxl_mode(uint64_t phb_id, uint64_t mode, uint64_t pe_number);
880int64_t opal_ipmi_send(uint64_t interface, struct opal_ipmi_msg *msg, 920int64_t opal_ipmi_send(uint64_t interface, struct opal_ipmi_msg *msg,
881 uint64_t msg_len); 921 uint64_t msg_len);
882int64_t opal_ipmi_recv(uint64_t interface, struct opal_ipmi_msg *msg, 922int64_t opal_ipmi_recv(uint64_t interface, struct opal_ipmi_msg *msg,
883 uint64_t *msg_len); 923 uint64_t *msg_len);
924int64_t opal_i2c_request(uint64_t async_token, uint32_t bus_id,
925 struct opal_i2c_request *oreq);
884 926
885/* Internal functions */ 927/* Internal functions */
886extern int early_init_dt_scan_opal(unsigned long node, const char *uname, 928extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 24a386cbb928..e5f22c6c4bf9 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -152,6 +152,16 @@ struct paca_struct {
152 u64 tm_scratch; /* TM scratch area for reclaim */ 152 u64 tm_scratch; /* TM scratch area for reclaim */
153#endif 153#endif
154 154
155#ifdef CONFIG_PPC_POWERNV
156 /* Per-core mask tracking idle threads and a lock bit-[L][TTTTTTTT] */
157 u32 *core_idle_state_ptr;
158 u8 thread_idle_state; /* PNV_THREAD_RUNNING/NAP/SLEEP */
159 /* Mask to indicate thread id in core */
160 u8 thread_mask;
161 /* Mask to denote subcore sibling threads */
162 u8 subcore_sibling_mask;
163#endif
164
155#ifdef CONFIG_PPC_BOOK3S_64 165#ifdef CONFIG_PPC_BOOK3S_64
156 /* Exclusive emergency stack pointer for machine check exception. */ 166 /* Exclusive emergency stack pointer for machine check exception. */
157 void *mc_emergency_sp; 167 void *mc_emergency_sp;
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 1a5287759fc8..03cd858a401c 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -194,6 +194,7 @@
194 194
195#define PPC_INST_NAP 0x4c000364 195#define PPC_INST_NAP 0x4c000364
196#define PPC_INST_SLEEP 0x4c0003a4 196#define PPC_INST_SLEEP 0x4c0003a4
197#define PPC_INST_WINKLE 0x4c0003e4
197 198
198/* A2 specific instructions */ 199/* A2 specific instructions */
199#define PPC_INST_ERATWE 0x7c0001a6 200#define PPC_INST_ERATWE 0x7c0001a6
@@ -375,6 +376,7 @@
375 376
376#define PPC_NAP stringify_in_c(.long PPC_INST_NAP) 377#define PPC_NAP stringify_in_c(.long PPC_INST_NAP)
377#define PPC_SLEEP stringify_in_c(.long PPC_INST_SLEEP) 378#define PPC_SLEEP stringify_in_c(.long PPC_INST_SLEEP)
379#define PPC_WINKLE stringify_in_c(.long PPC_INST_WINKLE)
378 380
379/* BHRB instructions */ 381/* BHRB instructions */
380#define PPC_CLRBHRB stringify_in_c(.long PPC_INST_CLRBHRB) 382#define PPC_CLRBHRB stringify_in_c(.long PPC_INST_CLRBHRB)
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 29c3798cf800..bf117d8fb45f 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -452,7 +452,8 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
452 452
453extern int powersave_nap; /* set if nap mode can be used in idle loop */ 453extern int powersave_nap; /* set if nap mode can be used in idle loop */
454extern unsigned long power7_nap(int check_irq); 454extern unsigned long power7_nap(int check_irq);
455extern void power7_sleep(void); 455extern unsigned long power7_sleep(void);
456extern unsigned long power7_winkle(void);
456extern void flush_instruction_cache(void); 457extern void flush_instruction_cache(void);
457extern void hard_reset_now(void); 458extern void hard_reset_now(void);
458extern void poweroff_now(void); 459extern void poweroff_now(void);
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index c998279bd85b..1c874fb533bb 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -118,8 +118,10 @@
118#define __MSR (MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV) 118#define __MSR (MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV)
119#ifdef __BIG_ENDIAN__ 119#ifdef __BIG_ENDIAN__
120#define MSR_ __MSR 120#define MSR_ __MSR
121#define MSR_IDLE (MSR_ME | MSR_SF | MSR_HV)
121#else 122#else
122#define MSR_ (__MSR | MSR_LE) 123#define MSR_ (__MSR | MSR_LE)
124#define MSR_IDLE (MSR_ME | MSR_SF | MSR_HV | MSR_LE)
123#endif 125#endif
124#define MSR_KERNEL (MSR_ | MSR_64BIT) 126#define MSR_KERNEL (MSR_ | MSR_64BIT)
125#define MSR_USER32 (MSR_ | MSR_PR | MSR_EE) 127#define MSR_USER32 (MSR_ | MSR_PR | MSR_EE)
@@ -371,6 +373,7 @@
371#define SPRN_DBAT7L 0x23F /* Data BAT 7 Lower Register */ 373#define SPRN_DBAT7L 0x23F /* Data BAT 7 Lower Register */
372#define SPRN_DBAT7U 0x23E /* Data BAT 7 Upper Register */ 374#define SPRN_DBAT7U 0x23E /* Data BAT 7 Upper Register */
373#define SPRN_PPR 0x380 /* SMT Thread status Register */ 375#define SPRN_PPR 0x380 /* SMT Thread status Register */
376#define SPRN_TSCR 0x399 /* Thread Switch Control Register */
374 377
375#define SPRN_DEC 0x016 /* Decrement Register */ 378#define SPRN_DEC 0x016 /* Decrement Register */
376#define SPRN_DER 0x095 /* Debug Enable Regsiter */ 379#define SPRN_DER 0x095 /* Debug Enable Regsiter */
@@ -728,6 +731,7 @@
728#define SPRN_BESCR 806 /* Branch event status and control register */ 731#define SPRN_BESCR 806 /* Branch event status and control register */
729#define BESCR_GE 0x8000000000000000ULL /* Global Enable */ 732#define BESCR_GE 0x8000000000000000ULL /* Global Enable */
730#define SPRN_WORT 895 /* Workload optimization register - thread */ 733#define SPRN_WORT 895 /* Workload optimization register - thread */
734#define SPRN_WORC 863 /* Workload optimization register - core */
731 735
732#define SPRN_PMC1 787 736#define SPRN_PMC1 787
733#define SPRN_PMC2 788 737#define SPRN_PMC2 788
diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
index 6240698fee9a..ff21b7a2f0cc 100644
--- a/arch/powerpc/include/asm/syscall.h
+++ b/arch/powerpc/include/asm/syscall.h
@@ -90,6 +90,10 @@ static inline void syscall_set_arguments(struct task_struct *task,
90 90
91static inline int syscall_get_arch(void) 91static inline int syscall_get_arch(void)
92{ 92{
93 return is_32bit_task() ? AUDIT_ARCH_PPC : AUDIT_ARCH_PPC64; 93 int arch = is_32bit_task() ? AUDIT_ARCH_PPC : AUDIT_ARCH_PPC64;
94#ifdef __LITTLE_ENDIAN__
95 arch |= __AUDIT_ARCH_LE;
96#endif
97 return arch;
94} 98}
95#endif /* _ASM_SYSCALL_H */ 99#endif /* _ASM_SYSCALL_H */
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index 9485b43a7c00..a0c071d24e0e 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -284,7 +284,7 @@ do { \
284 if (!is_kernel_addr((unsigned long)__gu_addr)) \ 284 if (!is_kernel_addr((unsigned long)__gu_addr)) \
285 might_fault(); \ 285 might_fault(); \
286 __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ 286 __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
287 (x) = (__typeof__(*(ptr)))__gu_val; \ 287 (x) = (__force __typeof__(*(ptr)))__gu_val; \
288 __gu_err; \ 288 __gu_err; \
289}) 289})
290#endif /* __powerpc64__ */ 290#endif /* __powerpc64__ */
@@ -297,7 +297,7 @@ do { \
297 might_fault(); \ 297 might_fault(); \
298 if (access_ok(VERIFY_READ, __gu_addr, (size))) \ 298 if (access_ok(VERIFY_READ, __gu_addr, (size))) \
299 __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ 299 __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
300 (x) = (__typeof__(*(ptr)))__gu_val; \ 300 (x) = (__force __typeof__(*(ptr)))__gu_val; \
301 __gu_err; \ 301 __gu_err; \
302}) 302})
303 303
@@ -308,7 +308,7 @@ do { \
308 const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ 308 const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
309 __chk_user_ptr(ptr); \ 309 __chk_user_ptr(ptr); \
310 __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ 310 __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
311 (x) = (__typeof__(*(ptr)))__gu_val; \ 311 (x) = (__force __typeof__(*(ptr)))__gu_val; \
312 __gu_err; \ 312 __gu_err; \
313}) 313})
314 314
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 24d78e1871c9..e624f9646350 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -726,5 +726,16 @@ int main(void)
726 arch.timing_last_enter.tv32.tbl)); 726 arch.timing_last_enter.tv32.tbl));
727#endif 727#endif
728 728
729#ifdef CONFIG_PPC_POWERNV
730 DEFINE(PACA_CORE_IDLE_STATE_PTR,
731 offsetof(struct paca_struct, core_idle_state_ptr));
732 DEFINE(PACA_THREAD_IDLE_STATE,
733 offsetof(struct paca_struct, thread_idle_state));
734 DEFINE(PACA_THREAD_MASK,
735 offsetof(struct paca_struct, thread_mask));
736 DEFINE(PACA_SUBCORE_SIBLING_MASK,
737 offsetof(struct paca_struct, subcore_sibling_mask));
738#endif
739
729 return 0; 740 return 0;
730} 741}
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index db08382e19f1..c2df8150bd7a 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -15,6 +15,7 @@
15#include <asm/hw_irq.h> 15#include <asm/hw_irq.h>
16#include <asm/exception-64s.h> 16#include <asm/exception-64s.h>
17#include <asm/ptrace.h> 17#include <asm/ptrace.h>
18#include <asm/cpuidle.h>
18 19
19/* 20/*
20 * We layout physical memory as follows: 21 * We layout physical memory as follows:
@@ -101,23 +102,34 @@ system_reset_pSeries:
101#ifdef CONFIG_PPC_P7_NAP 102#ifdef CONFIG_PPC_P7_NAP
102BEGIN_FTR_SECTION 103BEGIN_FTR_SECTION
103 /* Running native on arch 2.06 or later, check if we are 104 /* Running native on arch 2.06 or later, check if we are
104 * waking up from nap. We only handle no state loss and 105 * waking up from nap/sleep/winkle.
105 * supervisor state loss. We do -not- handle hypervisor
106 * state loss at this time.
107 */ 106 */
108 mfspr r13,SPRN_SRR1 107 mfspr r13,SPRN_SRR1
109 rlwinm. r13,r13,47-31,30,31 108 rlwinm. r13,r13,47-31,30,31
110 beq 9f 109 beq 9f
111 110
112 /* waking up from powersave (nap) state */ 111 cmpwi cr3,r13,2
113 cmpwi cr1,r13,2 112
114 /* Total loss of HV state is fatal, we could try to use the 113 /*
115 * PIR to locate a PACA, then use an emergency stack etc... 114 * Check if last bit of HSPGR0 is set. This indicates whether we are
116 * OPAL v3 based powernv platforms have new idle states 115 * waking up from winkle.
117 * which fall in this catagory.
118 */ 116 */
119 bgt cr1,8f
120 GET_PACA(r13) 117 GET_PACA(r13)
118 clrldi r5,r13,63
119 clrrdi r13,r13,1
120 cmpwi cr4,r5,1
121 mtspr SPRN_HSPRG0,r13
122
123 lbz r0,PACA_THREAD_IDLE_STATE(r13)
124 cmpwi cr2,r0,PNV_THREAD_NAP
125 bgt cr2,8f /* Either sleep or Winkle */
126
127 /* Waking up from nap should not cause hypervisor state loss */
128 bgt cr3,.
129
130 /* Waking up from nap */
131 li r0,PNV_THREAD_RUNNING
132 stb r0,PACA_THREAD_IDLE_STATE(r13) /* Clear thread state */
121 133
122#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 134#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
123 li r0,KVM_HWTHREAD_IN_KERNEL 135 li r0,KVM_HWTHREAD_IN_KERNEL
@@ -133,7 +145,7 @@ BEGIN_FTR_SECTION
133 145
134 /* Return SRR1 from power7_nap() */ 146 /* Return SRR1 from power7_nap() */
135 mfspr r3,SPRN_SRR1 147 mfspr r3,SPRN_SRR1
136 beq cr1,2f 148 beq cr3,2f
137 b power7_wakeup_noloss 149 b power7_wakeup_noloss
1382: b power7_wakeup_loss 1502: b power7_wakeup_loss
139 151
@@ -1382,6 +1394,7 @@ machine_check_handle_early:
1382 MACHINE_CHECK_HANDLER_WINDUP 1394 MACHINE_CHECK_HANDLER_WINDUP
1383 GET_PACA(r13) 1395 GET_PACA(r13)
1384 ld r1,PACAR1(r13) 1396 ld r1,PACAR1(r13)
1397 li r3,PNV_THREAD_NAP
1385 b power7_enter_nap_mode 1398 b power7_enter_nap_mode
13864: 13994:
1387#endif 1400#endif
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index 18c0687e5ab3..05adc8bbdef8 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -18,9 +18,25 @@
18#include <asm/hw_irq.h> 18#include <asm/hw_irq.h>
19#include <asm/kvm_book3s_asm.h> 19#include <asm/kvm_book3s_asm.h>
20#include <asm/opal.h> 20#include <asm/opal.h>
21#include <asm/cpuidle.h>
22#include <asm/mmu-hash64.h>
21 23
22#undef DEBUG 24#undef DEBUG
23 25
26/*
27 * Use unused space in the interrupt stack to save and restore
28 * registers for winkle support.
29 */
30#define _SDR1 GPR3
31#define _RPR GPR4
32#define _SPURR GPR5
33#define _PURR GPR6
34#define _TSCR GPR7
35#define _DSCR GPR8
36#define _AMOR GPR9
37#define _WORT GPR10
38#define _WORC GPR11
39
24/* Idle state entry routines */ 40/* Idle state entry routines */
25 41
26#define IDLE_STATE_ENTER_SEQ(IDLE_INST) \ 42#define IDLE_STATE_ENTER_SEQ(IDLE_INST) \
@@ -37,8 +53,7 @@
37 53
38/* 54/*
39 * Pass requested state in r3: 55 * Pass requested state in r3:
40 * 0 - nap 56 * r3 - PNV_THREAD_NAP/SLEEP/WINKLE
41 * 1 - sleep
42 * 57 *
43 * To check IRQ_HAPPENED in r4 58 * To check IRQ_HAPPENED in r4
44 * 0 - don't check 59 * 0 - don't check
@@ -101,18 +116,105 @@ _GLOBAL(power7_powersave_common)
101 std r9,_MSR(r1) 116 std r9,_MSR(r1)
102 std r1,PACAR1(r13) 117 std r1,PACAR1(r13)
103 118
104_GLOBAL(power7_enter_nap_mode) 119 /*
120 * Go to real mode to do the nap, as required by the architecture.
121 * Also, we need to be in real mode before setting hwthread_state,
122 * because as soon as we do that, another thread can switch
123 * the MMU context to the guest.
124 */
125 LOAD_REG_IMMEDIATE(r5, MSR_IDLE)
126 li r6, MSR_RI
127 andc r6, r9, r6
128 LOAD_REG_ADDR(r7, power7_enter_nap_mode)
129 mtmsrd r6, 1 /* clear RI before setting SRR0/1 */
130 mtspr SPRN_SRR0, r7
131 mtspr SPRN_SRR1, r5
132 rfid
133
134 .globl power7_enter_nap_mode
135power7_enter_nap_mode:
105#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 136#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
106 /* Tell KVM we're napping */ 137 /* Tell KVM we're napping */
107 li r4,KVM_HWTHREAD_IN_NAP 138 li r4,KVM_HWTHREAD_IN_NAP
108 stb r4,HSTATE_HWTHREAD_STATE(r13) 139 stb r4,HSTATE_HWTHREAD_STATE(r13)
109#endif 140#endif
110 cmpwi cr0,r3,1 141 stb r3,PACA_THREAD_IDLE_STATE(r13)
111 beq 2f 142 cmpwi cr3,r3,PNV_THREAD_SLEEP
143 bge cr3,2f
112 IDLE_STATE_ENTER_SEQ(PPC_NAP) 144 IDLE_STATE_ENTER_SEQ(PPC_NAP)
113 /* No return */ 145 /* No return */
1142: IDLE_STATE_ENTER_SEQ(PPC_SLEEP) 1462:
115 /* No return */ 147 /* Sleep or winkle */
148 lbz r7,PACA_THREAD_MASK(r13)
149 ld r14,PACA_CORE_IDLE_STATE_PTR(r13)
150lwarx_loop1:
151 lwarx r15,0,r14
152 andc r15,r15,r7 /* Clear thread bit */
153
154 andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS
155
156/*
157 * If cr0 = 0, then current thread is the last thread of the core entering
158 * sleep. Last thread needs to execute the hardware bug workaround code if
159 * required by the platform.
160 * Make the workaround call unconditionally here. The below branch call is
161 * patched out when the idle states are discovered if the platform does not
162 * require it.
163 */
164.global pnv_fastsleep_workaround_at_entry
165pnv_fastsleep_workaround_at_entry:
166 beq fastsleep_workaround_at_entry
167
168 stwcx. r15,0,r14
169 bne- lwarx_loop1
170 isync
171
172common_enter: /* common code for all the threads entering sleep or winkle */
173 bgt cr3,enter_winkle
174 IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
175
176fastsleep_workaround_at_entry:
177 ori r15,r15,PNV_CORE_IDLE_LOCK_BIT
178 stwcx. r15,0,r14
179 bne- lwarx_loop1
180 isync
181
182 /* Fast sleep workaround */
183 li r3,1
184 li r4,1
185 li r0,OPAL_CONFIG_CPU_IDLE_STATE
186 bl opal_call_realmode
187
188 /* Clear Lock bit */
189 li r0,0
190 lwsync
191 stw r0,0(r14)
192 b common_enter
193
194enter_winkle:
195 /*
196 * Note all register i.e per-core, per-subcore or per-thread is saved
197 * here since any thread in the core might wake up first
198 */
199 mfspr r3,SPRN_SDR1
200 std r3,_SDR1(r1)
201 mfspr r3,SPRN_RPR
202 std r3,_RPR(r1)
203 mfspr r3,SPRN_SPURR
204 std r3,_SPURR(r1)
205 mfspr r3,SPRN_PURR
206 std r3,_PURR(r1)
207 mfspr r3,SPRN_TSCR
208 std r3,_TSCR(r1)
209 mfspr r3,SPRN_DSCR
210 std r3,_DSCR(r1)
211 mfspr r3,SPRN_AMOR
212 std r3,_AMOR(r1)
213 mfspr r3,SPRN_WORT
214 std r3,_WORT(r1)
215 mfspr r3,SPRN_WORC
216 std r3,_WORC(r1)
217 IDLE_STATE_ENTER_SEQ(PPC_WINKLE)
116 218
117_GLOBAL(power7_idle) 219_GLOBAL(power7_idle)
118 /* Now check if user or arch enabled NAP mode */ 220 /* Now check if user or arch enabled NAP mode */
@@ -125,48 +227,21 @@ _GLOBAL(power7_idle)
125 227
126_GLOBAL(power7_nap) 228_GLOBAL(power7_nap)
127 mr r4,r3 229 mr r4,r3
128 li r3,0 230 li r3,PNV_THREAD_NAP
129 b power7_powersave_common 231 b power7_powersave_common
130 /* No return */ 232 /* No return */
131 233
132_GLOBAL(power7_sleep) 234_GLOBAL(power7_sleep)
133 li r3,1 235 li r3,PNV_THREAD_SLEEP
134 li r4,1 236 li r4,1
135 b power7_powersave_common 237 b power7_powersave_common
136 /* No return */ 238 /* No return */
137 239
138/* 240_GLOBAL(power7_winkle)
139 * Make opal call in realmode. This is a generic function to be called 241 li r3,3
140 * from realmode from reset vector. It handles endianess. 242 li r4,1
141 * 243 b power7_powersave_common
142 * r13 - paca pointer 244 /* No return */
143 * r1 - stack pointer
144 * r3 - opal token
145 */
146opal_call_realmode:
147 mflr r12
148 std r12,_LINK(r1)
149 ld r2,PACATOC(r13)
150 /* Set opal return address */
151 LOAD_REG_ADDR(r0,return_from_opal_call)
152 mtlr r0
153 /* Handle endian-ness */
154 li r0,MSR_LE
155 mfmsr r12
156 andc r12,r12,r0
157 mtspr SPRN_HSRR1,r12
158 mr r0,r3 /* Move opal token to r0 */
159 LOAD_REG_ADDR(r11,opal)
160 ld r12,8(r11)
161 ld r2,0(r11)
162 mtspr SPRN_HSRR0,r12
163 hrfid
164
165return_from_opal_call:
166 FIXUP_ENDIAN
167 ld r0,_LINK(r1)
168 mtlr r0
169 blr
170 245
171#define CHECK_HMI_INTERRUPT \ 246#define CHECK_HMI_INTERRUPT \
172 mfspr r0,SPRN_SRR1; \ 247 mfspr r0,SPRN_SRR1; \
@@ -181,7 +256,7 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66); \
181 ld r2,PACATOC(r13); \ 256 ld r2,PACATOC(r13); \
182 ld r1,PACAR1(r13); \ 257 ld r1,PACAR1(r13); \
183 std r3,ORIG_GPR3(r1); /* Save original r3 */ \ 258 std r3,ORIG_GPR3(r1); /* Save original r3 */ \
184 li r3,OPAL_HANDLE_HMI; /* Pass opal token argument*/ \ 259 li r0,OPAL_HANDLE_HMI; /* Pass opal token argument*/ \
185 bl opal_call_realmode; \ 260 bl opal_call_realmode; \
186 ld r3,ORIG_GPR3(r1); /* Restore original r3 */ \ 261 ld r3,ORIG_GPR3(r1); /* Restore original r3 */ \
18720: nop; 26220: nop;
@@ -190,16 +265,190 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66); \
190_GLOBAL(power7_wakeup_tb_loss) 265_GLOBAL(power7_wakeup_tb_loss)
191 ld r2,PACATOC(r13); 266 ld r2,PACATOC(r13);
192 ld r1,PACAR1(r13) 267 ld r1,PACAR1(r13)
268 /*
269 * Before entering any idle state, the NVGPRs are saved in the stack
270 * and they are restored before switching to the process context. Hence
271 * until they are restored, they are free to be used.
272 *
273 * Save SRR1 in a NVGPR as it might be clobbered in opal_call_realmode
274 * (called in CHECK_HMI_INTERRUPT). SRR1 is required to determine the
275 * wakeup reason if we branch to kvm_start_guest.
276 */
193 277
278 mfspr r16,SPRN_SRR1
194BEGIN_FTR_SECTION 279BEGIN_FTR_SECTION
195 CHECK_HMI_INTERRUPT 280 CHECK_HMI_INTERRUPT
196END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) 281END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
282
283 lbz r7,PACA_THREAD_MASK(r13)
284 ld r14,PACA_CORE_IDLE_STATE_PTR(r13)
285lwarx_loop2:
286 lwarx r15,0,r14
287 andi. r9,r15,PNV_CORE_IDLE_LOCK_BIT
288 /*
289 * Lock bit is set in one of the 2 cases-
290 * a. In the sleep/winkle enter path, the last thread is executing
291 * fastsleep workaround code.
292 * b. In the wake up path, another thread is executing fastsleep
293 * workaround undo code or resyncing timebase or restoring context
294 * In either case loop until the lock bit is cleared.
295 */
296 bne core_idle_lock_held
297
298 cmpwi cr2,r15,0
299 lbz r4,PACA_SUBCORE_SIBLING_MASK(r13)
300 and r4,r4,r15
301 cmpwi cr1,r4,0 /* Check if first in subcore */
302
303 /*
304 * At this stage
305 * cr1 - 0b0100 if first thread to wakeup in subcore
306 * cr2 - 0b0100 if first thread to wakeup in core
307 * cr3- 0b0010 if waking up from sleep or winkle
308 * cr4 - 0b0100 if waking up from winkle
309 */
310
311 or r15,r15,r7 /* Set thread bit */
312
313 beq cr1,first_thread_in_subcore
314
315 /* Not first thread in subcore to wake up */
316 stwcx. r15,0,r14
317 bne- lwarx_loop2
318 isync
319 b common_exit
320
321core_idle_lock_held:
322 HMT_LOW
323core_idle_lock_loop:
324 lwz r15,0(14)
325 andi. r9,r15,PNV_CORE_IDLE_LOCK_BIT
326 bne core_idle_lock_loop
327 HMT_MEDIUM
328 b lwarx_loop2
329
330first_thread_in_subcore:
331 /* First thread in subcore to wakeup */
332 ori r15,r15,PNV_CORE_IDLE_LOCK_BIT
333 stwcx. r15,0,r14
334 bne- lwarx_loop2
335 isync
336
337 /*
338 * If waking up from sleep, subcore state is not lost. Hence
339 * skip subcore state restore
340 */
341 bne cr4,subcore_state_restored
342
343 /* Restore per-subcore state */
344 ld r4,_SDR1(r1)
345 mtspr SPRN_SDR1,r4
346 ld r4,_RPR(r1)
347 mtspr SPRN_RPR,r4
348 ld r4,_AMOR(r1)
349 mtspr SPRN_AMOR,r4
350
351subcore_state_restored:
352 /*
353 * Check if the thread is also the first thread in the core. If not,
354 * skip to clear_lock.
355 */
356 bne cr2,clear_lock
357
358first_thread_in_core:
359
360 /*
361 * First thread in the core waking up from fastsleep. It needs to
362 * call the fastsleep workaround code if the platform requires it.
363 * Call it unconditionally here. The below branch instruction will
364 * be patched out when the idle states are discovered if platform
365 * does not require workaround.
366 */
367.global pnv_fastsleep_workaround_at_exit
368pnv_fastsleep_workaround_at_exit:
369 b fastsleep_workaround_at_exit
370
371timebase_resync:
372 /* Do timebase resync if we are waking up from sleep. Use cr3 value
373 * set in exceptions-64s.S */
374 ble cr3,clear_lock
197 /* Time base re-sync */ 375 /* Time base re-sync */
198 li r3,OPAL_RESYNC_TIMEBASE 376 li r0,OPAL_RESYNC_TIMEBASE
199 bl opal_call_realmode; 377 bl opal_call_realmode;
200
201 /* TODO: Check r3 for failure */ 378 /* TODO: Check r3 for failure */
202 379
380 /*
381 * If waking up from sleep, per core state is not lost, skip to
382 * clear_lock.
383 */
384 bne cr4,clear_lock
385
386 /* Restore per core state */
387 ld r4,_TSCR(r1)
388 mtspr SPRN_TSCR,r4
389 ld r4,_WORC(r1)
390 mtspr SPRN_WORC,r4
391
392clear_lock:
393 andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS
394 lwsync
395 stw r15,0(r14)
396
397common_exit:
398 /*
399 * Common to all threads.
400 *
401 * If waking up from sleep, hypervisor state is not lost. Hence
402 * skip hypervisor state restore.
403 */
404 bne cr4,hypervisor_state_restored
405
406 /* Waking up from winkle */
407
408 /* Restore per thread state */
409 bl __restore_cpu_power8
410
411 /* Restore SLB from PACA */
412 ld r8,PACA_SLBSHADOWPTR(r13)
413
414 .rept SLB_NUM_BOLTED
415 li r3, SLBSHADOW_SAVEAREA
416 LDX_BE r5, r8, r3
417 addi r3, r3, 8
418 LDX_BE r6, r8, r3
419 andis. r7,r5,SLB_ESID_V@h
420 beq 1f
421 slbmte r6,r5
4221: addi r8,r8,16
423 .endr
424
425 ld r4,_SPURR(r1)
426 mtspr SPRN_SPURR,r4
427 ld r4,_PURR(r1)
428 mtspr SPRN_PURR,r4
429 ld r4,_DSCR(r1)
430 mtspr SPRN_DSCR,r4
431 ld r4,_WORT(r1)
432 mtspr SPRN_WORT,r4
433
434hypervisor_state_restored:
435
436 li r5,PNV_THREAD_RUNNING
437 stb r5,PACA_THREAD_IDLE_STATE(r13)
438
439 mtspr SPRN_SRR1,r16
440#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
441 li r0,KVM_HWTHREAD_IN_KERNEL
442 stb r0,HSTATE_HWTHREAD_STATE(r13)
443 /* Order setting hwthread_state vs. testing hwthread_req */
444 sync
445 lbz r0,HSTATE_HWTHREAD_REQ(r13)
446 cmpwi r0,0
447 beq 6f
448 b kvm_start_guest
4496:
450#endif
451
203 REST_NVGPRS(r1) 452 REST_NVGPRS(r1)
204 REST_GPR(2, r1) 453 REST_GPR(2, r1)
205 ld r3,_CCR(r1) 454 ld r3,_CCR(r1)
@@ -212,6 +461,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
212 mtspr SPRN_SRR0,r5 461 mtspr SPRN_SRR0,r5
213 rfid 462 rfid
214 463
464fastsleep_workaround_at_exit:
465 li r3,1
466 li r4,0
467 li r0,OPAL_CONFIG_CPU_IDLE_STATE
468 bl opal_call_realmode
469 b timebase_resync
470
215/* 471/*
216 * R3 here contains the value that will be returned to the caller 472 * R3 here contains the value that will be returned to the caller
217 * of power7_nap. 473 * of power7_nap.
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 8b2d2dc8ef10..8ec017cb4446 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -700,7 +700,6 @@ void start_secondary(void *unused)
700 smp_store_cpu_info(cpu); 700 smp_store_cpu_info(cpu);
701 set_dec(tb_ticks_per_jiffy); 701 set_dec(tb_ticks_per_jiffy);
702 preempt_disable(); 702 preempt_disable();
703 cpu_callin_map[cpu] = 1;
704 703
705 if (smp_ops->setup_cpu) 704 if (smp_ops->setup_cpu)
706 smp_ops->setup_cpu(cpu); 705 smp_ops->setup_cpu(cpu);
@@ -739,6 +738,14 @@ void start_secondary(void *unused)
739 notify_cpu_starting(cpu); 738 notify_cpu_starting(cpu);
740 set_cpu_online(cpu, true); 739 set_cpu_online(cpu, true);
741 740
741 /*
742 * CPU must be marked active and online before we signal back to the
743 * master, because the scheduler needs to see the cpu_online and
744 * cpu_active bits set.
745 */
746 smp_wmb();
747 cpu_callin_map[cpu] = 1;
748
742 local_irq_enable(); 749 local_irq_enable();
743 750
744 cpu_startup_entry(CPUHP_ONLINE); 751 cpu_startup_entry(CPUHP_ONLINE);
diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c
index dba34088da28..f162d0b8eea3 100644
--- a/arch/powerpc/perf/hv-24x7.c
+++ b/arch/powerpc/perf/hv-24x7.c
@@ -177,7 +177,7 @@ static ssize_t _name##_show(struct device *dev, \
177 } \ 177 } \
178 ret = sprintf(buf, _fmt, _expr); \ 178 ret = sprintf(buf, _fmt, _expr); \
179e_free: \ 179e_free: \
180 kfree(page); \ 180 kmem_cache_free(hv_page_cache, page); \
181 return ret; \ 181 return ret; \
182} \ 182} \
183static DEVICE_ATTR_RO(_name) 183static DEVICE_ATTR_RO(_name)
@@ -217,11 +217,14 @@ static bool is_physical_domain(int domain)
217 domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CORE; 217 domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CORE;
218} 218}
219 219
220DEFINE_PER_CPU(char, hv_24x7_reqb[4096]) __aligned(4096);
221DEFINE_PER_CPU(char, hv_24x7_resb[4096]) __aligned(4096);
222
220static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix, 223static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
221 u16 lpar, u64 *res, 224 u16 lpar, u64 *res,
222 bool success_expected) 225 bool success_expected)
223{ 226{
224 unsigned long ret = -ENOMEM; 227 unsigned long ret;
225 228
226 /* 229 /*
227 * request_buffer and result_buffer are not required to be 4k aligned, 230 * request_buffer and result_buffer are not required to be 4k aligned,
@@ -243,13 +246,11 @@ static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
243 BUILD_BUG_ON(sizeof(*request_buffer) > 4096); 246 BUILD_BUG_ON(sizeof(*request_buffer) > 4096);
244 BUILD_BUG_ON(sizeof(*result_buffer) > 4096); 247 BUILD_BUG_ON(sizeof(*result_buffer) > 4096);
245 248
246 request_buffer = kmem_cache_zalloc(hv_page_cache, GFP_USER); 249 request_buffer = (void *)get_cpu_var(hv_24x7_reqb);
247 if (!request_buffer) 250 result_buffer = (void *)get_cpu_var(hv_24x7_resb);
248 goto out;
249 251
250 result_buffer = kmem_cache_zalloc(hv_page_cache, GFP_USER); 252 memset(request_buffer, 0, 4096);
251 if (!result_buffer) 253 memset(result_buffer, 0, 4096);
252 goto out_free_request_buffer;
253 254
254 *request_buffer = (struct reqb) { 255 *request_buffer = (struct reqb) {
255 .buf = { 256 .buf = {
@@ -278,15 +279,11 @@ static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
278 domain, offset, ix, lpar, ret, ret, 279 domain, offset, ix, lpar, ret, ret,
279 result_buffer->buf.detailed_rc, 280 result_buffer->buf.detailed_rc,
280 result_buffer->buf.failing_request_ix); 281 result_buffer->buf.failing_request_ix);
281 goto out_free_result_buffer; 282 goto out;
282 } 283 }
283 284
284 *res = be64_to_cpu(result_buffer->result); 285 *res = be64_to_cpu(result_buffer->result);
285 286
286out_free_result_buffer:
287 kfree(result_buffer);
288out_free_request_buffer:
289 kfree(request_buffer);
290out: 287out:
291 return ret; 288 return ret;
292} 289}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 0a299be588af..54eca8b3b288 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -158,6 +158,43 @@ opal_tracepoint_return:
158 blr 158 blr
159#endif 159#endif
160 160
161/*
162 * Make opal call in realmode. This is a generic function to be called
163 * from realmode. It handles endianness.
164 *
165 * r13 - paca pointer
166 * r1 - stack pointer
167 * r0 - opal token
168 */
169_GLOBAL(opal_call_realmode)
170 mflr r12
171 std r12,PPC_LR_STKOFF(r1)
172 ld r2,PACATOC(r13)
173 /* Set opal return address */
174 LOAD_REG_ADDR(r12,return_from_opal_call)
175 mtlr r12
176
177 mfmsr r12
178#ifdef __LITTLE_ENDIAN__
179 /* Handle endian-ness */
180 li r11,MSR_LE
181 andc r12,r12,r11
182#endif
183 mtspr SPRN_HSRR1,r12
184 LOAD_REG_ADDR(r11,opal)
185 ld r12,8(r11)
186 ld r2,0(r11)
187 mtspr SPRN_HSRR0,r12
188 hrfid
189
190return_from_opal_call:
191#ifdef __LITTLE_ENDIAN__
192 FIXUP_ENDIAN
193#endif
194 ld r12,PPC_LR_STKOFF(r1)
195 mtlr r12
196 blr
197
161OPAL_CALL(opal_invalid_call, OPAL_INVALID_CALL); 198OPAL_CALL(opal_invalid_call, OPAL_INVALID_CALL);
162OPAL_CALL(opal_console_write, OPAL_CONSOLE_WRITE); 199OPAL_CALL(opal_console_write, OPAL_CONSOLE_WRITE);
163OPAL_CALL(opal_console_read, OPAL_CONSOLE_READ); 200OPAL_CALL(opal_console_read, OPAL_CONSOLE_READ);
@@ -247,6 +284,7 @@ OPAL_CALL(opal_sensor_read, OPAL_SENSOR_READ);
247OPAL_CALL(opal_get_param, OPAL_GET_PARAM); 284OPAL_CALL(opal_get_param, OPAL_GET_PARAM);
248OPAL_CALL(opal_set_param, OPAL_SET_PARAM); 285OPAL_CALL(opal_set_param, OPAL_SET_PARAM);
249OPAL_CALL(opal_handle_hmi, OPAL_HANDLE_HMI); 286OPAL_CALL(opal_handle_hmi, OPAL_HANDLE_HMI);
287OPAL_CALL(opal_slw_set_reg, OPAL_SLW_SET_REG);
250OPAL_CALL(opal_register_dump_region, OPAL_REGISTER_DUMP_REGION); 288OPAL_CALL(opal_register_dump_region, OPAL_REGISTER_DUMP_REGION);
251OPAL_CALL(opal_unregister_dump_region, OPAL_UNREGISTER_DUMP_REGION); 289OPAL_CALL(opal_unregister_dump_region, OPAL_UNREGISTER_DUMP_REGION);
252OPAL_CALL(opal_pci_set_phb_cxl_mode, OPAL_PCI_SET_PHB_CXL_MODE); 290OPAL_CALL(opal_pci_set_phb_cxl_mode, OPAL_PCI_SET_PHB_CXL_MODE);
@@ -254,3 +292,4 @@ OPAL_CALL(opal_tpo_write, OPAL_WRITE_TPO);
254OPAL_CALL(opal_tpo_read, OPAL_READ_TPO); 292OPAL_CALL(opal_tpo_read, OPAL_READ_TPO);
255OPAL_CALL(opal_ipmi_send, OPAL_IPMI_SEND); 293OPAL_CALL(opal_ipmi_send, OPAL_IPMI_SEND);
256OPAL_CALL(opal_ipmi_recv, OPAL_IPMI_RECV); 294OPAL_CALL(opal_ipmi_recv, OPAL_IPMI_RECV);
295OPAL_CALL(opal_i2c_request, OPAL_I2C_REQUEST);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index cb0b6de79cd4..f10b9ec8c1f5 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -9,8 +9,9 @@
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 */ 10 */
11 11
12#undef DEBUG 12#define pr_fmt(fmt) "opal: " fmt
13 13
14#include <linux/printk.h>
14#include <linux/types.h> 15#include <linux/types.h>
15#include <linux/of.h> 16#include <linux/of.h>
16#include <linux/of_fdt.h> 17#include <linux/of_fdt.h>
@@ -625,6 +626,39 @@ static int opal_sysfs_init(void)
625 return 0; 626 return 0;
626} 627}
627 628
629static ssize_t symbol_map_read(struct file *fp, struct kobject *kobj,
630 struct bin_attribute *bin_attr,
631 char *buf, loff_t off, size_t count)
632{
633 return memory_read_from_buffer(buf, count, &off, bin_attr->private,
634 bin_attr->size);
635}
636
637static BIN_ATTR_RO(symbol_map, 0);
638
639static void opal_export_symmap(void)
640{
641 const __be64 *syms;
642 unsigned int size;
643 struct device_node *fw;
644 int rc;
645
646 fw = of_find_node_by_path("/ibm,opal/firmware");
647 if (!fw)
648 return;
649 syms = of_get_property(fw, "symbol-map", &size);
650 if (!syms || size != 2 * sizeof(__be64))
651 return;
652
653 /* Setup attributes */
654 bin_attr_symbol_map.private = __va(be64_to_cpu(syms[0]));
655 bin_attr_symbol_map.size = be64_to_cpu(syms[1]);
656
657 rc = sysfs_create_bin_file(opal_kobj, &bin_attr_symbol_map);
658 if (rc)
659 pr_warn("Error %d creating OPAL symbols file\n", rc);
660}
661
628static void __init opal_dump_region_init(void) 662static void __init opal_dump_region_init(void)
629{ 663{
630 void *addr; 664 void *addr;
@@ -653,6 +687,14 @@ static void opal_ipmi_init(struct device_node *opal_node)
653 of_platform_device_create(np, NULL, NULL); 687 of_platform_device_create(np, NULL, NULL);
654} 688}
655 689
690static void opal_i2c_create_devs(void)
691{
692 struct device_node *np;
693
694 for_each_compatible_node(np, NULL, "ibm,opal-i2c")
695 of_platform_device_create(np, NULL, NULL);
696}
697
656static int __init opal_init(void) 698static int __init opal_init(void)
657{ 699{
658 struct device_node *np, *consoles; 700 struct device_node *np, *consoles;
@@ -679,6 +721,9 @@ static int __init opal_init(void)
679 of_node_put(consoles); 721 of_node_put(consoles);
680 } 722 }
681 723
724 /* Create i2c platform devices */
725 opal_i2c_create_devs();
726
682 /* Find all OPAL interrupts and request them */ 727 /* Find all OPAL interrupts and request them */
683 irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); 728 irqs = of_get_property(opal_node, "opal-interrupts", &irqlen);
684 pr_debug("opal: Found %d interrupts reserved for OPAL\n", 729 pr_debug("opal: Found %d interrupts reserved for OPAL\n",
@@ -702,6 +747,8 @@ static int __init opal_init(void)
702 /* Create "opal" kobject under /sys/firmware */ 747 /* Create "opal" kobject under /sys/firmware */
703 rc = opal_sysfs_init(); 748 rc = opal_sysfs_init();
704 if (rc == 0) { 749 if (rc == 0) {
750 /* Export symbol map to userspace */
751 opal_export_symmap();
705 /* Setup dump region interface */ 752 /* Setup dump region interface */
706 opal_dump_region_init(); 753 opal_dump_region_init();
707 /* Setup error log interface */ 754 /* Setup error log interface */
@@ -824,3 +871,4 @@ EXPORT_SYMBOL_GPL(opal_rtc_read);
824EXPORT_SYMBOL_GPL(opal_rtc_write); 871EXPORT_SYMBOL_GPL(opal_rtc_write);
825EXPORT_SYMBOL_GPL(opal_tpo_read); 872EXPORT_SYMBOL_GPL(opal_tpo_read);
826EXPORT_SYMBOL_GPL(opal_tpo_write); 873EXPORT_SYMBOL_GPL(opal_tpo_write);
874EXPORT_SYMBOL_GPL(opal_i2c_request);
diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h
index 6c8e2d188cd0..604c48e7879a 100644
--- a/arch/powerpc/platforms/powernv/powernv.h
+++ b/arch/powerpc/platforms/powernv/powernv.h
@@ -29,6 +29,8 @@ static inline u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev)
29} 29}
30#endif 30#endif
31 31
32extern u32 pnv_get_supported_cpuidle_states(void);
33
32extern void pnv_lpc_init(void); 34extern void pnv_lpc_init(void);
33 35
34bool cpu_core_split_required(void); 36bool cpu_core_split_required(void);
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 30b1c3e298a6..b700a329c31d 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -36,8 +36,12 @@
36#include <asm/opal.h> 36#include <asm/opal.h>
37#include <asm/kexec.h> 37#include <asm/kexec.h>
38#include <asm/smp.h> 38#include <asm/smp.h>
39#include <asm/cputhreads.h>
40#include <asm/cpuidle.h>
41#include <asm/code-patching.h>
39 42
40#include "powernv.h" 43#include "powernv.h"
44#include "subcore.h"
41 45
42static void __init pnv_setup_arch(void) 46static void __init pnv_setup_arch(void)
43{ 47{
@@ -288,6 +292,168 @@ static void __init pnv_setup_machdep_rtas(void)
288} 292}
289#endif /* CONFIG_PPC_POWERNV_RTAS */ 293#endif /* CONFIG_PPC_POWERNV_RTAS */
290 294
295static u32 supported_cpuidle_states;
296
297int pnv_save_sprs_for_winkle(void)
298{
299 int cpu;
300 int rc;
301
302 /*
303 * hid0, hid1, hid4, hid5, hmeer and lpcr values are symmetric accross
304 * all cpus at boot. Get these reg values of current cpu and use the
305 * same accross all cpus.
306 */
307 uint64_t lpcr_val = mfspr(SPRN_LPCR);
308 uint64_t hid0_val = mfspr(SPRN_HID0);
309 uint64_t hid1_val = mfspr(SPRN_HID1);
310 uint64_t hid4_val = mfspr(SPRN_HID4);
311 uint64_t hid5_val = mfspr(SPRN_HID5);
312 uint64_t hmeer_val = mfspr(SPRN_HMEER);
313
314 for_each_possible_cpu(cpu) {
315 uint64_t pir = get_hard_smp_processor_id(cpu);
316 uint64_t hsprg0_val = (uint64_t)&paca[cpu];
317
318 /*
319 * HSPRG0 is used to store the cpu's pointer to paca. Hence last
320 * 3 bits are guaranteed to be 0. Program slw to restore HSPRG0
321 * with 63rd bit set, so that when a thread wakes up at 0x100 we
322 * can use this bit to distinguish between fastsleep and
323 * deep winkle.
324 */
325 hsprg0_val |= 1;
326
327 rc = opal_slw_set_reg(pir, SPRN_HSPRG0, hsprg0_val);
328 if (rc != 0)
329 return rc;
330
331 rc = opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val);
332 if (rc != 0)
333 return rc;
334
335 /* HIDs are per core registers */
336 if (cpu_thread_in_core(cpu) == 0) {
337
338 rc = opal_slw_set_reg(pir, SPRN_HMEER, hmeer_val);
339 if (rc != 0)
340 return rc;
341
342 rc = opal_slw_set_reg(pir, SPRN_HID0, hid0_val);
343 if (rc != 0)
344 return rc;
345
346 rc = opal_slw_set_reg(pir, SPRN_HID1, hid1_val);
347 if (rc != 0)
348 return rc;
349
350 rc = opal_slw_set_reg(pir, SPRN_HID4, hid4_val);
351 if (rc != 0)
352 return rc;
353
354 rc = opal_slw_set_reg(pir, SPRN_HID5, hid5_val);
355 if (rc != 0)
356 return rc;
357 }
358 }
359
360 return 0;
361}
362
363static void pnv_alloc_idle_core_states(void)
364{
365 int i, j;
366 int nr_cores = cpu_nr_cores();
367 u32 *core_idle_state;
368
369 /*
370 * core_idle_state - First 8 bits track the idle state of each thread
371 * of the core. The 8th bit is the lock bit. Initially all thread bits
372 * are set. They are cleared when the thread enters deep idle state
373 * like sleep and winkle. Initially the lock bit is cleared.
374 * The lock bit has 2 purposes
375 * a. While the first thread is restoring core state, it prevents
376 * other threads in the core from switching to process context.
377 * b. While the last thread in the core is saving the core state, it
378 * prevents a different thread from waking up.
379 */
380 for (i = 0; i < nr_cores; i++) {
381 int first_cpu = i * threads_per_core;
382 int node = cpu_to_node(first_cpu);
383
384 core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node);
385 *core_idle_state = PNV_CORE_IDLE_THREAD_BITS;
386
387 for (j = 0; j < threads_per_core; j++) {
388 int cpu = first_cpu + j;
389
390 paca[cpu].core_idle_state_ptr = core_idle_state;
391 paca[cpu].thread_idle_state = PNV_THREAD_RUNNING;
392 paca[cpu].thread_mask = 1 << j;
393 }
394 }
395
396 update_subcore_sibling_mask();
397
398 if (supported_cpuidle_states & OPAL_PM_WINKLE_ENABLED)
399 pnv_save_sprs_for_winkle();
400}
401
402u32 pnv_get_supported_cpuidle_states(void)
403{
404 return supported_cpuidle_states;
405}
406EXPORT_SYMBOL_GPL(pnv_get_supported_cpuidle_states);
407
408static int __init pnv_init_idle_states(void)
409{
410 struct device_node *power_mgt;
411 int dt_idle_states;
412 const __be32 *idle_state_flags;
413 u32 len_flags, flags;
414 int i;
415
416 supported_cpuidle_states = 0;
417
418 if (cpuidle_disable != IDLE_NO_OVERRIDE)
419 return 0;
420
421 if (!firmware_has_feature(FW_FEATURE_OPALv3))
422 return 0;
423
424 power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
425 if (!power_mgt) {
426 pr_warn("opal: PowerMgmt Node not found\n");
427 return 0;
428 }
429
430 idle_state_flags = of_get_property(power_mgt,
431 "ibm,cpu-idle-state-flags", &len_flags);
432 if (!idle_state_flags) {
433 pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-flags\n");
434 return 0;
435 }
436
437 dt_idle_states = len_flags / sizeof(u32);
438
439 for (i = 0; i < dt_idle_states; i++) {
440 flags = be32_to_cpu(idle_state_flags[i]);
441 supported_cpuidle_states |= flags;
442 }
443 if (!(supported_cpuidle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {
444 patch_instruction(
445 (unsigned int *)pnv_fastsleep_workaround_at_entry,
446 PPC_INST_NOP);
447 patch_instruction(
448 (unsigned int *)pnv_fastsleep_workaround_at_exit,
449 PPC_INST_NOP);
450 }
451 pnv_alloc_idle_core_states();
452 return 0;
453}
454
455subsys_initcall(pnv_init_idle_states);
456
291static int __init pnv_probe(void) 457static int __init pnv_probe(void)
292{ 458{
293 unsigned long root = of_get_flat_dt_root(); 459 unsigned long root = of_get_flat_dt_root();
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index b716f666e48a..fc34025ef822 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -150,6 +150,7 @@ static void pnv_smp_cpu_kill_self(void)
150{ 150{
151 unsigned int cpu; 151 unsigned int cpu;
152 unsigned long srr1; 152 unsigned long srr1;
153 u32 idle_states;
153 154
154 /* Standard hot unplug procedure */ 155 /* Standard hot unplug procedure */
155 local_irq_disable(); 156 local_irq_disable();
@@ -160,13 +161,23 @@ static void pnv_smp_cpu_kill_self(void)
160 generic_set_cpu_dead(cpu); 161 generic_set_cpu_dead(cpu);
161 smp_wmb(); 162 smp_wmb();
162 163
164 idle_states = pnv_get_supported_cpuidle_states();
163 /* We don't want to take decrementer interrupts while we are offline, 165 /* We don't want to take decrementer interrupts while we are offline,
164 * so clear LPCR:PECE1. We keep PECE2 enabled. 166 * so clear LPCR:PECE1. We keep PECE2 enabled.
165 */ 167 */
166 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); 168 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);
167 while (!generic_check_cpu_restart(cpu)) { 169 while (!generic_check_cpu_restart(cpu)) {
170
168 ppc64_runlatch_off(); 171 ppc64_runlatch_off();
169 srr1 = power7_nap(1); 172
173 if (idle_states & OPAL_PM_WINKLE_ENABLED)
174 srr1 = power7_winkle();
175 else if ((idle_states & OPAL_PM_SLEEP_ENABLED) ||
176 (idle_states & OPAL_PM_SLEEP_ENABLED_ER1))
177 srr1 = power7_sleep();
178 else
179 srr1 = power7_nap(1);
180
170 ppc64_runlatch_on(); 181 ppc64_runlatch_on();
171 182
172 /* 183 /*
@@ -198,13 +209,27 @@ static void pnv_smp_cpu_kill_self(void)
198 209
199#endif /* CONFIG_HOTPLUG_CPU */ 210#endif /* CONFIG_HOTPLUG_CPU */
200 211
212static int pnv_cpu_bootable(unsigned int nr)
213{
214 /*
215 * Starting with POWER8, the subcore logic relies on all threads of a
216 * core being booted so that they can participate in split mode
217 * switches. So on those machines we ignore the smt_enabled_at_boot
218 * setting (smt-enabled on the kernel command line).
219 */
220 if (cpu_has_feature(CPU_FTR_ARCH_207S))
221 return 1;
222
223 return smp_generic_cpu_bootable(nr);
224}
225
201static struct smp_ops_t pnv_smp_ops = { 226static struct smp_ops_t pnv_smp_ops = {
202 .message_pass = smp_muxed_ipi_message_pass, 227 .message_pass = smp_muxed_ipi_message_pass,
203 .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */ 228 .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */
204 .probe = xics_smp_probe, 229 .probe = xics_smp_probe,
205 .kick_cpu = pnv_smp_kick_cpu, 230 .kick_cpu = pnv_smp_kick_cpu,
206 .setup_cpu = pnv_smp_setup_cpu, 231 .setup_cpu = pnv_smp_setup_cpu,
207 .cpu_bootable = smp_generic_cpu_bootable, 232 .cpu_bootable = pnv_cpu_bootable,
208#ifdef CONFIG_HOTPLUG_CPU 233#ifdef CONFIG_HOTPLUG_CPU
209 .cpu_disable = pnv_smp_cpu_disable, 234 .cpu_disable = pnv_smp_cpu_disable,
210 .cpu_die = generic_cpu_die, 235 .cpu_die = generic_cpu_die,
diff --git a/arch/powerpc/platforms/powernv/subcore.c b/arch/powerpc/platforms/powernv/subcore.c
index c87f96b79d1a..f60f80ada903 100644
--- a/arch/powerpc/platforms/powernv/subcore.c
+++ b/arch/powerpc/platforms/powernv/subcore.c
@@ -160,6 +160,18 @@ static void wait_for_sync_step(int step)
160 mb(); 160 mb();
161} 161}
162 162
163static void update_hid_in_slw(u64 hid0)
164{
165 u64 idle_states = pnv_get_supported_cpuidle_states();
166
167 if (idle_states & OPAL_PM_WINKLE_ENABLED) {
168 /* OPAL call to patch slw with the new HID0 value */
169 u64 cpu_pir = hard_smp_processor_id();
170
171 opal_slw_set_reg(cpu_pir, SPRN_HID0, hid0);
172 }
173}
174
163static void unsplit_core(void) 175static void unsplit_core(void)
164{ 176{
165 u64 hid0, mask; 177 u64 hid0, mask;
@@ -179,6 +191,7 @@ static void unsplit_core(void)
179 hid0 = mfspr(SPRN_HID0); 191 hid0 = mfspr(SPRN_HID0);
180 hid0 &= ~HID0_POWER8_DYNLPARDIS; 192 hid0 &= ~HID0_POWER8_DYNLPARDIS;
181 mtspr(SPRN_HID0, hid0); 193 mtspr(SPRN_HID0, hid0);
194 update_hid_in_slw(hid0);
182 195
183 while (mfspr(SPRN_HID0) & mask) 196 while (mfspr(SPRN_HID0) & mask)
184 cpu_relax(); 197 cpu_relax();
@@ -215,6 +228,7 @@ static void split_core(int new_mode)
215 hid0 = mfspr(SPRN_HID0); 228 hid0 = mfspr(SPRN_HID0);
216 hid0 |= HID0_POWER8_DYNLPARDIS | split_parms[i].value; 229 hid0 |= HID0_POWER8_DYNLPARDIS | split_parms[i].value;
217 mtspr(SPRN_HID0, hid0); 230 mtspr(SPRN_HID0, hid0);
231 update_hid_in_slw(hid0);
218 232
219 /* Wait for it to happen */ 233 /* Wait for it to happen */
220 while (!(mfspr(SPRN_HID0) & split_parms[i].mask)) 234 while (!(mfspr(SPRN_HID0) & split_parms[i].mask))
@@ -251,6 +265,25 @@ bool cpu_core_split_required(void)
251 return true; 265 return true;
252} 266}
253 267
268void update_subcore_sibling_mask(void)
269{
270 int cpu;
271 /*
272 * sibling mask for the first cpu. Left shift this by required bits
273 * to get sibling mask for the rest of the cpus.
274 */
275 int sibling_mask_first_cpu = (1 << threads_per_subcore) - 1;
276
277 for_each_possible_cpu(cpu) {
278 int tid = cpu_thread_in_core(cpu);
279 int offset = (tid / threads_per_subcore) * threads_per_subcore;
280 int mask = sibling_mask_first_cpu << offset;
281
282 paca[cpu].subcore_sibling_mask = mask;
283
284 }
285}
286
254static int cpu_update_split_mode(void *data) 287static int cpu_update_split_mode(void *data)
255{ 288{
256 int cpu, new_mode = *(int *)data; 289 int cpu, new_mode = *(int *)data;
@@ -284,6 +317,7 @@ static int cpu_update_split_mode(void *data)
284 /* Make the new mode public */ 317 /* Make the new mode public */
285 subcores_per_core = new_mode; 318 subcores_per_core = new_mode;
286 threads_per_subcore = threads_per_core / subcores_per_core; 319 threads_per_subcore = threads_per_core / subcores_per_core;
320 update_subcore_sibling_mask();
287 321
288 /* Make sure the new mode is written before we exit */ 322 /* Make sure the new mode is written before we exit */
289 mb(); 323 mb();
diff --git a/arch/powerpc/platforms/powernv/subcore.h b/arch/powerpc/platforms/powernv/subcore.h
index 148abc91debf..84e02ae52895 100644
--- a/arch/powerpc/platforms/powernv/subcore.h
+++ b/arch/powerpc/platforms/powernv/subcore.h
@@ -14,5 +14,12 @@
14#define SYNC_STEP_FINISHED 3 /* Set by secondary when split/unsplit is done */ 14#define SYNC_STEP_FINISHED 3 /* Set by secondary when split/unsplit is done */
15 15
16#ifndef __ASSEMBLY__ 16#ifndef __ASSEMBLY__
17
18#ifdef CONFIG_SMP
17void split_core_secondary_loop(u8 *state); 19void split_core_secondary_loop(u8 *state);
18#endif 20extern void update_subcore_sibling_mask(void);
21#else
22static inline void update_subcore_sibling_mask(void) { };
23#endif /* CONFIG_SMP */
24
25#endif /* __ASSEMBLY__ */