1 /* 2 * ARC ARConnect (MultiCore IP) support (formerly known as MCIP) 3 * 4 * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11 #include <linux/smp.h> 12 #include <linux/irq.h> 13 #include <linux/spinlock.h> 14 #include <asm/mcip.h> 15 16 static char smp_cpuinfo_buf[128]; 17 18 static DEFINE_RAW_SPINLOCK(mcip_lock); 19 20 21 /* 22 * Any SMP specific init any CPU does when it comes up. 23 * Here we setup the CPU to enable Inter-Processor-Interrupts 24 * Called for each CPU 25 * -Master : init_IRQ() 26 * -Other(s) : start_kernel_secondary() 27 */ 28 void mcip_init_smp(unsigned int cpu) 29 { 30 smp_ipi_irq_setup(cpu, IPI_IRQ); 31 } 32 33 static void mcip_ipi_send(int cpu) 34 { 35 unsigned long flags; 36 37 raw_spin_lock_irqsave(&mcip_lock, flags); 38 __mcip_cmd(CMD_INTRPT_GENERATE_IRQ, cpu); 39 raw_spin_unlock_irqrestore(&mcip_lock, flags); 40 } 41 42 static void mcip_ipi_clear(int irq) 43 { 44 unsigned int cpu; 45 unsigned long flags; 46 47 raw_spin_lock_irqsave(&mcip_lock, flags); 48 49 /* Who sent the IPI */ 50 __mcip_cmd(CMD_INTRPT_CHECK_SOURCE, 0); 51 52 cpu = read_aux_reg(ARC_REG_MCIP_READBACK); /* 1,2,4,8... */ 53 54 __mcip_cmd(CMD_INTRPT_GENERATE_ACK, __ffs(cpu)); /* 0,1,2,3... */ 55 56 raw_spin_unlock_irqrestore(&mcip_lock, flags); 57 } 58 59 volatile int wake_flag; 60 61 static void mcip_wakeup_cpu(int cpu, unsigned long pc) 62 { 63 BUG_ON(cpu == 0); 64 wake_flag = cpu; 65 } 66 67 void arc_platform_smp_wait_to_boot(int cpu) 68 { 69 while (wake_flag != cpu) 70 ; 71 72 wake_flag = 0; 73 __asm__ __volatile__("j @first_lines_of_secondary \n"); 74 } 75 76 struct plat_smp_ops plat_smp_ops = { 77 .info = smp_cpuinfo_buf, 78 .cpu_kick = mcip_wakeup_cpu, 79 .ipi_send = mcip_ipi_send, 80 .ipi_clear = mcip_ipi_clear, 81 }; 82 83 void mcip_init_early_smp(void) 84 { 85 #define IS_AVAIL1(var, str) ((var) ? str : "") 86 87 struct mcip_bcr { 88 #ifdef CONFIG_CPU_BIG_ENDIAN 89 unsigned int pad3:8, 90 idu:1, llm:1, num_cores:6, 91 iocoh:1, grtc:1, dbg:1, pad2:1, 92 msg:1, sem:1, ipi:1, pad:1, 93 ver:8; 94 #else 95 unsigned int ver:8, 96 pad:1, ipi:1, sem:1, msg:1, 97 pad2:1, dbg:1, grtc:1, iocoh:1, 98 num_cores:6, llm:1, idu:1, 99 pad3:8; 100 #endif 101 } mp; 102 103 READ_BCR(ARC_REG_MCIP_BCR, mp); 104 105 sprintf(smp_cpuinfo_buf, 106 "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n", 107 mp.ver, mp.num_cores, 108 IS_AVAIL1(mp.ipi, "IPI "), 109 IS_AVAIL1(mp.idu, "IDU "), 110 IS_AVAIL1(mp.dbg, "DEBUG "), 111 IS_AVAIL1(mp.grtc, "GRTC")); 112 113 if (mp.dbg) { 114 __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf); 115 __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf); 116 } 117 } 118