hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * CBE Pervasive Monitor and Debug
 *
 * (C) Copyright IBM Corporation 2005
 *
 * Authors: Maximino Aguilar (maguilar@us.ibm.com)
 *          Michael N. Day (mnday@us.ibm.com)
 */
 
#undef DEBUG
 
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/percpu.h>
#include <linux/types.h>
#include <linux/kallsyms.h>
#include <linux/pgtable.h>
 
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/reg.h>
#include <asm/cell-regs.h>
#include <asm/cpu_has_feature.h>
 
#include "pervasive.h"
 
static void cbe_power_save(void)
{
   unsigned long ctrl, thread_switch_control;
 
   /* Ensure our interrupt state is properly tracked */
   if (!prep_irq_for_idle())
       return;
 
   ctrl = mfspr(SPRN_CTRLF);
 
   /* Enable DEC and EE interrupt request */
   thread_switch_control  = mfspr(SPRN_TSC_CELL);
   thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;
 
   switch (ctrl & CTRL_CT) {
   case CTRL_CT0:
       thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
       break;
   case CTRL_CT1:
       thread_switch_control |= TSC_CELL_DEC_ENABLE_1;
       break;
   default:
       printk(KERN_WARNING "%s: unknown configuration\n",
           __func__);
       break;
   }
   mtspr(SPRN_TSC_CELL, thread_switch_control);
 
   /*
    * go into low thread priority, medium priority will be
    * restored for us after wake-up.
    */
   HMT_low();
 
   /*
    * atomically disable thread execution and runlatch.
    * External and Decrementer exceptions are still handled when the
    * thread is disabled but now enter in cbe_system_reset_exception()
    */
   ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
   mtspr(SPRN_CTRLT, ctrl);
 
   /* Re-enable interrupts in MSR */
   __hard_irq_enable();
}
 
static int cbe_system_reset_exception(struct pt_regs *regs)
{
   switch (regs->msr & SRR1_WAKEMASK) {
   case SRR1_WAKEDEC:
       set_dec(1);
       break;
   case SRR1_WAKEEE:
       /*
        * Handle these when interrupts get re-enabled and we take
        * them as regular exceptions. We are in an NMI context
        * and can't handle these here.
        */
       break;
   case SRR1_WAKEMT:
       return cbe_sysreset_hack();
#ifdef CONFIG_CBE_RAS
   case SRR1_WAKESYSERR:
       cbe_system_error_exception(regs);
       break;
   case SRR1_WAKETHERM:
       cbe_thermal_exception(regs);
       break;
#endif /* CONFIG_CBE_RAS */
   default:
       /* do system reset */
       return 0;
   }
   /* everything handled */
   return 1;
}
 
void __init cbe_pervasive_init(void)
{
   int cpu;
 
   if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
       return;
 
   for_each_possible_cpu(cpu) {
       struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu);
       if (!regs)
           continue;
 
        /* Enable Pause(0) control bit */
       out_be64(&regs->pmcr, in_be64(&regs->pmcr) |
                       CBE_PMD_PAUSE_ZERO_CONTROL);
   }
 
   ppc_md.power_save = cbe_power_save;
   ppc_md.system_reset_exception = cbe_system_reset_exception;
}