u8 thread_mask;
        /* Mask to denote subcore sibling threads */
        u8 subcore_sibling_mask;
+       /*
+        * Pointer to an array which contains pointer
+        * to the sibling threads' paca.
+        */
+       struct paca_struct **thread_sibling_pacas;
 #endif
 
 #ifdef CONFIG_PPC_BOOK3S_64
 
        OFFSET(PACA_THREAD_IDLE_STATE, paca_struct, thread_idle_state);
        OFFSET(PACA_THREAD_MASK, paca_struct, thread_mask);
        OFFSET(PACA_SUBCORE_SIBLING_MASK, paca_struct, subcore_sibling_mask);
+       OFFSET(PACA_SIBLING_PACA_PTRS, paca_struct, thread_sibling_pacas);
 #endif
 
        DEFINE(PPC_DBELL_SERVER, PPC_DBELL_SERVER);
 
        li      r4,1
        b       pnv_powersave_common
        /* No return */
+
+
+/*
+ * On waking up from stop 0,1,2 with ESL=1 on POWER9 DD1,
+ * HSPRG0 will be set to the HSPRG0 value of one of the
+ * threads in this core. Thus the value we have in r13
+ * may not be this thread's paca pointer.
+ *
+ * Fortunately, the TIR remains invariant. Since this thread's
+ * paca pointer is recorded in all its sibling's paca, we can
+ * correctly recover this thread's paca pointer if we
+ * know the index of this thread in the core.
+ *
+ * This index can be obtained from the TIR.
+ *
+ * i.e, thread's position in the core = TIR.
+ * If this value is i, then this thread's paca is
+ * paca->thread_sibling_pacas[i].
+ */
+power9_dd1_recover_paca:
+       mfspr   r4, SPRN_TIR
+       /*
+        * Since each entry in thread_sibling_pacas is 8 bytes
+        * we need to left-shift by 3 bits. Thus r4 = i * 8
+        */
+       sldi    r4, r4, 3
+       /* Get &paca->thread_sibling_pacas[0] in r5 */
+       ld      r5, PACA_SIBLING_PACA_PTRS(r13)
+       /* Load paca->thread_sibling_pacas[i] into r13 */
+       ldx     r13, r4, r5
+       SET_PACA(r13)
+       ld      r2, PACATOC(r13)
+       /*
+        * Indicate that we have lost NVGPR state
+        * which needs to be restored from the stack.
+        */
+       li      r3, 1
+       stb     r0,PACA_NAPSTATELOST(r13)
+       blr
+
 /*
  * Called from reset vector. Check whether we have woken up with
  * hypervisor state loss. If yes, restore hypervisor state and return
  */
 _GLOBAL(pnv_restore_hyp_resource)
 BEGIN_FTR_SECTION
-       ld      r2,PACATOC(r13);
+BEGIN_FTR_SECTION_NESTED(70)
+       mflr    r6
+       bl      power9_dd1_recover_paca
+       mtlr    r6
+FTR_SECTION_ELSE_NESTED(70)
+       ld      r2, PACATOC(r13)
+ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_POWER9_DD1, 70)
        /*
         * POWER ISA 3. Use PSSCR to determine if we
         * are waking up from deep idle state
 
        for (i = 0; i < nr_cores; i++) {
                int first_cpu = i * threads_per_core;
                int node = cpu_to_node(first_cpu);
+               size_t paca_ptr_array_size;
 
                core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node);
                *core_idle_state = PNV_CORE_IDLE_THREAD_BITS;
+               paca_ptr_array_size = (threads_per_core *
+                                      sizeof(struct paca_struct *));
 
                for (j = 0; j < threads_per_core; j++) {
                        int cpu = first_cpu + j;
                        paca[cpu].core_idle_state_ptr = core_idle_state;
                        paca[cpu].thread_idle_state = PNV_THREAD_RUNNING;
                        paca[cpu].thread_mask = 1 << j;
+                       if (!cpu_has_feature(CPU_FTR_POWER9_DD1))
+                               continue;
+                       paca[cpu].thread_sibling_pacas =
+                               kmalloc_node(paca_ptr_array_size,
+                                            GFP_KERNEL, node);
                }
        }
 
 
        pnv_alloc_idle_core_states();
 
+       /*
+        * For each CPU, record its PACA address in each of it's
+        * sibling thread's PACA at the slot corresponding to this
+        * CPU's index in the core.
+        */
+       if (cpu_has_feature(CPU_FTR_POWER9_DD1)) {
+               int cpu;
+
+               pr_info("powernv: idle: Saving PACA pointers of all CPUs in their thread sibling PACA\n");
+               for_each_possible_cpu(cpu) {
+                       int base_cpu = cpu_first_thread_sibling(cpu);
+                       int idx = cpu_thread_in_core(cpu);
+                       int i;
+
+                       for (i = 0; i < threads_per_core; i++) {
+                               int j = base_cpu + i;
+
+                               paca[j].thread_sibling_pacas[idx] = &paca[cpu];
+                       }
+               }
+       }
+
        if (supported_cpuidle_states & OPAL_PM_NAP_ENABLED)
                ppc_md.power_save = power7_idle;