From patchwork Mon Oct 15 09:15:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akshay Adiga X-Patchwork-Id: 983989 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 ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42YXqQ0X4lz9sBj for ; Mon, 15 Oct 2018 20:16:02 +1100 (AEDT) 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 42YXqP6MpBzF3Ft for ; Mon, 15 Oct 2018 20:16:01 +1100 (AEDT) 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.158.5; 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 (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 42YXq60mXBzF3By for ; Mon, 15 Oct 2018 20:15:45 +1100 (AEDT) Received: from pps.filterd (m0098420.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9F9EV8M070342 for ; Mon, 15 Oct 2018 05:15:43 -0400 Received: from e06smtp05.uk.ibm.com (e06smtp05.uk.ibm.com [195.75.94.101]) by mx0b-001b2d01.pphosted.com with ESMTP id 2n4pkfkw1q-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 15 Oct 2018 05:15:43 -0400 Received: from localhost by e06smtp05.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 15 Oct 2018 10:15:41 +0100 Received: from b06cxnps3075.portsmouth.uk.ibm.com (9.149.109.195) by e06smtp05.uk.ibm.com (192.168.101.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Mon, 15 Oct 2018 10:15:39 +0100 Received: from d06av24.portsmouth.uk.ibm.com (mk.ibm.com [9.149.105.60]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w9F9FcDb7471468 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 15 Oct 2018 09:15:38 GMT Received: from d06av24.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5268942049; Mon, 15 Oct 2018 12:15:12 +0100 (BST) Received: from d06av24.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0215542045; Mon, 15 Oct 2018 12:15:11 +0100 (BST) Received: from aks.in.ibm.com (unknown [9.124.35.29]) by d06av24.portsmouth.uk.ibm.com (Postfix) with ESMTP; Mon, 15 Oct 2018 12:15:10 +0100 (BST) From: Akshay Adiga To: skiboot@lists.ozlabs.org Date: Mon, 15 Oct 2018 14:45:30 +0530 X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181015091531.14126-1-akshay.adiga@linux.vnet.ibm.com> References: <20181015091531.14126-1-akshay.adiga@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18101509-0020-0000-0000-000002D42C54 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18101509-0021-0000-0000-000021232EB3 Message-Id: <20181015091531.14126-2-akshay.adiga@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-15_07:, , 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-1807170000 definitions=main-1810150087 Subject: [Skiboot] [RFC PATCH v2 1/2] SLW: Add new idle device-tree format X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 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, ego@linux.vnet.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", "opal-supported"; type = "cpuidle"; psscr-mask = <0x0 0x3003ff>; handle = <0x102>; latency-ns = <0x186a0>; residency-ns = <0x989680>; psscr = <0x0 0x300374>; }; ... stop11 { ... compatible = "ibm,state-v1", "opal-supported"; type = "cpuoffline"; ... }; }; Signed-off-by: Akshay Adiga --- Changes from v1 : - Moved "cpuidle" and "cpuoffline" to a different property called "type" hw/slw.c | 124 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 27 deletions(-) diff --git a/hw/slw.c b/hw/slw.c index dfa9189b..c0181534 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,9 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop1", + .dt_node_type = 1, + .version = "ibm,state-v1", + .type = "cpuidle", .latency_ns = 5000, .residency_ns = 50000, .flags = 0*OPAL_PM_DEC_STOP \ @@ -557,6 +568,9 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop2", + .dt_node_type = 1, + .version = "ibm,state-v1", + .type = "cpuidle", .latency_ns = 10000, .residency_ns = 100000, .flags = 0*OPAL_PM_DEC_STOP \ @@ -573,6 +587,9 @@ 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", .latency_ns = 100000, .residency_ns = 10000000, .flags = 0*OPAL_PM_DEC_STOP \ @@ -589,6 +606,9 @@ 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", .latency_ns = 200000, .residency_ns = 20000000, .flags = 0*OPAL_PM_DEC_STOP \ @@ -606,6 +626,9 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop8", + .dt_node_type = 1, + .version = "ibm,state-v1", + .type = "cpuoffline", .latency_ns = 2000000, .residency_ns = 20000000, .flags = 1*OPAL_PM_DEC_STOP \ @@ -623,6 +646,9 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop11", + .dt_node_type = 1, + .version = "ibm,state-v1", + .type = "cpuoffline", .latency_ns = 10000000, .residency_ns = 100000000, .flags = 1*OPAL_PM_DEC_STOP \ @@ -1011,34 +1037,78 @@ void add_cpu_idle_state_properties(void) } } } + if (states[i].dt_node_type == 0) { + 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; + + *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++; + + *flags_buf = cpu_to_fdt32(states[i].flags); + flags_buf++; + + *pm_ctrl_reg_val_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_val); + pm_ctrl_reg_val_buf++; + + *pm_ctrl_reg_mask_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_mask); + pm_ctrl_reg_mask_buf++; + + /* Increment buffer length trackers */ + name_buf_len += strlen(states[i].name) + 1; + num_supported_idle_states++; + + } else if (states[i].dt_node_type == 1) { + + 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); + dt_add_property_strings(dt_state_node, "compatible", version_buf); + dt_add_property_strings(dt_state_node, "type", 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); - prlog(PR_INFO, "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; - - *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++; - - *flags_buf = cpu_to_fdt32(states[i].flags); - flags_buf++; - - *pm_ctrl_reg_val_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_val); - pm_ctrl_reg_val_buf++; - - *pm_ctrl_reg_mask_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_mask); - pm_ctrl_reg_mask_buf++; - - /* Increment buffer length trackers */ - name_buf_len += strlen(states[i].name) + 1; - num_supported_idle_states++; + } } From patchwork Mon Oct 15 09:15:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akshay Adiga X-Patchwork-Id: 983990 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 ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42YXql3vbxz9sBj for ; Mon, 15 Oct 2018 20:16:19 +1100 (AEDT) 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 42YXql2GWKzF3Fj for ; Mon, 15 Oct 2018 20:16:19 +1100 (AEDT) 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 42YXq93j2pzF3Bd for ; Mon, 15 Oct 2018 20:15:49 +1100 (AEDT) Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9F9EYMd094732 for ; Mon, 15 Oct 2018 05:15:47 -0400 Received: from e06smtp05.uk.ibm.com (e06smtp05.uk.ibm.com [195.75.94.101]) by mx0a-001b2d01.pphosted.com with ESMTP id 2n4knthyb5-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 15 Oct 2018 05:15:47 -0400 Received: from localhost by e06smtp05.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 15 Oct 2018 10:15:44 +0100 Received: from b06cxnps4076.portsmouth.uk.ibm.com (9.149.109.198) by e06smtp05.uk.ibm.com (192.168.101.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Mon, 15 Oct 2018 10:15:42 +0100 Received: from d06av24.portsmouth.uk.ibm.com (mk.ibm.com [9.149.105.60]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w9F9Ffwb3211726 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 15 Oct 2018 09:15:41 GMT Received: from d06av24.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BB96542045; Mon, 15 Oct 2018 12:15:14 +0100 (BST) Received: from d06av24.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 97E5E4204B; Mon, 15 Oct 2018 12:15:13 +0100 (BST) Received: from aks.in.ibm.com (unknown [9.124.35.29]) by d06av24.portsmouth.uk.ibm.com (Postfix) with ESMTP; Mon, 15 Oct 2018 12:15:13 +0100 (BST) From: Akshay Adiga To: skiboot@lists.ozlabs.org Date: Mon, 15 Oct 2018 14:45:31 +0530 X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181015091531.14126-1-akshay.adiga@linux.vnet.ibm.com> References: <20181015091531.14126-1-akshay.adiga@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18101509-0020-0000-0000-000002D42C55 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18101509-0021-0000-0000-000021232EB4 Message-Id: <20181015091531.14126-3-akshay.adiga@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-15_07:, , 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-1807170000 definitions=main-1810150087 Subject: [Skiboot] [RFC PATCH v2 2/2] opal : Support spr save-restore using new X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 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, ego@linux.vnet.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. 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 --- Changes from v1 : - All the decision making such as identifying first thread in the core and taking locks before restoring in such cases have also been moved to OPAL - Deep states have only opal-support asm/head.S | 2 - hw/chiptod.c | 2 +- hw/slw.c | 194 ++++++++++++++++++++++++++++++++++++++-- include/cpu.h | 28 ++++++ include/opal-api.h | 4 +- include/opal-internal.h | 1 + include/processor.h | 17 ++++ 7 files changed, 238 insertions(+), 10 deletions(-) diff --git a/asm/head.S b/asm/head.S index 803fbf1a..34368df5 100644 --- a/asm/head.S +++ b/asm/head.S @@ -28,8 +28,6 @@ #define PPC_INST_SLEEP .long 0x4c0003a4 #define PPC_INST_RVWINKLE .long 0x4c0003e4 -#define PPC_INST_STOP .long 0x4c0002e4 - #define GET_STACK(stack_reg,pir_reg) \ sldi stack_reg,pir_reg,STACK_SHIFT; \ addis stack_reg,stack_reg,CPU_STACKS_OFFSET@ha; \ diff --git a/hw/chiptod.c b/hw/chiptod.c index 97c8b8dd..8bb4e2f2 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) { /* Mambo and qemu doesn't simulate the chiptod */ if (chip_quirk(QUIRK_NO_CHIPTOD)) diff --git a/hw/slw.c b/hw/slw.c index c0181534..db7d7fb5 100644 --- a/hw/slw.c +++ b/hw/slw.c @@ -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[] = { @@ -526,6 +527,7 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { .latency_ns = 2000, .dt_node_type = 0, .version = "ibm,state-v1", + .opal_supported = false, .residency_ns = 20000, .flags = 0*OPAL_PM_DEC_STOP \ | 0*OPAL_PM_TIMEBASE_STOP \ @@ -546,6 +548,7 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { .name = "stop1", .dt_node_type = 1, .version = "ibm,state-v1", + .opal_supported = false, .type = "cpuidle", .latency_ns = 5000, .residency_ns = 50000, @@ -570,6 +573,7 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { .name = "stop2", .dt_node_type = 1, .version = "ibm,state-v1", + .opal_supported = false, .type = "cpuidle", .latency_ns = 10000, .residency_ns = 100000, @@ -588,7 +592,8 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop4", .dt_node_type = 1, - .version = "ibm,state-v1", + .version = "", + .opal_supported = true, .type = "cpuidle", .latency_ns = 100000, .residency_ns = 10000000, @@ -607,7 +612,8 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop5", .dt_node_type = 1, - .version = "ibm,state-v1", + .version = "", + .opal_supported = true, .type = "cpuidle", .latency_ns = 200000, .residency_ns = 20000000, @@ -627,7 +633,8 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop8", .dt_node_type = 1, - .version = "ibm,state-v1", + .version = "", + .opal_supported = false, .type = "cpuoffline", .latency_ns = 2000000, .residency_ns = 20000000, @@ -647,7 +654,8 @@ static struct cpu_idle_states power9_cpu_idle_states[] = { { .name = "stop11", .dt_node_type = 1, - .version = "ibm,state-v1", + .version = "", + .opal_supported = true, .type = "cpuoffline", .latency_ns = 10000000, .residency_ns = 100000000, @@ -844,6 +852,169 @@ static void slw_late_init_p9(struct proc_chip *chip) } } +#define PSSCR_RL_MASK 0xF +#define PSSCR_PLS_MASK 0xF000000000000000UL +#define PSSCR_PLS_SHIFT 60 +#define SRR1_WS_HVLOSS 0x30000 +#define NR_PNV_CORE_IDLE_LOCK_BIT 28 +#define PNV_CORE_IDLE_LOCK_BIT (0x1 << NR_PNV_CORE_IDLE_LOCK_BIT) +#define BIT_MASK(nr) (0x1 << ((nr) % 64)) +#define BIT_WORD(nr) ((nr) / 64) + +static u64 test_and_set_bit_lock(u64 mask, u64 *_p) +{ + u64 old, t; + u64 *p = (u64 *)_p; + + asm volatile( + "1: ldarx %0,0,%3,1 \n" + " or %1,%0,%2 \n" + " dcbt 0,%3 \n" + " stdcx. %1,0,%3 \n" + " bne- 1b \n" + " isync \n" + + : "=&r" (old), "=&r" (t) + : "r" (mask), "r" (p) + : "cc", "memory"); + + return (old & mask); +} + +static inline void atomic_unlock_and_stop_thread_idle(void) +{ + u64 new, tmp; + struct cpu_thread *first = this_cpu()->primary; + u64 *state = &first->idle_state; + u64 thread = 0x1 << (u64) cpu_get_thread_index(this_cpu()); + u64 s = *state; + + isync(); + +again: + new = (s | thread) & ~(PNV_CORE_IDLE_LOCK_BIT); + tmp = __cmpxchg64(state, s, new); + if (tmp != s) { + s = tmp; + goto again; + } +} + +/* + * opal_cpuidle_save: Save the SPRs and any other resources + * when going to a deep idle stop states. + * @psscr : The requested psscr values + */ +static int opal_cpuidle_save(u64 psscr) +{ + struct cpu_thread *first = this_cpu()->primary; + u64 *state = &first->idle_state; + struct p9_sprs *sprs = &this_cpu()->sprs; + + memset(sprs, 0, sizeof(sprs)); + /* + * 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_SUCCESS; + } + + /* saving all the SPRs */ + sprs->ldbar = mfspr(SPR_LDBAR); + sprs->ptcr = mfspr(SPR_PTCR); + sprs->tscr = mfspr(SPR_TSCR); + sprs->amor = mfspr(SPR_AMOR); + sprs->rpr = mfspr(SPR_RPR); + + sprs->wort = mfspr(SPR_WORT); + sprs->purr = mfspr(SPR_PURR); + sprs->spurr = mfspr(SPR_SPURR); + sprs->dscr = mfspr(SPR_DSCR); + sprs->lpcr = mfspr(SPR_LPCR); + sprs->pid = mfspr(SPR_PID); + sprs->fscr = mfspr(SPR_FSCR); + sprs->hfscr = mfspr(SPR_HFSCR); + sprs->mmcra = mfspr(SPR_MMCRA); + sprs->mmcr0 = mfspr(SPR_MMCR0); + sprs->mmcr1 = mfspr(SPR_MMCR1); + sprs->mmcr2 = mfspr(SPR_MMCR2); + sprs->sprg3 = mfspr(SPR_SPRG3); + + *state = (u64) cpu_get_thread_index(this_cpu()) & *state; + + this_cpu()->in_opal_call--; + asm volatile(PPC_STOP); + + return OPAL_WRONG_STATE; +} + +opal_call(OPAL_IDLE_SAVE, opal_cpuidle_save, 1); + +/* + * opal_cpuidle_restore: Restore the SPRs and any other resources + * on wakeup from a deep idle stop states. + * @psscr : The psscr value at wakeup from stop. + * @srr1 : The SRR1 value at wakeup from stop. + */ +static int opal_cpuidle_restore(u64 psscr, u64 srr1) +{ + struct cpu_thread *first = this_cpu()->primary; + u64 *state = &first->idle_state; + struct p9_sprs *sprs = &this_cpu()->sprs; + + while (test_and_set_bit_lock(BIT_MASK(NR_PNV_CORE_IDLE_LOCK_BIT), + state+BIT_WORD(NR_PNV_CORE_IDLE_LOCK_BIT)) != 0) + asm volatile("" : : : "memory"); + isync(); + + /* + * TODO Fix this to use the RL value of the first thread + * that loses hypervisor resources. + */ + if ((psscr & PSSCR_PLS_MASK) >> PSSCR_PLS_SHIFT < 4) { + prlog(PR_ERR, "opal cpuidle restore : unexpected opal call\n"); + return OPAL_SUCCESS; + } + + //Check if it is the first thread in the core + if ((*state & ((1 << cpu_thread_count) - 1)) != 0) + goto core_woken; + + /* Per-core SPRs */ + mtspr(SPR_PTCR, sprs->ptcr); + mtspr(SPR_RPR, sprs->rpr); + mtspr(SPR_TSCR, sprs->tscr); + mtspr(SPR_LDBAR, sprs->ldbar); + mtspr(SPR_AMOR, sprs->amor); + + if (srr1 & SRR1_WS_HVLOSS) + /* TB loss */ + opal_resync_timebase(); + +core_woken: + + atomic_unlock_and_stop_thread_idle(); + + mtspr(SPR_WORT, sprs->wort); + mtspr(SPR_PURR, sprs->purr); + mtspr(SPR_SPURR, sprs->spurr); + mtspr(SPR_DSCR, sprs->dscr); + mtspr(SPR_LPCR, sprs->lpcr); + mtspr(SPR_PID, sprs->pid); + mtspr(SPR_FSCR, sprs->fscr); + mtspr(SPR_HFSCR, sprs->hfscr); + mtspr(SPR_MMCRA, sprs->mmcra); + mtspr(SPR_MMCR0, sprs->mmcr0); + mtspr(SPR_MMCR1, sprs->mmcr1); + mtspr(SPR_MMCR2, sprs->mmcr2); + mtspr(SPR_SPRG3, sprs->sprg3); + return OPAL_SUCCESS; +} + +opal_call(OPAL_IDLE_RESTORE, opal_cpuidle_restore, 2); + /* Add device tree properties to describe idle states */ void add_cpu_idle_state_properties(void) { @@ -1088,8 +1259,19 @@ void add_cpu_idle_state_properties(void) 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); - dt_add_property_strings(dt_state_node, "compatible", version_buf); + /* If both version and opal-support are there */ + if (states[i].version[0] != '\0') { + 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, + "opal-support"); + } else { + dt_add_property_string(dt_state_node, "compatible", version_buf); + } + } else if (states[i].opal_supported) { + dt_add_property_string(dt_state_node, "compatible", "opal-support"); + } dt_add_property_strings(dt_state_node, "type", states[i].type); *lat_buf = cpu_to_fdt32(states[i].latency_ns); diff --git a/include/cpu.h b/include/cpu.h index 2fe47982..ea3517c7 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -44,6 +44,31 @@ enum cpu_thread_state { struct cpu_job; struct xive_cpu_state; +struct p9_sprs { + /* per core */ + u64 ptcr; + u64 rpr; + u64 tscr; + u64 ldbar; + u64 amor; + + /* per thread */ + u64 lpcr; + u64 hfscr; + u64 fscr; + u64 pid; + u64 purr; + u64 spurr; + u64 dscr; + u64 wort; + u64 sprg3; + + u64 mmcra; + u32 mmcr0; + u32 mmcr1; + u64 mmcr2; +}; + struct cpu_thread { /* * "stack_guard" must be at offset 0 to match the @@ -124,6 +149,9 @@ struct cpu_thread { /* The lock requested by this cpu, used for deadlock detection */ struct lock *requested_lock; #endif + + u64 idle_state; + struct p9_sprs sprs; }; /* This global is set to 1 to allow secondaries to callin, diff --git a/include/opal-api.h b/include/opal-api.h index 5f397c8e..1e69b6eb 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -226,7 +226,9 @@ #define OPAL_NX_COPROC_INIT 167 #define OPAL_NPU_SET_RELAXED_ORDER 168 #define OPAL_NPU_GET_RELAXED_ORDER 169 -#define OPAL_LAST 169 +#define OPAL_IDLE_SAVE 170 +#define OPAL_IDLE_RESTORE 171 +#define OPAL_LAST 171 #define QUIESCE_HOLD 1 /* Spin all calls at entry */ #define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */ diff --git a/include/opal-internal.h b/include/opal-internal.h index 40bad457..2f1ce86d 100644 --- a/include/opal-internal.h +++ b/include/opal-internal.h @@ -60,6 +60,7 @@ extern void add_opal_node(void); __opal_register((token) + 0*sizeof(func(__test_args##nargs)), \ (func), (nargs)) extern void __opal_register(uint64_t token, void *func, unsigned num_args); +extern int64_t opal_resync_timebase(void); int64_t opal_quiesce(uint32_t shutdown_type, int32_t cpu); diff --git a/include/processor.h b/include/processor.h index 6b262b45..11be1dc1 100644 --- a/include/processor.h +++ b/include/processor.h @@ -88,6 +88,19 @@ #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 */ @@ -202,6 +215,10 @@ #define PVR_TYPE_P8NVL 0x004c /* Naples */ #define PVR_TYPE_P9 0x004e +/* Power management instruction */ +#define PPC_INST_STOP .long 0x4c0002e4 +#define PPC_STOP stringify(PPC_INST_STOP) + #ifdef __ASSEMBLY__ /* Thread priority control opcodes */