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.c115
1 files changed, 89 insertions, 26 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index cd082c36ca03..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)
@@ -1225,11 +1285,13 @@ static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
1225{ 1285{
1226 if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || 1286 if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
1227 trigger == IOAPIC_LEVEL) 1287 trigger == IOAPIC_LEVEL)
1228 set_irq_chip_and_handler(irq, &ioapic_chip, 1288 set_irq_chip_and_handler_name(irq, &ioapic_chip,
1229 handle_fasteoi_irq); 1289 handle_fasteoi_irq, "fasteoi");
1230 else 1290 else {
1231 set_irq_chip_and_handler(irq, &ioapic_chip, 1291 irq_desc[irq].status |= IRQ_DELAYED_DISABLE;
1232 handle_edge_irq); 1292 set_irq_chip_and_handler_name(irq, &ioapic_chip,
1293 handle_edge_irq, "edge");
1294 }
1233 set_intr_gate(vector, interrupt[irq]); 1295 set_intr_gate(vector, interrupt[irq]);
1234} 1296}
1235 1297
@@ -2235,7 +2297,8 @@ static inline void check_timer(void)
2235 printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); 2297 printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
2236 2298
2237 disable_8259A_irq(0); 2299 disable_8259A_irq(0);
2238 set_irq_chip_and_handler(0, &lapic_chip, handle_fasteoi_irq); 2300 set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq,
2301 "fasteio");
2239 apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ 2302 apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
2240 enable_8259A_irq(0); 2303 enable_8259A_irq(0);
2241 2304
@@ -2541,7 +2604,8 @@ int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
2541 2604
2542 write_msi_msg(irq, &msg); 2605 write_msi_msg(irq, &msg);
2543 2606
2544 set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq); 2607 set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
2608 "edge");
2545 2609
2546 return 0; 2610 return 0;
2547} 2611}
@@ -2562,18 +2626,16 @@ void arch_teardown_msi_irq(unsigned int irq)
2562 2626
2563static void target_ht_irq(unsigned int irq, unsigned int dest) 2627static void target_ht_irq(unsigned int irq, unsigned int dest)
2564{ 2628{
2565 u32 low, high; 2629 struct ht_irq_msg msg;
2566 low = read_ht_irq_low(irq); 2630 fetch_ht_irq_msg(irq, &msg);
2567 high = read_ht_irq_high(irq);
2568 2631
2569 low &= ~(HT_IRQ_LOW_DEST_ID_MASK); 2632 msg.address_lo &= ~(HT_IRQ_LOW_DEST_ID_MASK);
2570 high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); 2633 msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
2571 2634
2572 low |= HT_IRQ_LOW_DEST_ID(dest); 2635 msg.address_lo |= HT_IRQ_LOW_DEST_ID(dest);
2573 high |= HT_IRQ_HIGH_DEST_ID(dest); 2636 msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
2574 2637
2575 write_ht_irq_low(irq, low); 2638 write_ht_irq_msg(irq, &msg);
2576 write_ht_irq_high(irq, high);
2577} 2639}
2578 2640
2579static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) 2641static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
@@ -2594,7 +2656,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
2594} 2656}
2595#endif 2657#endif
2596 2658
2597static struct hw_interrupt_type ht_irq_chip = { 2659static struct irq_chip ht_irq_chip = {
2598 .name = "PCI-HT", 2660 .name = "PCI-HT",
2599 .mask = mask_ht_irq, 2661 .mask = mask_ht_irq,
2600 .unmask = unmask_ht_irq, 2662 .unmask = unmask_ht_irq,
@@ -2611,7 +2673,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
2611 2673
2612 vector = assign_irq_vector(irq); 2674 vector = assign_irq_vector(irq);
2613 if (vector >= 0) { 2675 if (vector >= 0) {
2614 u32 low, high; 2676 struct ht_irq_msg msg;
2615 unsigned dest; 2677 unsigned dest;
2616 cpumask_t tmp; 2678 cpumask_t tmp;
2617 2679
@@ -2619,9 +2681,10 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
2619 cpu_set(vector >> 8, tmp); 2681 cpu_set(vector >> 8, tmp);
2620 dest = cpu_mask_to_apicid(tmp); 2682 dest = cpu_mask_to_apicid(tmp);
2621 2683
2622 high = HT_IRQ_HIGH_DEST_ID(dest); 2684 msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
2623 2685
2624 low = HT_IRQ_LOW_BASE | 2686 msg.address_lo =
2687 HT_IRQ_LOW_BASE |
2625 HT_IRQ_LOW_DEST_ID(dest) | 2688 HT_IRQ_LOW_DEST_ID(dest) |
2626 HT_IRQ_LOW_VECTOR(vector) | 2689 HT_IRQ_LOW_VECTOR(vector) |
2627 ((INT_DEST_MODE == 0) ? 2690 ((INT_DEST_MODE == 0) ?
@@ -2633,10 +2696,10 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
2633 HT_IRQ_LOW_MT_ARBITRATED) | 2696 HT_IRQ_LOW_MT_ARBITRATED) |
2634 HT_IRQ_LOW_IRQ_MASKED; 2697 HT_IRQ_LOW_IRQ_MASKED;
2635 2698
2636 write_ht_irq_low(irq, low); 2699 write_ht_irq_msg(irq, &msg);
2637 write_ht_irq_high(irq, high);
2638 2700
2639 set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq); 2701 set_irq_chip_and_handler_name(irq, &ht_irq_chip,
2702 handle_edge_irq, "edge");
2640 } 2703 }
2641 return vector; 2704 return vector;
2642} 2705}