From patchwork Thu Aug 2 04:45:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akshay Adiga X-Patchwork-Id: 952583 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41gyMQ5N0Lz9s2g for ; Thu, 2 Aug 2018 14:47:14 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 41gyMQ40bGzF2DB for ; Thu, 2 Aug 2018 14:47:14 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=akshay.adiga@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 41gyLk4YvNzF0pD for ; Thu, 2 Aug 2018 14:46:38 +1000 (AEST) Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w724kWmf130086 for ; Thu, 2 Aug 2018 00:46:36 -0400 Received: from e06smtp02.uk.ibm.com (e06smtp02.uk.ibm.com [195.75.94.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 2kks5akstx-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 02 Aug 2018 00:46:35 -0400 Received: from localhost by e06smtp02.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 2 Aug 2018 05:45:19 +0100 Received: from b06cxnps3074.portsmouth.uk.ibm.com (9.149.109.194) by e06smtp02.uk.ibm.com (192.168.101.132) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Thu, 2 Aug 2018 05:45:18 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w724jIdO43253874 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 2 Aug 2018 04:45:18 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2A21611C050; Thu, 2 Aug 2018 07:45:28 +0100 (BST) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1E81B11C052; Thu, 2 Aug 2018 07:45:27 +0100 (BST) Received: from aksadiga.ibm (unknown [9.79.222.241]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Thu, 2 Aug 2018 07:45:26 +0100 (BST) From: Akshay Adiga To: skiboot@lists.ozlabs.org Date: Thu, 2 Aug 2018 10:15:06 +0530 X-Mailer: git-send-email 2.18.0.rc2.85.g1fb9df7 In-Reply-To: <20180802044507.7579-1-akshay.adiga@linux.vnet.ibm.com> References: <20180802044507.7579-1-akshay.adiga@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18080204-0008-0000-0000-0000025B7A66 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18080204-0009-0000-0000-000021C2176E Message-Id: <20180802044507.7579-2-akshay.adiga@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-08-01_09:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=3 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1806210000 definitions=main-1808020051 Subject: [Skiboot] [RFC PATCH 1/2] SLW: Add new idle device-tree format X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: stewart@linux.vnet.ibm.com, huntbag@linux.ibm.com MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Add stop states under ibm,idle-states in addition to the current array based device tree properties. Drawback of the array based dt node is that versioning of idle states is not possible. Future kernels will have capability to handle newer stop sates, hence versioning will help kenrnel to selectively enable states based on its capability. The new device tree node is extensible and has a compatible string for each idle-state. Linux kernel can now look at the version string and decide if it has the ability to handle that idle state. Henceforth, if kernel does not know about a version it checks if it has "opal-supported", in which case it will use opal-call-based-method to execute stop state. When both "opal-supported" and version string are unknown, it will skip all deeper states. "cpuidle" and "cpuoffline" indicates that state should be used for cpuidle or hotplug. Final output power-mgt { ... ibm,enabled-stop-levels = <0xec000000>; ibm,cpu-idle-state-psscr-mask = <0x0 0x3003ff 0x0 0x3003ff>; ibm,cpu-idle-state-latencies-ns = <0x3e8 0x7d0>; ibm,cpu-idle-state-psscr = <0x0 0x330 0x0 0x300330>; ibm,cpu-idle-state-flags = <0x100000 0x101000>; ibm,cpu-idle-state-residency-ns = <0x2710 0x4e20>; ibm,idle-states { stop4 { flags = <0x207000>; compatible = "ibm,state-v1", "cpuidle", "opal-supported"; psscr-mask = <0x0 0x3003ff>; handle = <0x102>; latency-ns = <0x186a0>; residency-ns = <0x989680>; psscr = <0x0 0x300374>; }; ... stop11 { ... compatible = "ibm,state-v1", "cpuoffline", "opal-supported"; ... }; }; TODO: - Add seperate latency/residency for OPAL call. Signed-off-by: Akshay Adiga --- hw/slw.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 20 deletions(-) diff --git a/hw/slw.c b/hw/slw.c index 49bcd839..b00790ef 100644 --- a/hw/slw.c +++ b/hw/slw.c @@ -414,8 +414,12 @@ static bool idle_prepare_core(struct proc_chip *chip, struct cpu_thread *c) /* Define device-tree fields */ #define MAX_NAME_LEN 16 +#define MAX_VERSION_LEN 25 struct cpu_idle_states { char name[MAX_NAME_LEN]; + char version[MAX_VERSION_LEN]; + char type[MAX_VERSION_LEN]; + u32 dt_node_type; u32 latency_ns; u32 residency_ns; /* @@ -504,6 +508,8 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop0_lite", /* Enter stop0 with no state loss */ .latency_ns = 1000, + .dt_node_type = 0, + .version = "ibm,state-v1", .residency_ns = 10000, .flags = 0*OPAL_PM_DEC_STOP \ | 0*OPAL_PM_TIMEBASE_STOP \ @@ -518,6 +524,8 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop0", .latency_ns = 2000, + .dt_node_type = 0, + .version = "ibm,state-v1", .residency_ns = 20000, .flags = 0*OPAL_PM_DEC_STOP \ | 0*OPAL_PM_TIMEBASE_STOP \ @@ -536,6 +544,10 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop1", + .dt_node_type = 1, + .version = "ibm,state-v1", + .type = "cpuidle", + .opal_supported = true, .latency_ns = 5000, .residency_ns = 50000, .flags = 0*OPAL_PM_DEC_STOP \ @@ -557,6 +569,10 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop2", + .dt_node_type = 1, + .version = "ibm,state-v1", + .type = "cpuidle", + .opal_supported = true, .latency_ns = 10000, .residency_ns = 100000, .flags = 0*OPAL_PM_DEC_STOP \ @@ -573,6 +589,10 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { .pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK }, { .name = "stop4", + .dt_node_type = 1, + .version = "ibm,state-v1", + .type = "cpuidle", + .opal_supported = true, .latency_ns = 100000, .residency_ns = 10000000, .flags = 0*OPAL_PM_DEC_STOP \ @@ -589,6 +609,10 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { .pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK }, { .name = "stop5", + .dt_node_type = 1, + .version = "ibm,state-v1", + .type = "cpuidle", + .opal_supported = true, .latency_ns = 200000, .residency_ns = 20000000, .flags = 0*OPAL_PM_DEC_STOP \ @@ -606,6 +630,11 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop8", + .dt_node_type = 1, + .version = "ibm,cpuidle-state-v1", + .version = "ibm,state-v1", + .type = "cpuoffline", + .opal_supported = true, .latency_ns = 2000000, .residency_ns = 20000000, .flags = 1*OPAL_PM_DEC_STOP \ @@ -623,6 +652,10 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop11", + .dt_node_type = 1, + .version = "ibm,state-v1", + .type = "cpuoffline", + .opal_supported = true, .latency_ns = 10000000, .residency_ns = 100000000, .flags = 1*OPAL_PM_DEC_STOP \ @@ -1011,34 +1044,84 @@ void add_cpu_idle_state_properties(void) } } } + if ( states[i].dt_node_type == 0) { + prlog(PR_NOTICE, "SLW: Enabling: %s\n", states[i].name); - prlog(PR_NOTICE, "SLW: Enabling: %s\n", states[i].name); + /* + * If a state is supported add each of its property + * to its corresponding property buffer. + */ + strncpy(name_buf, states[i].name, MAX_NAME_LEN); + name_buf = name_buf + strlen(states[i].name) + 1; - /* - * If a state is supported add each of its property - * to its corresponding property buffer. - */ - strncpy(name_buf, states[i].name, MAX_NAME_LEN); - name_buf = name_buf + strlen(states[i].name) + 1; + *latency_ns_buf = cpu_to_fdt32(states[i].latency_ns); + latency_ns_buf++; + + *residency_ns_buf = cpu_to_fdt32(states[i].residency_ns); + residency_ns_buf++; - *latency_ns_buf = cpu_to_fdt32(states[i].latency_ns); - latency_ns_buf++; + *flags_buf = cpu_to_fdt32(states[i].flags); + flags_buf++; - *residency_ns_buf = cpu_to_fdt32(states[i].residency_ns); - residency_ns_buf++; + *pm_ctrl_reg_val_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_val); + pm_ctrl_reg_val_buf++; - *flags_buf = cpu_to_fdt32(states[i].flags); - flags_buf++; + *pm_ctrl_reg_mask_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_mask); + pm_ctrl_reg_mask_buf++; - *pm_ctrl_reg_val_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_val); - pm_ctrl_reg_val_buf++; + /* Increment buffer length trackers */ + name_buf_len += strlen(states[i].name) + 1; + num_supported_idle_states++; - *pm_ctrl_reg_mask_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_mask); - pm_ctrl_reg_mask_buf++; + } else if ( states[i].dt_node_type == 1 ) { - /* Increment buffer length trackers */ - name_buf_len += strlen(states[i].name) + 1; - num_supported_idle_states++; + struct dt_node *parent_node , *dt_state_node; + char version_buf[MAX_VERSION_LEN]; + u32 *lat_buf, *res_buf , *flg_buf; + u64 *psscr_buf , *psscr_mask_buf; + + lat_buf = malloc(sizeof(u32)); + res_buf = malloc(sizeof(u32)); + flg_buf = malloc(sizeof(u32)); + psscr_buf = malloc(sizeof(u64)); + psscr_mask_buf = malloc(sizeof(u64)); + prlog(PR_NOTICE, "SLW: Enabling: %s in new format\n", states[i].name); + + parent_node = dt_new_check(power_mgt, "ibm,idle-states"); + if (!parent_node) { + prlog(PR_ERR, "Error creating ibm,idle-states\n"); + } + dt_state_node = dt_new_check(parent_node, states[i].name); + if (!dt_state_node) { + prlog(PR_ERR, "Error creating %s\n", states[i].name); + } + strncpy(version_buf,states[i].version, strlen(states[i].version)+1); + if (states[i].opal_supported) { + dt_add_property_strings(dt_state_node, + "compatible",version_buf, states[i].type, + "opal-supported"); + } else { + dt_add_property_strings(dt_state_node, + "compatible",version_buf, states[i].type); + } + + *lat_buf = cpu_to_fdt32(states[i].latency_ns); + dt_add_property(dt_state_node, "latency-ns",lat_buf, sizeof(u32)); + *res_buf = cpu_to_fdt32(states[i].residency_ns); + dt_add_property(dt_state_node, "residency-ns",res_buf,sizeof(u32)); + *flg_buf = cpu_to_fdt32(states[i].flags); + dt_add_property(dt_state_node, "flags",flg_buf,sizeof(u32)); + *psscr_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_val); + dt_add_property(dt_state_node, "psscr", psscr_buf , sizeof(u64)); + *psscr_mask_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_mask); + dt_add_property(dt_state_node, "psscr-mask", psscr_mask_buf ,sizeof(u64)); + free(res_buf); + free(lat_buf); + free(flg_buf); + free(psscr_buf); + free(psscr_mask_buf); + + } } From patchwork Thu Aug 2 04:45:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akshay Adiga X-Patchwork-Id: 952581 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41gyLm5wdSz9s2g for ; Thu, 2 Aug 2018 14:46:40 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 41gyLm3YSrzF1RB for ; Thu, 2 Aug 2018 14:46:40 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=akshay.adiga@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 41gyLg1918zF1Qn for ; Thu, 2 Aug 2018 14:46:34 +1000 (AEST) Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w724kUeq129930 for ; Thu, 2 Aug 2018 00:46:32 -0400 Received: from e06smtp03.uk.ibm.com (e06smtp03.uk.ibm.com [195.75.94.99]) by mx0a-001b2d01.pphosted.com with ESMTP id 2kks5aksuv-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 02 Aug 2018 00:46:31 -0400 Received: from localhost by e06smtp03.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 2 Aug 2018 05:45:22 +0100 Received: from b06cxnps4076.portsmouth.uk.ibm.com (9.149.109.198) by e06smtp03.uk.ibm.com (192.168.101.133) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Thu, 2 Aug 2018 05:45:21 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w724jK6q39911648 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 2 Aug 2018 04:45:20 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8615211C052; Thu, 2 Aug 2018 07:45:30 +0100 (BST) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7A76311C058; Thu, 2 Aug 2018 07:45:29 +0100 (BST) Received: from aksadiga.ibm (unknown [9.79.222.241]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Thu, 2 Aug 2018 07:45:29 +0100 (BST) From: Akshay Adiga To: skiboot@lists.ozlabs.org Date: Thu, 2 Aug 2018 10:15:07 +0530 X-Mailer: git-send-email 2.18.0.rc2.85.g1fb9df7 In-Reply-To: <20180802044507.7579-1-akshay.adiga@linux.vnet.ibm.com> References: <20180802044507.7579-1-akshay.adiga@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18080204-0012-0000-0000-000002928D31 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18080204-0013-0000-0000-000020C497FF Message-Id: <20180802044507.7579-3-akshay.adiga@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-08-01_09:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1806210000 definitions=main-1808020051 Subject: [Skiboot] [RFC PATCH 2/2] SLW : Support spr save-restore using new opal call X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: stewart@linux.vnet.ibm.com, huntbag@linux.ibm.com MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" From: Abhishek Goel In an attempt to make the powernv idle code backward compatible, and to some extent forward compatible, add support for pre-stop entry and post-stop exit actions in OPAL. If a kernel knows about this opal call, then just a firmware supporting newer hardware is required, instead of waiting for kernel updates. This opal support for stop can be indicated by a compatibility string in the newly proposed device-tree format (Ref: https://patchwork.ozlabs.org/patch/923120/). Thus the kernel can enable a stop state, when the opal support for it exists, even if the kernel support doesn't exist. Signed-off-by: Abhishek Goel --- hw/chiptod.c | 7 +- hw/slw.c | 152 +++++++++++++++++++++++++++++++++++++++++++- include/opal-api.h | 6 +- include/processor.h | 13 ++++ 4 files changed, 174 insertions(+), 4 deletions(-) diff --git a/hw/chiptod.c b/hw/chiptod.c index df1274ca..7f52f6ac 100644 --- a/hw/chiptod.c +++ b/hw/chiptod.c @@ -1599,7 +1599,7 @@ error_out: return rc; } -static int64_t opal_resync_timebase(void) +int64_t __opal_resync_timebase(void) { if (!chiptod_wakeup_resync()) { prerror("OPAL: Resync timebase failed on CPU 0x%04x\n", @@ -1608,6 +1608,11 @@ static int64_t opal_resync_timebase(void) } return OPAL_SUCCESS; } + +static int64_t opal_resync_timebase(void) +{ + return __opal_resync_timebase(); +} opal_call(OPAL_RESYNC_TIMEBASE, opal_resync_timebase, 0); static void chiptod_print_tb(void *data __unused) diff --git a/hw/slw.c b/hw/slw.c index b00790ef..ec9e56a2 100644 --- a/hw/slw.c +++ b/hw/slw.c @@ -414,7 +414,7 @@ static bool idle_prepare_core(struct proc_chip *chip, struct cpu_thread *c) /* Define device-tree fields */ #define MAX_NAME_LEN 16 -#define MAX_VERSION_LEN 25 +#define MAX_VERSION_LEN 50 struct cpu_idle_states { char name[MAX_NAME_LEN]; char version[MAX_VERSION_LEN]; @@ -429,6 +429,7 @@ struct cpu_idle_states { u64 pm_ctrl_reg_val; u64 pm_ctrl_reg_mask; u32 flags; + bool opal_supported; }; static struct cpu_idle_states power7_cpu_idle_states[] = { @@ -631,7 +632,6 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop8", .dt_node_type = 1, - .version = "ibm,cpuidle-state-v1", .version = "ibm,state-v1", .type = "cpuoffline", .opal_supported = true, @@ -851,6 +851,154 @@ static void slw_late_init_p9(struct proc_chip *chip) } } +#define PTCR_IDX 0 +#define RPR_IDX 1 +#define SPURR_IDX 2 +#define PURR_IDX 3 +#define TSCR_IDX 4 +#define DSCR_IDX 5 +#define AMOR_IDX 6 +#define WORT_IDX 7 +#define WORC_IDX 8 +#define LPCR_IDX 9 +#define PID_IDX 10 +#define LDBAR_IDX 11 +#define FSCR_IDX 12 +#define HFSCR_IDX 13 +#define MMCRA_IDX 14 +#define MMCR0_IDX 15 +#define MMCR1_IDX 16 +#define MMCR2_IDX 17 +#define SPRG3_IDX 18 +#define PSSCR_RL_MASK 0xF +#define PSSCR_PLS_MASK 0xF000000000000000UL +#define PSSCR_PLS_SHIFT 60 +#define SRR1_WS_HVLOSS 0x30000 +#define SCOPE_CORE 0 +#define SCOPE_THREAD 1 + +/* + * opal_cpuidle_save: Save the SPRs and any other resources + * when going to a deep idle stop states. + * @stop_sprs : Pointer to a array where the SPR values of + * the relevant SPRs of this CPU have to be saved. + * @scope : Defines if the saving needs to be done + * for per-thread resources or per-core resources. + * @psscr : The requested psscr values + * @srr1 : The SRR1 value + * Returns OPAL_EMPTY when stop_sprs is NULL. + * Returns OPAL_UNSUPPORTED if we are going into a shallow state. + * Returns OPAL_SUCCESS in all the other cases. + * Returns OPAL_PARAMETER if scope is incorrectly passed. + */ +static int opal_cpuidle_save(u64 *stop_sprs, int scope, u64 psscr) +{ + if (scope != SCOPE_CORE && scope != SCOPE_THREAD) { + prlog(PR_ERR, "opal_cpuidle_save : invalid scope\n"); + return OPAL_PARAMETER; + } + if (!stop_sprs) { + prlog(PR_ERR, "opal_cpuidle_save : unallocated memory pointer\n"); + return OPAL_EMPTY; + } + /* + * TODO Fix this to use the RL value of the first thread + * that loses hypervisor resources. + */ + if ((psscr & PSSCR_RL_MASK) < 4) { + prlog(PR_ERR, "opal_cpuidle_save : unexpected opal call\n"); + return OPAL_UNSUPPORTED; + } + /* + * Saving all the sprs. In future, We may save core resources + * only if the thread entering in deep stop is the last in the + * core. scope can be used to take that decision. + */ + stop_sprs[RPR_IDX] = mfspr(SPR_RPR); + stop_sprs[WORC_IDX] = mfspr(SPR_WORC); + stop_sprs[PTCR_IDX] = mfspr(SPR_PTCR); + stop_sprs[TSCR_IDX] = mfspr(SPR_TSCR); + stop_sprs[AMOR_IDX] = mfspr(SPR_AMOR); + + stop_sprs[WORT_IDX] = mfspr(SPR_WORT); + stop_sprs[PURR_IDX] = mfspr(SPR_PURR); + stop_sprs[SPURR_IDX] = mfspr(SPR_SPURR); + stop_sprs[DSCR_IDX] = mfspr(SPR_DSCR); + stop_sprs[LPCR_IDX] = mfspr(SPR_LPCR); + stop_sprs[PID_IDX] = mfspr(SPR_PID); + stop_sprs[LDBAR_IDX] = mfspr(SPR_LDBAR); + stop_sprs[FSCR_IDX] = mfspr(SPR_FSCR); + stop_sprs[HFSCR_IDX] = mfspr(SPR_HFSCR); + stop_sprs[MMCRA_IDX] = mfspr(SPR_MMCRA); + stop_sprs[MMCR0_IDX] = mfspr(SPR_MMCR0); + stop_sprs[MMCR1_IDX] = mfspr(SPR_MMCR1); + stop_sprs[MMCR2_IDX] = mfspr(SPR_MMCR2); + stop_sprs[SPRG3_IDX] = mfspr(SPR_SPRG3); + return OPAL_SUCCESS; +} + +opal_call(OPAL_IDLE_SAVE, opal_cpuidle_save, 3); + +/* + * opal_cpuidle_restore: Restore the SPRs and any other resources + * on wakeup from a deep idle stop states. + * @stop_sprs : Pointer to a array where the SPR values of + * the relevant SPRs of this CPU have been stored. + * @scope : Defines if the restoration needs to be done + * for per-thread resources of per-core resources. + * @psscr : The psscr value at wakeup from stop. + * @srr1 : The SRR1 value at wakeup from stop. + * Returns OPAL_EMPTY when stop_sprs is NULL. + * Returns OPAL_UNSUPPORTED if we woke up from a shallow state. + * Returns OPAL_SUCCESS in all the other cases. + * Returns OPAL_PARAMETER if scope is incorrectly passed. + */ +static int opal_cpuidle_restore(u64 *stop_sprs, int scope, u64 psscr, u64 srr1) +{ + if (scope != SCOPE_CORE && scope != SCOPE_THREAD) { + prlog(PR_ERR, "opal_cpuidle_save : invalid scope\n"); + return OPAL_PARAMETER; + } + if (!stop_sprs) { + prlog(PR_ERR, "opal_cpuidle_save : incorrect pointer to save area\n"); + return OPAL_EMPTY; + } + if ((psscr & PSSCR_PLS_MASK) >> PSSCR_PLS_SHIFT < 4) { + prlog(PR_ERR, "opal_cpuidle_save : unexpected opal call\n"); + return OPAL_UNSUPPORTED; + } + /* if CORE scope, restore core resources as well as thread resources */ + if (scope == SCOPE_CORE) { + /* In case of complete hypervisor state loss + * we need to resync timebase + */ + if (srr1 & SRR1_WS_HVLOSS) + __opal_resync_timebase(); + mtspr(SPR_RPR, stop_sprs[RPR_IDX]); + mtspr(SPR_WORC, stop_sprs[WORC_IDX]); + mtspr(SPR_PTCR, stop_sprs[PTCR_IDX]); + mtspr(SPR_TSCR, stop_sprs[TSCR_IDX]); + mtspr(SPR_AMOR, stop_sprs[AMOR_IDX]); + } + mtspr(SPR_WORT, stop_sprs[WORT_IDX]); + mtspr(SPR_PURR, stop_sprs[PURR_IDX]); + mtspr(SPR_SPURR, stop_sprs[SPURR_IDX]); + mtspr(SPR_DSCR, stop_sprs[DSCR_IDX]); + mtspr(SPR_LPCR, stop_sprs[LPCR_IDX]); + mtspr(SPR_PID, stop_sprs[PID_IDX]); + mtspr(SPR_LDBAR, stop_sprs[LDBAR_IDX]); + mtspr(SPR_FSCR, stop_sprs[FSCR_IDX]); + mtspr(SPR_HFSCR, stop_sprs[HFSCR_IDX]); + mtspr(SPR_MMCRA, stop_sprs[MMCRA_IDX]); + mtspr(SPR_MMCR0, stop_sprs[MMCR0_IDX]); + mtspr(SPR_MMCR1, stop_sprs[MMCR1_IDX]); + mtspr(SPR_MMCR2, stop_sprs[MMCR2_IDX]); + mtspr(SPR_SPRG3, stop_sprs[SPRG3_IDX]); + return OPAL_SUCCESS; +} + +opal_call(OPAL_IDLE_RESTORE, opal_cpuidle_restore, 4); + /* Add device tree properties to describe idle states */ void add_cpu_idle_state_properties(void) { diff --git a/include/opal-api.h b/include/opal-api.h index 09c77c18..fbd69700 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -223,7 +223,9 @@ #define OPAL_PCI_GET_PBCQ_TUNNEL_BAR 164 #define OPAL_PCI_SET_PBCQ_TUNNEL_BAR 165 #define OPAL_HANDLE_HMI2 166 -#define OPAL_LAST 166 +#define OPAL_IDLE_SAVE 168 +#define OPAL_IDLE_RESTORE 169 +#define OPAL_LAST 169 #define QUIESCE_HOLD 1 /* Spin all calls at entry */ #define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */ @@ -1311,6 +1313,8 @@ enum { OPAL_PCI_P2P_TARGET = 1, }; +extern int64_t __opal_resync_timebase(void); + #endif /* __ASSEMBLY__ */ #endif /* __OPAL_API_H */ diff --git a/include/processor.h b/include/processor.h index 6b262b45..bab309a2 100644 --- a/include/processor.h +++ b/include/processor.h @@ -87,6 +87,19 @@ #define SPR_HID4 0x3f4 #define SPR_HID5 0x3f6 #define SPR_PIR 0x3ff /* RO: Processor Identification */ +#define SPR_PTCR 0x1D0 /* Partition table control Register */ +#define SPR_WORT 0x37f /* Workload optimization register - thread */ +#define SPR_WORC 0x35f /* Workload optimization register - core */ +#define SPR_FSCR 0x099 /* Facility Status & Control Register */ +#define SPR_HFSCR 0xbe /* HV=1 Facility Status & Control Register */ +#define SPR_LDBAR 0x352 /* LD Base Address Register */ +#define SPR_PID 0x030 /* Process ID */ +#define SPR_SPRG3 0x113 /* Special Purpose Register General 3 */ +/* Performance counter Registers */ +#define SPR_MMCR0 0x31b +#define SPR_MMCRA 0x312 +#define SPR_MMCR1 0x31e +#define SPR_MMCR2 0x311 /* Bits in LPCR */