diff options
| -rw-r--r-- | arch/x86_64/kernel/io_apic.c | 72 | ||||
| -rw-r--r-- | include/asm-x86_64/io_apic.h | 34 |
2 files changed, 69 insertions, 37 deletions
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index fe429e5d6b29..3b8f9c68ad3c 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c | |||
| @@ -88,6 +88,52 @@ static struct irq_pin_list { | |||
| 88 | short apic, pin, next; | 88 | short apic, pin, next; |
| 89 | } irq_2_pin[PIN_MAP_SIZE]; | 89 | } irq_2_pin[PIN_MAP_SIZE]; |
| 90 | 90 | ||
| 91 | struct io_apic { | ||
| 92 | unsigned int index; | ||
| 93 | unsigned int unused[3]; | ||
| 94 | unsigned int data; | ||
| 95 | }; | ||
| 96 | |||
| 97 | static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) | ||
| 98 | { | ||
| 99 | return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx) | ||
| 100 | + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK); | ||
| 101 | } | ||
| 102 | |||
| 103 | static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) | ||
| 104 | { | ||
| 105 | struct io_apic __iomem *io_apic = io_apic_base(apic); | ||
| 106 | writel(reg, &io_apic->index); | ||
| 107 | return readl(&io_apic->data); | ||
| 108 | } | ||
| 109 | |||
| 110 | static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) | ||
| 111 | { | ||
| 112 | struct io_apic __iomem *io_apic = io_apic_base(apic); | ||
| 113 | writel(reg, &io_apic->index); | ||
| 114 | writel(value, &io_apic->data); | ||
| 115 | } | ||
| 116 | |||
| 117 | /* | ||
| 118 | * Re-write a value: to be used for read-modify-write | ||
| 119 | * cycles where the read already set up the index register. | ||
| 120 | */ | ||
| 121 | static inline void io_apic_modify(unsigned int apic, unsigned int value) | ||
| 122 | { | ||
| 123 | struct io_apic __iomem *io_apic = io_apic_base(apic); | ||
| 124 | writel(value, &io_apic->data); | ||
| 125 | } | ||
| 126 | |||
| 127 | /* | ||
| 128 | * Synchronize the IO-APIC and the CPU by doing | ||
| 129 | * a dummy read from the IO-APIC | ||
| 130 | */ | ||
| 131 | static inline void io_apic_sync(unsigned int apic) | ||
| 132 | { | ||
| 133 | struct io_apic __iomem *io_apic = io_apic_base(apic); | ||
| 134 | readl(&io_apic->data); | ||
| 135 | } | ||
| 136 | |||
| 91 | #define __DO_ACTION(R, ACTION, FINAL) \ | 137 | #define __DO_ACTION(R, ACTION, FINAL) \ |
| 92 | \ | 138 | \ |
| 93 | { \ | 139 | { \ |
| @@ -126,12 +172,34 @@ static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin) | |||
| 126 | return eu.entry; | 172 | return eu.entry; |
| 127 | } | 173 | } |
| 128 | 174 | ||
| 175 | /* | ||
| 176 | * When we write a new IO APIC routing entry, we need to write the high | ||
| 177 | * word first! If the mask bit in the low word is clear, we will enable | ||
| 178 | * the interrupt, and we need to make sure the entry is fully populated | ||
| 179 | * before that happens. | ||
| 180 | */ | ||
| 129 | static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) | 181 | static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) |
| 130 | { | 182 | { |
| 131 | unsigned long flags; | 183 | unsigned long flags; |
| 132 | union entry_union eu; | 184 | union entry_union eu; |
| 133 | eu.entry = e; | 185 | eu.entry = e; |
| 134 | spin_lock_irqsave(&ioapic_lock, flags); | 186 | spin_lock_irqsave(&ioapic_lock, flags); |
| 187 | io_apic_write(apic, 0x11 + 2*pin, eu.w2); | ||
| 188 | io_apic_write(apic, 0x10 + 2*pin, eu.w1); | ||
| 189 | spin_unlock_irqrestore(&ioapic_lock, flags); | ||
| 190 | } | ||
| 191 | |||
| 192 | /* | ||
| 193 | * When we mask an IO APIC routing entry, we need to write the low | ||
| 194 | * word first, in order to set the mask bit before we change the | ||
| 195 | * high bits! | ||
| 196 | */ | ||
| 197 | static void ioapic_mask_entry(int apic, int pin) | ||
| 198 | { | ||
| 199 | unsigned long flags; | ||
| 200 | union entry_union eu = { .entry.mask = 1 }; | ||
| 201 | |||
| 202 | spin_lock_irqsave(&ioapic_lock, flags); | ||
| 135 | io_apic_write(apic, 0x10 + 2*pin, eu.w1); | 203 | io_apic_write(apic, 0x10 + 2*pin, eu.w1); |
| 136 | io_apic_write(apic, 0x11 + 2*pin, eu.w2); | 204 | io_apic_write(apic, 0x11 + 2*pin, eu.w2); |
| 137 | spin_unlock_irqrestore(&ioapic_lock, flags); | 205 | spin_unlock_irqrestore(&ioapic_lock, flags); |
| @@ -256,9 +324,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) | |||
| 256 | /* | 324 | /* |
| 257 | * Disable it in the IO-APIC irq-routing table: | 325 | * Disable it in the IO-APIC irq-routing table: |
| 258 | */ | 326 | */ |
| 259 | memset(&entry, 0, sizeof(entry)); | 327 | ioapic_mask_entry(apic, pin); |
| 260 | entry.mask = 1; | ||
| 261 | ioapic_write_entry(apic, pin, entry); | ||
| 262 | } | 328 | } |
| 263 | 329 | ||
| 264 | static void clear_IO_APIC (void) | 330 | static void clear_IO_APIC (void) |
diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h index 171ec2dc8c04..561ecbfd4cb5 100644 --- a/include/asm-x86_64/io_apic.h +++ b/include/asm-x86_64/io_apic.h | |||
| @@ -12,10 +12,6 @@ | |||
| 12 | 12 | ||
| 13 | #define APIC_MISMATCH_DEBUG | 13 | #define APIC_MISMATCH_DEBUG |
| 14 | 14 | ||
| 15 | #define IO_APIC_BASE(idx) \ | ||
| 16 | ((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \ | ||
| 17 | + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK))) | ||
| 18 | |||
| 19 | /* | 15 | /* |
| 20 | * The structure of the IO-APIC: | 16 | * The structure of the IO-APIC: |
| 21 | */ | 17 | */ |
| @@ -119,36 +115,6 @@ extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; | |||
| 119 | /* non-0 if default (table-less) MP configuration */ | 115 | /* non-0 if default (table-less) MP configuration */ |
| 120 | extern int mpc_default_type; | 116 | extern int mpc_default_type; |
| 121 | 117 | ||
| 122 | static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) | ||
| 123 | { | ||
| 124 | *IO_APIC_BASE(apic) = reg; | ||
| 125 | return *(IO_APIC_BASE(apic)+4); | ||
| 126 | } | ||
| 127 | |||
| 128 | static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) | ||
| 129 | { | ||
| 130 | *IO_APIC_BASE(apic) = reg; | ||
| 131 | *(IO_APIC_BASE(apic)+4) = value; | ||
| 132 | } | ||
| 133 | |||
| 134 | /* | ||
| 135 | * Re-write a value: to be used for read-modify-write | ||
| 136 | * cycles where the read already set up the index register. | ||
| 137 | */ | ||
| 138 | static inline void io_apic_modify(unsigned int apic, unsigned int value) | ||
| 139 | { | ||
| 140 | *(IO_APIC_BASE(apic)+4) = value; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* | ||
| 144 | * Synchronize the IO-APIC and the CPU by doing | ||
| 145 | * a dummy read from the IO-APIC | ||
| 146 | */ | ||
| 147 | static inline void io_apic_sync(unsigned int apic) | ||
| 148 | { | ||
| 149 | (void) *(IO_APIC_BASE(apic)+4); | ||
| 150 | } | ||
| 151 | |||
| 152 | /* 1 if "noapic" boot option passed */ | 118 | /* 1 if "noapic" boot option passed */ |
| 153 | extern int skip_ioapic_setup; | 119 | extern int skip_ioapic_setup; |
| 154 | 120 | ||
