diff options
Diffstat (limited to 'arch/x86/kernel/apic/io_apic.c')
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 180 |
1 files changed, 81 insertions, 99 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 7cbd397884f5..a951ef7decb1 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -2224,81 +2224,6 @@ void send_cleanup_vector(struct irq_cfg *cfg) | |||
2224 | cfg->move_in_progress = 0; | 2224 | cfg->move_in_progress = 0; |
2225 | } | 2225 | } |
2226 | 2226 | ||
2227 | static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg) | ||
2228 | { | ||
2229 | int apic, pin; | ||
2230 | struct irq_pin_list *entry; | ||
2231 | u8 vector = cfg->vector; | ||
2232 | |||
2233 | for_each_irq_pin(entry, cfg->irq_2_pin) { | ||
2234 | unsigned int reg; | ||
2235 | |||
2236 | apic = entry->apic; | ||
2237 | pin = entry->pin; | ||
2238 | /* | ||
2239 | * With interrupt-remapping, destination information comes | ||
2240 | * from interrupt-remapping table entry. | ||
2241 | */ | ||
2242 | if (!irq_remapped(cfg)) | ||
2243 | io_apic_write(apic, 0x11 + pin*2, dest); | ||
2244 | reg = io_apic_read(apic, 0x10 + pin*2); | ||
2245 | reg &= ~IO_APIC_REDIR_VECTOR_MASK; | ||
2246 | reg |= vector; | ||
2247 | io_apic_modify(apic, 0x10 + pin*2, reg); | ||
2248 | } | ||
2249 | } | ||
2250 | |||
2251 | /* | ||
2252 | * Either sets data->affinity to a valid value, and returns | ||
2253 | * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and | ||
2254 | * leaves data->affinity untouched. | ||
2255 | */ | ||
2256 | int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | ||
2257 | unsigned int *dest_id) | ||
2258 | { | ||
2259 | struct irq_cfg *cfg = data->chip_data; | ||
2260 | unsigned int irq = data->irq; | ||
2261 | int err; | ||
2262 | |||
2263 | if (!cpumask_intersects(mask, cpu_online_mask)) | ||
2264 | return -EINVAL; | ||
2265 | |||
2266 | err = assign_irq_vector(irq, cfg, mask); | ||
2267 | if (err) | ||
2268 | return err; | ||
2269 | |||
2270 | err = apic->cpu_mask_to_apicid_and(mask, cfg->domain, dest_id); | ||
2271 | if (err) { | ||
2272 | if (assign_irq_vector(irq, cfg, data->affinity)) | ||
2273 | pr_err("Failed to recover vector for irq %d\n", irq); | ||
2274 | return err; | ||
2275 | } | ||
2276 | |||
2277 | cpumask_copy(data->affinity, mask); | ||
2278 | |||
2279 | return 0; | ||
2280 | } | ||
2281 | |||
2282 | static int | ||
2283 | ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | ||
2284 | bool force) | ||
2285 | { | ||
2286 | unsigned int dest, irq = data->irq; | ||
2287 | unsigned long flags; | ||
2288 | int ret; | ||
2289 | |||
2290 | raw_spin_lock_irqsave(&ioapic_lock, flags); | ||
2291 | ret = __ioapic_set_affinity(data, mask, &dest); | ||
2292 | if (!ret) { | ||
2293 | /* Only the high 8 bits are valid. */ | ||
2294 | dest = SET_APIC_LOGICAL_ID(dest); | ||
2295 | __target_IO_APIC_irq(irq, dest, data->chip_data); | ||
2296 | ret = IRQ_SET_MASK_OK_NOCOPY; | ||
2297 | } | ||
2298 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2299 | return ret; | ||
2300 | } | ||
2301 | |||
2302 | asmlinkage void smp_irq_move_cleanup_interrupt(void) | 2227 | asmlinkage void smp_irq_move_cleanup_interrupt(void) |
2303 | { | 2228 | { |
2304 | unsigned vector, me; | 2229 | unsigned vector, me; |
@@ -2386,6 +2311,87 @@ void irq_force_complete_move(int irq) | |||
2386 | static inline void irq_complete_move(struct irq_cfg *cfg) { } | 2311 | static inline void irq_complete_move(struct irq_cfg *cfg) { } |
2387 | #endif | 2312 | #endif |
2388 | 2313 | ||
2314 | static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg) | ||
2315 | { | ||
2316 | int apic, pin; | ||
2317 | struct irq_pin_list *entry; | ||
2318 | u8 vector = cfg->vector; | ||
2319 | |||
2320 | for_each_irq_pin(entry, cfg->irq_2_pin) { | ||
2321 | unsigned int reg; | ||
2322 | |||
2323 | apic = entry->apic; | ||
2324 | pin = entry->pin; | ||
2325 | /* | ||
2326 | * With interrupt-remapping, destination information comes | ||
2327 | * from interrupt-remapping table entry. | ||
2328 | */ | ||
2329 | if (!irq_remapped(cfg)) | ||
2330 | io_apic_write(apic, 0x11 + pin*2, dest); | ||
2331 | reg = io_apic_read(apic, 0x10 + pin*2); | ||
2332 | reg &= ~IO_APIC_REDIR_VECTOR_MASK; | ||
2333 | reg |= vector; | ||
2334 | io_apic_modify(apic, 0x10 + pin*2, reg); | ||
2335 | } | ||
2336 | } | ||
2337 | |||
2338 | /* | ||
2339 | * Either sets data->affinity to a valid value, and returns | ||
2340 | * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and | ||
2341 | * leaves data->affinity untouched. | ||
2342 | */ | ||
2343 | int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | ||
2344 | unsigned int *dest_id) | ||
2345 | { | ||
2346 | struct irq_cfg *cfg = data->chip_data; | ||
2347 | unsigned int irq = data->irq; | ||
2348 | int err; | ||
2349 | |||
2350 | if (!config_enabled(CONFIG_SMP)) | ||
2351 | return -1; | ||
2352 | |||
2353 | if (!cpumask_intersects(mask, cpu_online_mask)) | ||
2354 | return -EINVAL; | ||
2355 | |||
2356 | err = assign_irq_vector(irq, cfg, mask); | ||
2357 | if (err) | ||
2358 | return err; | ||
2359 | |||
2360 | err = apic->cpu_mask_to_apicid_and(mask, cfg->domain, dest_id); | ||
2361 | if (err) { | ||
2362 | if (assign_irq_vector(irq, cfg, data->affinity)) | ||
2363 | pr_err("Failed to recover vector for irq %d\n", irq); | ||
2364 | return err; | ||
2365 | } | ||
2366 | |||
2367 | cpumask_copy(data->affinity, mask); | ||
2368 | |||
2369 | return 0; | ||
2370 | } | ||
2371 | |||
2372 | static int | ||
2373 | ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | ||
2374 | bool force) | ||
2375 | { | ||
2376 | unsigned int dest, irq = data->irq; | ||
2377 | unsigned long flags; | ||
2378 | int ret; | ||
2379 | |||
2380 | if (!config_enabled(CONFIG_SMP)) | ||
2381 | return -1; | ||
2382 | |||
2383 | raw_spin_lock_irqsave(&ioapic_lock, flags); | ||
2384 | ret = __ioapic_set_affinity(data, mask, &dest); | ||
2385 | if (!ret) { | ||
2386 | /* Only the high 8 bits are valid. */ | ||
2387 | dest = SET_APIC_LOGICAL_ID(dest); | ||
2388 | __target_IO_APIC_irq(irq, dest, data->chip_data); | ||
2389 | ret = IRQ_SET_MASK_OK_NOCOPY; | ||
2390 | } | ||
2391 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2392 | return ret; | ||
2393 | } | ||
2394 | |||
2389 | static void ack_apic_edge(struct irq_data *data) | 2395 | static void ack_apic_edge(struct irq_data *data) |
2390 | { | 2396 | { |
2391 | irq_complete_move(data->chip_data); | 2397 | irq_complete_move(data->chip_data); |
@@ -2565,9 +2571,7 @@ static void irq_remap_modify_chip_defaults(struct irq_chip *chip) | |||
2565 | chip->irq_ack = ir_ack_apic_edge; | 2571 | chip->irq_ack = ir_ack_apic_edge; |
2566 | chip->irq_eoi = ir_ack_apic_level; | 2572 | chip->irq_eoi = ir_ack_apic_level; |
2567 | 2573 | ||
2568 | #ifdef CONFIG_SMP | ||
2569 | chip->irq_set_affinity = set_remapped_irq_affinity; | 2574 | chip->irq_set_affinity = set_remapped_irq_affinity; |
2570 | #endif | ||
2571 | } | 2575 | } |
2572 | #endif /* CONFIG_IRQ_REMAP */ | 2576 | #endif /* CONFIG_IRQ_REMAP */ |
2573 | 2577 | ||
@@ -2578,9 +2582,7 @@ static struct irq_chip ioapic_chip __read_mostly = { | |||
2578 | .irq_unmask = unmask_ioapic_irq, | 2582 | .irq_unmask = unmask_ioapic_irq, |
2579 | .irq_ack = ack_apic_edge, | 2583 | .irq_ack = ack_apic_edge, |
2580 | .irq_eoi = ack_apic_level, | 2584 | .irq_eoi = ack_apic_level, |
2581 | #ifdef CONFIG_SMP | ||
2582 | .irq_set_affinity = ioapic_set_affinity, | 2585 | .irq_set_affinity = ioapic_set_affinity, |
2583 | #endif | ||
2584 | .irq_retrigger = ioapic_retrigger_irq, | 2586 | .irq_retrigger = ioapic_retrigger_irq, |
2585 | }; | 2587 | }; |
2586 | 2588 | ||
@@ -3099,7 +3101,6 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, | |||
3099 | return err; | 3101 | return err; |
3100 | } | 3102 | } |
3101 | 3103 | ||
3102 | #ifdef CONFIG_SMP | ||
3103 | static int | 3104 | static int |
3104 | msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) | 3105 | msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) |
3105 | { | 3106 | { |
@@ -3121,7 +3122,6 @@ msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) | |||
3121 | 3122 | ||
3122 | return IRQ_SET_MASK_OK_NOCOPY; | 3123 | return IRQ_SET_MASK_OK_NOCOPY; |
3123 | } | 3124 | } |
3124 | #endif /* CONFIG_SMP */ | ||
3125 | 3125 | ||
3126 | /* | 3126 | /* |
3127 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, | 3127 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, |
@@ -3132,9 +3132,7 @@ static struct irq_chip msi_chip = { | |||
3132 | .irq_unmask = unmask_msi_irq, | 3132 | .irq_unmask = unmask_msi_irq, |
3133 | .irq_mask = mask_msi_irq, | 3133 | .irq_mask = mask_msi_irq, |
3134 | .irq_ack = ack_apic_edge, | 3134 | .irq_ack = ack_apic_edge, |
3135 | #ifdef CONFIG_SMP | ||
3136 | .irq_set_affinity = msi_set_affinity, | 3135 | .irq_set_affinity = msi_set_affinity, |
3137 | #endif | ||
3138 | .irq_retrigger = ioapic_retrigger_irq, | 3136 | .irq_retrigger = ioapic_retrigger_irq, |
3139 | }; | 3137 | }; |
3140 | 3138 | ||
@@ -3219,7 +3217,6 @@ void native_teardown_msi_irq(unsigned int irq) | |||
3219 | } | 3217 | } |
3220 | 3218 | ||
3221 | #ifdef CONFIG_DMAR_TABLE | 3219 | #ifdef CONFIG_DMAR_TABLE |
3222 | #ifdef CONFIG_SMP | ||
3223 | static int | 3220 | static int |
3224 | dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, | 3221 | dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, |
3225 | bool force) | 3222 | bool force) |
@@ -3244,16 +3241,12 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, | |||
3244 | return IRQ_SET_MASK_OK_NOCOPY; | 3241 | return IRQ_SET_MASK_OK_NOCOPY; |
3245 | } | 3242 | } |
3246 | 3243 | ||
3247 | #endif /* CONFIG_SMP */ | ||
3248 | |||
3249 | static struct irq_chip dmar_msi_type = { | 3244 | static struct irq_chip dmar_msi_type = { |
3250 | .name = "DMAR_MSI", | 3245 | .name = "DMAR_MSI", |
3251 | .irq_unmask = dmar_msi_unmask, | 3246 | .irq_unmask = dmar_msi_unmask, |
3252 | .irq_mask = dmar_msi_mask, | 3247 | .irq_mask = dmar_msi_mask, |
3253 | .irq_ack = ack_apic_edge, | 3248 | .irq_ack = ack_apic_edge, |
3254 | #ifdef CONFIG_SMP | ||
3255 | .irq_set_affinity = dmar_msi_set_affinity, | 3249 | .irq_set_affinity = dmar_msi_set_affinity, |
3256 | #endif | ||
3257 | .irq_retrigger = ioapic_retrigger_irq, | 3250 | .irq_retrigger = ioapic_retrigger_irq, |
3258 | }; | 3251 | }; |
3259 | 3252 | ||
@@ -3274,7 +3267,6 @@ int arch_setup_dmar_msi(unsigned int irq) | |||
3274 | 3267 | ||
3275 | #ifdef CONFIG_HPET_TIMER | 3268 | #ifdef CONFIG_HPET_TIMER |
3276 | 3269 | ||
3277 | #ifdef CONFIG_SMP | ||
3278 | static int hpet_msi_set_affinity(struct irq_data *data, | 3270 | static int hpet_msi_set_affinity(struct irq_data *data, |
3279 | const struct cpumask *mask, bool force) | 3271 | const struct cpumask *mask, bool force) |
3280 | { | 3272 | { |
@@ -3297,16 +3289,12 @@ static int hpet_msi_set_affinity(struct irq_data *data, | |||
3297 | return IRQ_SET_MASK_OK_NOCOPY; | 3289 | return IRQ_SET_MASK_OK_NOCOPY; |
3298 | } | 3290 | } |
3299 | 3291 | ||
3300 | #endif /* CONFIG_SMP */ | ||
3301 | |||
3302 | static struct irq_chip hpet_msi_type = { | 3292 | static struct irq_chip hpet_msi_type = { |
3303 | .name = "HPET_MSI", | 3293 | .name = "HPET_MSI", |
3304 | .irq_unmask = hpet_msi_unmask, | 3294 | .irq_unmask = hpet_msi_unmask, |
3305 | .irq_mask = hpet_msi_mask, | 3295 | .irq_mask = hpet_msi_mask, |
3306 | .irq_ack = ack_apic_edge, | 3296 | .irq_ack = ack_apic_edge, |
3307 | #ifdef CONFIG_SMP | ||
3308 | .irq_set_affinity = hpet_msi_set_affinity, | 3297 | .irq_set_affinity = hpet_msi_set_affinity, |
3309 | #endif | ||
3310 | .irq_retrigger = ioapic_retrigger_irq, | 3298 | .irq_retrigger = ioapic_retrigger_irq, |
3311 | }; | 3299 | }; |
3312 | 3300 | ||
@@ -3341,8 +3329,6 @@ int arch_setup_hpet_msi(unsigned int irq, unsigned int id) | |||
3341 | */ | 3329 | */ |
3342 | #ifdef CONFIG_HT_IRQ | 3330 | #ifdef CONFIG_HT_IRQ |
3343 | 3331 | ||
3344 | #ifdef CONFIG_SMP | ||
3345 | |||
3346 | static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) | 3332 | static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) |
3347 | { | 3333 | { |
3348 | struct ht_irq_msg msg; | 3334 | struct ht_irq_msg msg; |
@@ -3370,16 +3356,12 @@ ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) | |||
3370 | return IRQ_SET_MASK_OK_NOCOPY; | 3356 | return IRQ_SET_MASK_OK_NOCOPY; |
3371 | } | 3357 | } |
3372 | 3358 | ||
3373 | #endif | ||
3374 | |||
3375 | static struct irq_chip ht_irq_chip = { | 3359 | static struct irq_chip ht_irq_chip = { |
3376 | .name = "PCI-HT", | 3360 | .name = "PCI-HT", |
3377 | .irq_mask = mask_ht_irq, | 3361 | .irq_mask = mask_ht_irq, |
3378 | .irq_unmask = unmask_ht_irq, | 3362 | .irq_unmask = unmask_ht_irq, |
3379 | .irq_ack = ack_apic_edge, | 3363 | .irq_ack = ack_apic_edge, |
3380 | #ifdef CONFIG_SMP | ||
3381 | .irq_set_affinity = ht_set_affinity, | 3364 | .irq_set_affinity = ht_set_affinity, |
3382 | #endif | ||
3383 | .irq_retrigger = ioapic_retrigger_irq, | 3365 | .irq_retrigger = ioapic_retrigger_irq, |
3384 | }; | 3366 | }; |
3385 | 3367 | ||