1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * ARC ARConnect (MultiCore IP) support (formerly known as MCIP) 4 * 5 * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) 6 */ 7 8 #include <linux/smp.h> 9 #include <linux/irq.h> 10 #include <linux/irqchip/chained_irq.h> 11 #include <linux/spinlock.h> 12 #include <soc/arc/mcip.h> 13 #include <asm/irqflags-arcv2.h> 14 #include <asm/setup.h> 15 16 static DEFINE_RAW_SPINLOCK(mcip_lock); 17 18 #ifdef CONFIG_SMP 19 20 static char smp_cpuinfo_buf[128]; 21 22 /* 23 * Set mask to halt GFRC if any online core in SMP cluster is halted. 24 * Only works for ARC HS v3.0+, on earlier versions has no effect. 25 */ 26 static void mcip_update_gfrc_halt_mask(int cpu) 27 { 28 struct bcr_generic gfrc; 29 unsigned long flags; 30 u32 gfrc_halt_mask; 31 32 READ_BCR(ARC_REG_GFRC_BUILD, gfrc); 33 34 /* 35 * CMD_GFRC_SET_CORE and CMD_GFRC_READ_CORE commands were added in 36 * GFRC 0x3 version. 37 */ 38 if (gfrc.ver < 0x3) 39 return; 40 41 raw_spin_lock_irqsave(&mcip_lock, flags); 42 43 __mcip_cmd(CMD_GFRC_READ_CORE, 0); 44 gfrc_halt_mask = read_aux_reg(ARC_REG_MCIP_READBACK); 45 gfrc_halt_mask |= BIT(cpu); 46 __mcip_cmd_data(CMD_GFRC_SET_CORE, 0, gfrc_halt_mask); 47 48 raw_spin_unlock_irqrestore(&mcip_lock, flags); 49 } 50 51 static void mcip_update_debug_halt_mask(int cpu) 52 { 53 u32 mcip_mask = 0; 54 unsigned long flags; 55 56 raw_spin_lock_irqsave(&mcip_lock, flags); 57 58 /* 59 * mcip_mask is same for CMD_DEBUG_SET_SELECT and CMD_DEBUG_SET_MASK 60 * commands. So read it once instead of reading both CMD_DEBUG_READ_MASK 61 * and CMD_DEBUG_READ_SELECT. 62 */ 63 __mcip_cmd(CMD_DEBUG_READ_SELECT, 0); 64 mcip_mask = read_aux_reg(ARC_REG_MCIP_READBACK); 65 66 mcip_mask |= BIT(cpu); 67 68 __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, mcip_mask); 69 /* 70 * Parameter specified halt cause: 71 * STATUS32[H]/actionpoint/breakpoint/self-halt 72 * We choose all of them (0xF). 73 */ 74 __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xF, mcip_mask); 75 76 raw_spin_unlock_irqrestore(&mcip_lock, flags); 77 } 78 79 static void mcip_setup_per_cpu(int cpu) 80 { 81 struct mcip_bcr mp; 82 83 READ_BCR(ARC_REG_MCIP_BCR, mp); 84 85 smp_ipi_irq_setup(cpu, IPI_IRQ); 86 smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); 87 88 /* Update GFRC halt mask as new CPU came online */ 89 if (mp.gfrc) 90 mcip_update_gfrc_halt_mask(cpu); 91 92 /* Update MCIP debug mask as new CPU came online */ 93 if (mp.dbg) 94 mcip_update_debug_halt_mask(cpu); 95 } 96 97 static void mcip_ipi_send(int cpu) 98 { 99 unsigned long flags; 100 int ipi_was_pending; 101 102 /* ARConnect can only send IPI to others */ 103 if (unlikely(cpu == raw_smp_processor_id())) { 104 arc_softirq_trigger(SOFTIRQ_IRQ); 105 return; 106 } 107 108 raw_spin_lock_irqsave(&mcip_lock, flags); 109 110 /* 111 * If receiver already has a pending interrupt, elide sending this one. 112 * Linux cross core calling works well with concurrent IPIs 113 * coalesced into one 114 * see arch/arc/kernel/smp.c: ipi_send_msg_one() 115 */ 116 __mcip_cmd(CMD_INTRPT_READ_STATUS, cpu); 117 ipi_was_pending = read_aux_reg(ARC_REG_MCIP_READBACK); 118 if (!ipi_was_pending) 119 __mcip_cmd(CMD_INTRPT_GENERATE_IRQ, cpu); 120 121 raw_spin_unlock_irqrestore(&mcip_lock, flags); 122 } 123 124 static void mcip_ipi_clear(int irq) 125 { 126 unsigned int cpu, c; 127 unsigned long flags; 128 129 if (unlikely(irq == SOFTIRQ_IRQ)) { 130 arc_softirq_clear(irq); 131 return; 132 } 133 134 raw_spin_lock_irqsave(&mcip_lock, flags); 135 136 /* Who sent the IPI */ 137 __mcip_cmd(CMD_INTRPT_CHECK_SOURCE, 0); 138 139 cpu = read_aux_reg(ARC_REG_MCIP_READBACK); /* 1,2,4,8... */ 140 141 /* 142 * In rare case, multiple concurrent IPIs sent to same target can 143 * possibly be coalesced by MCIP into 1 asserted IRQ, so @cpus can be 144 * "vectored" (multiple bits sets) as opposed to typical single bit 145 */ 146 do { 147 c = __ffs(cpu); /* 0,1,2,3 */ 148 __mcip_cmd(CMD_INTRPT_GENERATE_ACK, c); 149 cpu &= ~(1U << c); 150 } while (cpu); 151 152 raw_spin_unlock_irqrestore(&mcip_lock, flags); 153 } 154 155 static void mcip_probe_n_setup(void) 156 { 157 struct mcip_bcr mp; 158 159 READ_BCR(ARC_REG_MCIP_BCR, mp); 160 161 sprintf(smp_cpuinfo_buf, 162 "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n", 163 mp.ver, mp.num_cores, 164 IS_AVAIL1(mp.ipi, "IPI "), 165 IS_AVAIL1(mp.idu, "IDU "), 166 IS_AVAIL1(mp.dbg, "DEBUG "), 167 IS_AVAIL1(mp.gfrc, "GFRC")); 168 169 cpuinfo_arc700[0].extn.gfrc = mp.gfrc; 170 } 171 172 struct plat_smp_ops plat_smp_ops = { 173 .info = smp_cpuinfo_buf, 174 .init_early_smp = mcip_probe_n_setup, 175 .init_per_cpu = mcip_setup_per_cpu, 176 .ipi_send = mcip_ipi_send, 177 .ipi_clear = mcip_ipi_clear, 178 }; 179 180 #endif 181 182 /*************************************************************************** 183 * ARCv2 Interrupt Distribution Unit (IDU) 184 * 185 * Connects external "COMMON" IRQs to core intc, providing: 186 * -dynamic routing (IRQ affinity) 187 * -load balancing (Round Robin interrupt distribution) 188 * -1:N distribution 189 * 190 * It physically resides in the MCIP hw block 191 */ 192 193 #include <linux/irqchip.h> 194 #include <linux/of.h> 195 #include <linux/of_irq.h> 196 197 /* 198 * Set the DEST for @cmn_irq to @cpu_mask (1 bit per core) 199 */ 200 static void idu_set_dest(unsigned int cmn_irq, unsigned int cpu_mask) 201 { 202 __mcip_cmd_data(CMD_IDU_SET_DEST, cmn_irq, cpu_mask); 203 } 204 205 static void idu_set_mode(unsigned int cmn_irq, unsigned int lvl, 206 unsigned int distr) 207 { 208 union { 209 unsigned int word; 210 struct { 211 unsigned int distr:2, pad:2, lvl:1, pad2:27; 212 }; 213 } data; 214 215 data.distr = distr; 216 data.lvl = lvl; 217 __mcip_cmd_data(CMD_IDU_SET_MODE, cmn_irq, data.word); 218 } 219 220 static void idu_irq_mask_raw(irq_hw_number_t hwirq) 221 { 222 unsigned long flags; 223 224 raw_spin_lock_irqsave(&mcip_lock, flags); 225 __mcip_cmd_data(CMD_IDU_SET_MASK, hwirq, 1); 226 raw_spin_unlock_irqrestore(&mcip_lock, flags); 227 } 228 229 static void idu_irq_mask(struct irq_data *data) 230 { 231 idu_irq_mask_raw(data->hwirq); 232 } 233 234 static void idu_irq_unmask(struct irq_data *data) 235 { 236 unsigned long flags; 237 238 raw_spin_lock_irqsave(&mcip_lock, flags); 239 __mcip_cmd_data(CMD_IDU_SET_MASK, data->hwirq, 0); 240 raw_spin_unlock_irqrestore(&mcip_lock, flags); 241 } 242 243 static int 244 idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, 245 bool force) 246 { 247 unsigned long flags; 248 cpumask_t online; 249 unsigned int destination_bits; 250 unsigned int distribution_mode; 251 252 /* errout if no online cpu per @cpumask */ 253 if (!cpumask_and(&online, cpumask, cpu_online_mask)) 254 return -EINVAL; 255 256 raw_spin_lock_irqsave(&mcip_lock, flags); 257 258 destination_bits = cpumask_bits(&online)[0]; 259 idu_set_dest(data->hwirq, destination_bits); 260 261 if (ffs(destination_bits) == fls(destination_bits)) 262 distribution_mode = IDU_M_DISTRI_DEST; 263 else 264 distribution_mode = IDU_M_DISTRI_RR; 265 266 idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, distribution_mode); 267 268 raw_spin_unlock_irqrestore(&mcip_lock, flags); 269 270 return IRQ_SET_MASK_OK; 271 } 272 273 static void idu_irq_enable(struct irq_data *data) 274 { 275 /* 276 * By default send all common interrupts to all available online CPUs. 277 * The affinity of common interrupts in IDU must be set manually since 278 * in some cases the kernel will not call irq_set_affinity() by itself: 279 * 1. When the kernel is not configured with support of SMP. 280 * 2. When the kernel is configured with support of SMP but upper 281 * interrupt controllers does not support setting of the affinity 282 * and cannot propagate it to IDU. 283 */ 284 idu_irq_set_affinity(data, cpu_online_mask, false); 285 idu_irq_unmask(data); 286 } 287 288 static struct irq_chip idu_irq_chip = { 289 .name = "MCIP IDU Intc", 290 .irq_mask = idu_irq_mask, 291 .irq_unmask = idu_irq_unmask, 292 .irq_enable = idu_irq_enable, 293 #ifdef CONFIG_SMP 294 .irq_set_affinity = idu_irq_set_affinity, 295 #endif 296 297 }; 298 299 static void idu_cascade_isr(struct irq_desc *desc) 300 { 301 struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); 302 struct irq_chip *core_chip = irq_desc_get_chip(desc); 303 irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); 304 irq_hw_number_t idu_hwirq = core_hwirq - FIRST_EXT_IRQ; 305 306 chained_irq_enter(core_chip, desc); 307 generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); 308 chained_irq_exit(core_chip, desc); 309 } 310 311 static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) 312 { 313 irq_set_chip_and_handler(virq, &idu_irq_chip, handle_level_irq); 314 irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); 315 316 return 0; 317 } 318 319 static const struct irq_domain_ops idu_irq_ops = { 320 .xlate = irq_domain_xlate_onecell, 321 .map = idu_irq_map, 322 }; 323 324 /* 325 * [16, 23]: Statically assigned always private-per-core (Timers, WDT, IPI) 326 * [24, 23+C]: If C > 0 then "C" common IRQs 327 * [24+C, N]: Not statically assigned, private-per-core 328 */ 329 330 331 static int __init 332 idu_of_init(struct device_node *intc, struct device_node *parent) 333 { 334 struct irq_domain *domain; 335 int nr_irqs; 336 int i, virq; 337 struct mcip_bcr mp; 338 struct mcip_idu_bcr idu_bcr; 339 340 READ_BCR(ARC_REG_MCIP_BCR, mp); 341 342 if (!mp.idu) 343 panic("IDU not detected, but DeviceTree using it"); 344 345 READ_BCR(ARC_REG_MCIP_IDU_BCR, idu_bcr); 346 nr_irqs = mcip_idu_bcr_to_nr_irqs(idu_bcr); 347 348 pr_info("MCIP: IDU supports %u common irqs\n", nr_irqs); 349 350 domain = irq_domain_add_linear(intc, nr_irqs, &idu_irq_ops, NULL); 351 352 /* Parent interrupts (core-intc) are already mapped */ 353 354 for (i = 0; i < nr_irqs; i++) { 355 /* Mask all common interrupts by default */ 356 idu_irq_mask_raw(i); 357 358 /* 359 * Return parent uplink IRQs (towards core intc) 24,25,..... 360 * this step has been done before already 361 * however we need it to get the parent virq and set IDU handler 362 * as first level isr 363 */ 364 virq = irq_create_mapping(NULL, i + FIRST_EXT_IRQ); 365 BUG_ON(!virq); 366 irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain); 367 } 368 369 __mcip_cmd(CMD_IDU_ENABLE, 0); 370 371 return 0; 372 } 373 IRQCHIP_DECLARE(arcv2_idu_intc, "snps,archs-idu-intc", idu_of_init); 374