]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - arch/i386/kernel/io_apic.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/agpgart
[mirror_ubuntu-jammy-kernel.git] / arch / i386 / kernel / io_apic.c
index 03e7606be6e61f14b2e13b05e1373be902b4e2f0..350192d6ab986f70314abb98e7e2a68a04d0b9e7 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/module.h>
 #include <linux/sysdev.h>
 #include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/htirq.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -40,6 +42,7 @@
 #include <asm/i8259.h>
 #include <asm/nmi.h>
 #include <asm/msidef.h>
+#include <asm/hypertransport.h>
 
 #include <mach_apic.h>
 #include <mach_apicdef.h>
@@ -1181,8 +1184,8 @@ static int __assign_irq_vector(int irq)
 
        BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
 
-       if (IO_APIC_VECTOR(irq) > 0)
-               return IO_APIC_VECTOR(irq);
+       if (irq_vector[irq] > 0)
+               return irq_vector[irq];
 
        current_vector += 8;
        if (current_vector == SYSCALL_VECTOR)
@@ -1196,7 +1199,7 @@ static int __assign_irq_vector(int irq)
        }
 
        vector = current_vector;
-       IO_APIC_VECTOR(irq) = vector;
+       irq_vector[irq] = vector;
 
        return vector;
 }
@@ -1222,11 +1225,11 @@ static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
                        trigger == IOAPIC_LEVEL)
-               set_irq_chip_and_handler(irq, &ioapic_chip,
-                                        handle_fasteoi_irq);
+               set_irq_chip_and_handler_name(irq, &ioapic_chip,
+                                        handle_fasteoi_irq, "fasteoi");
        else
-               set_irq_chip_and_handler(irq, &ioapic_chip,
-                                        handle_edge_irq);
+               set_irq_chip_and_handler_name(irq, &ioapic_chip,
+                                        handle_edge_irq, "edge");
        set_intr_gate(vector, interrupt[irq]);
 }
 
@@ -1964,7 +1967,7 @@ static void ack_ioapic_quirk_irq(unsigned int irq)
  * operation to prevent an edge-triggered interrupt escaping meanwhile.
  * The idea is from Manfred Spraul.  --macro
  */
-       i = IO_APIC_VECTOR(irq);
+       i = irq_vector[irq];
 
        v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
 
@@ -1981,7 +1984,7 @@ static void ack_ioapic_quirk_irq(unsigned int irq)
 
 static int ioapic_retrigger_irq(unsigned int irq)
 {
-       send_IPI_self(IO_APIC_VECTOR(irq));
+       send_IPI_self(irq_vector[irq]);
 
        return 1;
 }
