// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later /* * NX Accellerator unit support * * Copyright 2013-2019 IBM Corp. */ #include #include #include #include #include #include #include #include #include #include #include #include static void darn_init(void) { struct dt_node *nx; struct proc_chip *chip; struct cpu_thread *c; uint64_t bar, default_bar; if (chip_quirk(QUIRK_NO_RNG)) return; /* * To allow the DARN instruction to function there must be at least * one NX available in the system. Otherwise using DARN will result * in a checkstop. I suppose we could mask the FIR... */ dt_for_each_compatible(dt_root, nx, "ibm,power9-nx") break; assert(nx); phys_map_get(dt_get_chip_id(nx), NX_RNG, 0, &default_bar, NULL); for_each_chip(chip) { /* is this NX enabled? */ xscom_read(chip->id, P9X_NX_MMIO_BAR, &bar); if (!(bar & ~P9X_NX_MMIO_BAR_EN)) bar = default_bar; for_each_available_core_in_chip(c, chip->id) { uint64_t addr; if (proc_gen == proc_gen_p9) { addr = XSCOM_ADDR_P9_EX(pir_to_core_id(c->pir), P9X_EX_NCU_DARN_BAR); xscom_write(chip->id, addr, bar | P9X_EX_NCU_DARN_BAR_EN); } else if (proc_gen >= proc_gen_p10) { addr = XSCOM_ADDR_P10_NCU(pir_to_core_id(c->pir), P10_NCU_DARN_BAR); xscom_write(chip->id, addr, bar | P10_NCU_DARN_BAR_EN); /* Init for sibling core also */ if (c->is_fused_core) { addr = XSCOM_ADDR_P10_NCU(pir_to_core_id(c->pir + 1), P10_NCU_DARN_BAR); xscom_write(chip->id, addr, bar | P10_NCU_DARN_BAR_EN); } } } } } void nx_p9_rng_late_init(void) { struct cpu_thread *c; uint64_t rc; if (proc_gen < proc_gen_p9) return; if (chip_quirk(QUIRK_NO_RNG)) return; prlog(PR_INFO, "SLW: Configuring self-restore for P9X_EX_NCU_DARN_BAR\n"); for_each_present_cpu(c) { if(cpu_is_thread0(c)) { struct proc_chip *chip = get_chip(c->chip_id); uint64_t addr, bar; phys_map_get(chip->id, NX_RNG, 0, &bar, NULL); addr = XSCOM_ADDR_P9_EX(pir_to_core_id(c->pir), P9X_EX_NCU_DARN_BAR); /* Bail out if wakeup engine has already failed */ if ( wakeup_engine_state != WAKEUP_ENGINE_PRESENT) { prlog(PR_ERR,"DARN BAR p9_stop_api fail detected\n"); break; } rc = p9_stop_save_scom((void *)chip->homer_base, addr, bar | P9X_EX_NCU_DARN_BAR_EN, P9_STOP_SCOM_REPLACE, P9_STOP_SECTION_EQ_SCOM); if (rc) { prlog(PR_ERR, "p9_stop_api for DARN_BAR failed rc= %lld", rc); prlog(PR_ERR, "Disabling deep stop states\n"); wakeup_engine_state = WAKEUP_ENGINE_FAILED; break; } } } } static void nx_init_one(struct dt_node *node) { nx_create_rng_node(node); if (!vas_nx_enabled()) return; nx_create_crypto_node(node); nx_create_compress_node(node); } void nx_init(void) { struct dt_node *node; dt_for_each_compatible(dt_root, node, "ibm,power-nx") { nx_init_one(node); } dt_for_each_compatible(dt_root, node, "ibm,power9-nx") { nx_init_one(node); } if (proc_gen >= proc_gen_p9) darn_init(); } DEFINE_HWPROBE_DEPS(nx, nx_init, "vas");