aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/pci.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-02-10 20:41:02 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-02-11 02:50:37 -0500
commit35a17eb6a87c9ceb0d35dcb51f464fe6faf584ab (patch)
tree7f56095a56e9f62dca7514cdfe781739548011f5 /arch/sparc64/kernel/pci.c
parent68c921869491c119142612fa5796c9f8b4e9970b (diff)
[SPARC64]: Add PCI MSI support on Niagara.
This is kind of hokey, we could use the hardware provided facilities much better. MSIs are assosciated with MSI Queues. MSI Queues generate interrupts when any MSI assosciated with it is signalled. This suggests a two-tiered IRQ dispatch scheme: MSI Queue interrupt --> queue interrupt handler MSI dispatch --> driver interrupt handler But we just get one-level under Linux currently. What I'd like to do is possibly stick the IRQ actions into a per-MSI-Queue data structure, and dispatch them form there, but the generic IRQ layer doesn't provide a way to do that right now. So, the current kludge is to "ACK" the interrupt by processing the MSI Queue data structures and ACK'ing them, then we run the actual handler like normal. We are wasting a lot of useful information, for example the MSI data and address are provided with ever MSI, as well as a system tick if available. If we could pass this into the IRQ handler it could help with certain things, in particular for PCI-Express error messages. The MSI entries on sparc64 also tell you exactly which bus/device/fn sent the MSI, which would be great for error handling when no registered IRQ handler can service the interrupt. We override the disable/enable IRQ chip methods in sun4v_msi, so we have to call {mask,unmask}_msi_irq() directly from there. This is another ugly wart. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/pci.c')
-rw-r--r--arch/sparc64/kernel/pci.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index dfc41cd4bb5d..6b740eb6fe7e 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -13,6 +13,8 @@
13#include <linux/capability.h> 13#include <linux/capability.h>
14#include <linux/errno.h> 14#include <linux/errno.h>
15#include <linux/smp_lock.h> 15#include <linux/smp_lock.h>
16#include <linux/msi.h>
17#include <linux/irq.h>
16#include <linux/init.h> 18#include <linux/init.h>
17 19
18#include <asm/uaccess.h> 20#include <asm/uaccess.h>
@@ -646,4 +648,37 @@ int pci_domain_nr(struct pci_bus *pbus)
646} 648}
647EXPORT_SYMBOL(pci_domain_nr); 649EXPORT_SYMBOL(pci_domain_nr);
648 650
651#ifdef CONFIG_PCI_MSI
652int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
653{
654 struct pcidev_cookie *pcp = pdev->sysdata;
655 struct pci_pbm_info *pbm = pcp->pbm;
656 struct pci_controller_info *p = pbm->parent;
657 int virt_irq, err;
658
659 if (!pbm->msi_num || !p->setup_msi_irq)
660 return -EINVAL;
661
662 err = p->setup_msi_irq(&virt_irq, pdev, desc);
663 if (err < 0)
664 return err;
665
666 return virt_irq;
667}
668
669void arch_teardown_msi_irq(unsigned int virt_irq)
670{
671 struct msi_desc *entry = get_irq_data(virt_irq);
672 struct pci_dev *pdev = entry->dev;
673 struct pcidev_cookie *pcp = pdev->sysdata;
674 struct pci_pbm_info *pbm = pcp->pbm;
675 struct pci_controller_info *p = pbm->parent;
676
677 if (!pbm->msi_num || !p->setup_msi_irq)
678 return;
679
680 return p->teardown_msi_irq(virt_irq, pdev);
681}
682#endif /* !(CONFIG_PCI_MSI) */
683
649#endif /* !(CONFIG_PCI) */ 684#endif /* !(CONFIG_PCI) */