@@ -2017,7 +2020,7 @@ static inline void init_IO_APIC_traps(void)
         */
        for (irq = 0; irq < NR_IRQS ; irq++) {
                int tmp = irq;
-               if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
+               if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) {
                        /*
                         * Hmm.. We don't have an entry for this,
                         * so default to an old-fashioned 8259
@@ -2232,7 +2235,8 @@ static inline void check_timer(void)
        printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
        disable_8259A_irq(0);
-       set_irq_chip_and_handler(0, &lapic_chip, handle_fasteoi_irq);
+       set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq,
+                                     "fasteio");
        apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);   /* Fixed mode */
        enable_8259A_irq(0);
 
@@ -2407,9 +2411,8 @@ static int __init ioapic_init_sysfs(void)
 
 device_initcall(ioapic_init_sysfs);
 
-#ifdef CONFIG_PCI_MSI
 /*
- * Dynamic irq allocate and deallocation for MSI
+ * Dynamic irq allocate and deallocation
  */
 int create_irq(void)
 {
@@ -2448,17 +2451,13 @@ void destroy_irq(unsigned int irq)
        irq_vector[irq] = 0;
        spin_unlock_irqrestore(&vector_lock, flags);
 }
-#endif /* CONFIG_PCI_MSI */
 
 /*
  * MSI mesage composition
  */
 #ifdef CONFIG_PCI_MSI
-static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
 {
-       /* For now always this code always uses physical delivery
-        * mode.
-        */
        int vector;
        unsigned dest;
 
@@ -2488,35 +2487,163 @@ static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg
        return vector;
 }
 
-static void msi_msg_teardown(unsigned int irq)
+#ifdef CONFIG_SMP
+static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+       struct msi_msg msg;
+       unsigned int dest;
+       cpumask_t tmp;
+       int vector;
+
+       cpus_and(tmp, mask, cpu_online_map);
+       if (cpus_empty(tmp))
+               tmp = TARGET_CPUS;
+
+       vector = assign_irq_vector(irq);
+       if (vector < 0)
+               return;
+
+       dest = cpu_mask_to_apicid(mask);
+
+       read_msi_msg(irq, &msg);
+
+       msg.data &= ~MSI_DATA_VECTOR_MASK;
+       msg.data |= MSI_DATA_VECTOR(vector);
+       msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+       msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+       write_msi_msg(irq, &msg);
+       set_native_irq_info(irq, mask);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI or MSI-X Capability Structure.
+ */
+static struct irq_chip msi_chip = {
+       .name           = "PCI-MSI",
+       .unmask         = unmask_msi_irq,
+       .mask           = mask_msi_irq,
+       .ack            = ack_ioapic_irq,
+#ifdef CONFIG_SMP
+       .set_affinity   = set_msi_irq_affinity,
+#endif
+       .retrigger      = ioapic_retrigger_irq,
+};
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+{
+       struct msi_msg msg;
+       int ret;
+       ret = msi_compose_msg(dev, irq, &msg);
+       if (ret < 0)
+               return ret;
+
+       write_msi_msg(irq, &msg);
+
+       set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
+                                     "edge");
+
+       return 0;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
 {
        return;
 }
 
-static void msi_msg_set_affinity(unsigned int irq, cpumask_t mask, struct msi_msg *msg)
+#endif /* CONFIG_PCI_MSI */
+
+/*
+ * Hypertransport interrupt support
+ */
+#ifdef CONFIG_HT_IRQ
+
+#ifdef CONFIG_SMP
+
+static void target_ht_irq(unsigned int irq, unsigned int dest)
+{
+       u32 low, high;
+       low  = read_ht_irq_low(irq);
+       high = read_ht_irq_high(irq);
+
+       low  &= ~(HT_IRQ_LOW_DEST_ID_MASK);
+       high &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
+
+       low  |= HT_IRQ_LOW_DEST_ID(dest);
+       high |= HT_IRQ_HIGH_DEST_ID(dest);
+
+       write_ht_irq_low(irq, low);
+       write_ht_irq_high(irq, high);
+}
+
+static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
 {
-       int vector;
-       unsigned dest;
+       unsigned int dest;
+       cpumask_t tmp;
 
-       vector = assign_irq_vector(irq);
-       if (vector > 0) {
-               dest = cpu_mask_to_apicid(mask);
+       cpus_and(tmp, mask, cpu_online_map);
+       if (cpus_empty(tmp))
+               tmp = TARGET_CPUS;
 
-               msg->data &= ~MSI_DATA_VECTOR_MASK;
-               msg->data |= MSI_DATA_VECTOR(vector);
-               msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK;
-               msg->address_lo |= MSI_ADDR_DEST_ID(dest);
-       }
+       cpus_and(mask, tmp, CPU_MASK_ALL);
+
+       dest = cpu_mask_to_apicid(mask);
+
+       target_ht_irq(irq, dest);
+       set_native_irq_info(irq, mask);
 }
+#endif
 
-struct msi_ops arch_msi_ops = {
-       .needs_64bit_address = 0,
-       .setup = msi_msg_setup,
-       .teardown = msi_msg_teardown,
-       .target = msi_msg_set_affinity,
+static struct irq_chip ht_irq_chip = {
+       .name           = "PCI-HT",
+       .mask           = mask_ht_irq,
+       .unmask         = unmask_ht_irq,
+       .ack            = ack_ioapic_irq,
+#ifdef CONFIG_SMP
+       .set_affinity   = set_ht_irq_affinity,
+#endif
+       .retrigger      = ioapic_retrigger_irq,
 };
 
-#endif /* CONFIG_PCI_MSI */
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
+{
+       int vector;
+
+       vector = assign_irq_vector(irq);
+       if (vector >= 0) {
+               u32 low, high;
+               unsigned dest;
+               cpumask_t tmp;
+
+               cpus_clear(tmp);
+               cpu_set(vector >> 8, tmp);
+               dest = cpu_mask_to_apicid(tmp);
+
+               high =  HT_IRQ_HIGH_DEST_ID(dest);
+
+               low =   HT_IRQ_LOW_BASE |
+                       HT_IRQ_LOW_DEST_ID(dest) |
+                       HT_IRQ_LOW_VECTOR(vector) |
+                       ((INT_DEST_MODE == 0) ?
+                               HT_IRQ_LOW_DM_PHYSICAL :
+                               HT_IRQ_LOW_DM_LOGICAL) |
+                       HT_IRQ_LOW_RQEOI_EDGE |
+                       ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+                               HT_IRQ_LOW_MT_FIXED :
+                               HT_IRQ_LOW_MT_ARBITRATED) |
+                       HT_IRQ_LOW_IRQ_MASKED;
+
+               write_ht_irq_low(irq, low);
+               write_ht_irq_high(irq, high);
+
+               set_irq_chip_and_handler_name(irq, &ht_irq_chip,
+                                             handle_edge_irq, "edge");
+       }
+       return vector;
+}
+#endif /* CONFIG_HT_IRQ */
 
 /* --------------------------------------------------------------------------
                           ACPI-based IOAPIC Configuration