aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-01-21 15:12:17 +0000
committerKeir Fraser <keir.fraser@citrix.com>2010-01-21 15:12:17 +0000
commitceb3df776e3faf356150f3d67d461505a63cfee2 (patch)
tree987772702869204b215629c18f8cfc08725394db
parentec7895237498a37ccbfb4667e809e63903ca61db (diff)
downloadxen-ceb3df776e3faf356150f3d67d461505a63cfee2.tar.gz
xen-ceb3df776e3faf356150f3d67d461505a63cfee2.tar.bz2
xen-ceb3df776e3faf356150f3d67d461505a63cfee2.zip
x86: add keyhandler to dump MSI state
Equivalent to dumping IO-APIC state; the question is whether this ought to live on its own key (as done here), or whether it should be chanined to from the 'i' handler. Signed-off-by: Jan Beulich <jbeulich@novell.com>
-rw-r--r--xen/arch/x86/msi.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c
index fedac7f7aa..67f48a3555 100644
--- a/xen/arch/x86/msi.c
+++ b/xen/arch/x86/msi.c
@@ -391,6 +391,21 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
entry->msi_attrib.masked = !!flag;
}
+static int msi_get_mask_bit(const struct msi_desc *entry)
+{
+ switch (entry->msi_attrib.type) {
+ case PCI_CAP_ID_MSI:
+ if (!entry->dev || !entry->msi_attrib.maskbit)
+ break;
+ return pci_conf_read32(entry->dev->bus, PCI_SLOT(entry->dev->devfn),
+ PCI_FUNC(entry->dev->devfn),
+ (unsigned long)entry->mask_base) & 1;
+ case PCI_CAP_ID_MSIX:
+ return readl(entry->mask_base + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET) & 1;
+ }
+ return -1;
+}
+
void mask_msi_irq(unsigned int irq)
{
msi_set_mask_bit(irq, 1);
@@ -834,3 +849,65 @@ unsigned int pci_msix_get_table_len(struct pci_dev *pdev)
return len;
}
+
+static void dump_msi(unsigned char key)
+{
+ unsigned int irq;
+
+ printk("PCI-MSI interrupt information:\n");
+
+ for ( irq = 0; irq < nr_irqs; irq++ )
+ {
+ struct irq_desc *desc = irq_to_desc(irq);
+ const struct msi_desc *entry;
+ u32 addr, data;
+ unsigned long flags;
+ char type;
+
+ spin_lock_irqsave(&desc->lock, flags);
+
+ entry = desc->msi_desc;
+ type = desc->handler == &pci_msi_type && entry;
+
+ spin_unlock_irqrestore(&desc->lock, flags);
+
+ if ( !type )
+ continue;
+
+ switch ( entry->msi_attrib.type )
+ {
+ case PCI_CAP_ID_MSI: type = ' '; break;
+ case PCI_CAP_ID_MSIX: type = 'X'; break;
+ default: type = '?'; break;
+ }
+
+ data = entry->msg.data;
+ addr = entry->msg.address_lo;
+
+ printk(" MSI%c %4u vec=%02x%7s%6s%3sassert%5s%7s"
+ " dest=%08x mask=%d/%d/%d\n",
+ type, irq,
+ (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT,
+ data & MSI_DATA_DELIVERY_LOWPRI ? "lowest" : "fixed",
+ data & MSI_DATA_TRIGGER_LEVEL ? "level" : "edge",
+ data & MSI_DATA_LEVEL_ASSERT ? "" : "de",
+ addr & MSI_ADDR_DESTMODE_LOGIC ? "log" : "phys",
+ addr & MSI_ADDR_REDIRECTION_LOWPRI ? "lowest" : "cpu",
+ entry->msg.dest32,
+ entry->msi_attrib.maskbit, entry->msi_attrib.masked,
+ msi_get_mask_bit(entry));
+ }
+}
+
+static struct keyhandler dump_msi_keyhandler = {
+ .diagnostic = 1,
+ .u.fn = dump_msi,
+ .desc = "dump MSI state"
+};
+
+static int __init msi_setup_keyhandler(void)
+{
+ register_keyhandler('M', &dump_msi_keyhandler);
+ return 0;
+}
+__initcall(msi_setup_keyhandler);