get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/406251/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 406251,
    "url": "http://patchwork.ozlabs.org/api/patches/406251/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/1415030910-5799-5-git-send-email-shreyas@linux.vnet.ibm.com/",
    "project": {
        "id": 2,
        "url": "http://patchwork.ozlabs.org/api/projects/2/?format=api",
        "name": "Linux PPC development",
        "link_name": "linuxppc-dev",
        "list_id": "linuxppc-dev.lists.ozlabs.org",
        "list_email": "linuxppc-dev@lists.ozlabs.org",
        "web_url": "https://github.com/linuxppc/wiki/wiki",
        "scm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git",
        "webscm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/",
        "list_archive_url": "https://lore.kernel.org/linuxppc-dev/",
        "list_archive_url_format": "https://lore.kernel.org/linuxppc-dev/{}/",
        "commit_url_format": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/commit/?id={}"
    },
    "msgid": "<1415030910-5799-5-git-send-email-shreyas@linux.vnet.ibm.com>",
    "list_archive_url": "https://lore.kernel.org/linuxppc-dev/1415030910-5799-5-git-send-email-shreyas@linux.vnet.ibm.com/",
    "date": "2014-11-03T16:08:30",
    "name": "[4/4] powernv: powerpc: Add winkle support for offline cpus",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "1fad5f7d486071aa7a7a3bec2301248b949381f6",
    "submitter": {
        "id": 64129,
        "url": "http://patchwork.ozlabs.org/api/people/64129/?format=api",
        "name": "Shreyas B. Prabhu",
        "email": "shreyas@linux.vnet.ibm.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/1415030910-5799-5-git-send-email-shreyas@linux.vnet.ibm.com/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/406251/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/406251/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org>",
        "X-Original-To": [
            "patchwork-incoming@ozlabs.org",
            "linuxppc-dev@lists.ozlabs.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@ozlabs.org",
            "linuxppc-dev@lists.ozlabs.org"
        ],
        "Received": [
            "from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 011A014009F\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue,  4 Nov 2014 03:12:47 +1100 (AEDT)",
            "from ozlabs.org (ozlabs.org [103.22.144.67])\n\tby lists.ozlabs.org (Postfix) with ESMTP id B5DEA1A1986\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue,  4 Nov 2014 03:12:47 +1100 (AEDT)",
            "from e34.co.us.ibm.com (e34.co.us.ibm.com [32.97.110.152])\n\t(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby lists.ozlabs.org (Postfix) with ESMTPS id 25C641A04B5\n\tfor <linuxppc-dev@lists.ozlabs.org>;\n\tTue,  4 Nov 2014 03:09:05 +1100 (AEDT)",
            "from /spool/local\n\tby e34.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use\n\tOnly! Violators will be prosecuted\n\tfor <linuxppc-dev@lists.ozlabs.org> from <shreyas@linux.vnet.ibm.com>;\n\tMon, 3 Nov 2014 09:09:03 -0700",
            "from d03dlp03.boulder.ibm.com (9.17.202.179)\n\tby e34.co.us.ibm.com (192.168.1.134) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tMon, 3 Nov 2014 09:09:02 -0700",
            "from b03cxnp07028.gho.boulder.ibm.com\n\t(b03cxnp07028.gho.boulder.ibm.com [9.17.130.15])\n\tby d03dlp03.boulder.ibm.com (Postfix) with ESMTP id D85E619D8048\n\tfor <linuxppc-dev@lists.ozlabs.org>;\n\tMon,  3 Nov 2014 08:57:43 -0700 (MST)",
            "from d03av01.boulder.ibm.com (d03av01.boulder.ibm.com\n\t[9.17.195.167])\n\tby b03cxnp07028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with\n\tESMTP id sA3G91qA49676312\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 3 Nov 2014 17:09:01 +0100",
            "from d03av01.boulder.ibm.com (localhost [127.0.0.1])\n\tby d03av01.boulder.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP\n\tid sA3G8wk1027556\n\tfor <linuxppc-dev@lists.ozlabs.org>; Mon, 3 Nov 2014 09:09:01 -0700",
            "from adminib-ovr2cdm.in.ibm.com ([9.79.201.189])\n\tby d03av01.boulder.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP\n\tid sA3G8YBA025138; Mon, 3 Nov 2014 09:08:55 -0700"
        ],
        "From": "\"Shreyas B. Prabhu\" <shreyas@linux.vnet.ibm.com>",
        "To": "linux-kernel@vger.kernel.org",
        "Subject": "[PATCH 4/4] powernv: powerpc: Add winkle support for offline cpus",
        "Date": "Mon,  3 Nov 2014 21:38:30 +0530",
        "Message-Id": "<1415030910-5799-5-git-send-email-shreyas@linux.vnet.ibm.com>",
        "X-Mailer": "git-send-email 1.9.3",
        "In-Reply-To": "<1415030910-5799-1-git-send-email-shreyas@linux.vnet.ibm.com>",
        "References": "<1415030910-5799-1-git-send-email-shreyas@linux.vnet.ibm.com>",
        "X-TM-AS-MML": "disable",
        "X-Content-Scanned": "Fidelis XPS MAILER",
        "x-cbid": "14110316-0017-0000-0000-000006061304",
        "Cc": "\"Shreyas B. Prabhu\" <shreyas@linux.vnet.ibm.com>,\n\tlinuxppc-dev@lists.ozlabs.org, Paul Mackerras <paulus@samba.org>",
        "X-BeenThere": "linuxppc-dev@lists.ozlabs.org",
        "X-Mailman-Version": "2.1.18",
        "Precedence": "list",
        "List-Id": "Linux on PowerPC Developers Mail List\n\t<linuxppc-dev.lists.ozlabs.org>",
        "List-Unsubscribe": "<https://lists.ozlabs.org/options/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@lists.ozlabs.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.ozlabs.org/pipermail/linuxppc-dev/>",
        "List-Post": "<mailto:linuxppc-dev@lists.ozlabs.org>",
        "List-Help": "<mailto:linuxppc-dev-request@lists.ozlabs.org?subject=help>",
        "List-Subscribe": "<https://lists.ozlabs.org/listinfo/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@lists.ozlabs.org?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org",
        "Sender": "\"Linuxppc-dev\"\n\t<linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org>"
    },
    "content": "Winkle is a deep idle state supported in power8 chips. A core enters\nwinkle when all the threads of the core enter winkle. In this state\npower supply to the entire chiplet i.e core, private L2 and private L3\nis turned off. As a result it gives higher powersavings compared to\nsleep.\n\nBut entering winkle results in a total hypervisor state loss. Hence the\nhypervisor context has to be preserved before entering winkle and\nrestored upon wake up.\n\nPower-on Reset Engine (PORE) is a dedicated engine which is responsible\nfor powering on the chiplet during wake up. It can be programmed to\nrestore the register contests of a few specific registers. This patch\nuses PORE to restore register state wherever possible and uses stack to\nsave and restore rest of the necessary registers.\n\nWith hypervisor state restore things fall under three categories-\nper-core state, per-subcore state and per-thread state. To manage this,\nextend the infrastructure introduced for sleep. Mainly we add a paca\nvariable subcore_sibling_mask. Using this and the core_idle_state we can\ndistingush first thread in core and subcore.\n\nSigned-off-by: Shreyas B. Prabhu <shreyas@linux.vnet.ibm.com>\nCc: Benjamin Herrenschmidt <benh@kernel.crashing.org>\nCc: Paul Mackerras <paulus@samba.org>\nCc: Michael Ellerman <mpe@ellerman.id.au>\nCc: linuxppc-dev@lists.ozlabs.org\n---\n arch/powerpc/include/asm/opal.h                |   3 +\n arch/powerpc/include/asm/paca.h                |   2 +\n arch/powerpc/include/asm/ppc-opcode.h          |   2 +\n arch/powerpc/include/asm/processor.h           |   1 +\n arch/powerpc/include/asm/reg.h                 |   2 +\n arch/powerpc/kernel/asm-offsets.c              |   2 +\n arch/powerpc/kernel/cpu_setup_power.S          |   4 +\n arch/powerpc/kernel/exceptions-64s.S           |  10 ++\n arch/powerpc/kernel/idle_power7.S              | 161 ++++++++++++++++++++++---\n arch/powerpc/platforms/powernv/opal-wrappers.S |   2 +\n arch/powerpc/platforms/powernv/setup.c         |  73 +++++++++++\n arch/powerpc/platforms/powernv/smp.c           |   4 +-\n arch/powerpc/platforms/powernv/subcore.c       |  34 ++++++\n arch/powerpc/platforms/powernv/subcore.h       |   1 +\n 14 files changed, 285 insertions(+), 16 deletions(-)",
    "diff": "diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h\nindex bef7fbc..f0ca2d9 100644\n--- a/arch/powerpc/include/asm/opal.h\n+++ b/arch/powerpc/include/asm/opal.h\n@@ -153,6 +153,7 @@ struct opal_sg_list {\n #define OPAL_PCI_EEH_FREEZE_SET\t\t\t97\n #define OPAL_HANDLE_HMI\t\t\t\t98\n #define OPAL_CONFIG_CPU_IDLE_STATE\t\t99\n+#define OPAL_SLW_SET_REG\t\t\t100\n #define OPAL_REGISTER_DUMP_REGION\t\t101\n #define OPAL_UNREGISTER_DUMP_REGION\t\t102\n \n@@ -163,6 +164,7 @@ struct opal_sg_list {\n  */\n #define OPAL_PM_NAP_ENABLED\t0x00010000\n #define OPAL_PM_SLEEP_ENABLED\t0x00020000\n+#define OPAL_PM_WINKLE_ENABLED\t0x00040000\n #define OPAL_PM_SLEEP_ENABLED_ER1\t0x00080000\n \n #ifndef __ASSEMBLY__\n@@ -972,6 +974,7 @@ int64_t opal_sensor_read(uint32_t sensor_hndl, int token, __be32 *sensor_data);\n int64_t opal_handle_hmi(void);\n int64_t opal_register_dump_region(uint32_t id, uint64_t start, uint64_t end);\n int64_t opal_unregister_dump_region(uint32_t id);\n+int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);\n int64_t opal_pci_set_phb_cxl_mode(uint64_t phb_id, uint64_t mode, uint64_t pe_number);\n \n /* Internal functions */\ndiff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h\nindex 85aeedb..c2e51b7 100644\n--- a/arch/powerpc/include/asm/paca.h\n+++ b/arch/powerpc/include/asm/paca.h\n@@ -162,6 +162,8 @@ struct paca_struct {\n \t/* Per-core mask tracking idle threads and a lock bit-[L][TTTTTTTT] */\n \tu32 *core_idle_state_ptr;\n \tu8 thread_idle_state;\t\t/* ~Idle[0]/Nap[1]/Sleep[2]/Winkle[3] */\n+\t/* Mask to denote subcore sibling threads */\n+\tu8 subcore_sibling_mask;\n #endif\n #ifdef CONFIG_PPC_BOOK3S_64\n \t/* Exclusive emergency stack pointer for machine check exception. */\ndiff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h\nindex 6f85362..5155be7 100644\n--- a/arch/powerpc/include/asm/ppc-opcode.h\n+++ b/arch/powerpc/include/asm/ppc-opcode.h\n@@ -194,6 +194,7 @@\n \n #define PPC_INST_NAP\t\t\t0x4c000364\n #define PPC_INST_SLEEP\t\t\t0x4c0003a4\n+#define PPC_INST_WINKLE\t\t\t0x4c0003e4\n \n /* A2 specific instructions */\n #define PPC_INST_ERATWE\t\t\t0x7c0001a6\n@@ -374,6 +375,7 @@\n \n #define PPC_NAP\t\t\tstringify_in_c(.long PPC_INST_NAP)\n #define PPC_SLEEP\t\tstringify_in_c(.long PPC_INST_SLEEP)\n+#define PPC_WINKLE\t\tstringify_in_c(.long PPC_INST_WINKLE)\n \n /* BHRB instructions */\n #define PPC_CLRBHRB\t\tstringify_in_c(.long PPC_INST_CLRBHRB)\ndiff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h\nindex dda7ac4..c076842 100644\n--- a/arch/powerpc/include/asm/processor.h\n+++ b/arch/powerpc/include/asm/processor.h\n@@ -453,6 +453,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};\n extern int powersave_nap;\t/* set if nap mode can be used in idle loop */\n extern void power7_nap(int check_irq);\n extern void power7_sleep(void);\n+extern void power7_winkle(void);\n extern void flush_instruction_cache(void);\n extern void hard_reset_now(void);\n extern void poweroff_now(void);\ndiff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h\nindex a68ee15..1c874fb 100644\n--- a/arch/powerpc/include/asm/reg.h\n+++ b/arch/powerpc/include/asm/reg.h\n@@ -373,6 +373,7 @@\n #define SPRN_DBAT7L\t0x23F\t/* Data BAT 7 Lower Register */\n #define SPRN_DBAT7U\t0x23E\t/* Data BAT 7 Upper Register */\n #define SPRN_PPR\t0x380\t/* SMT Thread status Register */\n+#define SPRN_TSCR\t0x399\t/* Thread Switch Control Register */\n \n #define SPRN_DEC\t0x016\t\t/* Decrement Register */\n #define SPRN_DER\t0x095\t\t/* Debug Enable Regsiter */\n@@ -730,6 +731,7 @@\n #define SPRN_BESCR\t806\t/* Branch event status and control register */\n #define   BESCR_GE\t0x8000000000000000ULL /* Global Enable */\n #define SPRN_WORT\t895\t/* Workload optimization register - thread */\n+#define SPRN_WORC\t863\t/* Workload optimization register - core */\n \n #define SPRN_PMC1\t787\n #define SPRN_PMC2\t788\ndiff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c\nindex 50f299e..b7fb63a 100644\n--- a/arch/powerpc/kernel/asm-offsets.c\n+++ b/arch/powerpc/kernel/asm-offsets.c\n@@ -735,6 +735,8 @@ int main(void)\n \t\t\toffsetof(struct paca_struct, core_idle_state_ptr));\n \tDEFINE(PACA_THREAD_IDLE_STATE,\n \t\t\toffsetof(struct paca_struct, thread_idle_state));\n+\tDEFINE(PACA_SUBCORE_SIBLING_MASK,\n+\t\t\toffsetof(struct paca_struct, subcore_sibling_mask));\n #endif\n \n \treturn 0;\ndiff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S\nindex 4673353..66874aa 100644\n--- a/arch/powerpc/kernel/cpu_setup_power.S\n+++ b/arch/powerpc/kernel/cpu_setup_power.S\n@@ -55,6 +55,8 @@ _GLOBAL(__setup_cpu_power8)\n \tbeqlr\n \tli\tr0,0\n \tmtspr\tSPRN_LPID,r0\n+\tmtspr\tSPRN_WORT,r0\n+\tmtspr\tSPRN_WORC,r0\n \tmfspr\tr3,SPRN_LPCR\n \tori\tr3, r3, LPCR_PECEDH\n \tbl\t__init_LPCR\n@@ -75,6 +77,8 @@ _GLOBAL(__restore_cpu_power8)\n \tli\tr0,0\n \tmtspr\tSPRN_LPID,r0\n \tmfspr   r3,SPRN_LPCR\n+\tmtspr\tSPRN_WORT,r0\n+\tmtspr\tSPRN_WORC,r0\n \tori\tr3, r3, LPCR_PECEDH\n \tbl\t__init_LPCR\n \tbl\t__init_HFSCR\ndiff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S\nindex 3311c8d..c9897cb 100644\n--- a/arch/powerpc/kernel/exceptions-64s.S\n+++ b/arch/powerpc/kernel/exceptions-64s.S\n@@ -112,6 +112,16 @@ BEGIN_FTR_SECTION\n \n \tcmpwi\tcr1,r13,2\n \n+\t/* Check if last bit of HSPGR0 is set. This indicates whether we are\n+\t * waking up from winkle */\n+\tli\tr3,1\n+\tmfspr\tr4,SPRN_HSPRG0\n+\tand\tr5,r4,r3\n+\tcmpwi\tcr4,r5,1\t/* Store result in cr4 for later use */\n+\n+\tandc\tr4,r4,r3\n+\tmtspr\tSPRN_HSPRG0,r4\n+\n \tGET_PACA(r13)\n \tlbz\tr0,PACA_THREAD_IDLE_STATE(r13)\n \tcmpwi   cr2,r0,PNV_THREAD_NAP\ndiff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S\nindex df11acb..3cfdea9 100644\n--- a/arch/powerpc/kernel/idle_power7.S\n+++ b/arch/powerpc/kernel/idle_power7.S\n@@ -19,8 +19,22 @@\n #include <asm/kvm_book3s_asm.h>\n #include <asm/opal.h>\n #include <asm/cpuidle.h>\n+#include <asm/mmu-hash64.h>\n \n #undef DEBUG\n+/*\n+ * Use unused space in the interrupt stack to save and restore\n+ * registers for winkle support.\n+ */\n+#define _SDR1\tGPR3\n+#define _RPR\tGPR4\n+#define _SPURR\tGPR5\n+#define _PURR\tGPR6\n+#define _TSCR\tGPR7\n+#define _DSCR\tGPR8\n+#define _AMOR\tGPR9\n+#define _PMC5\tGPR10\n+#define _PMC6\tGPR11\n \n /* Idle state entry routines */\n \n@@ -38,8 +52,9 @@\n \n /*\n  * Pass requested state in r3:\n- * \t0 - nap\n- * \t1 - sleep\n+ * \t1 - nap\n+ * \t2 - sleep\n+ *\t3 - winkle\n  *\n  * To check IRQ_HAPPENED in r4\n  * \t0 - don't check\n@@ -154,32 +169,60 @@ lwarx_loop1:\n \tb\tcommon_enter\n \n last_thread:\n-\tLOAD_REG_ADDR(r3, pnv_need_fastsleep_workaround)\n-\tlbz\tr3,0(r3)\n-\tcmpwi\tr3,1\n-\tbne\tcommon_enter\n \t/*\n \t * Last thread of the core entering sleep. Last thread needs to execute\n \t * the hardware bug workaround code. Before that, set the lock bit to\n \t * avoid the race of other threads waking up and undoing workaround\n \t * before workaround is applied.\n \t */\n+\tLOAD_REG_ADDR(r3, pnv_need_fastsleep_workaround)\n+\tlbz\tr3,0(r3)\n+\tcmpwi\tr3,1\n+\tbne\tcommon_enter\n+\n \tori\tr15,r15,PNV_CORE_IDLE_LOCK_BIT\n \tstwcx.\tr15,0,r14\n \tbne-\tlwarx_loop1\n \n \t/* Fast sleep workaround */\n+\tmfcr\tr16\t/* Backup CR to a non-volatile register */\n \tli\tr3,1\n \tli\tr4,1\n \tli\tr0,OPAL_CONFIG_CPU_IDLE_STATE\n \tbl\topal_call_realmode\n+\tmtcr\tr16\t/* Restore CR */\n \n \t/* Clear Lock bit */\n \tandi.\tr15,r15,PNV_CORE_IDLE_THREAD_BITS\n \tstw\tr15,0(r14)\n \n-common_enter: /* common code for all the threads entering sleep */\n+common_enter: /* common code for all the threads entering sleep or winkle*/\n+\tbgt\tcr1,enter_winkle\n \tIDLE_STATE_ENTER_SEQ(PPC_SLEEP)\n+enter_winkle:\n+\t/*\n+\t * Note all register i.e per-core, per-subcore or per-thread is saved\n+\t * here since any thread in the core might wake up first\n+\t */\n+\tmfspr\tr3,SPRN_SDR1\n+\tstd\tr3,_SDR1(r1)\n+\tmfspr\tr3,SPRN_RPR\n+\tstd\tr3,_RPR(r1)\n+\tmfspr\tr3,SPRN_SPURR\n+\tstd\tr3,_SPURR(r1)\n+\tmfspr\tr3,SPRN_PURR\n+\tstd\tr3,_PURR(r1)\n+\tmfspr\tr3,SPRN_TSCR\n+\tstd\tr3,_TSCR(r1)\n+\tmfspr\tr3,SPRN_DSCR\n+\tstd\tr3,_DSCR(r1)\n+\tmfspr\tr3,SPRN_AMOR\n+\tstd\tr3,_AMOR(r1)\n+\tmfspr\tr3,SPRN_PMC5\n+\tstd\tr3,_PMC5(r1)\n+\tmfspr\tr3,SPRN_PMC6\n+\tstd\tr3,_PMC6(r1)\n+\tIDLE_STATE_ENTER_SEQ(PPC_WINKLE)\n \n _GLOBAL(power7_idle)\n \t/* Now check if user or arch enabled NAP mode */\n@@ -202,6 +245,12 @@ _GLOBAL(power7_sleep)\n \tb\tpower7_powersave_common\n \t/* No return */\n \n+_GLOBAL(power7_winkle)\n+\tli\tr3,3\n+\tli\tr4,1\n+\tb\tpower7_powersave_common\n+\t/* No return */\n+\n #define CHECK_HMI_INTERRUPT\t\t\t\t\t\t\\\n \tmfspr\tr0,SPRN_SRR1;\t\t\t\t\t\t\\\n BEGIN_FTR_SECTION_NESTED(66);\t\t\t\t\t\t\\\n@@ -251,22 +300,54 @@ lwarx_loop2:\n \t */\n \tbne\tlwarx_loop2\n \n-\tcmpwi\tcr2,r15,0\n+\tcmpwi\tcr2,r15,0\t/* Check if first in core */\n+\tlbz\tr4,PACA_SUBCORE_SIBLING_MASK(r13)\n+\tand\tr4,r4,r15\n+\tcmpwi\tcr3,r4,0\t/* Check if first in subcore */\n+\n+\t/*\n+\t * At this stage\n+\t * cr1 - 01 if waking up from sleep or winkle\n+\t * cr2 - 10 if first thread to wakeup in core\n+\t * cr3 - 10 if first thread to wakeup in subcore\n+\t * cr4 - 10 if waking up from winkle\n+\t */\n+\n \tor\tr15,r15,r7\t\t/* Set thread bit */\n \n-\tbeq\tcr2,first_thread\n+\tbeq\tcr3,first_thread_in_subcore\n \n-\t/* Not first thread in core to wake up */\n+\t/* Not first thread in subcore to wake up */\n \tstwcx.\tr15,0,r14\n \tbne-\tlwarx_loop2\n \tb\tcommon_exit\n \n-first_thread:\n-\t/* First thread in core to wakeup */\n+first_thread_in_subcore:\n+\t/* First thread in subcore to wakeup set the lock bit */\n \tori\tr15,r15,PNV_CORE_IDLE_LOCK_BIT\n \tstwcx.\tr15,0,r14\n \tbne-\tlwarx_loop2\n \n+\t/*\n+\t * If waking up from sleep, subcore state is not lost. Hence\n+\t * skip subcore state restore\n+\t */\n+\tbne\tcr4,subcore_state_restored\n+\n+\t/* Restore per-subcore state */\n+\tld      r4,_SDR1(r1)\n+\tmtspr   SPRN_SDR1,r4\n+\tld      r4,_RPR(r1)\n+\tmtspr   SPRN_RPR,r4\n+\tld\tr4,_AMOR(r1)\n+\tmtspr\tSPRN_AMOR,r4\n+\n+subcore_state_restored:\n+\t/* Check if the thread is also the first thread in the core. If not,\n+\t * skip to clear_lock */\n+\tbne\tcr2,clear_lock\n+\n+first_thread_in_core:\n \tLOAD_REG_ADDR(r3, pnv_need_fastsleep_workaround)\n \tlbz\tr3,0(r3)\n \tcmpwi\tr3,1\n@@ -281,21 +362,71 @@ first_thread:\n \tbl\topal_call_realmode\n \tmtcr\tr16\t/* Restore CR */\n \n-\t/* Do timebase resync if we are waking up from sleep. Use cr1 value\n-\t * set in exceptions-64s.S */\n+timebase_resync:\n+\t/* Do timebase resync only if the core truly woke up from\n+\t * sleep/winkle */\n \tble\tcr1,clear_lock\n \n-timebase_resync:\n \t/* Time base re-sync */\n+\tmfcr\tr16\t/* Backup CR into a non-volatile register */\n \tli\tr0,OPAL_RESYNC_TIMEBASE\n \tbl\topal_call_realmode;\n \t/* TODO: Check r3 for failure */\n+\tmtcr\tr16\t/* Restore CR */\n+\n+\t/*\n+\t * If waking up from sleep, per core state is not lost, skip to\n+\t * clear_lock.\n+\t */\n+\tbne\tcr4,clear_lock\n+\n+\t/* Restore per core state */\n+\tld\tr4,_TSCR(r1)\n+\tmtspr\tSPRN_TSCR,r4\n \n clear_lock:\n \tandi.\tr15,r15,PNV_CORE_IDLE_THREAD_BITS\n \tstw\tr15,0(r14)\n \n common_exit:\n+\t/* Common to all threads\n+\t *\n+\t * If waking up from sleep, hypervisor state is not lost. Hence\n+\t * skip hypervisor state restore.\n+\t */\n+\tbne\tcr4,hypervisor_state_restored\n+\n+\t/* Waking up from winkle */\n+\n+\t/* Restore per thread state */\n+\tbl\t__restore_cpu_power8\n+\n+\t/* Restore SLB  from PACA */\n+\tld\tr8,PACA_SLBSHADOWPTR(r13)\n+\n+\t.rept\tSLB_NUM_BOLTED\n+\tli\tr3, SLBSHADOW_SAVEAREA\n+\tLDX_BE\tr5, r8, r3\n+\taddi\tr3, r3, 8\n+\tLDX_BE\tr6, r8, r3\n+\tandis.\tr7,r5,SLB_ESID_V@h\n+\tbeq\t1f\n+\tslbmte\tr6,r5\n+1:\taddi\tr8,r8,16\n+\t.endr\n+\n+\tld\tr4,_SPURR(r1)\n+\tmtspr\tSPRN_SPURR,r4\n+\tld\tr4,_PURR(r1)\n+\tmtspr\tSPRN_PURR,r4\n+\tld\tr4,_DSCR(r1)\n+\tmtspr\tSPRN_DSCR,r4\n+\tld\tr4,_PMC5(r1)\n+\tmtspr\tSPRN_PMC5,r4\n+\tld\tr4,_PMC6(r1)\n+\tmtspr\tSPRN_PMC6,r4\n+\n+hypervisor_state_restored:\n \tli\tr5,PNV_THREAD_RUNNING\n \tstb     r5,PACA_THREAD_IDLE_STATE(r13)\n \ndiff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S\nindex b2aa93b..e1e91e0 100644\n--- a/arch/powerpc/platforms/powernv/opal-wrappers.S\n+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S\n@@ -191,6 +191,7 @@ return_from_opal_call:\n #ifdef __LITTLE_ENDIAN__\n \tFIXUP_ENDIAN\n #endif\n+\tld\tr2,PACATOC(r13)\n \tld\tr12,_LINK(r1)\n \tmtlr\tr12\n \tblr\n@@ -284,6 +285,7 @@ OPAL_CALL(opal_sensor_read,\t\t\tOPAL_SENSOR_READ);\n OPAL_CALL(opal_get_param,\t\t\tOPAL_GET_PARAM);\n OPAL_CALL(opal_set_param,\t\t\tOPAL_SET_PARAM);\n OPAL_CALL(opal_handle_hmi,\t\t\tOPAL_HANDLE_HMI);\n+OPAL_CALL(opal_slw_set_reg,\t\t\tOPAL_SLW_SET_REG);\n OPAL_CALL(opal_register_dump_region,\t\tOPAL_REGISTER_DUMP_REGION);\n OPAL_CALL(opal_unregister_dump_region,\t\tOPAL_UNREGISTER_DUMP_REGION);\n OPAL_CALL(opal_pci_set_phb_cxl_mode,\t\tOPAL_PCI_SET_PHB_CXL_MODE);\ndiff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c\nindex 980c964..3caaae1 100644\n--- a/arch/powerpc/platforms/powernv/setup.c\n+++ b/arch/powerpc/platforms/powernv/setup.c\n@@ -40,6 +40,7 @@\n #include <asm/cpuidle.h>\n \n #include \"powernv.h\"\n+#include \"subcore.h\"\n \n static void __init pnv_setup_arch(void)\n {\n@@ -293,6 +294,74 @@ static void __init pnv_setup_machdep_rtas(void)\n #endif /* CONFIG_PPC_POWERNV_RTAS */\n \n static u32 supported_cpuidle_states;\n+int pnv_save_sprs_for_winkle(void)\n+{\n+\tint cpu;\n+\tint rc;\n+\n+\t/*\n+\t * hid0, hid1, hid4, hid5, hmeer and lpcr values are symmetric accross\n+\t * all cpus at boot. Get these reg values of current cpu and use the\n+\t * same accross all cpus.\n+\t */\n+\tuint64_t lpcr_val = mfspr(SPRN_LPCR);\n+\tuint64_t hid0_val = mfspr(SPRN_HID0);\n+\tuint64_t hid1_val = mfspr(SPRN_HID1);\n+\tuint64_t hid4_val = mfspr(SPRN_HID4);\n+\tuint64_t hid5_val = mfspr(SPRN_HID5);\n+\tuint64_t hmeer_val = mfspr(SPRN_HMEER);\n+\n+\tfor_each_possible_cpu(cpu) {\n+\t\tuint64_t pir = get_hard_smp_processor_id(cpu);\n+\t\tuint64_t hsprg0_val = (uint64_t)&paca[cpu];\n+\n+\t\t/*\n+\t\t * HSPRG0 is used to store the cpu's pointer to paca. Hence last\n+\t\t * 3 bits are guaranteed to be 0. Program slw to restore HSPRG0\n+\t\t * with 63rd bit set, so that when a thread wakes up at 0x100 we\n+\t\t * can use this bit to distinguish between fastsleep and\n+\t\t * deep winkle.\n+\t\t */\n+\t\thsprg0_val |= 1;\n+\n+\t\trc = opal_slw_set_reg(pir, SPRN_HSPRG0, hsprg0_val);\n+\t\tif (rc != 0)\n+\t\t\treturn rc;\n+\n+\t\trc = opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val);\n+\t\tif (rc != 0)\n+\t\t\treturn rc;\n+\n+\t\t/* HIDs are per core registers */\n+\t\tif (cpu_thread_in_core(cpu) == 0) {\n+\n+\t\t\trc = opal_slw_set_reg(pir, SPRN_HMEER, hmeer_val);\n+\t\t\tif (rc != 0)\n+\t\t\t\treturn rc;\n+\n+\t\t\trc = opal_slw_set_reg(pir, SPRN_HID0, hid0_val);\n+\t\t\tif (rc != 0)\n+\t\t\t\treturn rc;\n+\n+\t\t\trc = opal_slw_set_reg(pir, SPRN_HID1, hid1_val);\n+\t\t\tif (rc != 0)\n+\t\t\t\treturn rc;\n+\n+\t\t\trc = opal_slw_set_reg(pir, SPRN_HID4, hid4_val);\n+\t\t\tif (rc != 0)\n+\t\t\t\treturn rc;\n+\n+\t\t\trc = opal_slw_set_reg(pir, SPRN_HID5, hid5_val);\n+\t\t\tif (rc != 0)\n+\t\t\t\treturn rc;\n+\n+\t\t}\n+\n+\t}\n+\n+\treturn 0;\n+\n+}\n \n static void pnv_alloc_idle_core_states(void)\n {\n@@ -334,6 +403,10 @@ static void pnv_alloc_idle_core_states(void)\n \n \t\t}\n \t}\n+\tupdate_subcore_sibling_mask();\n+\tif (supported_cpuidle_states & OPAL_PM_WINKLE_ENABLED)\n+\t\tpnv_save_sprs_for_winkle();\n+\n }\n \n u32 pnv_get_supported_cpuidle_states(void)\ndiff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c\nindex 12b761a..5e35857 100644\n--- a/arch/powerpc/platforms/powernv/smp.c\n+++ b/arch/powerpc/platforms/powernv/smp.c\n@@ -167,7 +167,9 @@ static void pnv_smp_cpu_kill_self(void)\n \tmtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);\n \twhile (!generic_check_cpu_restart(cpu)) {\n \t\tppc64_runlatch_off();\n-\t\tif ((idle_states & OPAL_PM_SLEEP_ENABLED) ||\n+\t\tif (idle_states & OPAL_PM_WINKLE_ENABLED)\n+\t\t\tpower7_winkle();\n+\t\telse if ((idle_states & OPAL_PM_SLEEP_ENABLED) ||\n \t\t\t\t(idle_states & OPAL_PM_SLEEP_ENABLED_ER1))\n \t\t\tpower7_sleep();\n \t\telse\ndiff --git a/arch/powerpc/platforms/powernv/subcore.c b/arch/powerpc/platforms/powernv/subcore.c\nindex c87f96b..f60f80a 100644\n--- a/arch/powerpc/platforms/powernv/subcore.c\n+++ b/arch/powerpc/platforms/powernv/subcore.c\n@@ -160,6 +160,18 @@ static void wait_for_sync_step(int step)\n \tmb();\n }\n \n+static void update_hid_in_slw(u64 hid0)\n+{\n+\tu64 idle_states = pnv_get_supported_cpuidle_states();\n+\n+\tif (idle_states & OPAL_PM_WINKLE_ENABLED) {\n+\t\t/* OPAL call to patch slw with the new HID0 value */\n+\t\tu64 cpu_pir = hard_smp_processor_id();\n+\n+\t\topal_slw_set_reg(cpu_pir, SPRN_HID0, hid0);\n+\t}\n+}\n+\n static void unsplit_core(void)\n {\n \tu64 hid0, mask;\n@@ -179,6 +191,7 @@ static void unsplit_core(void)\n \thid0 = mfspr(SPRN_HID0);\n \thid0 &= ~HID0_POWER8_DYNLPARDIS;\n \tmtspr(SPRN_HID0, hid0);\n+\tupdate_hid_in_slw(hid0);\n \n \twhile (mfspr(SPRN_HID0) & mask)\n \t\tcpu_relax();\n@@ -215,6 +228,7 @@ static void split_core(int new_mode)\n \thid0  = mfspr(SPRN_HID0);\n \thid0 |= HID0_POWER8_DYNLPARDIS | split_parms[i].value;\n \tmtspr(SPRN_HID0, hid0);\n+\tupdate_hid_in_slw(hid0);\n \n \t/* Wait for it to happen */\n \twhile (!(mfspr(SPRN_HID0) & split_parms[i].mask))\n@@ -251,6 +265,25 @@ bool cpu_core_split_required(void)\n \treturn true;\n }\n \n+void update_subcore_sibling_mask(void)\n+{\n+\tint cpu;\n+\t/*\n+\t * sibling mask for the first cpu. Left shift this by required bits\n+\t * to get sibling mask for the rest of the cpus.\n+\t */\n+\tint sibling_mask_first_cpu =  (1 << threads_per_subcore) - 1;\n+\n+\tfor_each_possible_cpu(cpu) {\n+\t\tint tid = cpu_thread_in_core(cpu);\n+\t\tint offset = (tid / threads_per_subcore) * threads_per_subcore;\n+\t\tint mask = sibling_mask_first_cpu << offset;\n+\n+\t\tpaca[cpu].subcore_sibling_mask = mask;\n+\n+\t}\n+}\n+\n static int cpu_update_split_mode(void *data)\n {\n \tint cpu, new_mode = *(int *)data;\n@@ -284,6 +317,7 @@ static int cpu_update_split_mode(void *data)\n \t\t/* Make the new mode public */\n \t\tsubcores_per_core = new_mode;\n \t\tthreads_per_subcore = threads_per_core / subcores_per_core;\n+\t\tupdate_subcore_sibling_mask();\n \n \t\t/* Make sure the new mode is written before we exit */\n \t\tmb();\ndiff --git a/arch/powerpc/platforms/powernv/subcore.h b/arch/powerpc/platforms/powernv/subcore.h\nindex 148abc9..604eb40 100644\n--- a/arch/powerpc/platforms/powernv/subcore.h\n+++ b/arch/powerpc/platforms/powernv/subcore.h\n@@ -15,4 +15,5 @@\n \n #ifndef __ASSEMBLY__\n void split_core_secondary_loop(u8 *state);\n+extern void update_subcore_sibling_mask(void);\n #endif\n",
    "prefixes": [
        "4/4"
    ]
}