|
@@ -394,13 +394,21 @@ union entry_union {
|
|
|
struct IO_APIC_route_entry entry;
|
|
|
};
|
|
|
|
|
|
+static struct IO_APIC_route_entry __ioapic_read_entry(int apic, int pin)
|
|
|
+{
|
|
|
+ union entry_union eu;
|
|
|
+
|
|
|
+ eu.w1 = io_apic_read(apic, 0x10 + 2 * pin);
|
|
|
+ eu.w2 = io_apic_read(apic, 0x11 + 2 * pin);
|
|
|
+ return eu.entry;
|
|
|
+}
|
|
|
+
|
|
|
static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
|
|
|
{
|
|
|
union entry_union eu;
|
|
|
unsigned long flags;
|
|
|
raw_spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
- eu.w1 = io_apic_read(apic, 0x10 + 2 * pin);
|
|
|
- eu.w2 = io_apic_read(apic, 0x11 + 2 * pin);
|
|
|
+ eu.entry = __ioapic_read_entry(apic, pin);
|
|
|
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
return eu.entry;
|
|
|
}
|
|
@@ -529,18 +537,6 @@ static void io_apic_modify_irq(struct irq_cfg *cfg,
|
|
|
__io_apic_modify_irq(entry, mask_and, mask_or, final);
|
|
|
}
|
|
|
|
|
|
-static void __mask_and_edge_IO_APIC_irq(struct irq_pin_list *entry)
|
|
|
-{
|
|
|
- __io_apic_modify_irq(entry, ~IO_APIC_REDIR_LEVEL_TRIGGER,
|
|
|
- IO_APIC_REDIR_MASKED, NULL);
|
|
|
-}
|
|
|
-
|
|
|
-static void __unmask_and_level_IO_APIC_irq(struct irq_pin_list *entry)
|
|
|
-{
|
|
|
- __io_apic_modify_irq(entry, ~IO_APIC_REDIR_MASKED,
|
|
|
- IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
|
|
|
-}
|
|
|
-
|
|
|
static void io_apic_sync(struct irq_pin_list *entry)
|
|
|
{
|
|
|
/*
|
|
@@ -585,6 +581,66 @@ static void unmask_ioapic_irq(struct irq_data *data)
|
|
|
unmask_ioapic(data->chip_data);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * IO-APIC versions below 0x20 don't support EOI register.
|
|
|
+ * For the record, here is the information about various versions:
|
|
|
+ * 0Xh 82489DX
|
|
|
+ * 1Xh I/OAPIC or I/O(x)APIC which are not PCI 2.2 Compliant
|
|
|
+ * 2Xh I/O(x)APIC which is PCI 2.2 Compliant
|
|
|
+ * 30h-FFh Reserved
|
|
|
+ *
|
|
|
+ * Some of the Intel ICH Specs (ICH2 to ICH5) documents the io-apic
|
|
|
+ * version as 0x2. This is an error with documentation and these ICH chips
|
|
|
+ * use io-apic's of version 0x20.
|
|
|
+ *
|
|
|
+ * For IO-APIC's with EOI register, we use that to do an explicit EOI.
|
|
|
+ * Otherwise, we simulate the EOI message manually by changing the trigger
|
|
|
+ * mode to edge and then back to level, with RTE being masked during this.
|
|
|
+ */
|
|
|
+static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg)
|
|
|
+{
|
|
|
+ if (mpc_ioapic_ver(apic) >= 0x20) {
|
|
|
+ /*
|
|
|
+ * Intr-remapping uses pin number as the virtual vector
|
|
|
+ * in the RTE. Actual vector is programmed in
|
|
|
+ * intr-remapping table entry. Hence for the io-apic
|
|
|
+ * EOI we use the pin number.
|
|
|
+ */
|
|
|
+ if (cfg && irq_remapped(cfg))
|
|
|
+ io_apic_eoi(apic, pin);
|
|
|
+ else
|
|
|
+ io_apic_eoi(apic, vector);
|
|
|
+ } else {
|
|
|
+ struct IO_APIC_route_entry entry, entry1;
|
|
|
+
|
|
|
+ entry = entry1 = __ioapic_read_entry(apic, pin);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Mask the entry and change the trigger mode to edge.
|
|
|
+ */
|
|
|
+ entry1.mask = 1;
|
|
|
+ entry1.trigger = IOAPIC_EDGE;
|
|
|
+
|
|
|
+ __ioapic_write_entry(apic, pin, entry1);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Restore the previous level triggered entry.
|
|
|
+ */
|
|
|
+ __ioapic_write_entry(apic, pin, entry);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
|
|
|
+{
|
|
|
+ struct irq_pin_list *entry;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ raw_spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
+ for_each_irq_pin(entry, cfg->irq_2_pin)
|
|
|
+ __eoi_ioapic_pin(entry->apic, entry->pin, cfg->vector, cfg);
|
|
|
+ raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
|
|
|
{
|
|
|
struct IO_APIC_route_entry entry;
|
|
@@ -593,10 +649,44 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
|
|
|
entry = ioapic_read_entry(apic, pin);
|
|
|
if (entry.delivery_mode == dest_SMI)
|
|
|
return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Make sure the entry is masked and re-read the contents to check
|
|
|
+ * if it is a level triggered pin and if the remote-IRR is set.
|
|
|
+ */
|
|
|
+ if (!entry.mask) {
|
|
|
+ entry.mask = 1;
|
|
|
+ ioapic_write_entry(apic, pin, entry);
|
|
|
+ entry = ioapic_read_entry(apic, pin);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (entry.irr) {
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Make sure the trigger mode is set to level. Explicit EOI
|
|
|
+ * doesn't clear the remote-IRR if the trigger mode is not
|
|
|
+ * set to level.
|
|
|
+ */
|
|
|
+ if (!entry.trigger) {
|
|
|
+ entry.trigger = IOAPIC_LEVEL;
|
|
|
+ ioapic_write_entry(apic, pin, entry);
|
|
|
+ }
|
|
|
+
|
|
|
+ raw_spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
+ __eoi_ioapic_pin(apic, pin, entry.vector, NULL);
|
|
|
+ raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
- * Disable it in the IO-APIC irq-routing table:
|
|
|
+ * Clear the rest of the bits in the IO-APIC RTE except for the mask
|
|
|
+ * bit.
|
|
|
*/
|
|
|
ioapic_mask_entry(apic, pin);
|
|
|
+ entry = ioapic_read_entry(apic, pin);
|
|
|
+ if (entry.irr)
|
|
|
+ printk(KERN_ERR "Unable to reset IRR for apic: %d, pin :%d\n",
|
|
|
+ mpc_ioapic_id(apic), pin);
|
|
|
}
|
|
|
|
|
|
static void clear_IO_APIC (void)
|
|
@@ -1202,7 +1292,6 @@ void __setup_vector_irq(int cpu)
|
|
|
}
|
|
|
|
|
|
static struct irq_chip ioapic_chip;
|
|
|
-static struct irq_chip ir_ioapic_chip;
|
|
|
|
|
|
#ifdef CONFIG_X86_32
|
|
|
static inline int IO_APIC_irq_trigger(int irq)
|
|
@@ -1246,7 +1335,7 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
|
|
|
|
|
|
if (irq_remapped(cfg)) {
|
|
|
irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
|
|
|
- chip = &ir_ioapic_chip;
|
|
|
+ irq_remap_modify_chip_defaults(chip);
|
|
|
fasteoi = trigger != 0;
|
|
|
}
|
|
|
|
|
@@ -2255,7 +2344,7 @@ ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
+#ifdef CONFIG_IRQ_REMAP
|
|
|
|
|
|
/*
|
|
|
* Migrate the IO-APIC irq in the presence of intr-remapping.
|
|
@@ -2267,6 +2356,9 @@ ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
|
|
* updated vector information), by using a virtual vector (io-apic pin number).
|
|
|
* Real vector that is used for interrupting cpu will be coming from
|
|
|
* the interrupt-remapping table entry.
|
|
|
+ *
|
|
|
+ * As the migration is a simple atomic update of IRTE, the same mechanism
|
|
|
+ * is used to migrate MSI irq's in the presence of interrupt-remapping.
|
|
|
*/
|
|
|
static int
|
|
|
ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
|
@@ -2291,10 +2383,16 @@ ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
|
|
irte.dest_id = IRTE_DEST(dest);
|
|
|
|
|
|
/*
|
|
|
- * Modified the IRTE and flushes the Interrupt entry cache.
|
|
|
+ * Atomically updates the IRTE with the new destination, vector
|
|
|
+ * and flushes the interrupt entry cache.
|
|
|
*/
|
|
|
modify_irte(irq, &irte);
|
|
|
|
|
|
+ /*
|
|
|
+ * After this point, all the interrupts will start arriving
|
|
|
+ * at the new destination. So, time to cleanup the previous
|
|
|
+ * vector allocation.
|
|
|
+ */
|
|
|
if (cfg->move_in_progress)
|
|
|
send_cleanup_vector(cfg);
|
|
|
|
|
@@ -2407,48 +2505,6 @@ static void ack_apic_edge(struct irq_data *data)
|
|
|
|
|
|
atomic_t irq_mis_count;
|
|
|
|
|
|
-/*
|
|
|
- * IO-APIC versions below 0x20 don't support EOI register.
|
|
|
- * For the record, here is the information about various versions:
|
|
|
- * 0Xh 82489DX
|
|
|
- * 1Xh I/OAPIC or I/O(x)APIC which are not PCI 2.2 Compliant
|
|
|
- * 2Xh I/O(x)APIC which is PCI 2.2 Compliant
|
|
|
- * 30h-FFh Reserved
|
|
|
- *
|
|
|
- * Some of the Intel ICH Specs (ICH2 to ICH5) documents the io-apic
|
|
|
- * version as 0x2. This is an error with documentation and these ICH chips
|
|
|
- * use io-apic's of version 0x20.
|
|
|
- *
|
|
|
- * For IO-APIC's with EOI register, we use that to do an explicit EOI.
|
|
|
- * Otherwise, we simulate the EOI message manually by changing the trigger
|
|
|
- * mode to edge and then back to level, with RTE being masked during this.
|
|
|
-*/
|
|
|
-static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
|
|
|
-{
|
|
|
- struct irq_pin_list *entry;
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- raw_spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
- for_each_irq_pin(entry, cfg->irq_2_pin) {
|
|
|
- if (mpc_ioapic_ver(entry->apic) >= 0x20) {
|
|
|
- /*
|
|
|
- * Intr-remapping uses pin number as the virtual vector
|
|
|
- * in the RTE. Actual vector is programmed in
|
|
|
- * intr-remapping table entry. Hence for the io-apic
|
|
|
- * EOI we use the pin number.
|
|
|
- */
|
|
|
- if (irq_remapped(cfg))
|
|
|
- io_apic_eoi(entry->apic, entry->pin);
|
|
|
- else
|
|
|
- io_apic_eoi(entry->apic, cfg->vector);
|
|
|
- } else {
|
|
|
- __mask_and_edge_IO_APIC_irq(entry);
|
|
|
- __unmask_and_level_IO_APIC_irq(entry);
|
|
|
- }
|
|
|
- }
|
|
|
- raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
-}
|
|
|
-
|
|
|
static void ack_apic_level(struct irq_data *data)
|
|
|
{
|
|
|
struct irq_cfg *cfg = data->chip_data;
|
|
@@ -2552,7 +2608,7 @@ static void ack_apic_level(struct irq_data *data)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
+#ifdef CONFIG_IRQ_REMAP
|
|
|
static void ir_ack_apic_edge(struct irq_data *data)
|
|
|
{
|
|
|
ack_APIC_irq();
|
|
@@ -2563,7 +2619,23 @@ static void ir_ack_apic_level(struct irq_data *data)
|
|
|
ack_APIC_irq();
|
|
|
eoi_ioapic_irq(data->irq, data->chip_data);
|
|
|
}
|
|
|
-#endif /* CONFIG_INTR_REMAP */
|
|
|
+
|
|
|
+static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
|
|
|
+{
|
|
|
+ seq_printf(p, " IR-%s", data->chip->name);
|
|
|
+}
|
|
|
+
|
|
|
+static void irq_remap_modify_chip_defaults(struct irq_chip *chip)
|
|
|
+{
|
|
|
+ chip->irq_print_chip = ir_print_prefix;
|
|
|
+ chip->irq_ack = ir_ack_apic_edge;
|
|
|
+ chip->irq_eoi = ir_ack_apic_level;
|
|
|
+
|
|
|
+#ifdef CONFIG_SMP
|
|
|
+ chip->irq_set_affinity = ir_ioapic_set_affinity;
|
|
|
+#endif
|
|
|
+}
|
|
|
+#endif /* CONFIG_IRQ_REMAP */
|
|
|
|
|
|
static struct irq_chip ioapic_chip __read_mostly = {
|
|
|
.name = "IO-APIC",
|
|
@@ -2578,21 +2650,6 @@ static struct irq_chip ioapic_chip __read_mostly = {
|
|
|
.irq_retrigger = ioapic_retrigger_irq,
|
|
|
};
|
|
|
|
|
|
-static struct irq_chip ir_ioapic_chip __read_mostly = {
|
|
|
- .name = "IR-IO-APIC",
|
|
|
- .irq_startup = startup_ioapic_irq,
|
|
|
- .irq_mask = mask_ioapic_irq,
|
|
|
- .irq_unmask = unmask_ioapic_irq,
|
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
- .irq_ack = ir_ack_apic_edge,
|
|
|
- .irq_eoi = ir_ack_apic_level,
|
|
|
-#ifdef CONFIG_SMP
|
|
|
- .irq_set_affinity = ir_ioapic_set_affinity,
|
|
|
-#endif
|
|
|
-#endif
|
|
|
- .irq_retrigger = ioapic_retrigger_irq,
|
|
|
-};
|
|
|
-
|
|
|
static inline void init_IO_APIC_traps(void)
|
|
|
{
|
|
|
struct irq_cfg *cfg;
|
|
@@ -3144,45 +3201,6 @@ msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
-/*
|
|
|
- * Migrate the MSI irq to another cpumask. This migration is
|
|
|
- * done in the process context using interrupt-remapping hardware.
|
|
|
- */
|
|
|
-static int
|
|
|
-ir_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
|
|
- bool force)
|
|
|
-{
|
|
|
- struct irq_cfg *cfg = data->chip_data;
|
|
|
- unsigned int dest, irq = data->irq;
|
|
|
- struct irte irte;
|
|
|
-
|
|
|
- if (get_irte(irq, &irte))
|
|
|
- return -1;
|
|
|
-
|
|
|
- if (__ioapic_set_affinity(data, mask, &dest))
|
|
|
- return -1;
|
|
|
-
|
|
|
- irte.vector = cfg->vector;
|
|
|
- irte.dest_id = IRTE_DEST(dest);
|
|
|
-
|
|
|
- /*
|
|
|
- * atomically update the IRTE with the new destination and vector.
|
|
|
- */
|
|
|
- modify_irte(irq, &irte);
|
|
|
-
|
|
|
- /*
|
|
|
- * After this point, all the interrupts will start arriving
|
|
|
- * at the new destination. So, time to cleanup the previous
|
|
|
- * vector allocation.
|
|
|
- */
|
|
|
- if (cfg->move_in_progress)
|
|
|
- send_cleanup_vector(cfg);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-#endif
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
|
|
/*
|
|
@@ -3200,19 +3218,6 @@ static struct irq_chip msi_chip = {
|
|
|
.irq_retrigger = ioapic_retrigger_irq,
|
|
|
};
|
|
|
|
|
|
-static struct irq_chip msi_ir_chip = {
|
|
|
- .name = "IR-PCI-MSI",
|
|
|
- .irq_unmask = unmask_msi_irq,
|
|
|
- .irq_mask = mask_msi_irq,
|
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
- .irq_ack = ir_ack_apic_edge,
|
|
|
-#ifdef CONFIG_SMP
|
|
|
- .irq_set_affinity = ir_msi_set_affinity,
|
|
|
-#endif
|
|
|
-#endif
|
|
|
- .irq_retrigger = ioapic_retrigger_irq,
|
|
|
-};
|
|
|
-
|
|
|
/*
|
|
|
* Map the PCI dev to the corresponding remapping hardware unit
|
|
|
* and allocate 'nvec' consecutive interrupt-remapping table entries
|
|
@@ -3255,7 +3260,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
|
|
|
|
|
|
if (irq_remapped(irq_get_chip_data(irq))) {
|
|
|
irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
|
|
|
- chip = &msi_ir_chip;
|
|
|
+ irq_remap_modify_chip_defaults(chip);
|
|
|
}
|
|
|
|
|
|
irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
|
|
@@ -3328,7 +3333,7 @@ void native_teardown_msi_irq(unsigned int irq)
|
|
|
destroy_irq(irq);
|
|
|
}
|
|
|
|
|
|
-#if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP)
|
|
|
+#ifdef CONFIG_DMAR_TABLE
|
|
|
#ifdef CONFIG_SMP
|
|
|
static int
|
|
|
dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
|
@@ -3409,19 +3414,6 @@ static int hpet_msi_set_affinity(struct irq_data *data,
|
|
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
|
|
-static struct irq_chip ir_hpet_msi_type = {
|
|
|
- .name = "IR-HPET_MSI",
|
|
|
- .irq_unmask = hpet_msi_unmask,
|
|
|
- .irq_mask = hpet_msi_mask,
|
|
|
-#ifdef CONFIG_INTR_REMAP
|
|
|
- .irq_ack = ir_ack_apic_edge,
|
|
|
-#ifdef CONFIG_SMP
|
|
|
- .irq_set_affinity = ir_msi_set_affinity,
|
|
|
-#endif
|
|
|
-#endif
|
|
|
- .irq_retrigger = ioapic_retrigger_irq,
|
|
|
-};
|
|
|
-
|
|
|
static struct irq_chip hpet_msi_type = {
|
|
|
.name = "HPET_MSI",
|
|
|
.irq_unmask = hpet_msi_unmask,
|
|
@@ -3458,7 +3450,7 @@ int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
|
|
|
hpet_msi_write(irq_get_handler_data(irq), &msg);
|
|
|
irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
|
|
|
if (irq_remapped(irq_get_chip_data(irq)))
|
|
|
- chip = &ir_hpet_msi_type;
|
|
|
+ irq_remap_modify_chip_defaults(chip);
|
|
|
|
|
|
irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
|
|
|
return 0;
|