Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750967AbdLGF7p (ORCPT ); Thu, 7 Dec 2017 00:59:45 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:47710 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750744AbdLGF7n (ORCPT ); Thu, 7 Dec 2017 00:59:43 -0500 From: "Gautham R. Shenoy" To: Shilpasri G Bhat , viresh.kumar@linaro.org, rjw@rjwysocki.net, huntbag@linux.vnet.ibm.com, akshay.adiga@linux.vnet.ibm.com, Michael Ellerman , Vaidyanathan Srinivasan Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, "Gautham R. Shenoy" , Subject: [v2 PATCH] cpufreq: powernv: Correctly parse the sign of pstates on POWER8 vs POWER9 Date: Thu, 7 Dec 2017 11:29:25 +0530 X-Mailer: git-send-email 1.8.3.1 X-TM-AS-GCONF: 00 x-cbid: 17120705-0040-0000-0000-000003CE3058 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008164; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000244; SDB=6.00956593; UDB=6.00483571; IPR=6.00736625; BA=6.00005729; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00018397; XFM=3.00000015; UTC=2017-12-07 05:59:39 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17120705-0041-0000-0000-000007C36981 Message-Id: <1512626365-22845-1-git-send-email-ego@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2017-12-07_01:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1712070093 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4900 Lines: 134 From: "Gautham R. Shenoy" On POWERNV platform, Pstates are 8-bit values. On POWER8 they are negatively numbered while on POWER9 they are positively numbered. Thus, on POWER9, the maximum number of pstates could be as high as 256. The current code interprets pstates as a signed 8-bit value. This causes a problem on POWER9 platforms which have more than 128 pstates. On such systems, on a CPU that is in a lower pstate whose number is greater than 128, querying the current pstate returns a "pstate X is out of bound" error message and the current pstate is reported as the nominal pstate. This patch fixes the aforementioned issue by correctly differentiating the sign whenever a pstate value read, depending on whether the pstates are positively numbered or negatively numbered. Fixes: commit 09ca4c9b5958 ("cpufreq: powernv: Replacing pstate_id with frequency table index") Cc: #v4.8 Signed-off-by: Gautham R. Shenoy Tested-and-reviewed-by: Shilpasri G Bhat Acked-by: Viresh Kumar --- drivers/cpufreq/powernv-cpufreq.c | 43 ++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index b6d7c4c..bb7586e 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -41,11 +41,14 @@ #define POWERNV_MAX_PSTATES 256 #define PMSR_PSAFE_ENABLE (1UL << 30) #define PMSR_SPR_EM_DISABLE (1UL << 31) -#define PMSR_MAX(x) ((x >> 32) & 0xFF) +#define EXTRACT_BYTE(x, shift) (((x) >> shift) & 0xFF) +#define MAX_SHIFT 32 #define LPSTATE_SHIFT 48 #define GPSTATE_SHIFT 56 -#define GET_LPSTATE(x) (((x) >> LPSTATE_SHIFT) & 0xFF) -#define GET_GPSTATE(x) (((x) >> GPSTATE_SHIFT) & 0xFF) +#define GET_PMSR_MAX(x) EXTRACT_BYTE(x, MAX_SHIFT) +#define GET_LPSTATE(x) EXTRACT_BYTE(x, LPSTATE_SHIFT) +#define GET_GPSTATE(x) EXTRACT_BYTE(x, GPSTATE_SHIFT) + #define MAX_RAMP_DOWN_TIME 5120 /* @@ -64,6 +67,12 @@ /* Interval after which the timer is queued to bring down global pstate */ #define GPSTATE_TIMER_INTERVAL 2000 +/* + * On POWER8 the pstates are negatively numbered. On POWER9, they are + * positively numbered. Use this flag to track whether we have + * positive or negative numbered pstates. + */ +static bool pos_pstates; /** * struct global_pstate_info - Per policy data structure to maintain history of @@ -164,7 +173,7 @@ static inline unsigned int pstate_to_idx(int pstate) int min = powernv_freqs[powernv_pstate_info.min].driver_data; int max = powernv_freqs[powernv_pstate_info.max].driver_data; - if (min > 0) { + if (pos_pstates) { if (unlikely((pstate < max) || (pstate > min))) { pr_warn_once("pstate %d is out of bound\n", pstate); return powernv_pstate_info.nominal; @@ -301,6 +310,9 @@ static int init_powernv_pstates(void) } } + if ((int)pstate_min > 0) + pos_pstates = true; + /* End of list marker entry */ powernv_freqs[i].frequency = CPUFREQ_TABLE_END; return 0; @@ -438,7 +450,6 @@ struct powernv_smp_call_data { static void powernv_read_cpu_freq(void *arg) { unsigned long pmspr_val; - s8 local_pstate_id; struct powernv_smp_call_data *freq_data = arg; pmspr_val = get_pmspr(SPRN_PMSR); @@ -447,8 +458,11 @@ static void powernv_read_cpu_freq(void *arg) * The local pstate id corresponds bits 48..55 in the PMSR. * Note: Watch out for the sign! */ - local_pstate_id = (pmspr_val >> 48) & 0xFF; - freq_data->pstate_id = local_pstate_id; + if (pos_pstates) + freq_data->pstate_id = (u8)GET_LPSTATE(pmspr_val); + else + freq_data->pstate_id = (s8)GET_LPSTATE(pmspr_val); + freq_data->freq = pstate_id_to_freq(freq_data->pstate_id); pr_debug("cpu %d pmsr %016lX pstate_id %d frequency %d kHz\n", @@ -522,7 +536,10 @@ static void powernv_cpufreq_throttle_check(void *data) chip = this_cpu_read(chip_info); /* Check for Pmax Capping */ - pmsr_pmax = (s8)PMSR_MAX(pmsr); + if (pos_pstates) + pmsr_pmax = (u8)GET_PMSR_MAX(pmsr); + else + pmsr_pmax = (s8)GET_PMSR_MAX(pmsr); pmsr_pmax_idx = pstate_to_idx(pmsr_pmax); if (pmsr_pmax_idx != powernv_pstate_info.max) { if (chip->throttled) @@ -645,8 +662,14 @@ void gpstate_timer_handler(struct timer_list *t) * value. Hence, read from PMCR to get correct data. */ val = get_pmspr(SPRN_PMCR); - freq_data.gpstate_id = (s8)GET_GPSTATE(val); - freq_data.pstate_id = (s8)GET_LPSTATE(val); + if (pos_pstates) { + freq_data.gpstate_id = (u8)GET_GPSTATE(val); + freq_data.pstate_id = (u8)GET_LPSTATE(val); + } else { + freq_data.gpstate_id = (s8)GET_GPSTATE(val); + freq_data.pstate_id = (s8)GET_LPSTATE(val); + } + if (freq_data.gpstate_id == freq_data.pstate_id) { reset_gpstates(policy); spin_unlock(&gpstates->gpstate_lock); -- 1.8.3.1