aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/io_apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/io_apic.c')
-rw-r--r--arch/i386/kernel/io_apic.c96
1 files changed, 78 insertions, 18 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 350192d6ab98..3b7a63e0ed1a 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -91,6 +91,46 @@ static struct irq_pin_list {
91 int apic, pin, next; 91 int apic, pin, next;
92} irq_2_pin[PIN_MAP_SIZE]; 92} irq_2_pin[PIN_MAP_SIZE];
93 93
94struct io_apic {
95 unsigned int index;
96 unsigned int unused[3];
97 unsigned int data;
98};
99
100static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
101{
102 return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx)
103 + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK);
104}
105
106static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
107{
108 struct io_apic __iomem *io_apic = io_apic_base(apic);
109 writel(reg, &io_apic->index);
110 return readl(&io_apic->data);
111}
112
113static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
114{
115 struct io_apic __iomem *io_apic = io_apic_base(apic);
116 writel(reg, &io_apic->index);
117 writel(value, &io_apic->data);
118}
119
120/*
121 * Re-write a value: to be used for read-modify-write
122 * cycles where the read already set up the index register.
123 *
124 * Older SiS APIC requires we rewrite the index register
125 */
126static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
127{
128 volatile struct io_apic *io_apic = io_apic_base(apic);
129 if (sis_apic_bug)
130 writel(reg, &io_apic->index);
131 writel(value, &io_apic->data);
132}
133
94union entry_union { 134union entry_union {
95 struct { u32 w1, w2; }; 135 struct { u32 w1, w2; };
96 struct IO_APIC_route_entry entry; 136 struct IO_APIC_route_entry entry;
@@ -107,12 +147,34 @@ static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
107 return eu.entry; 147 return eu.entry;
108} 148}
109 149
150/*
151 * When we write a new IO APIC routing entry, we need to write the high
152 * word first! If the mask bit in the low word is clear, we will enable
153 * the interrupt, and we need to make sure the entry is fully populated
154 * before that happens.
155 */
110static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) 156static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
111{ 157{
112 unsigned long flags; 158 unsigned long flags;
113 union entry_union eu; 159 union entry_union eu;
114 eu.entry = e; 160 eu.entry = e;
115 spin_lock_irqsave(&ioapic_lock, flags); 161 spin_lock_irqsave(&ioapic_lock, flags);
162 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
163 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
164 spin_unlock_irqrestore(&ioapic_lock, flags);
165}
166
167/*
168 * When we mask an IO APIC routing entry, we need to write the low
169 * word first, in order to set the mask bit before we change the
170 * high bits!
171 */
172static void ioapic_mask_entry(int apic, int pin)
173{
174 unsigned long flags;
175 union entry_union eu = { .entry.mask = 1 };
176
177 spin_lock_irqsave(&ioapic_lock, flags);
116 io_apic_write(apic, 0x10 + 2*pin, eu.w1); 178 io_apic_write(apic, 0x10 + 2*pin, eu.w1);
117 io_apic_write(apic, 0x11 + 2*pin, eu.w2); 179 io_apic_write(apic, 0x11 + 2*pin, eu.w2);
118 spin_unlock_irqrestore(&ioapic_lock, flags); 180 spin_unlock_irqrestore(&ioapic_lock, flags);
@@ -234,9 +296,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
234 /* 296 /*
235 * Disable it in the IO-APIC irq-routing table: 297 * Disable it in the IO-APIC irq-routing table:
236 */ 298 */
237 memset(&entry, 0, sizeof(entry)); 299 ioapic_mask_entry(apic, pin);
238 entry.mask = 1;
239 ioapic_write_entry(apic, pin, entry);
240} 300}
241 301
242static void clear_IO_APIC (void) 302static void clear_IO_APIC (void)
@@ -1227,9 +1287,11 @@ static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
1227 trigger == IOAPIC_LEVEL) 1287 trigger == IOAPIC_LEVEL)
1228 set_irq_chip_and_handler_name(irq, &ioapic_chip, 1288 set_irq_chip_and_handler_name(irq, &ioapic_chip,
1229 handle_fasteoi_irq, "fasteoi"); 1289 handle_fasteoi_irq, "fasteoi");
1230 else 1290 else {
1291 irq_desc[irq].status |= IRQ_DELAYED_DISABLE;
1231 set_irq_chip_and_handler_name(irq, &ioapic_chip, 1292 set_irq_chip_and_handler_name(irq, &ioapic_chip,
1232 handle_edge_irq, "edge"); 1293 handle_edge_irq, "edge");
1294 }
1233 set_intr_gate(vector, interrupt[irq]); 1295 set_intr_gate(vector, interrupt[irq]);
1234} 1296}
1235 1297
@@ -2564,18 +2626,16 @@ void arch_teardown_msi_irq(unsigned int irq)
2564 2626
2565static void target_ht_irq(unsigned int irq, unsigned int dest) 2627static void target_ht_irq(unsigned int irq, unsigned int dest)
2566{ 2628{
2567 u32 low, high; 2629 struct ht_irq_msg msg;
2568 low = read_ht_irq_low(irq); 2630 fetch_ht_irq_msg(irq, &msg);
2569 high = read_ht_irq_high(irq);
2570 2631
2571 low &= ~(HT_IRQ_LOW_DEST_ID_MASK); 2632 msg.address_lo &= ~(HT_IRQ_LOW_DEST_ID_MASK);
2572 high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); 2633 msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
2573 2634
2574 low |= HT_IRQ_LOW_DEST_ID(dest); 2635 msg.address_lo |= HT_IRQ_LOW_DEST_ID(dest);
2575 high |= HT_IRQ_HIGH_DEST_ID(dest); 2636 msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
2576 2637
2577 write_ht_irq_low(irq, low); 2638 write_ht_irq_msg(irq, &msg);
2578 write_ht_irq_high(irq, high);
2579} 2639}
2580 2640
2581static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) 2641static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
@@ -2613,7 +2673,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
2613 2673
2614 vector = assign_irq_vector(irq); 2674 vector = assign_irq_vector(irq);
2615 if (vector >= 0) { 2675 if (vector >= 0) {
2616 u32 low, high; 2676 struct ht_irq_msg msg;
2617 unsigned dest; 2677 unsigned dest;
2618 cpumask_t tmp; 2678 cpumask_t tmp;
2619 2679
@@ -2621,9 +2681,10 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
2621 cpu_set(vector >> 8, tmp); 2681 cpu_set(vector >> 8, tmp);
2622 dest = cpu_mask_to_apicid(tmp); 2682 dest = cpu_mask_to_apicid(tmp);
2623 2683
2624 high = HT_IRQ_HIGH_DEST_ID(dest); 2684 msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
2625 2685
2626 low = HT_IRQ_LOW_BASE | 2686 msg.address_lo =
2687 HT_IRQ_LOW_BASE |
2627 HT_IRQ_LOW_DEST_ID(dest) | 2688 HT_IRQ_LOW_DEST_ID(dest) |
2628 HT_IRQ_LOW_VECTOR(vector) | 2689 HT_IRQ_LOW_VECTOR(vector) |
2629 ((INT_DEST_MODE == 0) ? 2690 ((INT_DEST_MODE == 0) ?
@@ -2635,8 +2696,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
2635 HT_IRQ_LOW_MT_ARBITRATED) | 2696 HT_IRQ_LOW_MT_ARBITRATED) |
2636 HT_IRQ_LOW_IRQ_MASKED; 2697 HT_IRQ_LOW_IRQ_MASKED;
2637 2698
2638 write_ht_irq_low(irq, low); 2699 write_ht_irq_msg(irq, &msg);
2639 write_ht_irq_high(irq, high);
2640 2700
2641 set_irq_chip_and_handler_name(irq, &ht_irq_chip, 2701 set_irq_chip_and_handler_name(irq, &ht_irq_chip,
2642 handle_edge_irq, "edge"); 2702 handle_edge_irq, "edge");