diff options
Diffstat (limited to 'arch/arc/kernel/mcip.c')
-rw-r--r-- | arch/arc/kernel/mcip.c | 74 |
1 files changed, 69 insertions, 5 deletions
diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index f61a52b01625..5fe84e481654 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c | |||
@@ -22,10 +22,79 @@ static DEFINE_RAW_SPINLOCK(mcip_lock); | |||
22 | 22 | ||
23 | static char smp_cpuinfo_buf[128]; | 23 | static char smp_cpuinfo_buf[128]; |
24 | 24 | ||
25 | /* | ||
26 | * Set mask to halt GFRC if any online core in SMP cluster is halted. | ||
27 | * Only works for ARC HS v3.0+, on earlier versions has no effect. | ||
28 | */ | ||
29 | static void mcip_update_gfrc_halt_mask(int cpu) | ||
30 | { | ||
31 | struct bcr_generic gfrc; | ||
32 | unsigned long flags; | ||
33 | u32 gfrc_halt_mask; | ||
34 | |||
35 | READ_BCR(ARC_REG_GFRC_BUILD, gfrc); | ||
36 | |||
37 | /* | ||
38 | * CMD_GFRC_SET_CORE and CMD_GFRC_READ_CORE commands were added in | ||
39 | * GFRC 0x3 version. | ||
40 | */ | ||
41 | if (gfrc.ver < 0x3) | ||
42 | return; | ||
43 | |||
44 | raw_spin_lock_irqsave(&mcip_lock, flags); | ||
45 | |||
46 | __mcip_cmd(CMD_GFRC_READ_CORE, 0); | ||
47 | gfrc_halt_mask = read_aux_reg(ARC_REG_MCIP_READBACK); | ||
48 | gfrc_halt_mask |= BIT(cpu); | ||
49 | __mcip_cmd_data(CMD_GFRC_SET_CORE, 0, gfrc_halt_mask); | ||
50 | |||
51 | raw_spin_unlock_irqrestore(&mcip_lock, flags); | ||
52 | } | ||
53 | |||
54 | static void mcip_update_debug_halt_mask(int cpu) | ||
55 | { | ||
56 | u32 mcip_mask = 0; | ||
57 | unsigned long flags; | ||
58 | |||
59 | raw_spin_lock_irqsave(&mcip_lock, flags); | ||
60 | |||
61 | /* | ||
62 | * mcip_mask is same for CMD_DEBUG_SET_SELECT and CMD_DEBUG_SET_MASK | ||
63 | * commands. So read it once instead of reading both CMD_DEBUG_READ_MASK | ||
64 | * and CMD_DEBUG_READ_SELECT. | ||
65 | */ | ||
66 | __mcip_cmd(CMD_DEBUG_READ_SELECT, 0); | ||
67 | mcip_mask = read_aux_reg(ARC_REG_MCIP_READBACK); | ||
68 | |||
69 | mcip_mask |= BIT(cpu); | ||
70 | |||
71 | __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, mcip_mask); | ||
72 | /* | ||
73 | * Parameter specified halt cause: | ||
74 | * STATUS32[H]/actionpoint/breakpoint/self-halt | ||
75 | * We choose all of them (0xF). | ||
76 | */ | ||
77 | __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xF, mcip_mask); | ||
78 | |||
79 | raw_spin_unlock_irqrestore(&mcip_lock, flags); | ||
80 | } | ||
81 | |||
25 | static void mcip_setup_per_cpu(int cpu) | 82 | static void mcip_setup_per_cpu(int cpu) |
26 | { | 83 | { |
84 | struct mcip_bcr mp; | ||
85 | |||
86 | READ_BCR(ARC_REG_MCIP_BCR, mp); | ||
87 | |||
27 | smp_ipi_irq_setup(cpu, IPI_IRQ); | 88 | smp_ipi_irq_setup(cpu, IPI_IRQ); |
28 | smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); | 89 | smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); |
90 | |||
91 | /* Update GFRC halt mask as new CPU came online */ | ||
92 | if (mp.gfrc) | ||
93 | mcip_update_gfrc_halt_mask(cpu); | ||
94 | |||
95 | /* Update MCIP debug mask as new CPU came online */ | ||
96 | if (mp.dbg) | ||
97 | mcip_update_debug_halt_mask(cpu); | ||
29 | } | 98 | } |
30 | 99 | ||
31 | static void mcip_ipi_send(int cpu) | 100 | static void mcip_ipi_send(int cpu) |
@@ -101,11 +170,6 @@ static void mcip_probe_n_setup(void) | |||
101 | IS_AVAIL1(mp.gfrc, "GFRC")); | 170 | IS_AVAIL1(mp.gfrc, "GFRC")); |
102 | 171 | ||
103 | cpuinfo_arc700[0].extn.gfrc = mp.gfrc; | 172 | cpuinfo_arc700[0].extn.gfrc = mp.gfrc; |
104 | |||
105 | if (mp.dbg) { | ||
106 | __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf); | ||
107 | __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf); | ||
108 | } | ||
109 | } | 173 | } |
110 | 174 | ||
111 | struct plat_smp_ops plat_smp_ops = { | 175 | struct plat_smp_ops plat_smp_ops = { |