]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/xen/multicalls.c
Rename SMSC phy functions to be more generic
[linux-2.6-omap-h63xx.git] / arch / x86 / xen / multicalls.c
index c837e8e463db3567c0336357e0f0e0590af1bdaf..5791eb2e37508dc87ab6d9f74bdc53da6f24ae4b 100644 (file)
 
 #include "multicalls.h"
 
+#define MC_DEBUG       1
+
 #define MC_BATCH       32
 #define MC_ARGS                (MC_BATCH * 16 / sizeof(u64))
 
 struct mc_buffer {
        struct multicall_entry entries[MC_BATCH];
+#if MC_DEBUG
+       struct multicall_entry debug[MC_BATCH];
+#endif
        u64 args[MC_ARGS];
-       unsigned mcidx, argidx;
+       struct callback {
+               void (*fn)(void *);
+               void *data;
+       } callbacks[MC_BATCH];
+       unsigned mcidx, argidx, cbidx;
 };
 
 static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
@@ -43,6 +52,7 @@ void xen_mc_flush(void)
        struct mc_buffer *b = &__get_cpu_var(mc_buffer);
        int ret = 0;
        unsigned long flags;
+       int i;
 
        BUG_ON(preemptible());
 
@@ -51,13 +61,31 @@ void xen_mc_flush(void)
        local_irq_save(flags);
 
        if (b->mcidx) {
-               int i;
+#if MC_DEBUG
+               memcpy(b->debug, b->entries,
+                      b->mcidx * sizeof(struct multicall_entry));
+#endif
 
                if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0)
                        BUG();
                for (i = 0; i < b->mcidx; i++)
                        if (b->entries[i].result < 0)
                                ret++;
+
+#if MC_DEBUG
+               if (ret) {
+                       printk(KERN_ERR "%d multicall(s) failed: cpu %d\n",
+                              ret, smp_processor_id());
+                       for (i = 0; i < b->mcidx; i++) {
+                               printk("  call %2d/%d: op=%lu arg=[%lx] result=%ld\n",
+                                      i+1, b->mcidx,
+                                      b->debug[i].op,
+                                      b->debug[i].args[0],
+                                      b->entries[i].result);
+                       }
+               }
+#endif
+
                b->mcidx = 0;
                b->argidx = 0;
        } else
@@ -65,6 +93,13 @@ void xen_mc_flush(void)
 
        local_irq_restore(flags);
 
+       for (i = 0; i < b->cbidx; i++) {
+               struct callback *cb = &b->callbacks[i];
+
+               (*cb->fn)(cb->data);
+       }
+       b->cbidx = 0;
+
        BUG_ON(ret);
 }
 
@@ -88,3 +123,16 @@ struct multicall_space __xen_mc_entry(size_t args)
 
        return ret;
 }
+
+void xen_mc_callback(void (*fn)(void *), void *data)
+{
+       struct mc_buffer *b = &__get_cpu_var(mc_buffer);
+       struct callback *cb;
+
+       if (b->cbidx == MC_BATCH)
+               xen_mc_flush();
+
+       cb = &b->callbacks[b->cbidx++];
+       cb->fn = fn;
+       cb->data = data;
+}