diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-10-04 05:16:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 10:55:29 -0400 |
commit | 8b955b0dddb35e398b07e217a81f8bd49400796f (patch) | |
tree | 6fc307371b6889ac08fa5a7187cde1c137c8d765 /arch/x86_64/kernel/io_apic.c | |
parent | e78d01693be38bf93dd6bb49b86e143da450de86 (diff) |
[PATCH] Initial generic hypertransport interrupt support
This patch implements two functions ht_create_irq and ht_destroy_irq for
use by drivers. Several other functions are implemented as helpers for
arch specific irq_chip handlers.
The driver for the card I tested this on isn't yet ready to be merged.
However this code is and hypertransport irqs are in use in a few other
places in the kernel. Not that any of this will get merged before 2.6.19
Because the ipath-ht400 is slightly out of spec this code will need to be
generalized to work there.
I think all of the powerpc uses are for a plain interrupt controller in a
chipset so support for native hypertransport devices is a little less
interesting.
However I think this is a half way decent model on how to separate arch
specific and generic helper code, and I think this is a functional model of
how to get the architecture dependencies out of the msi code.
[akpm@osdl.org: Kconfig fix]
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Greg KH <greg@kroah.com>
Cc: Andi Kleen <ak@muc.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64/kernel/io_apic.c')
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 7cc29b50b0c1..31c270fee337 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <asm/dma.h> | 43 | #include <asm/dma.h> |
44 | #include <asm/nmi.h> | 44 | #include <asm/nmi.h> |
45 | #include <asm/msidef.h> | 45 | #include <asm/msidef.h> |
46 | #include <asm/hypertransport.h> | ||
46 | 47 | ||
47 | static int assign_irq_vector(int irq, cpumask_t mask); | 48 | static int assign_irq_vector(int irq, cpumask_t mask); |
48 | 49 | ||
@@ -1772,6 +1773,101 @@ struct msi_ops arch_msi_ops = { | |||
1772 | 1773 | ||
1773 | #endif | 1774 | #endif |
1774 | 1775 | ||
1776 | /* | ||
1777 | * Hypertransport interrupt support | ||
1778 | */ | ||
1779 | #ifdef CONFIG_HT_IRQ | ||
1780 | |||
1781 | #ifdef CONFIG_SMP | ||
1782 | |||
1783 | static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) | ||
1784 | { | ||
1785 | u32 low, high; | ||
1786 | low = read_ht_irq_low(irq); | ||
1787 | high = read_ht_irq_high(irq); | ||
1788 | |||
1789 | low &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK); | ||
1790 | high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); | ||
1791 | |||
1792 | low |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest); | ||
1793 | high |= HT_IRQ_HIGH_DEST_ID(dest); | ||
1794 | |||
1795 | write_ht_irq_low(irq, low); | ||
1796 | write_ht_irq_high(irq, high); | ||
1797 | } | ||
1798 | |||
1799 | static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) | ||
1800 | { | ||
1801 | unsigned int dest; | ||
1802 | cpumask_t tmp; | ||
1803 | int vector; | ||
1804 | |||
1805 | cpus_and(tmp, mask, cpu_online_map); | ||
1806 | if (cpus_empty(tmp)) | ||
1807 | tmp = TARGET_CPUS; | ||
1808 | |||
1809 | cpus_and(mask, tmp, CPU_MASK_ALL); | ||
1810 | |||
1811 | vector = assign_irq_vector(irq, mask); | ||
1812 | if (vector < 0) | ||
1813 | return; | ||
1814 | |||
1815 | cpus_clear(tmp); | ||
1816 | cpu_set(vector >> 8, tmp); | ||
1817 | dest = cpu_mask_to_apicid(tmp); | ||
1818 | |||
1819 | target_ht_irq(irq, dest, vector & 0xff); | ||
1820 | set_native_irq_info(irq, mask); | ||
1821 | } | ||
1822 | #endif | ||
1823 | |||
1824 | static struct hw_interrupt_type ht_irq_chip = { | ||
1825 | .name = "PCI-HT", | ||
1826 | .mask = mask_ht_irq, | ||
1827 | .unmask = unmask_ht_irq, | ||
1828 | .ack = ack_apic_edge, | ||
1829 | #ifdef CONFIG_SMP | ||
1830 | .set_affinity = set_ht_irq_affinity, | ||
1831 | #endif | ||
1832 | .retrigger = ioapic_retrigger_irq, | ||
1833 | }; | ||
1834 | |||
1835 | int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) | ||
1836 | { | ||
1837 | int vector; | ||
1838 | |||
1839 | vector = assign_irq_vector(irq, TARGET_CPUS); | ||
1840 | if (vector >= 0) { | ||
1841 | u32 low, high; | ||
1842 | unsigned dest; | ||
1843 | cpumask_t tmp; | ||
1844 | |||
1845 | cpus_clear(tmp); | ||
1846 | cpu_set(vector >> 8, tmp); | ||
1847 | dest = cpu_mask_to_apicid(tmp); | ||
1848 | |||
1849 | high = HT_IRQ_HIGH_DEST_ID(dest); | ||
1850 | |||
1851 | low = HT_IRQ_LOW_BASE | | ||
1852 | HT_IRQ_LOW_DEST_ID(dest) | | ||
1853 | HT_IRQ_LOW_VECTOR(vector) | | ||
1854 | ((INT_DEST_MODE == 0) ? | ||
1855 | HT_IRQ_LOW_DM_PHYSICAL : | ||
1856 | HT_IRQ_LOW_DM_LOGICAL) | | ||
1857 | HT_IRQ_LOW_RQEOI_EDGE | | ||
1858 | ((INT_DELIVERY_MODE != dest_LowestPrio) ? | ||
1859 | HT_IRQ_LOW_MT_FIXED : | ||
1860 | HT_IRQ_LOW_MT_ARBITRATED); | ||
1861 | |||
1862 | write_ht_irq_low(irq, low); | ||
1863 | write_ht_irq_high(irq, high); | ||
1864 | |||
1865 | set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq); | ||
1866 | } | ||
1867 | return vector; | ||
1868 | } | ||
1869 | #endif /* CONFIG_HT_IRQ */ | ||
1870 | |||
1775 | /* -------------------------------------------------------------------------- | 1871 | /* -------------------------------------------------------------------------- |
1776 | ACPI-based IOAPIC Configuration | 1872 | ACPI-based IOAPIC Configuration |
1777 | -------------------------------------------------------------------------- */ | 1873 | -------------------------------------------------------------------------- */ |