Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp228200ybl; Wed, 4 Dec 2019 01:34:28 -0800 (PST) X-Google-Smtp-Source: APXvYqyS8fvtxPnxSWPnhbc5nBs2dUq5BBkTneWrnXYSnEvJTIeYJS4A4tYKtSpAvnvNQENrgmGU X-Received: by 2002:aca:c389:: with SMTP id t131mr1659842oif.102.1575452068694; Wed, 04 Dec 2019 01:34:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1575452068; cv=none; d=google.com; s=arc-20160816; b=jFJRboYuVmQqa7yhZBeFuiqfShyqlZ2KaFxL16yb19L+CFe35l1cvIgSuin22C7/g6 6WKeVThn6rT7vfbHttjIKXVff82mV0w/oZ5VBsCuEXjSya2li/bYHsxqLx5Q7cW9meBG 16CXxPH3mYx17muH52/7I7lLIZEc7cVY4RHPhTFOaRG/4xiMBdSygzRWqB5RM2d0KWUr auuxoawoWh1rdgEI4kcBr0hs/on/HpW5YqkuStfNk30iFANfHZHwXCcSVVG1g2WM7Qg3 ntPEvwz6HzkELUflGQ4WeCQyBrE/WYtuI1xNiN8zGQkELWmK/o+AhzSbkFleHmQrDaNI kDVA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:content-transfer-encoding :mime-version:references:in-reply-to:date:subject:to:from; bh=RRQ7PLRw3suCjQlQC82+8b57MezxX1EhUO6eY8B0MUc=; b=vFayugth3UaB8nEI+Ng3X1yd1cNzmMAsj4ebJpQ2720B4Qnf1pWYsM94zh7SdvuJ2C ig5IVHIM28ns7bNABGf7vhSr3R3Vln32/VXvgfXALDCbxjkhHWSscwBFeYP0iihLXAzl r4FXij2gYq18JPquS0yav3gRsNkQy8OsVo7pobnAsGSbupLnVQxCPtgRpMswJh0m34e3 3/SVmeVe68tO7K3opzrTDbnq4BS+HxijVMzRRJAfpjX4vaLVszdt9ZbSzaPhHMxUHWeS WD8H4fGBefRSAnWsSaW0KNocG9KYJoSuRmkBxNWpCDN5crNl2CnzOUTC5Blak6nezjxV Ts3g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=ibm.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p28si2867780oth.296.2019.12.04.01.34.14; Wed, 04 Dec 2019 01:34:28 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=ibm.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727492AbfLDJdK (ORCPT + 99 others); Wed, 4 Dec 2019 04:33:10 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:14376 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726899AbfLDJdJ (ORCPT ); Wed, 4 Dec 2019 04:33:09 -0500 Received: from pps.filterd (m0098416.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id xB49VpEI136012 for ; Wed, 4 Dec 2019 04:33:07 -0500 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0b-001b2d01.pphosted.com with ESMTP id 2wnsd4vb2s-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Wed, 04 Dec 2019 04:33:07 -0500 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 4 Dec 2019 09:33:06 -0000 Received: from b06cxnps3074.portsmouth.uk.ibm.com (9.149.109.194) by e06smtp04.uk.ibm.com (192.168.101.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Wed, 4 Dec 2019 09:33:04 -0000 Received: from b06wcsmtp001.portsmouth.uk.ibm.com (b06wcsmtp001.portsmouth.uk.ibm.com [9.149.105.160]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id xB49X24D36503582 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 4 Dec 2019 09:33:02 GMT Received: from b06wcsmtp001.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7AF7EA405C; Wed, 4 Dec 2019 09:33:02 +0000 (GMT) Received: from b06wcsmtp001.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E4DF7A4054; Wed, 4 Dec 2019 09:32:59 +0000 (GMT) Received: from pratiks-thinkpad.ibmuc.com (unknown [9.85.83.83]) by b06wcsmtp001.portsmouth.uk.ibm.com (Postfix) with ESMTP; Wed, 4 Dec 2019 09:32:59 +0000 (GMT) From: Pratik Rajesh Sampat To: linux-kernel@vger.kernel.org, linuxppc-dev@ozlabs.org, mpe@ellerman.id.au, svaidy@linux.ibm.com, ego@linux.vnet.ibm.com, linuxram@us.ibm.com, psampat@linux.ibm.com, pratik.sampat@in.ibm.com Subject: [RFC 1/3] powerpc/powernv: Interface to define support and preference for a SPR Date: Wed, 4 Dec 2019 15:02:53 +0530 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191204093255.11849-1-psampat@linux.ibm.com> References: <20191204093255.11849-1-psampat@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-TM-AS-GCONF: 00 x-cbid: 19120409-0016-0000-0000-000002D0E227 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19120409-0017-0000-0000-00003332E0AA Message-Id: <20191204093255.11849-2-psampat@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.95,18.0.572 definitions=2019-12-04_02:2019-12-04,2019-12-04 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 phishscore=0 spamscore=0 priorityscore=1501 mlxscore=0 malwarescore=0 lowpriorityscore=0 adultscore=0 mlxlogscore=999 impostorscore=0 suspectscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-1912040073 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Define a bitmask interface to determine support for the Self Restore, Self Save or both. Also define an interface to determine the preference of that SPR to be strictly saved or restored or encapsulated with an order of preference. The preference bitmask is shown as below: ---------------------------- |... | 2nd pref | 1st pref | ---------------------------- MSB LSB The preference from higher to lower is from LSB to MSB with a shift of 8 bits. Example: Prefer self save first, if not available then prefer self restore The preference mask for this scenario will be seen as below. ((SELF_RESTORE_STRICT << PREFERENCE_SHIFT) | SELF_SAVE_STRICT) --------------------------------- |... | Self restore | Self save | --------------------------------- MSB LSB Finally, declare a list of preferred SPRs which encapsulate the bitmaks for preferred and supported with defaults of both being set to support legacy firmware. This commit also implements using the above interface and retains the legacy functionality of self restore. Signed-off-by: Pratik Rajesh Sampat --- arch/powerpc/platforms/powernv/idle.c | 325 +++++++++++++++++++++----- 1 file changed, 269 insertions(+), 56 deletions(-) diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c index 78599bca66c2..d38b8b6dcbce 100644 --- a/arch/powerpc/platforms/powernv/idle.c +++ b/arch/powerpc/platforms/powernv/idle.c @@ -32,9 +32,106 @@ #define P9_STOP_SPR_MSR 2000 #define P9_STOP_SPR_PSSCR 855 +/* Interface for the stop state supported and preference */ +#define SELF_RESTORE_TYPE 0 +#define SELF_SAVE_TYPE 1 + +#define NR_PREFERENCES 2 +#define PREFERENCE_SHIFT 8 +#define PREFERENCE_MASK 0xff + +#define UNSUPPORTED 0x0 +#define SELF_RESTORE_STRICT 0x01 +#define SELF_SAVE_STRICT 0x10 + +/* + * Bitmask defining the kind of preferences available. + * Note : The higher to lower preference is from LSB to MSB, with a shift of + * 8 bits. + * ---------------------------- + * | | 2nd pref | 1st pref | + * ---------------------------- + * MSB LSB + */ +/* Prefer Restore if available, otherwise unsupported */ +#define PREFER_SELF_RESTORE_ONLY SELF_RESTORE_STRICT +/* Prefer Save if available, otherwise unsupported */ +#define PREFER_SELF_SAVE_ONLY SELF_SAVE_STRICT +/* Prefer Restore when available, otherwise prefer Save */ +#define PREFER_RESTORE_SAVE ((SELF_SAVE_STRICT << \ + PREFERENCE_SHIFT)\ + | SELF_RESTORE_STRICT) +/* Prefer Save when available, otherwise prefer Restore*/ +#define PREFER_SAVE_RESTORE ((SELF_RESTORE_STRICT <<\ + PREFERENCE_SHIFT)\ + | SELF_SAVE_STRICT) static u32 supported_cpuidle_states; struct pnv_idle_states_t *pnv_idle_states; int nr_pnv_idle_states; +/* Caching the lpcr & ptcr support to use later */ +static bool is_lpcr_self_save; +static bool is_ptcr_self_save; + +struct preferred_sprs { + u64 spr; + u32 preferred_mode; + u32 supported_mode; +}; + +struct preferred_sprs preferred_sprs[] = { + { + .spr = SPRN_HSPRG0, + .preferred_mode = PREFER_RESTORE_SAVE, + .supported_mode = SELF_RESTORE_STRICT, + }, + { + .spr = SPRN_LPCR, + .preferred_mode = PREFER_RESTORE_SAVE, + .supported_mode = SELF_RESTORE_STRICT, + }, + { + .spr = SPRN_PTCR, + .preferred_mode = PREFER_SAVE_RESTORE, + .supported_mode = SELF_RESTORE_STRICT, + }, + { + .spr = SPRN_HMEER, + .preferred_mode = PREFER_RESTORE_SAVE, + .supported_mode = SELF_RESTORE_STRICT, + }, + { + .spr = SPRN_HID0, + .preferred_mode = PREFER_RESTORE_SAVE, + .supported_mode = SELF_RESTORE_STRICT, + }, + { + .spr = P9_STOP_SPR_MSR, + .preferred_mode = PREFER_RESTORE_SAVE, + .supported_mode = SELF_RESTORE_STRICT, + }, + { + .spr = P9_STOP_SPR_PSSCR, + .preferred_mode = PREFER_SAVE_RESTORE, + .supported_mode = SELF_RESTORE_STRICT, + }, + { + .spr = SPRN_HID1, + .preferred_mode = PREFER_RESTORE_SAVE, + .supported_mode = SELF_RESTORE_STRICT, + }, + { + .spr = SPRN_HID4, + .preferred_mode = PREFER_RESTORE_SAVE, + .supported_mode = SELF_RESTORE_STRICT, + }, + { + .spr = SPRN_HID5, + .preferred_mode = PREFER_RESTORE_SAVE, + .supported_mode = SELF_RESTORE_STRICT, + } +}; + +const int nr_preferred_sprs = ARRAY_SIZE(preferred_sprs); /* * The default stop state that will be used by ppc_md.power_save @@ -61,78 +158,187 @@ static bool deepest_stop_found; static unsigned long power7_offline_type; -static int pnv_save_sprs_for_deep_states(void) +static int pnv_self_restore_sprs(u64 pir, int cpu, u64 spr) { - int cpu; + u64 reg_val; int rc; - /* - * hid0, hid1, hid4, hid5, hmeer and lpcr values are symmetric across - * all cpus at boot. Get these reg values of current cpu and use the - * same across all cpus. - */ - uint64_t lpcr_val = mfspr(SPRN_LPCR); - uint64_t hid0_val = mfspr(SPRN_HID0); - uint64_t hid1_val = mfspr(SPRN_HID1); - uint64_t hid4_val = mfspr(SPRN_HID4); - uint64_t hid5_val = mfspr(SPRN_HID5); - uint64_t hmeer_val = mfspr(SPRN_HMEER); - uint64_t msr_val = MSR_IDLE; - uint64_t psscr_val = pnv_deepest_stop_psscr_val; - - for_each_present_cpu(cpu) { - uint64_t pir = get_hard_smp_processor_id(cpu); - uint64_t hsprg0_val = (uint64_t)paca_ptrs[cpu]; - - rc = opal_slw_set_reg(pir, SPRN_HSPRG0, hsprg0_val); + switch (spr) { + case SPRN_HSPRG0: + reg_val = (uint64_t)paca_ptrs[cpu]; + rc = opal_slw_set_reg(pir, SPRN_HSPRG0, reg_val); if (rc != 0) return rc; - - rc = opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val); + break; + case SPRN_LPCR: + reg_val = mfspr(SPRN_LPCR); + rc = opal_slw_set_reg(pir, SPRN_LPCR, reg_val); if (rc != 0) return rc; - + break; + case P9_STOP_SPR_MSR: + reg_val = MSR_IDLE; if (cpu_has_feature(CPU_FTR_ARCH_300)) { - rc = opal_slw_set_reg(pir, P9_STOP_SPR_MSR, msr_val); + rc = opal_slw_set_reg(pir, P9_STOP_SPR_MSR, reg_val); if (rc) return rc; - - rc = opal_slw_set_reg(pir, - P9_STOP_SPR_PSSCR, psscr_val); - + } + break; + case P9_STOP_SPR_PSSCR: + reg_val = pnv_deepest_stop_psscr_val; + if (cpu_has_feature(CPU_FTR_ARCH_300)) { + rc = opal_slw_set_reg(pir, P9_STOP_SPR_PSSCR, reg_val); if (rc) return rc; } - - /* HIDs are per core registers */ + break; + case SPRN_HMEER: + reg_val = mfspr(SPRN_HMEER); if (cpu_thread_in_core(cpu) == 0) { - - rc = opal_slw_set_reg(pir, SPRN_HMEER, hmeer_val); - if (rc != 0) + rc = opal_slw_set_reg(pir, SPRN_HMEER, reg_val); + if (rc) return rc; - - rc = opal_slw_set_reg(pir, SPRN_HID0, hid0_val); - if (rc != 0) + } + break; + case SPRN_HID0: + reg_val = mfspr(SPRN_HID0); + if (cpu_thread_in_core(cpu) == 0) { + rc = opal_slw_set_reg(pir, SPRN_HID0, reg_val); + if (rc) return rc; + } + break; + case SPRN_HID1: + reg_val = mfspr(SPRN_HID1); + if (cpu_thread_in_core(cpu) == 0 && + !cpu_has_feature(CPU_FTR_ARCH_300)) { + rc = opal_slw_set_reg(pir, SPRN_HID1, reg_val); + if (rc) + return rc; + } + break; + case SPRN_HID4: + reg_val = mfspr(SPRN_HID4); + if (cpu_thread_in_core(cpu) == 0 && + !cpu_has_feature(CPU_FTR_ARCH_300)) { + rc = opal_slw_set_reg(pir, SPRN_HID4, reg_val); + if (rc) + return rc; + } + break; + case SPRN_HID5: + reg_val = mfspr(SPRN_HID5); + if (cpu_thread_in_core(cpu) == 0 && + !cpu_has_feature(CPU_FTR_ARCH_300)) { + rc = opal_slw_set_reg(pir, SPRN_HID5, reg_val); + if (rc) + return rc; + } + break; + default: + return -EINVAL; + } + return 0; +} - /* Only p8 needs to set extra HID regiters */ - if (!cpu_has_feature(CPU_FTR_ARCH_300)) { - - rc = opal_slw_set_reg(pir, SPRN_HID1, hid1_val); - if (rc != 0) - return rc; +static int pnv_self_save_restore_sprs(void) +{ + int rc, index, cpu, k; + u64 pir; + struct preferred_sprs curr_spr; + bool is_initialized; + u32 preferred; + + is_lpcr_self_save = false; + is_ptcr_self_save = false; + for_each_present_cpu(cpu) { + pir = get_hard_smp_processor_id(cpu); + for (index = 0; index < nr_preferred_sprs; index++) { + curr_spr = preferred_sprs[index]; + is_initialized = false; + /* + * Go through each of the preferences + * Check if it is preferred as well as supported + */ + for (k = 0; k < NR_PREFERENCES; k++) { + preferred = curr_spr.preferred_mode + & PREFERENCE_MASK; + if (preferred & curr_spr.supported_mode + & SELF_RESTORE_STRICT) { + is_initialized = true; + rc = pnv_self_restore_sprs(pir, cpu, + curr_spr.spr); + if (rc != 0) + return rc; + break; + } else if (preferred & curr_spr.supported_mode + & SELF_SAVE_STRICT) { + is_initialized = true; + if (curr_spr.spr == SPRN_HMEER && + cpu_thread_in_core(cpu) != 0) { + continue; + } + rc = opal_slw_self_save_reg(pir, + curr_spr.spr); + if (rc != 0) + return rc; + switch (curr_spr.spr) { + case SPRN_LPCR: + is_lpcr_self_save = true; + break; + case SPRN_PTCR: + is_ptcr_self_save = true; + break; + } + break; + } + preferred_sprs[index].preferred_mode = + preferred_sprs[index].preferred_mode >> + PREFERENCE_SHIFT; + curr_spr = preferred_sprs[index]; + } + if (!is_initialized) { + if (preferred_sprs[index].spr == SPRN_PTCR || + (cpu_has_feature(CPU_FTR_ARCH_300) && + (preferred_sprs[index].spr == SPRN_HID1 || + preferred_sprs[index].spr == SPRN_HID4 || + preferred_sprs[index].spr == SPRN_HID5))) + continue; + return OPAL_UNSUPPORTED; + } + } + } + return 0; +} - rc = opal_slw_set_reg(pir, SPRN_HID4, hid4_val); - if (rc != 0) - return rc; +static int pnv_save_sprs_for_deep_states(void) +{ + int rc; + int index; - rc = opal_slw_set_reg(pir, SPRN_HID5, hid5_val); - if (rc != 0) - return rc; - } + /* + * Iterate over the preffered SPRs and if even one of them is + * still unsupported We cut support for deep stop states + */ + for (index = 0; index < nr_preferred_sprs; index++) { + if (preferred_sprs[index].supported_mode == UNSUPPORTED) { + if (preferred_sprs[index].spr == SPRN_PTCR || + (cpu_has_feature(CPU_FTR_ARCH_300) && + (preferred_sprs[index].spr == SPRN_HID1 || + preferred_sprs[index].spr == SPRN_HID4 || + preferred_sprs[index].spr == SPRN_HID5))) + continue; + return OPAL_UNSUPPORTED; } } + /* + * Try to self restore or self save the registers based on their support + * and respective preferences + */ + rc = pnv_self_save_restore_sprs(); + if (rc != 0) + return rc; return 0; } @@ -658,7 +864,8 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on) mmcr0 = mfspr(SPRN_MMCR0); } if ((psscr & PSSCR_RL_MASK) >= pnv_first_spr_loss_level) { - sprs.lpcr = mfspr(SPRN_LPCR); + if (!is_lpcr_self_save) + sprs.lpcr = mfspr(SPRN_LPCR); sprs.hfscr = mfspr(SPRN_HFSCR); sprs.fscr = mfspr(SPRN_FSCR); sprs.pid = mfspr(SPRN_PID); @@ -672,7 +879,8 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on) sprs.mmcr1 = mfspr(SPRN_MMCR1); sprs.mmcr2 = mfspr(SPRN_MMCR2); - sprs.ptcr = mfspr(SPRN_PTCR); + if (!is_ptcr_self_save) + sprs.ptcr = mfspr(SPRN_PTCR); sprs.rpr = mfspr(SPRN_RPR); sprs.tscr = mfspr(SPRN_TSCR); if (!firmware_has_feature(FW_FEATURE_ULTRAVISOR)) @@ -756,7 +964,8 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on) goto core_woken; /* Per-core SPRs */ - mtspr(SPRN_PTCR, sprs.ptcr); + if (!is_ptcr_self_save) + mtspr(SPRN_PTCR, sprs.ptcr); mtspr(SPRN_RPR, sprs.rpr); mtspr(SPRN_TSCR, sprs.tscr); @@ -777,7 +986,8 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on) atomic_unlock_and_stop_thread_idle(); /* Per-thread SPRs */ - mtspr(SPRN_LPCR, sprs.lpcr); + if (!is_lpcr_self_save) + mtspr(SPRN_LPCR, sprs.lpcr); mtspr(SPRN_HFSCR, sprs.hfscr); mtspr(SPRN_FSCR, sprs.fscr); mtspr(SPRN_PID, sprs.pid); @@ -956,8 +1166,11 @@ void pnv_program_cpu_hotplug_lpcr(unsigned int cpu, u64 lpcr_val) * Program the LPCR via stop-api only if the deepest stop state * can lose hypervisor context. */ - if (supported_cpuidle_states & OPAL_PM_LOSE_FULL_CONTEXT) - opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val); + if (supported_cpuidle_states & OPAL_PM_LOSE_FULL_CONTEXT) { + if (!is_lpcr_self_save) + opal_slw_set_reg(pir, SPRN_LPCR, + lpcr_val); + } } /* -- 2.21.0