ARCv2: SMP: ARConnect debug/robustness
- Handle possible interrupt coalescing from MCIP - chk if prev IPI ack before sending new Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
This commit is contained in:
parent
82fea5a1bb
commit
aa6083ed50
|
@ -448,9 +448,10 @@ menuconfig ARC_DBG
|
|||
bool "ARC debugging"
|
||||
default y
|
||||
|
||||
if ARC_DBG
|
||||
|
||||
config ARC_DW2_UNWIND
|
||||
bool "Enable DWARF specific kernel stack unwind"
|
||||
depends on ARC_DBG
|
||||
default y
|
||||
select KALLSYMS
|
||||
help
|
||||
|
@ -464,18 +465,26 @@ config ARC_DW2_UNWIND
|
|||
|
||||
config ARC_DBG_TLB_PARANOIA
|
||||
bool "Paranoia Checks in Low Level TLB Handlers"
|
||||
depends on ARC_DBG
|
||||
default n
|
||||
|
||||
config ARC_DBG_TLB_MISS_COUNT
|
||||
bool "Profile TLB Misses"
|
||||
default n
|
||||
select DEBUG_FS
|
||||
depends on ARC_DBG
|
||||
help
|
||||
Counts number of I and D TLB Misses and exports them via Debugfs
|
||||
The counters can be cleared via Debugfs as well
|
||||
|
||||
if SMP
|
||||
|
||||
config ARC_IPI_DBG
|
||||
bool "Debug Inter Core interrupts"
|
||||
default n
|
||||
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
config ARC_UBOOT_SUPPORT
|
||||
bool "Support uboot arg Handling"
|
||||
default n
|
||||
|
|
|
@ -33,27 +33,67 @@ void mcip_init_smp(unsigned int cpu)
|
|||
static void mcip_ipi_send(int cpu)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ipi_was_pending;
|
||||
|
||||
/*
|
||||
* NOTE: We must spin here if the other cpu hasn't yet
|
||||
* serviced a previous message. This can burn lots
|
||||
* of time, but we MUST follows this protocol or
|
||||
* ipi messages can be lost!!!
|
||||
* Also, we must release the lock in this loop because
|
||||
* the other side may get to this same loop and not
|
||||
* be able to ack -- thus causing deadlock.
|
||||
*/
|
||||
|
||||
do {
|
||||
raw_spin_lock_irqsave(&mcip_lock, flags);
|
||||
__mcip_cmd(CMD_INTRPT_READ_STATUS, cpu);
|
||||
ipi_was_pending = read_aux_reg(ARC_REG_MCIP_READBACK);
|
||||
if (ipi_was_pending == 0)
|
||||
break; /* break out but keep lock */
|
||||
raw_spin_unlock_irqrestore(&mcip_lock, flags);
|
||||
} while (1);
|
||||
|
||||
raw_spin_lock_irqsave(&mcip_lock, flags);
|
||||
__mcip_cmd(CMD_INTRPT_GENERATE_IRQ, cpu);
|
||||
raw_spin_unlock_irqrestore(&mcip_lock, flags);
|
||||
|
||||
#ifdef CONFIG_ARC_IPI_DBG
|
||||
if (ipi_was_pending)
|
||||
pr_info("IPI ACK delayed from cpu %d\n", cpu);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mcip_ipi_clear(int irq)
|
||||
{
|
||||
unsigned int cpu;
|
||||
unsigned int cpu, c;
|
||||
unsigned long flags;
|
||||
unsigned int __maybe_unused copy;
|
||||
|
||||
raw_spin_lock_irqsave(&mcip_lock, flags);
|
||||
|
||||
/* Who sent the IPI */
|
||||
__mcip_cmd(CMD_INTRPT_CHECK_SOURCE, 0);
|
||||
|
||||
cpu = read_aux_reg(ARC_REG_MCIP_READBACK); /* 1,2,4,8... */
|
||||
copy = cpu = read_aux_reg(ARC_REG_MCIP_READBACK); /* 1,2,4,8... */
|
||||
|
||||
__mcip_cmd(CMD_INTRPT_GENERATE_ACK, __ffs(cpu)); /* 0,1,2,3... */
|
||||
/*
|
||||
* In rare case, multiple concurrent IPIs sent to same target can
|
||||
* possibly be coalesced by MCIP into 1 asserted IRQ, so @cpus can be
|
||||
* "vectored" (multiple bits sets) as opposed to typical single bit
|
||||
*/
|
||||
do {
|
||||
c = __ffs(cpu); /* 0,1,2,3 */
|
||||
__mcip_cmd(CMD_INTRPT_GENERATE_ACK, c);
|
||||
cpu &= ~(1U << c);
|
||||
} while (cpu);
|
||||
|
||||
raw_spin_unlock_irqrestore(&mcip_lock, flags);
|
||||
|
||||
#ifdef CONFIG_ARC_IPI_DBG
|
||||
if (c != __ffs(copy))
|
||||
pr_info("IPIs from %x coalesced to %x\n",
|
||||
copy, raw_smp_processor_id());
|
||||
#endif
|
||||
}
|
||||
|
||||
volatile int wake_flag;
|
||||
|
|
|
@ -278,8 +278,10 @@ static void ipi_cpu_stop(void)
|
|||
machine_halt();
|
||||
}
|
||||
|
||||
static inline void __do_IPI(unsigned long msg)
|
||||
static inline int __do_IPI(unsigned long msg)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
switch (msg) {
|
||||
case IPI_RESCHEDULE:
|
||||
scheduler_ipi();
|
||||
|
@ -294,8 +296,10 @@ static inline void __do_IPI(unsigned long msg)
|
|||
break;
|
||||
|
||||
default:
|
||||
pr_warn("IPI with unexpected msg %ld\n", msg);
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -305,6 +309,7 @@ static inline void __do_IPI(unsigned long msg)
|
|||
irqreturn_t do_IPI(int irq, void *dev_id)
|
||||
{
|
||||
unsigned long pending;
|
||||
unsigned long __maybe_unused copy;
|
||||
|
||||
pr_debug("IPI [%ld] received on cpu %d\n",
|
||||
*this_cpu_ptr(&ipi_data), smp_processor_id());
|
||||
|
@ -316,11 +321,18 @@ irqreturn_t do_IPI(int irq, void *dev_id)
|
|||
* "dequeue" the msg corresponding to this IPI (and possibly other
|
||||
* piggybacked msg from elided IPIs: see ipi_send_msg_one() above)
|
||||
*/
|
||||
pending = xchg(this_cpu_ptr(&ipi_data), 0);
|
||||
copy = pending = xchg(this_cpu_ptr(&ipi_data), 0);
|
||||
|
||||
do {
|
||||
unsigned long msg = __ffs(pending);
|
||||
__do_IPI(msg);
|
||||
int rc;
|
||||
|
||||
rc = __do_IPI(msg);
|
||||
#ifdef CONFIG_ARC_IPI_DBG
|
||||
/* IPI received but no valid @msg */
|
||||
if (rc)
|
||||
pr_info("IPI with bogus msg %ld in %ld\n", msg, copy);
|
||||
#endif
|
||||
pending &= ~(1U << msg);
|
||||
} while (pending);
|
||||
|
||||
|
|
Loading…
Reference in New Issue