>From 65f5703b9a7634bea440ebfea908120aaa6b35de Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 15 Oct 2018 12:26:42 +0200 Subject: [PATCH] PEOI debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrew Cooper [power state tracing] Signed-off-by: Roger Pau Monné --- xen/arch/x86/acpi/cpu_idle.c | 4 + xen/arch/x86/cpu/mwait-idle.c | 2 + xen/arch/x86/irq.c | 182 +++++++++++++++++++++++++++++++++- xen/include/asm-x86/apic.h | 14 +++ xen/include/asm-x86/irq.h | 44 ++++++++ 5 files changed, 244 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c index 14b02789c5..08e3ffd996 100644 --- a/xen/arch/x86/acpi/cpu_idle.c +++ b/xen/arch/x86/acpi/cpu_idle.c @@ -420,6 +420,8 @@ void mwait_idle_with_hints(unsigned int eax, unsigned int ecx) { struct cpu_info *info = get_cpu_info(); + peoi_debug_apic(PEOI_IDLE); + cpumask_set_cpu(cpu, &cpuidle_mwait_flags); spec_ctrl_enter_idle(info); @@ -427,6 +429,8 @@ void mwait_idle_with_hints(unsigned int eax, unsigned int ecx) spec_ctrl_exit_idle(info); cpumask_clear_cpu(cpu, &cpuidle_mwait_flags); + + peoi_debug_apic(PEOI_WAKE); } if ( expires <= NOW() && expires > 0 ) diff --git a/xen/arch/x86/cpu/mwait-idle.c b/xen/arch/x86/cpu/mwait-idle.c index 77fc3ddacc..8ccbdc97ae 100644 --- a/xen/arch/x86/cpu/mwait-idle.c +++ b/xen/arch/x86/cpu/mwait-idle.c @@ -781,6 +781,8 @@ static void mwait_idle(void) before = cpuidle_get_tick(); TRACE_4D(TRC_PM_IDLE_ENTRY, cx->type, before, exp, pred); + peoi_debug_power(PEOI_POWER, cx->type); + update_last_cx_stat(power, cx, before); if (cpu_is_haltable(cpu)) diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 35e7de594f..5f12f2497c 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -1148,6 +1148,161 @@ static void irq_guest_eoi_timer_fn(void *data) spin_unlock_irqrestore(&desc->lock, flags); } +DEFINE_PER_CPU(struct peoi_dbg_record, peoi_dbg[NR_PEOI_RECORDS]); +DEFINE_PER_CPU(unsigned int, peoi_dbg_idx); + +void peoi_debug_stack(enum peoi_dbg_type action, unsigned int sp, + unsigned int irq, unsigned int vector) +{ + unsigned int *idx = &this_cpu(peoi_dbg_idx); + struct peoi_dbg_record *rec = + &this_cpu(peoi_dbg)[*idx & (NR_PEOI_RECORDS - 1)]; + struct peoi_dbg_stack *stack = &rec->stack; + + rec->seq = *idx; + rec->action = action; + + stack->sp = sp; + stack->irq = irq; + stack->vector = vector; + + (*idx)++; +} + +void peoi_debug_apic(enum peoi_dbg_type action) +{ + unsigned int i, *idx = &this_cpu(peoi_dbg_idx); + struct peoi_dbg_record *rec = + &this_cpu(peoi_dbg)[*idx & (NR_PEOI_RECORDS - 1)]; + struct peoi_dbg_apic *apic = &rec->apic; + uint32_t *irr = _p(apic->irr); + uint32_t *isr = _p(apic->isr); + + rec->seq = *idx; + rec->action = action; + + for ( i = 0; i < APIC_ISR_NR; i++ ) + { + irr[i] = apic_read(APIC_IRR + i * 0x10); + isr[i] = apic_read(APIC_ISR + i * 0x10); + } + + apic->ppr = apic_read(APIC_PROCPRI); + + (*idx)++; +} + +void peoi_debug_power(enum peoi_dbg_type action, unsigned int state) +{ + unsigned int *idx = &this_cpu(peoi_dbg_idx); + struct peoi_dbg_record *rec = + &this_cpu(peoi_dbg)[*idx & (NR_PEOI_RECORDS - 1)]; + struct peoi_dbg_power *power = &rec->power; + + rec->seq = *idx; + rec->action = action; + + power->state = state; + + (*idx)++; +} + +static void dump_peoi_record(const struct peoi_dbg_record *r) +{ + const struct peoi_dbg_stack *s = &r->stack; + const struct peoi_dbg_apic *a = &r->apic; + const struct peoi_dbg_power *p = &r->power; + + switch ( r->action ) + { + case PEOI_PUSH: + printk(" [%5u] PUSH {sp %2d, irq %3d, vec 0x%02x}\n", + r->seq, s->sp, s->irq, s->vector); + break; + + case PEOI_SETREADY: + printk(" [%5u] READY {sp %2d, irq %3d, vec 0x%02x}\n", + r->seq, s->sp, s->irq, s->vector); + break; + + case PEOI_FLUSH: + printk(" [%5u] FLUSH %d -> 0\n", r->seq, s->sp); + break; + + case PEOI_POP: + printk(" [%5u] POP {sp %2d, irq %3d, vec 0x%02x}\n", + r->seq, s->sp, s->irq, s->vector); + break; + + case PEOI_IDLE: + printk(" [%5u] IDLE PPR 0x%08x\n", r->seq, a->ppr); + + dump_apic_bitmaps: + printk(" IRR %*phN\n" + " ISR %*phN\n", + (int)sizeof(a->irr), a->irr, (int)sizeof(a->isr), a->isr); + break; + + case PEOI_WAKE: + printk(" [%5u] WAKE PPR 0x%08x\n", r->seq, a->ppr); + goto dump_apic_bitmaps; + + case PEOI_ACK_PRE: + printk(" [%5u] ACK_PRE PPR 0x%08x\n", r->seq, a->ppr); + goto dump_apic_bitmaps; + + case PEOI_ACK_POST: + printk(" [%5u] ACK_POST PPR 0x%08x\n", r->seq, a->ppr); + goto dump_apic_bitmaps; + + case PEOI_POWER: + printk(" [%5u] POWER TYPE %u\n", r->seq, p->state); + break; + + default: + printk(" [%5u] ??? %d\n", r->seq, r->action); + break; + } +} + +static void dump_peoi_records(void) +{ + unsigned int i, idx = this_cpu(peoi_dbg_idx); + struct peoi_dbg_record *rec = this_cpu(peoi_dbg); + + printk("Peoi stack trace records:\n"); + for ( i = 0; i < NR_PEOI_RECORDS; ++i ) + dump_peoi_record(&rec[(idx + i) & (NR_PEOI_RECORDS - 1)]); +} + +static void dump_lapic(void) +{ + unsigned int i; + + printk("All LAPIC state:\n"); + printk(" [vector] %8s %8s %8s\n", "ISR", "TMR", "IRR"); + for ( i = 0; i < APIC_ISR_NR; ++i ) + printk(" [%02x:%02x] %08"PRIx32" %08"PRIx32" %08"PRIx32"\n", + (i * 32) + 31, i * 32, + apic_read(APIC_ISR + i * 0x10), + apic_read(APIC_TMR + i * 0x10), + apic_read(APIC_IRR + i * 0x10)); +} + +static void dump_peoi_stack(int sp) +{ + struct pending_eoi *peoi = this_cpu(pending_eoi); + int i; + + printk("Peoi stack: sp %d\n", sp); + for ( i = sp - 1; i >= 0; --i ) + printk(" [%2d] irq %3d, vec 0x%02x, ready %u, ISR %u, TMR %u, IRR %u\n", + i, peoi[i].irq, peoi[i].vector, peoi[i].ready, + apic_isr_read(peoi[i].vector), + apic_tmr_read(peoi[i].vector), + apic_irr_read(peoi[i].vector)); +} + static void __do_IRQ_guest(int irq) { struct irq_desc *desc = irq_to_desc(irq); @@ -1170,13 +1325,29 @@ static void __do_IRQ_guest(int irq) if ( action->ack_type == ACKTYPE_EOI ) { sp = pending_eoi_sp(peoi); - ASSERT((sp == 0) || (peoi[sp-1].vector < vector)); + if ( !((sp == 0) || (peoi[sp-1].vector < vector)) ) + { + printk("*** Pending EOI error ***\n"); + printk(" cpu #%u, irq %d, vector 0x%x, sp %d\n", + smp_processor_id(), irq, vector, sp); + + dump_peoi_stack(sp); + dump_peoi_records(); + dump_lapic(); + + spin_unlock(&desc->lock); + + assert_failed("(sp == 0) || (peoi[sp-1].vector < vector)"); + } + ASSERT(sp < (NR_DYNAMIC_VECTORS-1)); peoi[sp].irq = irq; peoi[sp].vector = vector; peoi[sp].ready = 0; pending_eoi_sp(peoi) = sp+1; cpumask_set_cpu(smp_processor_id(), action->cpu_eoi_map); + + peoi_debug_stack(PEOI_PUSH, sp, irq, peoi[sp].vector); } for ( i = 0; i < action->nr_guests; i++ ) @@ -1383,6 +1554,8 @@ static void flush_ready_eoi(void) if ( desc->handler->end ) desc->handler->end(desc, peoi[sp].vector); spin_unlock(&desc->lock); + + peoi_debug_stack(PEOI_POP, sp + 1, irq, peoi[sp].vector); } pending_eoi_sp(peoi) = sp+1; @@ -1409,6 +1582,8 @@ static void __set_eoi_ready(struct irq_desc *desc) } while ( peoi[--sp].irq != irq ); ASSERT(!peoi[sp].ready); peoi[sp].ready = 1; + + peoi_debug_stack(PEOI_SETREADY, sp + 1, irq, desc->arch.vector); } /* Mark specified IRQ as ready-for-EOI (if it really is) and attempt to EOI. */ @@ -2276,7 +2451,7 @@ void free_domain_pirqs(struct domain *d) pcidevs_unlock(); } -static void dump_irqs(unsigned char key) +void dump_irqs(unsigned char key) { int i, irq, pirq; struct irq_desc *desc; @@ -2448,6 +2623,9 @@ void fixup_eoi(void) /* Flush the interrupt EOI stack. */ peoi = this_cpu(pending_eoi); + + peoi_debug_stack(PEOI_FLUSH, pending_eoi_sp(peoi), -1, -1); + for ( sp = 0; sp < pending_eoi_sp(peoi); sp++ ) peoi[sp].ready = 1; flush_ready_eoi(); diff --git a/xen/include/asm-x86/apic.h b/xen/include/asm-x86/apic.h index 9d7ec93042..77a60f8ac1 100644 --- a/xen/include/asm-x86/apic.h +++ b/xen/include/asm-x86/apic.h @@ -149,6 +149,16 @@ static __inline bool_t apic_isr_read(u8 vector) (vector & 0x1f)) & 1; } +static inline bool apic_tmr_read(u8 vector) +{ + return apic_read(APIC_TMR + ((vector & ~0x1f) >> 1)) >> (vector & 0x1f); +} + +static inline bool apic_irr_read(u8 vector) +{ + return apic_read(APIC_IRR + ((vector & ~0x1f) >> 1)) >> (vector & 0x1f); +} + static __inline u32 get_apic_id(void) /* Get the physical APIC id */ { u32 id = apic_read(APIC_ID); @@ -161,8 +171,12 @@ int get_physical_broadcast(void); static inline void ack_APIC_irq(void) { + peoi_debug_apic(PEOI_ACK_PRE); + /* Docs say use 0 for future compatibility */ apic_write(APIC_EOI, 0); + + peoi_debug_apic(PEOI_ACK_POST); } extern int get_maxlvt(void); diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h index 4b39997f09..938e5ef6b5 100644 --- a/xen/include/asm-x86/irq.h +++ b/xen/include/asm-x86/irq.h @@ -27,6 +27,50 @@ typedef struct { DECLARE_BITMAP(_bits,NR_VECTORS); } vmask_t; +struct peoi_dbg_record +{ + unsigned int seq; + + enum peoi_dbg_type { + PEOI_PUSH, + PEOI_SETREADY, + PEOI_FLUSH, + PEOI_POP, + + PEOI_IDLE, + PEOI_WAKE, + PEOI_ACK_PRE, + PEOI_ACK_POST, + + PEOI_POWER, + } action; + + union { + struct peoi_dbg_stack { + unsigned int sp, irq, vector; + } stack; + + struct peoi_dbg_apic { + DECLARE_BITMAP(irr, NR_VECTORS); + DECLARE_BITMAP(isr, NR_VECTORS); + unsigned int ppr; + } apic; + + struct peoi_dbg_power { + unsigned int state; + } power; + }; +}; + +#define NR_PEOI_RECORDS 32 +DECLARE_PER_CPU(struct peoi_dbg_record, peoi_dbg[NR_PEOI_RECORDS]); +DECLARE_PER_CPU(unsigned int, peoi_dbg_idx); + +void peoi_debug_stack(enum peoi_dbg_type action, unsigned int sp, + unsigned int irq, unsigned int vector); +void peoi_debug_apic(enum peoi_dbg_type action); +void peoi_debug_power(enum peoi_dbg_type action, unsigned int state); + struct irq_desc; struct arch_irq_desc { -- 2.19.1