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);  static char smp_cpuinfo_buf[128]; +/* + * Set mask to halt GFRC if any online core in SMP cluster is halted. + * Only works for ARC HS v3.0+, on earlier versions has no effect. + */ +static void mcip_update_gfrc_halt_mask(int cpu) +{ +	struct bcr_generic gfrc; +	unsigned long flags; +	u32 gfrc_halt_mask; + +	READ_BCR(ARC_REG_GFRC_BUILD, gfrc); + +	/* +	 * CMD_GFRC_SET_CORE and CMD_GFRC_READ_CORE commands were added in +	 * GFRC 0x3 version. +	 */ +	if (gfrc.ver < 0x3) +		return; + +	raw_spin_lock_irqsave(&mcip_lock, flags); + +	__mcip_cmd(CMD_GFRC_READ_CORE, 0); +	gfrc_halt_mask = read_aux_reg(ARC_REG_MCIP_READBACK); +	gfrc_halt_mask |= BIT(cpu); +	__mcip_cmd_data(CMD_GFRC_SET_CORE, 0, gfrc_halt_mask); + +	raw_spin_unlock_irqrestore(&mcip_lock, flags); +} + +static void mcip_update_debug_halt_mask(int cpu) +{ +	u32 mcip_mask = 0; +	unsigned long flags; + +	raw_spin_lock_irqsave(&mcip_lock, flags); + +	/* +	 * mcip_mask is same for CMD_DEBUG_SET_SELECT and CMD_DEBUG_SET_MASK +	 * commands. So read it once instead of reading both CMD_DEBUG_READ_MASK +	 * and CMD_DEBUG_READ_SELECT. +	 */ +	__mcip_cmd(CMD_DEBUG_READ_SELECT, 0); +	mcip_mask = read_aux_reg(ARC_REG_MCIP_READBACK); + +	mcip_mask |= BIT(cpu); + +	__mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, mcip_mask); +	/* +	 * Parameter specified halt cause: +	 * STATUS32[H]/actionpoint/breakpoint/self-halt +	 * We choose all of them (0xF). +	 */ +	__mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xF, mcip_mask); + +	raw_spin_unlock_irqrestore(&mcip_lock, flags); +} +  static void mcip_setup_per_cpu(int cpu)  { +	struct mcip_bcr mp; + +	READ_BCR(ARC_REG_MCIP_BCR, mp); +  	smp_ipi_irq_setup(cpu, IPI_IRQ);  	smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); + +	/* Update GFRC halt mask as new CPU came online */ +	if (mp.gfrc) +		mcip_update_gfrc_halt_mask(cpu); + +	/* Update MCIP debug mask as new CPU came online */ +	if (mp.dbg) +		mcip_update_debug_halt_mask(cpu);  }  static void mcip_ipi_send(int cpu) @@ -101,11 +170,6 @@ static void mcip_probe_n_setup(void)  		IS_AVAIL1(mp.gfrc, "GFRC"));  	cpuinfo_arc700[0].extn.gfrc = mp.gfrc; - -	if (mp.dbg) { -		__mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf); -		__mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf); -	}  }  struct plat_smp_ops plat_smp_ops = { |