19a868f63SMichael Ellerman // SPDX-License-Identifier: GPL-2.0+ 29a868f63SMichael Ellerman // 39a868f63SMichael Ellerman // Security related flags and so on. 49a868f63SMichael Ellerman // 59a868f63SMichael Ellerman // Copyright 2018, Michael Ellerman, IBM Corporation. 69a868f63SMichael Ellerman 79a868f63SMichael Ellerman #include <linux/kernel.h> 88ad33041SMichael Ellerman #include <linux/device.h> 9ff348355SMichael Ellerman #include <linux/seq_buf.h> 108ad33041SMichael Ellerman 11*ee13cb24SMichael Ellerman #include <asm/asm-prototypes.h> 12*ee13cb24SMichael Ellerman #include <asm/code-patching.h> 13a048a07dSNicholas Piggin #include <asm/debugfs.h> 149a868f63SMichael Ellerman #include <asm/security_features.h> 152eea7f06SMichal Suchanek #include <asm/setup.h> 169a868f63SMichael Ellerman 179a868f63SMichael Ellerman 18e7347a86SMauricio Faria de Oliveira unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; 198ad33041SMichael Ellerman 20*ee13cb24SMichael Ellerman enum count_cache_flush_type { 21*ee13cb24SMichael Ellerman COUNT_CACHE_FLUSH_NONE = 0x1, 22*ee13cb24SMichael Ellerman COUNT_CACHE_FLUSH_SW = 0x2, 23*ee13cb24SMichael Ellerman COUNT_CACHE_FLUSH_HW = 0x4, 24*ee13cb24SMichael Ellerman }; 25*ee13cb24SMichael Ellerman static enum count_cache_flush_type count_cache_flush_type; 26*ee13cb24SMichael Ellerman 27815069caSMichal Suchanek bool barrier_nospec_enabled; 28cf175dc3SDiana Craciun static bool no_nospec; 292eea7f06SMichal Suchanek 302eea7f06SMichal Suchanek static void enable_barrier_nospec(bool enable) 312eea7f06SMichal Suchanek { 322eea7f06SMichal Suchanek barrier_nospec_enabled = enable; 332eea7f06SMichal Suchanek do_barrier_nospec_fixups(enable); 342eea7f06SMichal Suchanek } 352eea7f06SMichal Suchanek 36cb3d6759SMichal Suchanek void setup_barrier_nospec(void) 37cb3d6759SMichal Suchanek { 38cb3d6759SMichal Suchanek bool enable; 39cb3d6759SMichal Suchanek 40cb3d6759SMichal Suchanek /* 41cb3d6759SMichal Suchanek * It would make sense to check SEC_FTR_SPEC_BAR_ORI31 below as well. 42cb3d6759SMichal Suchanek * But there's a good reason not to. The two flags we check below are 43cb3d6759SMichal Suchanek * both are enabled by default in the kernel, so if the hcall is not 44cb3d6759SMichal Suchanek * functional they will be enabled. 45cb3d6759SMichal Suchanek * On a system where the host firmware has been updated (so the ori 46cb3d6759SMichal Suchanek * functions as a barrier), but on which the hypervisor (KVM/Qemu) has 47cb3d6759SMichal Suchanek * not been updated, we would like to enable the barrier. Dropping the 48cb3d6759SMichal Suchanek * check for SEC_FTR_SPEC_BAR_ORI31 achieves that. The only downside is 49cb3d6759SMichal Suchanek * we potentially enable the barrier on systems where the host firmware 50cb3d6759SMichal Suchanek * is not updated, but that's harmless as it's a no-op. 51cb3d6759SMichal Suchanek */ 52cb3d6759SMichal Suchanek enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && 53cb3d6759SMichal Suchanek security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); 54cb3d6759SMichal Suchanek 55cf175dc3SDiana Craciun if (!no_nospec) 56cb3d6759SMichal Suchanek enable_barrier_nospec(enable); 57cb3d6759SMichal Suchanek } 58cb3d6759SMichal Suchanek 59cf175dc3SDiana Craciun static int __init handle_nospectre_v1(char *p) 60cf175dc3SDiana Craciun { 61cf175dc3SDiana Craciun no_nospec = true; 62cf175dc3SDiana Craciun 63cf175dc3SDiana Craciun return 0; 64cf175dc3SDiana Craciun } 65cf175dc3SDiana Craciun early_param("nospectre_v1", handle_nospectre_v1); 66cf175dc3SDiana Craciun 67cb3d6759SMichal Suchanek #ifdef CONFIG_DEBUG_FS 68cb3d6759SMichal Suchanek static int barrier_nospec_set(void *data, u64 val) 69cb3d6759SMichal Suchanek { 70cb3d6759SMichal Suchanek switch (val) { 71cb3d6759SMichal Suchanek case 0: 72cb3d6759SMichal Suchanek case 1: 73cb3d6759SMichal Suchanek break; 74cb3d6759SMichal Suchanek default: 75cb3d6759SMichal Suchanek return -EINVAL; 76cb3d6759SMichal Suchanek } 77cb3d6759SMichal Suchanek 78cb3d6759SMichal Suchanek if (!!val == !!barrier_nospec_enabled) 79cb3d6759SMichal Suchanek return 0; 80cb3d6759SMichal Suchanek 81cb3d6759SMichal Suchanek enable_barrier_nospec(!!val); 82cb3d6759SMichal Suchanek 83cb3d6759SMichal Suchanek return 0; 84cb3d6759SMichal Suchanek } 85cb3d6759SMichal Suchanek 86cb3d6759SMichal Suchanek static int barrier_nospec_get(void *data, u64 *val) 87cb3d6759SMichal Suchanek { 88cb3d6759SMichal Suchanek *val = barrier_nospec_enabled ? 1 : 0; 89cb3d6759SMichal Suchanek return 0; 90cb3d6759SMichal Suchanek } 91cb3d6759SMichal Suchanek 92cb3d6759SMichal Suchanek DEFINE_SIMPLE_ATTRIBUTE(fops_barrier_nospec, 93cb3d6759SMichal Suchanek barrier_nospec_get, barrier_nospec_set, "%llu\n"); 94cb3d6759SMichal Suchanek 95cb3d6759SMichal Suchanek static __init int barrier_nospec_debugfs_init(void) 96cb3d6759SMichal Suchanek { 97cb3d6759SMichal Suchanek debugfs_create_file("barrier_nospec", 0600, powerpc_debugfs_root, NULL, 98cb3d6759SMichal Suchanek &fops_barrier_nospec); 99cb3d6759SMichal Suchanek return 0; 100cb3d6759SMichal Suchanek } 101cb3d6759SMichal Suchanek device_initcall(barrier_nospec_debugfs_init); 102cb3d6759SMichal Suchanek #endif /* CONFIG_DEBUG_FS */ 103cb3d6759SMichal Suchanek 104406d2b6aSDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64 1058ad33041SMichael Ellerman ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) 1068ad33041SMichael Ellerman { 107ff348355SMichael Ellerman bool thread_priv; 108ff348355SMichael Ellerman 109ff348355SMichael Ellerman thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); 110ff348355SMichael Ellerman 111ff348355SMichael Ellerman if (rfi_flush || thread_priv) { 112ff348355SMichael Ellerman struct seq_buf s; 113ff348355SMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 114ff348355SMichael Ellerman 115ff348355SMichael Ellerman seq_buf_printf(&s, "Mitigation: "); 116ff348355SMichael Ellerman 1178ad33041SMichael Ellerman if (rfi_flush) 118ff348355SMichael Ellerman seq_buf_printf(&s, "RFI Flush"); 119ff348355SMichael Ellerman 120ff348355SMichael Ellerman if (rfi_flush && thread_priv) 121ff348355SMichael Ellerman seq_buf_printf(&s, ", "); 122ff348355SMichael Ellerman 123ff348355SMichael Ellerman if (thread_priv) 124ff348355SMichael Ellerman seq_buf_printf(&s, "L1D private per thread"); 125ff348355SMichael Ellerman 126ff348355SMichael Ellerman seq_buf_printf(&s, "\n"); 127ff348355SMichael Ellerman 128ff348355SMichael Ellerman return s.len; 129ff348355SMichael Ellerman } 130ff348355SMichael Ellerman 131ff348355SMichael Ellerman if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && 132ff348355SMichael Ellerman !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) 133ff348355SMichael Ellerman return sprintf(buf, "Not affected\n"); 1348ad33041SMichael Ellerman 1358ad33041SMichael Ellerman return sprintf(buf, "Vulnerable\n"); 1368ad33041SMichael Ellerman } 137406d2b6aSDiana Craciun #endif 13856986016SMichael Ellerman 13956986016SMichael Ellerman ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) 14056986016SMichael Ellerman { 1416d44acaeSMichael Ellerman struct seq_buf s; 14256986016SMichael Ellerman 1436d44acaeSMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 1446d44acaeSMichael Ellerman 1456d44acaeSMichael Ellerman if (security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) { 146a3775145SMichal Suchanek if (barrier_nospec_enabled) 1476d44acaeSMichael Ellerman seq_buf_printf(&s, "Mitigation: __user pointer sanitization"); 1486d44acaeSMichael Ellerman else 1496d44acaeSMichael Ellerman seq_buf_printf(&s, "Vulnerable"); 150a3775145SMichal Suchanek 1516d44acaeSMichael Ellerman if (security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31)) 1526d44acaeSMichael Ellerman seq_buf_printf(&s, ", ori31 speculation barrier enabled"); 1536d44acaeSMichael Ellerman 1546d44acaeSMichael Ellerman seq_buf_printf(&s, "\n"); 1556d44acaeSMichael Ellerman } else 1566d44acaeSMichael Ellerman seq_buf_printf(&s, "Not affected\n"); 1576d44acaeSMichael Ellerman 1586d44acaeSMichael Ellerman return s.len; 15956986016SMichael Ellerman } 160d6fbe1c5SMichael Ellerman 161d6fbe1c5SMichael Ellerman ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) 162d6fbe1c5SMichael Ellerman { 163d6fbe1c5SMichael Ellerman struct seq_buf s; 1646d44acaeSMichael Ellerman bool bcs, ccd; 165d6fbe1c5SMichael Ellerman 166d6fbe1c5SMichael Ellerman seq_buf_init(&s, buf, PAGE_SIZE - 1); 167d6fbe1c5SMichael Ellerman 168d6fbe1c5SMichael Ellerman bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED); 169d6fbe1c5SMichael Ellerman ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); 170d6fbe1c5SMichael Ellerman 171*ee13cb24SMichael Ellerman if (bcs || ccd || count_cache_flush_type != COUNT_CACHE_FLUSH_NONE) { 172*ee13cb24SMichael Ellerman bool comma = false; 173d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Mitigation: "); 174d6fbe1c5SMichael Ellerman 175*ee13cb24SMichael Ellerman if (bcs) { 176d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); 177*ee13cb24SMichael Ellerman comma = true; 178*ee13cb24SMichael Ellerman } 179d6fbe1c5SMichael Ellerman 180*ee13cb24SMichael Ellerman if (ccd) { 181*ee13cb24SMichael Ellerman if (comma) 182*ee13cb24SMichael Ellerman seq_buf_printf(&s, ", "); 183*ee13cb24SMichael Ellerman seq_buf_printf(&s, "Indirect branch cache disabled"); 184*ee13cb24SMichael Ellerman comma = true; 185*ee13cb24SMichael Ellerman } 186*ee13cb24SMichael Ellerman 187*ee13cb24SMichael Ellerman if (comma) 188d6fbe1c5SMichael Ellerman seq_buf_printf(&s, ", "); 189d6fbe1c5SMichael Ellerman 190*ee13cb24SMichael Ellerman seq_buf_printf(&s, "Software count cache flush"); 191*ee13cb24SMichael Ellerman 192*ee13cb24SMichael Ellerman if (count_cache_flush_type == COUNT_CACHE_FLUSH_HW) 193*ee13cb24SMichael Ellerman seq_buf_printf(&s, "(hardware accelerated)"); 194d6fbe1c5SMichael Ellerman } else 195d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "Vulnerable"); 196d6fbe1c5SMichael Ellerman 197d6fbe1c5SMichael Ellerman seq_buf_printf(&s, "\n"); 198d6fbe1c5SMichael Ellerman 199d6fbe1c5SMichael Ellerman return s.len; 200d6fbe1c5SMichael Ellerman } 201a048a07dSNicholas Piggin 2026453b532SDiana Craciun #ifdef CONFIG_PPC_BOOK3S_64 203a048a07dSNicholas Piggin /* 204a048a07dSNicholas Piggin * Store-forwarding barrier support. 205a048a07dSNicholas Piggin */ 206a048a07dSNicholas Piggin 207a048a07dSNicholas Piggin static enum stf_barrier_type stf_enabled_flush_types; 208a048a07dSNicholas Piggin static bool no_stf_barrier; 209a048a07dSNicholas Piggin bool stf_barrier; 210a048a07dSNicholas Piggin 211a048a07dSNicholas Piggin static int __init handle_no_stf_barrier(char *p) 212a048a07dSNicholas Piggin { 213a048a07dSNicholas Piggin pr_info("stf-barrier: disabled on command line."); 214a048a07dSNicholas Piggin no_stf_barrier = true; 215a048a07dSNicholas Piggin return 0; 216a048a07dSNicholas Piggin } 217a048a07dSNicholas Piggin 218a048a07dSNicholas Piggin early_param("no_stf_barrier", handle_no_stf_barrier); 219a048a07dSNicholas Piggin 220a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */ 221a048a07dSNicholas Piggin static int __init handle_ssbd(char *p) 222a048a07dSNicholas Piggin { 223a048a07dSNicholas Piggin if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { 224a048a07dSNicholas Piggin /* Until firmware tells us, we have the barrier with auto */ 225a048a07dSNicholas Piggin return 0; 226a048a07dSNicholas Piggin } else if (strncmp(p, "off", 3) == 0) { 227a048a07dSNicholas Piggin handle_no_stf_barrier(NULL); 228a048a07dSNicholas Piggin return 0; 229a048a07dSNicholas Piggin } else 230a048a07dSNicholas Piggin return 1; 231a048a07dSNicholas Piggin 232a048a07dSNicholas Piggin return 0; 233a048a07dSNicholas Piggin } 234a048a07dSNicholas Piggin early_param("spec_store_bypass_disable", handle_ssbd); 235a048a07dSNicholas Piggin 236a048a07dSNicholas Piggin /* This is the generic flag used by other architectures */ 237a048a07dSNicholas Piggin static int __init handle_no_ssbd(char *p) 238a048a07dSNicholas Piggin { 239a048a07dSNicholas Piggin handle_no_stf_barrier(NULL); 240a048a07dSNicholas Piggin return 0; 241a048a07dSNicholas Piggin } 242a048a07dSNicholas Piggin early_param("nospec_store_bypass_disable", handle_no_ssbd); 243a048a07dSNicholas Piggin 244a048a07dSNicholas Piggin static void stf_barrier_enable(bool enable) 245a048a07dSNicholas Piggin { 246a048a07dSNicholas Piggin if (enable) 247a048a07dSNicholas Piggin do_stf_barrier_fixups(stf_enabled_flush_types); 248a048a07dSNicholas Piggin else 249a048a07dSNicholas Piggin do_stf_barrier_fixups(STF_BARRIER_NONE); 250a048a07dSNicholas Piggin 251a048a07dSNicholas Piggin stf_barrier = enable; 252a048a07dSNicholas Piggin } 253a048a07dSNicholas Piggin 254a048a07dSNicholas Piggin void setup_stf_barrier(void) 255a048a07dSNicholas Piggin { 256a048a07dSNicholas Piggin enum stf_barrier_type type; 257a048a07dSNicholas Piggin bool enable, hv; 258a048a07dSNicholas Piggin 259a048a07dSNicholas Piggin hv = cpu_has_feature(CPU_FTR_HVMODE); 260a048a07dSNicholas Piggin 261a048a07dSNicholas Piggin /* Default to fallback in case fw-features are not available */ 262a048a07dSNicholas Piggin if (cpu_has_feature(CPU_FTR_ARCH_300)) 263a048a07dSNicholas Piggin type = STF_BARRIER_EIEIO; 264a048a07dSNicholas Piggin else if (cpu_has_feature(CPU_FTR_ARCH_207S)) 265a048a07dSNicholas Piggin type = STF_BARRIER_SYNC_ORI; 266a048a07dSNicholas Piggin else if (cpu_has_feature(CPU_FTR_ARCH_206)) 267a048a07dSNicholas Piggin type = STF_BARRIER_FALLBACK; 268a048a07dSNicholas Piggin else 269a048a07dSNicholas Piggin type = STF_BARRIER_NONE; 270a048a07dSNicholas Piggin 271a048a07dSNicholas Piggin enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && 272a048a07dSNicholas Piggin (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || 273a048a07dSNicholas Piggin (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); 274a048a07dSNicholas Piggin 275a048a07dSNicholas Piggin if (type == STF_BARRIER_FALLBACK) { 276a048a07dSNicholas Piggin pr_info("stf-barrier: fallback barrier available\n"); 277a048a07dSNicholas Piggin } else if (type == STF_BARRIER_SYNC_ORI) { 278a048a07dSNicholas Piggin pr_info("stf-barrier: hwsync barrier available\n"); 279a048a07dSNicholas Piggin } else if (type == STF_BARRIER_EIEIO) { 280a048a07dSNicholas Piggin pr_info("stf-barrier: eieio barrier available\n"); 281a048a07dSNicholas Piggin } 282a048a07dSNicholas Piggin 283a048a07dSNicholas Piggin stf_enabled_flush_types = type; 284a048a07dSNicholas Piggin 285a048a07dSNicholas Piggin if (!no_stf_barrier) 286a048a07dSNicholas Piggin stf_barrier_enable(enable); 287a048a07dSNicholas Piggin } 288a048a07dSNicholas Piggin 289a048a07dSNicholas Piggin ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) 290a048a07dSNicholas Piggin { 291a048a07dSNicholas Piggin if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { 292a048a07dSNicholas Piggin const char *type; 293a048a07dSNicholas Piggin switch (stf_enabled_flush_types) { 294a048a07dSNicholas Piggin case STF_BARRIER_EIEIO: 295a048a07dSNicholas Piggin type = "eieio"; 296a048a07dSNicholas Piggin break; 297a048a07dSNicholas Piggin case STF_BARRIER_SYNC_ORI: 298a048a07dSNicholas Piggin type = "hwsync"; 299a048a07dSNicholas Piggin break; 300a048a07dSNicholas Piggin case STF_BARRIER_FALLBACK: 301a048a07dSNicholas Piggin type = "fallback"; 302a048a07dSNicholas Piggin break; 303a048a07dSNicholas Piggin default: 304a048a07dSNicholas Piggin type = "unknown"; 305a048a07dSNicholas Piggin } 306a048a07dSNicholas Piggin return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); 307a048a07dSNicholas Piggin } 308a048a07dSNicholas Piggin 309a048a07dSNicholas Piggin if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && 310a048a07dSNicholas Piggin !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) 311a048a07dSNicholas Piggin return sprintf(buf, "Not affected\n"); 312a048a07dSNicholas Piggin 313a048a07dSNicholas Piggin return sprintf(buf, "Vulnerable\n"); 314a048a07dSNicholas Piggin } 315a048a07dSNicholas Piggin 316a048a07dSNicholas Piggin #ifdef CONFIG_DEBUG_FS 317a048a07dSNicholas Piggin static int stf_barrier_set(void *data, u64 val) 318a048a07dSNicholas Piggin { 319a048a07dSNicholas Piggin bool enable; 320a048a07dSNicholas Piggin 321a048a07dSNicholas Piggin if (val == 1) 322a048a07dSNicholas Piggin enable = true; 323a048a07dSNicholas Piggin else if (val == 0) 324a048a07dSNicholas Piggin enable = false; 325a048a07dSNicholas Piggin else 326a048a07dSNicholas Piggin return -EINVAL; 327a048a07dSNicholas Piggin 328a048a07dSNicholas Piggin /* Only do anything if we're changing state */ 329a048a07dSNicholas Piggin if (enable != stf_barrier) 330a048a07dSNicholas Piggin stf_barrier_enable(enable); 331a048a07dSNicholas Piggin 332a048a07dSNicholas Piggin return 0; 333a048a07dSNicholas Piggin } 334a048a07dSNicholas Piggin 335a048a07dSNicholas Piggin static int stf_barrier_get(void *data, u64 *val) 336a048a07dSNicholas Piggin { 337a048a07dSNicholas Piggin *val = stf_barrier ? 1 : 0; 338a048a07dSNicholas Piggin return 0; 339a048a07dSNicholas Piggin } 340a048a07dSNicholas Piggin 341a048a07dSNicholas Piggin DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n"); 342a048a07dSNicholas Piggin 343a048a07dSNicholas Piggin static __init int stf_barrier_debugfs_init(void) 344a048a07dSNicholas Piggin { 345a048a07dSNicholas Piggin debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier); 346a048a07dSNicholas Piggin return 0; 347a048a07dSNicholas Piggin } 348a048a07dSNicholas Piggin device_initcall(stf_barrier_debugfs_init); 349a048a07dSNicholas Piggin #endif /* CONFIG_DEBUG_FS */ 350*ee13cb24SMichael Ellerman 351*ee13cb24SMichael Ellerman static void toggle_count_cache_flush(bool enable) 352*ee13cb24SMichael Ellerman { 353*ee13cb24SMichael Ellerman if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) { 354*ee13cb24SMichael Ellerman patch_instruction_site(&patch__call_flush_count_cache, PPC_INST_NOP); 355*ee13cb24SMichael Ellerman count_cache_flush_type = COUNT_CACHE_FLUSH_NONE; 356*ee13cb24SMichael Ellerman pr_info("count-cache-flush: software flush disabled.\n"); 357*ee13cb24SMichael Ellerman return; 358*ee13cb24SMichael Ellerman } 359*ee13cb24SMichael Ellerman 360*ee13cb24SMichael Ellerman patch_branch_site(&patch__call_flush_count_cache, 361*ee13cb24SMichael Ellerman (u64)&flush_count_cache, BRANCH_SET_LINK); 362*ee13cb24SMichael Ellerman 363*ee13cb24SMichael Ellerman if (!security_ftr_enabled(SEC_FTR_BCCTR_FLUSH_ASSIST)) { 364*ee13cb24SMichael Ellerman count_cache_flush_type = COUNT_CACHE_FLUSH_SW; 365*ee13cb24SMichael Ellerman pr_info("count-cache-flush: full software flush sequence enabled.\n"); 366*ee13cb24SMichael Ellerman return; 367*ee13cb24SMichael Ellerman } 368*ee13cb24SMichael Ellerman 369*ee13cb24SMichael Ellerman patch_instruction_site(&patch__flush_count_cache_return, PPC_INST_BLR); 370*ee13cb24SMichael Ellerman count_cache_flush_type = COUNT_CACHE_FLUSH_HW; 371*ee13cb24SMichael Ellerman pr_info("count-cache-flush: hardware assisted flush sequence enabled\n"); 372*ee13cb24SMichael Ellerman } 373*ee13cb24SMichael Ellerman 374*ee13cb24SMichael Ellerman void setup_count_cache_flush(void) 375*ee13cb24SMichael Ellerman { 376*ee13cb24SMichael Ellerman toggle_count_cache_flush(true); 377*ee13cb24SMichael Ellerman } 378*ee13cb24SMichael Ellerman 379*ee13cb24SMichael Ellerman #ifdef CONFIG_DEBUG_FS 380*ee13cb24SMichael Ellerman static int count_cache_flush_set(void *data, u64 val) 381*ee13cb24SMichael Ellerman { 382*ee13cb24SMichael Ellerman bool enable; 383*ee13cb24SMichael Ellerman 384*ee13cb24SMichael Ellerman if (val == 1) 385*ee13cb24SMichael Ellerman enable = true; 386*ee13cb24SMichael Ellerman else if (val == 0) 387*ee13cb24SMichael Ellerman enable = false; 388*ee13cb24SMichael Ellerman else 389*ee13cb24SMichael Ellerman return -EINVAL; 390*ee13cb24SMichael Ellerman 391*ee13cb24SMichael Ellerman toggle_count_cache_flush(enable); 392*ee13cb24SMichael Ellerman 393*ee13cb24SMichael Ellerman return 0; 394*ee13cb24SMichael Ellerman } 395*ee13cb24SMichael Ellerman 396*ee13cb24SMichael Ellerman static int count_cache_flush_get(void *data, u64 *val) 397*ee13cb24SMichael Ellerman { 398*ee13cb24SMichael Ellerman if (count_cache_flush_type == COUNT_CACHE_FLUSH_NONE) 399*ee13cb24SMichael Ellerman *val = 0; 400*ee13cb24SMichael Ellerman else 401*ee13cb24SMichael Ellerman *val = 1; 402*ee13cb24SMichael Ellerman 403*ee13cb24SMichael Ellerman return 0; 404*ee13cb24SMichael Ellerman } 405*ee13cb24SMichael Ellerman 406*ee13cb24SMichael Ellerman DEFINE_SIMPLE_ATTRIBUTE(fops_count_cache_flush, count_cache_flush_get, 407*ee13cb24SMichael Ellerman count_cache_flush_set, "%llu\n"); 408*ee13cb24SMichael Ellerman 409*ee13cb24SMichael Ellerman static __init int count_cache_flush_debugfs_init(void) 410*ee13cb24SMichael Ellerman { 411*ee13cb24SMichael Ellerman debugfs_create_file("count_cache_flush", 0600, powerpc_debugfs_root, 412*ee13cb24SMichael Ellerman NULL, &fops_count_cache_flush); 413*ee13cb24SMichael Ellerman return 0; 414*ee13cb24SMichael Ellerman } 415*ee13cb24SMichael Ellerman device_initcall(count_cache_flush_debugfs_init); 416*ee13cb24SMichael Ellerman #endif /* CONFIG_DEBUG_FS */ 4176453b532SDiana Craciun #endif /* CONFIG_PPC_BOOK3S_64 */ 418