On Tue, Nov 18, 2014 at 05:20:44PM +0000, Jan Beulich wrote: > >>> On 18.11.14 at 18:03, <li...@eikelenboom.it> wrote: > > Tuesday, November 18, 2014, 5:16:50 PM, you wrote: > >> 1) test_and_[set|clear]_bit sometimes return unexpected values. > >> [But this might be invalid as the addition of the ffff8303faaf25a8 > >> might be correct - as the second dpci the softirq is processing > >> could be the MSI one] > > > > Would there be an easy way to stress test this function separately in some > > debugging function to see if it indeed is returning unexpected values ? > > I don't think there's a reasonable chance of these functions to return > "unexpected" values - they're being used elsewhere, and you'd have > had other problems in the past if they didn't behave as expected.
Interestingly most of the 'test_and_[set|clear]_bit operate on 'unsigned long' while we do 'unsigned int' here. But the 'test_and'' are all btXl so double-word safe. The fact that Sander is able to get 'test_and_clear_bit(STATE_SCHED)' to return zero - when in fact it should return a positive value - implies that some actor is messing with the 'state' outside our raise/softirq dialogue. pt_irq_guest_eoi does pirq_dpci->state = 0 unconditionally! Lets see if this debug + potential patch helps. This should be applied on top of the other patch you had. Just in case I am attaching all four to this email. >From 8093140e374fceb9121ccd07726fb3898b212bfb Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> Date: Tue, 18 Nov 2014 15:08:15 -0500 Subject: [PATCH 4/5] DEBUG4: Add an 'stamp' and potential fix. Signed-off-by: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> --- xen/drivers/passthrough/io.c | 57 +++++++++++++++++++++++++++++++------------- xen/include/xen/hvm/irq.h | 1 + 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index b786bd2..8a8fc62 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -26,6 +26,8 @@ #include <asm/hvm/iommu.h> #include <asm/hvm/support.h> #include <xen/hvm/irq.h> +#include <xen/console.h> + static DEFINE_PER_CPU(struct list_head, dpci_list); @@ -61,21 +63,29 @@ struct _debug_f { struct list_head list; unsigned int state; struct hvm_pirq_dpci *dpci; + unsigned long stamp; }; struct __debug { struct _debug_f ok; struct _debug_f poison; struct _debug_f raise; + struct _debug_f busy_raise; struct _debug_f reset; struct _debug_f zombie_softirq; struct _debug_f zombie_raise; + struct _debug_f timeout; + struct _debug_f clear; }; static DEFINE_PER_CPU(struct __debug, _d); void _record(struct _debug_f *d, struct hvm_pirq_dpci *pirq_dpci) { + + if (pirq_dpci->pirq) + return; + if (pirq_dpci->dom) d->domid = pirq_dpci->dom->domain_id; else @@ -86,6 +96,7 @@ void _record(struct _debug_f *d, struct hvm_pirq_dpci *pirq_dpci) d->list.prev = pirq_dpci->softirq_list.prev; d->state = pirq_dpci->state; d->dpci = pirq_dpci; + d->stamp = pirq_dpci->stamp++; } enum { @@ -95,6 +106,9 @@ enum { OK_SOFTIRQ, OK_RAISE, OK_RESET, + OK_TIMEOUT, + OK_BUSY, + OK_CLEAR, }; static void dump_record(struct _debug_f *d, unsigned int type) @@ -106,7 +120,11 @@ static void dump_record(struct _debug_f *d, unsigned int type) [OK_SOFTIRQ] = "OK-softirq", [OK_RAISE] = "OK-raise ", [OK_RESET] = "OK-reset ", + [OK_TIMEOUT] = "OK-timeout", + [OK_BUSY] = "OK-busy ", + [OK_CLEAR] = "OK-clear ", }; +#if 0 #define LONG(x) [_HVM_IRQ_DPCI_##x] = #x static const char *const names_flag[] = { LONG(MACH_PCI_SHIFT), @@ -117,6 +135,7 @@ static void dump_record(struct _debug_f *d, unsigned int type) }; #undef LONG unsigned int i; +#endif s_time_t now; if ( d->domid == 0 ) @@ -126,20 +145,21 @@ static void dump_record(struct _debug_f *d, unsigned int type) BUG(); now = NOW(); - printk("d%d %s %lumsec ago, state:%x, %ld count, [prev:%p, next:%p] %p", + printk("d%d %s %lumsec ago, state:%x, %ld count, [prev:%p, next:%p] %p %lx", d->domid, names[type], (unsigned long)((now - d->last) / MILLISECS(1)), - d->state, d->count, d->list.prev, d->list.next, d->dpci); + d->state, d->count, d->list.prev, d->list.next, d->dpci, d->stamp); if ( d->dpci ) { struct hvm_pirq_dpci *pirq_dpci = d->dpci; - +#if 0 for ( i = 0; i <= _HVM_IRQ_DPCI_GUEST_MSI_SHIFT; i++ ) if ( pirq_dpci->flags & (1 << i) ) printk("%s ", names_flag[i]); printk(" PIRQ:%d", pirq_dpci->pirq); +#endif if (pirq_dpci->line) printk(" LINE: %d", pirq_dpci->line); } @@ -159,7 +179,10 @@ static void dump_debug(unsigned char key) printk("CPU%02d: \n" ,cpu); dump_record(&d->ok, OK_SOFTIRQ); dump_record(&d->raise, OK_RAISE); + dump_record(&d->busy_raise, OK_RAISE); dump_record(&d->reset, OK_RESET); + dump_record(&d->timeout, OK_TIMEOUT); + dump_record(&d->clear, OK_TIMEOUT); dump_record(&d->poison, ERR_POISON); dump_record(&d->zombie_softirq, Z_SOFTIRQ); dump_record(&d->zombie_raise, Z_RAISE); @@ -184,8 +207,10 @@ static void raise_softirq_for(struct hvm_pirq_dpci *pirq_dpci) return; } if ( test_and_set_bit(STATE_SCHED, &pirq_dpci->state) ) + { + _record(&d->busy_raise, pirq_dpci); return; - + } _record(&d->raise, pirq_dpci); get_knownalive_domain(pirq_dpci->dom); @@ -264,10 +289,14 @@ bool_t pt_irq_need_timer(uint32_t flags) static int pt_irq_guest_eoi(struct domain *d, struct hvm_pirq_dpci *pirq_dpci, void *arg) { + struct __debug *debug = &__get_cpu_var(_d); + if ( __test_and_clear_bit(_HVM_IRQ_DPCI_EOI_LATCH_SHIFT, &pirq_dpci->flags) ) { - pirq_dpci->state = 0; + _record(&debug->clear, pirq_dpci); + pt_pirq_softirq_reset(pirq_dpci); + /* pirq_dpci->state = 0; <= OUCH! */ pirq_dpci->pending = 0; pirq_guest_eoi(dpci_pirq(pirq_dpci)); } @@ -280,11 +309,13 @@ static void pt_irq_time_out(void *data) struct hvm_pirq_dpci *irq_map = data; const struct hvm_irq_dpci *dpci; const struct dev_intx_gsi_link *digl; - + struct __debug *d = &__get_cpu_var(_d); spin_lock(&irq_map->dom->event_lock); dpci = domain_get_irq_dpci(irq_map->dom); ASSERT(dpci); + + _record(&d->timeout, irq_map); list_for_each_entry ( digl, &irq_map->digl_list, list ) { unsigned int guest_gsi = hvm_pci_intx_gsi(digl->device, digl->intx); @@ -302,6 +333,9 @@ static void pt_irq_time_out(void *data) pt_pirq_iterate(irq_map->dom, pt_irq_guest_eoi, NULL); spin_unlock(&irq_map->dom->event_lock); + console_start_sync(); + dump_debug((char)0); + console_end_sync(); } struct hvm_irq_dpci *domain_get_irq_dpci(const struct domain *d) @@ -901,8 +935,6 @@ unlock: spin_unlock(&d->event_lock); } -#include <xen/console.h> - /* * Note: 'pt_pirq_softirq_reset' can clear the STATE_SCHED before we get to * doing it. If that is the case we let 'pt_pirq_softirq_reset' do ref-counting. @@ -919,26 +951,17 @@ static void dpci_softirq(void) struct hvm_pirq_dpci *dpci; } l[4]; unsigned int i = 0; -#if DIFF_LIST - struct hvm_pirq_dpci *n; -#endif debug = &per_cpu(_d, cpu); local_irq_disable(); list_splice_init(&per_cpu(dpci_list, cpu), &our_list); local_irq_enable(); -#if DIFF_LIST - list_for_each_entry_safe(pirq_dpci, n, &our_list, softirq_list) -#else while ( !list_empty(&our_list) ) -#endif { struct domain *d; struct list_head *entry; -#ifndef DIFF_LIST pirq_dpci = list_entry(our_list.next, struct hvm_pirq_dpci, softirq_list); -#endif entry = &pirq_dpci->softirq_list; if ( i <= 3 ) { diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h index 1fb1292..f5b6061 100644 --- a/xen/include/xen/hvm/irq.h +++ b/xen/include/xen/hvm/irq.h @@ -102,6 +102,7 @@ struct hvm_pirq_dpci { struct list_head softirq_list; unsigned int pirq; unsigned int line; + unsigned long stamp; }; void pt_pirq_init(struct domain *, struct hvm_pirq_dpci *); -- 1.9.3
>From b8c267ea34663a9585e1aee9c09dede240b546f9 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> Date: Fri, 14 Nov 2014 12:15:26 -0500 Subject: [PATCH 1/5] dpci: Add ZOMBIE state. Signed-off-by: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> --- xen/drivers/passthrough/io.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index efc66dc..8e9141e 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -50,20 +50,25 @@ static DEFINE_PER_CPU(struct list_head, dpci_list); enum { STATE_SCHED, - STATE_RUN + STATE_RUN, + STATE_ZOMBIE }; /* * This can be called multiple times, but the softirq is only raised once. - * That is until the STATE_SCHED state has been cleared. The state can be - * cleared by: the 'dpci_softirq' (when it has executed 'hvm_dirq_assist'), - * or by 'pt_pirq_softirq_reset' (which will try to clear the state before - * the softirq had a chance to run). + * That is until the STATE_SCHED and STATE_ZOMBIE state has been cleared. The + * STATE_SCHED and STATE_ZOMBIE state can be cleared by the 'dpci_softirq' + * (when it has executed 'hvm_dirq_assist'). The STATE_SCHED can be cleared + * by 'pt_pirq_softirq_reset' (which will try to clear the state before the + * softirq had a chance to run). */ static void raise_softirq_for(struct hvm_pirq_dpci *pirq_dpci) { unsigned long flags; + if ( test_bit(STATE_ZOMBIE, &pirq_dpci->state) ) + return; + if ( test_and_set_bit(STATE_SCHED, &pirq_dpci->state) ) return; @@ -85,7 +90,7 @@ static void raise_softirq_for(struct hvm_pirq_dpci *pirq_dpci) */ bool_t pt_pirq_softirq_active(struct hvm_pirq_dpci *pirq_dpci) { - if ( pirq_dpci->state & ((1 << STATE_RUN) | (1 << STATE_SCHED)) ) + if ( pirq_dpci->state & ((1 << STATE_RUN) | (1 << STATE_SCHED) | (1 << STATE_ZOMBIE) ) ) return 1; /* @@ -109,7 +114,7 @@ static void pt_pirq_softirq_reset(struct hvm_pirq_dpci *pirq_dpci) ASSERT(spin_is_locked(&d->event_lock)); - switch ( cmpxchg(&pirq_dpci->state, 1 << STATE_SCHED, 0) ) + switch ( cmpxchg(&pirq_dpci->state, 1 << STATE_SCHED, 1 << STATE_ZOMBIE ) ) { case (1 << STATE_SCHED): /* @@ -120,6 +125,7 @@ static void pt_pirq_softirq_reset(struct hvm_pirq_dpci *pirq_dpci) /* fallthrough. */ case (1 << STATE_RUN): case (1 << STATE_RUN) | (1 << STATE_SCHED): + case (1 << STATE_RUN) | (1 << STATE_SCHED) | (1 << STATE_ZOMBIE): /* * The reason it is OK to reset 'dom' when STATE_RUN bit is set is due * to a shortcut the 'dpci_softirq' implements. It stashes the 'dom' @@ -779,6 +785,7 @@ unlock: static void dpci_softirq(void) { unsigned int cpu = smp_processor_id(); + unsigned int reset = 0; LIST_HEAD(our_list); local_irq_disable(); @@ -805,7 +812,15 @@ static void dpci_softirq(void) hvm_dirq_assist(d, pirq_dpci); put_domain(d); } + else + reset = 1; + clear_bit(STATE_RUN, &pirq_dpci->state); + if ( reset ) + { + clear_bit(STATE_ZOMBIE, &pirq_dpci->state); + reset = 0; + } } } -- 1.9.3
>From a4171fa12583eabd126bc5b4c305f49b2fb2b515 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> Date: Fri, 14 Nov 2014 15:00:39 -0500 Subject: [PATCH 2/5] debug: Signed-off-by: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> --- xen/drivers/passthrough/io.c | 180 ++++++++++++++++++++++++++++++++++++++++++- xen/include/xen/hvm/irq.h | 2 + 2 files changed, 178 insertions(+), 4 deletions(-) diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index 8e9141e..23e5ed1 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -54,6 +54,117 @@ enum { STATE_ZOMBIE }; +struct _debug_f { + unsigned int domid; + unsigned long count; + s_time_t last; + struct list_head list; + unsigned int state; + struct hvm_pirq_dpci *dpci; +}; + +struct __debug { + struct _debug_f ok; + struct _debug_f poison; + struct _debug_f raise; + struct _debug_f reset; + struct _debug_f zombie_softirq; + struct _debug_f zombie_raise; +}; + +static DEFINE_PER_CPU(struct __debug, _d); + +void _record(struct _debug_f *d, struct hvm_pirq_dpci *pirq_dpci) +{ + if (pirq_dpci->dom) + d->domid = pirq_dpci->dom->domain_id; + else + d->domid = 0xdead; + d->count ++; + d->last = NOW(); + d->list.next = pirq_dpci->softirq_list.next; + d->list.prev = pirq_dpci->softirq_list.prev; + d->state = pirq_dpci->state; + d->dpci = pirq_dpci; +} + +enum { + Z_SOFTIRQ, + Z_RAISE, + ERR_POISON, + OK_SOFTIRQ, + OK_RAISE, + OK_RESET, +}; + +static void dump_record(struct _debug_f *d, unsigned int type) +{ + static const char *const names[] = { + [Z_SOFTIRQ] = "Z-softirq ", + [Z_RAISE] = "Z-raise ", + [ERR_POISON] = "ERR-poison", + [OK_SOFTIRQ] = "OK-softirq", + [OK_RAISE] = "OK-raise ", + [OK_RESET] = "OK-reset ", + }; +#define LONG(x) [_HVM_IRQ_DPCI_##x] = #x + static const char *const names_flag[] = { + LONG(MACH_PCI_SHIFT), + LONG(MAPPED_SHIFT), + LONG(EOI_LATCH_SHIFT), + LONG(GUEST_PCI_SHIFT), + LONG(GUEST_MSI_SHIFT), + }; +#undef LONG + unsigned int i; + s_time_t now; + + if ( d->domid == 0 ) + return; + + if ( type >= ARRAY_SIZE(names) ) + BUG(); + + now = NOW(); + printk("d%d %s %lumsec ago, state:%x, %ld count, [prev:%p, next:%p] ", + d->domid, names[type], + (unsigned long)((now - d->last) / MILLISECS(1)), + d->state, d->count, d->list.prev, d->list.next); + + if ( d->dpci ) + { + struct hvm_pirq_dpci *pirq_dpci = d->dpci; + + for ( i = 0; i <= _HVM_IRQ_DPCI_GUEST_MSI_SHIFT; i++ ) + if ( pirq_dpci->flags & 1 << _HVM_IRQ_DPCI_TRANSLATE_SHIFT ) + printk("%s ", names_flag[i]); + + printk(" PIRQ:%d", pirq_dpci->pirq); + if (pirq_dpci->line) + printk(" LINE: %d", pirq_dpci->line); + } + printk("\n"); + memset(d, 0, sizeof(struct _debug_f)); +} + +static void dump_debug(unsigned char key) +{ + unsigned int cpu; + + for_each_online_cpu ( cpu ) + { + struct __debug *d; + d = &per_cpu(_d, cpu); + + printk("CPU%02d: \n" ,cpu); + dump_record(&d->ok, OK_SOFTIRQ); + dump_record(&d->raise, OK_RAISE); + dump_record(&d->reset, OK_RESET); + dump_record(&d->poison, ERR_POISON); + dump_record(&d->zombie_softirq, Z_SOFTIRQ); + dump_record(&d->zombie_raise, Z_RAISE); + } +} /* * This can be called multiple times, but the softirq is only raised once. * That is until the STATE_SCHED and STATE_ZOMBIE state has been cleared. The @@ -65,13 +176,18 @@ enum { static void raise_softirq_for(struct hvm_pirq_dpci *pirq_dpci) { unsigned long flags; + struct __debug *d = &__get_cpu_var(_d); if ( test_bit(STATE_ZOMBIE, &pirq_dpci->state) ) + { + _record(&d->zombie_raise, pirq_dpci); return; - + } if ( test_and_set_bit(STATE_SCHED, &pirq_dpci->state) ) return; + _record(&d->raise, pirq_dpci); + get_knownalive_domain(pirq_dpci->dom); local_irq_save(flags); @@ -111,9 +227,12 @@ bool_t pt_pirq_softirq_active(struct hvm_pirq_dpci *pirq_dpci) static void pt_pirq_softirq_reset(struct hvm_pirq_dpci *pirq_dpci) { struct domain *d = pirq_dpci->dom; + struct __debug *debug = &__get_cpu_var(_d); ASSERT(spin_is_locked(&d->event_lock)); + _record(&debug->reset, pirq_dpci); + switch ( cmpxchg(&pirq_dpci->state, 1 << STATE_SCHED, 1 << STATE_ZOMBIE ) ) { case (1 << STATE_SCHED): @@ -277,6 +396,7 @@ int pt_irq_create_bind( * As such on every 'pt_irq_create_bind' call we MUST set it. */ pirq_dpci->dom = d; + pirq_dpci->pirq = pirq; /* bind after hvm_irq_dpci is setup to avoid race with irq handler*/ rc = pirq_guest_bind(d->vcpu[0], info, 0); if ( rc == 0 && pt_irq_bind->u.msi.gtable ) @@ -291,6 +411,7 @@ int pt_irq_create_bind( * to be scheduled but we must deal with the one that may be * in the queue. */ + pirq_dpci->line = __LINE__; pt_pirq_softirq_reset(pirq_dpci); } } @@ -300,6 +421,7 @@ int pt_irq_create_bind( pirq_dpci->gmsi.gvec = 0; pirq_dpci->dom = NULL; pirq_dpci->flags = 0; + pirq_dpci->pirq = -pirq; pirq_cleanup_check(info, d); spin_unlock(&d->event_lock); return rc; @@ -544,6 +666,7 @@ int pt_irq_destroy_bind( * See comment in pt_irq_create_bind's PT_IRQ_TYPE_MSI before the * call to pt_pirq_softirq_reset. */ + pirq_dpci->line = __LINE__; pt_pirq_softirq_reset(pirq_dpci); pirq_cleanup_check(pirq, d); @@ -778,6 +901,8 @@ unlock: spin_unlock(&d->event_lock); } +#include <xen/console.h> + /* * Note: 'pt_pirq_softirq_reset' can clear the STATE_SCHED before we get to * doing it. If that is the case we let 'pt_pirq_softirq_reset' do ref-counting. @@ -787,6 +912,9 @@ static void dpci_softirq(void) unsigned int cpu = smp_processor_id(); unsigned int reset = 0; LIST_HEAD(our_list); + struct __debug *debug; + + debug = &per_cpu(_d, cpu); local_irq_disable(); list_splice_init(&per_cpu(dpci_list, cpu), &our_list); @@ -796,9 +924,22 @@ static void dpci_softirq(void) { struct hvm_pirq_dpci *pirq_dpci; struct domain *d; + struct list_head *entry; pirq_dpci = list_entry(our_list.next, struct hvm_pirq_dpci, softirq_list); - list_del(&pirq_dpci->softirq_list); + entry = &pirq_dpci->softirq_list; + if ( entry->next == LIST_POISON1 || entry->next == LIST_POISON2 || + entry->prev == LIST_POISON2 || entry->prev == LIST_POISON2 ) + { + _record(&debug->poison, pirq_dpci); + console_start_sync(); + dump_debug((char)0); + console_end_sync(); + domain_crash(pirq_dpci->dom); + break; + } + _record(&debug->ok, pirq_dpci); + list_del(entry); d = pirq_dpci->dom; smp_mb(); /* 'd' MUST be saved before we set/clear the bits. */ @@ -813,8 +954,10 @@ static void dpci_softirq(void) put_domain(d); } else + { + _record(&debug->zombie_softirq, pirq_dpci); reset = 1; - + } clear_bit(STATE_RUN, &pirq_dpci->state); if ( reset ) { @@ -833,6 +976,7 @@ static int cpu_callback( { case CPU_UP_PREPARE: INIT_LIST_HEAD(&per_cpu(dpci_list, cpu)); + memset(&per_cpu(_d, cpu), 0, sizeof(struct __debug)); break; case CPU_UP_CANCELED: case CPU_DEAD: @@ -854,15 +998,43 @@ static struct notifier_block cpu_nfb = { .notifier_call = cpu_callback, }; +#include <xen/keyhandler.h> + +static struct keyhandler dump_debug_keyhandler = { + .diagnostic = 1, + .u.fn = dump_debug, + .desc = "dpci debug stats" +}; +static struct timer debug_timer; +static s_time_t last_time = 0; +static unsigned int debug_cnt = 0; + +static void debug_timer_fn(void *d) +{ + if ( ( debug_cnt ++ % 10 ) == 0 ) + printk("--MARK--\n"); + + last_time = NOW(); + set_timer(&debug_timer, last_time + SECONDS(1)); +} + static int __init setup_dpci_softirq(void) { unsigned int cpu; for_each_online_cpu(cpu) + { INIT_LIST_HEAD(&per_cpu(dpci_list, cpu)); - + memset(&per_cpu(_d, cpu), 0, sizeof(struct __debug)); + } open_softirq(HVM_DPCI_SOFTIRQ, dpci_softirq); register_cpu_notifier(&cpu_nfb); + + init_timer(&debug_timer, debug_timer_fn, NULL, smp_processor_id()); + last_time = NOW(); + set_timer(&debug_timer, NOW() + SECONDS(1)); + register_keyhandler('k', &dump_debug_keyhandler); + return 0; } __initcall(setup_dpci_softirq); diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h index 9709397..1fb1292 100644 --- a/xen/include/xen/hvm/irq.h +++ b/xen/include/xen/hvm/irq.h @@ -100,6 +100,8 @@ struct hvm_pirq_dpci { struct hvm_gmsi_info gmsi; struct timer timer; struct list_head softirq_list; + unsigned int pirq; + unsigned int line; }; void pt_pirq_init(struct domain *, struct hvm_pirq_dpci *); -- 1.9.3
>From 3163117e2ceb8dfcc11545dcc385aa3d147614e8 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> Date: Mon, 17 Nov 2014 17:32:43 -0500 Subject: [PATCH 3/5] DEBUG 2 --- xen/drivers/passthrough/io.c | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index 23e5ed1..b786bd2 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -126,17 +126,17 @@ static void dump_record(struct _debug_f *d, unsigned int type) BUG(); now = NOW(); - printk("d%d %s %lumsec ago, state:%x, %ld count, [prev:%p, next:%p] ", + printk("d%d %s %lumsec ago, state:%x, %ld count, [prev:%p, next:%p] %p", d->domid, names[type], (unsigned long)((now - d->last) / MILLISECS(1)), - d->state, d->count, d->list.prev, d->list.next); + d->state, d->count, d->list.prev, d->list.next, d->dpci); if ( d->dpci ) { struct hvm_pirq_dpci *pirq_dpci = d->dpci; for ( i = 0; i <= _HVM_IRQ_DPCI_GUEST_MSI_SHIFT; i++ ) - if ( pirq_dpci->flags & 1 << _HVM_IRQ_DPCI_TRANSLATE_SHIFT ) + if ( pirq_dpci->flags & (1 << i) ) printk("%s ", names_flag[i]); printk(" PIRQ:%d", pirq_dpci->pirq); @@ -545,9 +545,9 @@ int pt_irq_create_bind( if ( iommu_verbose ) dprintk(XENLOG_G_INFO, - "d%d: bind: m_gsi=%u g_gsi=%u dev=%02x.%02x.%u intx=%u\n", + "d%d: bind: m_gsi=%u g_gsi=%u dev=%02x.%02x.%u intx=%u %p\n", d->domain_id, pirq, guest_gsi, bus, - PCI_SLOT(device), PCI_FUNC(device), intx); + PCI_SLOT(device), PCI_FUNC(device), intx, pirq_dpci); break; } @@ -913,26 +913,52 @@ static void dpci_softirq(void) unsigned int reset = 0; LIST_HEAD(our_list); struct __debug *debug; - + struct hvm_pirq_dpci *pirq_dpci; + struct __x { + struct list_head l; + struct hvm_pirq_dpci *dpci; + } l[4]; + unsigned int i = 0; +#if DIFF_LIST + struct hvm_pirq_dpci *n; +#endif debug = &per_cpu(_d, cpu); local_irq_disable(); list_splice_init(&per_cpu(dpci_list, cpu), &our_list); local_irq_enable(); - +#if DIFF_LIST + list_for_each_entry_safe(pirq_dpci, n, &our_list, softirq_list) +#else while ( !list_empty(&our_list) ) +#endif { - struct hvm_pirq_dpci *pirq_dpci; struct domain *d; struct list_head *entry; +#ifndef DIFF_LIST pirq_dpci = list_entry(our_list.next, struct hvm_pirq_dpci, softirq_list); +#endif entry = &pirq_dpci->softirq_list; + if ( i <= 3 ) + { + struct __x *p; + + p = &l[i]; + p->dpci = pirq_dpci; + p->l.prev = entry->prev; + p->l.next = entry->next; + i++; + } if ( entry->next == LIST_POISON1 || entry->next == LIST_POISON2 || entry->prev == LIST_POISON2 || entry->prev == LIST_POISON2 ) { + unsigned int j; + _record(&debug->poison, pirq_dpci); console_start_sync(); + for (j=0; j < i;j++) + printk(" %u: %p [p:%p, n:%p]\n", j, l[j].dpci, l[j].l.prev, l[j].l.next); dump_debug((char)0); console_end_sync(); domain_crash(pirq_dpci->dom); -- 1.9.3
>From 8093140e374fceb9121ccd07726fb3898b212bfb Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> Date: Tue, 18 Nov 2014 15:08:15 -0500 Subject: [PATCH 4/5] DEBUG4: Add an 'stamp' and potential fix. Signed-off-by: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> --- xen/drivers/passthrough/io.c | 57 +++++++++++++++++++++++++++++++------------- xen/include/xen/hvm/irq.h | 1 + 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index b786bd2..8a8fc62 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -26,6 +26,8 @@ #include <asm/hvm/iommu.h> #include <asm/hvm/support.h> #include <xen/hvm/irq.h> +#include <xen/console.h> + static DEFINE_PER_CPU(struct list_head, dpci_list); @@ -61,21 +63,29 @@ struct _debug_f { struct list_head list; unsigned int state; struct hvm_pirq_dpci *dpci; + unsigned long stamp; }; struct __debug { struct _debug_f ok; struct _debug_f poison; struct _debug_f raise; + struct _debug_f busy_raise; struct _debug_f reset; struct _debug_f zombie_softirq; struct _debug_f zombie_raise; + struct _debug_f timeout; + struct _debug_f clear; }; static DEFINE_PER_CPU(struct __debug, _d); void _record(struct _debug_f *d, struct hvm_pirq_dpci *pirq_dpci) { + + if (pirq_dpci->pirq) + return; + if (pirq_dpci->dom) d->domid = pirq_dpci->dom->domain_id; else @@ -86,6 +96,7 @@ void _record(struct _debug_f *d, struct hvm_pirq_dpci *pirq_dpci) d->list.prev = pirq_dpci->softirq_list.prev; d->state = pirq_dpci->state; d->dpci = pirq_dpci; + d->stamp = pirq_dpci->stamp++; } enum { @@ -95,6 +106,9 @@ enum { OK_SOFTIRQ, OK_RAISE, OK_RESET, + OK_TIMEOUT, + OK_BUSY, + OK_CLEAR, }; static void dump_record(struct _debug_f *d, unsigned int type) @@ -106,7 +120,11 @@ static void dump_record(struct _debug_f *d, unsigned int type) [OK_SOFTIRQ] = "OK-softirq", [OK_RAISE] = "OK-raise ", [OK_RESET] = "OK-reset ", + [OK_TIMEOUT] = "OK-timeout", + [OK_BUSY] = "OK-busy ", + [OK_CLEAR] = "OK-clear ", }; +#if 0 #define LONG(x) [_HVM_IRQ_DPCI_##x] = #x static const char *const names_flag[] = { LONG(MACH_PCI_SHIFT), @@ -117,6 +135,7 @@ static void dump_record(struct _debug_f *d, unsigned int type) }; #undef LONG unsigned int i; +#endif s_time_t now; if ( d->domid == 0 ) @@ -126,20 +145,21 @@ static void dump_record(struct _debug_f *d, unsigned int type) BUG(); now = NOW(); - printk("d%d %s %lumsec ago, state:%x, %ld count, [prev:%p, next:%p] %p", + printk("d%d %s %lumsec ago, state:%x, %ld count, [prev:%p, next:%p] %p %lx", d->domid, names[type], (unsigned long)((now - d->last) / MILLISECS(1)), - d->state, d->count, d->list.prev, d->list.next, d->dpci); + d->state, d->count, d->list.prev, d->list.next, d->dpci, d->stamp); if ( d->dpci ) { struct hvm_pirq_dpci *pirq_dpci = d->dpci; - +#if 0 for ( i = 0; i <= _HVM_IRQ_DPCI_GUEST_MSI_SHIFT; i++ ) if ( pirq_dpci->flags & (1 << i) ) printk("%s ", names_flag[i]); printk(" PIRQ:%d", pirq_dpci->pirq); +#endif if (pirq_dpci->line) printk(" LINE: %d", pirq_dpci->line); } @@ -159,7 +179,10 @@ static void dump_debug(unsigned char key) printk("CPU%02d: \n" ,cpu); dump_record(&d->ok, OK_SOFTIRQ); dump_record(&d->raise, OK_RAISE); + dump_record(&d->busy_raise, OK_RAISE); dump_record(&d->reset, OK_RESET); + dump_record(&d->timeout, OK_TIMEOUT); + dump_record(&d->clear, OK_TIMEOUT); dump_record(&d->poison, ERR_POISON); dump_record(&d->zombie_softirq, Z_SOFTIRQ); dump_record(&d->zombie_raise, Z_RAISE); @@ -184,8 +207,10 @@ static void raise_softirq_for(struct hvm_pirq_dpci *pirq_dpci) return; } if ( test_and_set_bit(STATE_SCHED, &pirq_dpci->state) ) + { + _record(&d->busy_raise, pirq_dpci); return; - + } _record(&d->raise, pirq_dpci); get_knownalive_domain(pirq_dpci->dom); @@ -264,10 +289,14 @@ bool_t pt_irq_need_timer(uint32_t flags) static int pt_irq_guest_eoi(struct domain *d, struct hvm_pirq_dpci *pirq_dpci, void *arg) { + struct __debug *debug = &__get_cpu_var(_d); + if ( __test_and_clear_bit(_HVM_IRQ_DPCI_EOI_LATCH_SHIFT, &pirq_dpci->flags) ) { - pirq_dpci->state = 0; + _record(&debug->clear, pirq_dpci); + pt_pirq_softirq_reset(pirq_dpci); + /* pirq_dpci->state = 0; <= OUCH! */ pirq_dpci->pending = 0; pirq_guest_eoi(dpci_pirq(pirq_dpci)); } @@ -280,11 +309,13 @@ static void pt_irq_time_out(void *data) struct hvm_pirq_dpci *irq_map = data; const struct hvm_irq_dpci *dpci; const struct dev_intx_gsi_link *digl; - + struct __debug *d = &__get_cpu_var(_d); spin_lock(&irq_map->dom->event_lock); dpci = domain_get_irq_dpci(irq_map->dom); ASSERT(dpci); + + _record(&d->timeout, irq_map); list_for_each_entry ( digl, &irq_map->digl_list, list ) { unsigned int guest_gsi = hvm_pci_intx_gsi(digl->device, digl->intx); @@ -302,6 +333,9 @@ static void pt_irq_time_out(void *data) pt_pirq_iterate(irq_map->dom, pt_irq_guest_eoi, NULL); spin_unlock(&irq_map->dom->event_lock); + console_start_sync(); + dump_debug((char)0); + console_end_sync(); } struct hvm_irq_dpci *domain_get_irq_dpci(const struct domain *d) @@ -901,8 +935,6 @@ unlock: spin_unlock(&d->event_lock); } -#include <xen/console.h> - /* * Note: 'pt_pirq_softirq_reset' can clear the STATE_SCHED before we get to * doing it. If that is the case we let 'pt_pirq_softirq_reset' do ref-counting. @@ -919,26 +951,17 @@ static void dpci_softirq(void) struct hvm_pirq_dpci *dpci; } l[4]; unsigned int i = 0; -#if DIFF_LIST - struct hvm_pirq_dpci *n; -#endif debug = &per_cpu(_d, cpu); local_irq_disable(); list_splice_init(&per_cpu(dpci_list, cpu), &our_list); local_irq_enable(); -#if DIFF_LIST - list_for_each_entry_safe(pirq_dpci, n, &our_list, softirq_list) -#else while ( !list_empty(&our_list) ) -#endif { struct domain *d; struct list_head *entry; -#ifndef DIFF_LIST pirq_dpci = list_entry(our_list.next, struct hvm_pirq_dpci, softirq_list); -#endif entry = &pirq_dpci->softirq_list; if ( i <= 3 ) { diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h index 1fb1292..f5b6061 100644 --- a/xen/include/xen/hvm/irq.h +++ b/xen/include/xen/hvm/irq.h @@ -102,6 +102,7 @@ struct hvm_pirq_dpci { struct list_head softirq_list; unsigned int pirq; unsigned int line; + unsigned long stamp; }; void pt_pirq_init(struct domain *, struct hvm_pirq_dpci *); -- 1.9.3
>From 8e0edc1e6d51eeb5a401f686adccefa623332bcd Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> Date: Tue, 18 Nov 2014 15:29:12 -0500 Subject: [PATCH 5/5] debug: Remove the --MARK-- code. We could use it to check every 1msec for some case and print data, but we never used it. Signed-off-by: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> --- xen/drivers/passthrough/io.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index 8a8fc62..aad5607 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -1054,18 +1054,6 @@ static struct keyhandler dump_debug_keyhandler = { .u.fn = dump_debug, .desc = "dpci debug stats" }; -static struct timer debug_timer; -static s_time_t last_time = 0; -static unsigned int debug_cnt = 0; - -static void debug_timer_fn(void *d) -{ - if ( ( debug_cnt ++ % 10 ) == 0 ) - printk("--MARK--\n"); - - last_time = NOW(); - set_timer(&debug_timer, last_time + SECONDS(1)); -} static int __init setup_dpci_softirq(void) { @@ -1079,9 +1067,6 @@ static int __init setup_dpci_softirq(void) open_softirq(HVM_DPCI_SOFTIRQ, dpci_softirq); register_cpu_notifier(&cpu_nfb); - init_timer(&debug_timer, debug_timer_fn, NULL, smp_processor_id()); - last_time = NOW(); - set_timer(&debug_timer, NOW() + SECONDS(1)); register_keyhandler('k', &dump_debug_keyhandler); return 0; -- 1.9.3
_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel