aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2009-03-16 20:05:01 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2009-03-17 18:44:27 -0400
commit0280f7c416c652a2fd95d166f52b199ae61122c0 (patch)
treeea932eec97b8852c047fdbd9e33b8e7c73a8f4a8 /arch
parentcf6567fe40c55e9cffca7355cd34e50fb2871e4e (diff)
x86, x2apic: cleanup the IO-APIC level migration with interrupt-remapping
Impact: simplification In the current code, for level triggered migration, we need to modify the io-apic RTE with the update vector information, along with modifying interrupt remapping table entry(IRTE) with vector and destination. This is to ensure that remote IRR bit inthe IOAPIC RTE gets cleared when the cpu does EOI. With this patch, for level triggered, we eliminate the io-apic RTE modification (with the 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. Trigger mode in the IRTE will always be edge, and the actual level or edge trigger will be setup in the IO-APIC RTE. So a level triggered interrupt will appear as an edge to the local apic cpu but still as level to the IO-APIC. With this change, level irq migration can be done by simply modifying the interrupt-remapping table entry with out changing the io-apic RTE. And as the interrupt appears as edge at the cpu, in addition to do the local apic EOI, we need to do IO-APIC directed EOI to clear the remote IRR bit in the IO-APIC RTE. This simplies the irq migration in the presence of interrupt-remapping. Idea-by: Rajesh Sankaran <rajesh.sankaran@intel.com> Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/io_apic.h2
-rw-r--r--arch/x86/kernel/apic/io_apic.c156
2 files changed, 66 insertions, 92 deletions
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 59cb4a1317b..ffcd08f96e4 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -172,7 +172,7 @@ extern void probe_nr_irqs_gsi(void);
172extern int setup_ioapic_entry(int apic, int irq, 172extern int setup_ioapic_entry(int apic, int irq,
173 struct IO_APIC_route_entry *entry, 173 struct IO_APIC_route_entry *entry,
174 unsigned int destination, int trigger, 174 unsigned int destination, int trigger,
175 int polarity, int vector); 175 int polarity, int vector, int pin);
176extern void ioapic_write_entry(int apic, int pin, 176extern void ioapic_write_entry(int apic, int pin,
177 struct IO_APIC_route_entry e); 177 struct IO_APIC_route_entry e);
178#else /* !CONFIG_X86_IO_APIC */ 178#else /* !CONFIG_X86_IO_APIC */
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 4d975d0e358..e074eac5bd3 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -389,6 +389,8 @@ struct io_apic {
389 unsigned int index; 389 unsigned int index;
390 unsigned int unused[3]; 390 unsigned int unused[3];
391 unsigned int data; 391 unsigned int data;
392 unsigned int unused2[11];
393 unsigned int eoi;
392}; 394};
393 395
394static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) 396static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
@@ -397,6 +399,12 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
397 + (mp_ioapics[idx].apicaddr & ~PAGE_MASK); 399 + (mp_ioapics[idx].apicaddr & ~PAGE_MASK);
398} 400}
399 401
402static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
403{
404 struct io_apic __iomem *io_apic = io_apic_base(apic);
405 writel(vector, &io_apic->eoi);
406}
407
400static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) 408static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
401{ 409{
402 struct io_apic __iomem *io_apic = io_apic_base(apic); 410 struct io_apic __iomem *io_apic = io_apic_base(apic);
@@ -1478,7 +1486,7 @@ static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long t
1478int setup_ioapic_entry(int apic_id, int irq, 1486int setup_ioapic_entry(int apic_id, int irq,
1479 struct IO_APIC_route_entry *entry, 1487 struct IO_APIC_route_entry *entry,
1480 unsigned int destination, int trigger, 1488 unsigned int destination, int trigger,
1481 int polarity, int vector) 1489 int polarity, int vector, int pin)
1482{ 1490{
1483 /* 1491 /*
1484 * add it to the IO-APIC irq-routing table: 1492 * add it to the IO-APIC irq-routing table:
@@ -1504,7 +1512,14 @@ int setup_ioapic_entry(int apic_id, int irq,
1504 1512
1505 irte.present = 1; 1513 irte.present = 1;
1506 irte.dst_mode = apic->irq_dest_mode; 1514 irte.dst_mode = apic->irq_dest_mode;
1507 irte.trigger_mode = trigger; 1515 /*
1516 * Trigger mode in the IRTE will always be edge, and the
1517 * actual level or edge trigger will be setup in the IO-APIC
1518 * RTE. This will help simplify level triggered irq migration.
1519 * For more details, see the comments above explainig IO-APIC
1520 * irq migration in the presence of interrupt-remapping.
1521 */
1522 irte.trigger_mode = 0;
1508 irte.dlvry_mode = apic->irq_delivery_mode; 1523 irte.dlvry_mode = apic->irq_delivery_mode;
1509 irte.vector = vector; 1524 irte.vector = vector;
1510 irte.dest_id = IRTE_DEST(destination); 1525 irte.dest_id = IRTE_DEST(destination);
@@ -1515,18 +1530,23 @@ int setup_ioapic_entry(int apic_id, int irq,
1515 ir_entry->zero = 0; 1530 ir_entry->zero = 0;
1516 ir_entry->format = 1; 1531 ir_entry->format = 1;
1517 ir_entry->index = (index & 0x7fff); 1532 ir_entry->index = (index & 0x7fff);
1533 /*
1534 * IO-APIC RTE will be configured with virtual vector.
1535 * irq handler will do the explicit EOI to the io-apic.
1536 */
1537 ir_entry->vector = pin;
1518 } else 1538 } else
1519#endif 1539#endif
1520 { 1540 {
1521 entry->delivery_mode = apic->irq_delivery_mode; 1541 entry->delivery_mode = apic->irq_delivery_mode;
1522 entry->dest_mode = apic->irq_dest_mode; 1542 entry->dest_mode = apic->irq_dest_mode;
1523 entry->dest = destination; 1543 entry->dest = destination;
1544 entry->vector = vector;
1524 } 1545 }
1525 1546
1526 entry->mask = 0; /* enable IRQ */ 1547 entry->mask = 0; /* enable IRQ */
1527 entry->trigger = trigger; 1548 entry->trigger = trigger;
1528 entry->polarity = polarity; 1549 entry->polarity = polarity;
1529 entry->vector = vector;
1530 1550
1531 /* Mask level triggered irqs. 1551 /* Mask level triggered irqs.
1532 * Use IRQ_DELAYED_DISABLE for edge triggered irqs. 1552 * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
@@ -1561,7 +1581,7 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq
1561 1581
1562 1582
1563 if (setup_ioapic_entry(mp_ioapics[apic_id].apicid, irq, &entry, 1583 if (setup_ioapic_entry(mp_ioapics[apic_id].apicid, irq, &entry,
1564 dest, trigger, polarity, cfg->vector)) { 1584 dest, trigger, polarity, cfg->vector, pin)) {
1565 printk("Failed to setup ioapic entry for ioapic %d, pin %d\n", 1585 printk("Failed to setup ioapic entry for ioapic %d, pin %d\n",
1566 mp_ioapics[apic_id].apicid, pin); 1586 mp_ioapics[apic_id].apicid, pin);
1567 __clear_irq_vector(irq, cfg); 1587 __clear_irq_vector(irq, cfg);
@@ -2311,37 +2331,24 @@ static int ioapic_retrigger_irq(unsigned int irq)
2311#ifdef CONFIG_SMP 2331#ifdef CONFIG_SMP
2312 2332
2313#ifdef CONFIG_INTR_REMAP 2333#ifdef CONFIG_INTR_REMAP
2314static void ir_irq_migration(struct work_struct *work);
2315
2316static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration);
2317 2334
2318/* 2335/*
2319 * Migrate the IO-APIC irq in the presence of intr-remapping. 2336 * Migrate the IO-APIC irq in the presence of intr-remapping.
2320 * 2337 *
2321 * For edge triggered, irq migration is a simple atomic update(of vector 2338 * For both level and edge triggered, irq migration is a simple atomic
2322 * and cpu destination) of IRTE and flush the hardware cache. 2339 * update(of vector and cpu destination) of IRTE and flush the hardware cache.
2323 *
2324 * For level triggered, we need to modify the io-apic RTE aswell with the update
2325 * vector information, along with modifying IRTE with vector and destination.
2326 * So irq migration for level triggered is little bit more complex compared to
2327 * edge triggered migration. But the good news is, we use the same algorithm
2328 * for level triggered migration as we have today, only difference being,
2329 * we now initiate the irq migration from process context instead of the
2330 * interrupt context.
2331 * 2340 *
2332 * In future, when we do a directed EOI (combined with cpu EOI broadcast 2341 * For level triggered, we eliminate the io-apic RTE modification (with the
2333 * suppression) to the IO-APIC, level triggered irq migration will also be 2342 * updated vector information), by using a virtual vector (io-apic pin number).
2334 * as simple as edge triggered migration and we can do the irq migration 2343 * Real vector that is used for interrupting cpu will be coming from
2335 * with a simple atomic update to IO-APIC RTE. 2344 * the interrupt-remapping table entry.
2336 */ 2345 */
2337static void 2346static void
2338migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask) 2347migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
2339{ 2348{
2340 struct irq_cfg *cfg; 2349 struct irq_cfg *cfg;
2341 struct irte irte; 2350 struct irte irte;
2342 int modify_ioapic_rte;
2343 unsigned int dest; 2351 unsigned int dest;
2344 unsigned long flags;
2345 unsigned int irq; 2352 unsigned int irq;
2346 2353
2347 if (!cpumask_intersects(mask, cpu_online_mask)) 2354 if (!cpumask_intersects(mask, cpu_online_mask))
@@ -2359,13 +2366,6 @@ migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
2359 2366
2360 dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask); 2367 dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
2361 2368
2362 modify_ioapic_rte = desc->status & IRQ_LEVEL;
2363 if (modify_ioapic_rte) {
2364 spin_lock_irqsave(&ioapic_lock, flags);
2365 __target_IO_APIC_irq(irq, dest, cfg);
2366 spin_unlock_irqrestore(&ioapic_lock, flags);
2367 }
2368
2369 irte.vector = cfg->vector; 2369 irte.vector = cfg->vector;
2370 irte.dest_id = IRTE_DEST(dest); 2370 irte.dest_id = IRTE_DEST(dest);
2371 2371
@@ -2380,73 +2380,12 @@ migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
2380 cpumask_copy(desc->affinity, mask); 2380 cpumask_copy(desc->affinity, mask);
2381} 2381}
2382 2382
2383static int migrate_irq_remapped_level_desc(struct irq_desc *desc)
2384{
2385 int ret = -1;
2386 struct irq_cfg *cfg = desc->chip_data;
2387
2388 mask_IO_APIC_irq_desc(desc);
2389
2390 if (io_apic_level_ack_pending(cfg)) {
2391 /*
2392 * Interrupt in progress. Migrating irq now will change the
2393 * vector information in the IO-APIC RTE and that will confuse
2394 * the EOI broadcast performed by cpu.
2395 * So, delay the irq migration to the next instance.
2396 */
2397 schedule_delayed_work(&ir_migration_work, 1);
2398 goto unmask;
2399 }
2400
2401 /* everthing is clear. we have right of way */
2402 migrate_ioapic_irq_desc(desc, desc->pending_mask);
2403
2404 ret = 0;
2405 desc->status &= ~IRQ_MOVE_PENDING;
2406 cpumask_clear(desc->pending_mask);
2407
2408unmask:
2409 unmask_IO_APIC_irq_desc(desc);
2410
2411 return ret;
2412}
2413
2414static void ir_irq_migration(struct work_struct *work)
2415{
2416 unsigned int irq;
2417 struct irq_desc *desc;
2418
2419 for_each_irq_desc(irq, desc) {
2420 if (desc->status & IRQ_MOVE_PENDING) {
2421 unsigned long flags;
2422
2423 spin_lock_irqsave(&desc->lock, flags);
2424 if (!desc->chip->set_affinity ||
2425 !(desc->status & IRQ_MOVE_PENDING)) {
2426 desc->status &= ~IRQ_MOVE_PENDING;
2427 spin_unlock_irqrestore(&desc->lock, flags);
2428 continue;
2429 }
2430
2431 desc->chip->set_affinity(irq, desc->pending_mask);
2432 spin_unlock_irqrestore(&desc->lock, flags);
2433 }
2434 }
2435}
2436
2437/* 2383/*
2438 * Migrates the IRQ destination in the process context. 2384 * Migrates the IRQ destination in the process context.
2439 */ 2385 */
2440static void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc, 2386static void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
2441 const struct cpumask *mask) 2387 const struct cpumask *mask)
2442{ 2388{
2443 if (desc->status & IRQ_LEVEL) {
2444 desc->status |= IRQ_MOVE_PENDING;
2445 cpumask_copy(desc->pending_mask, mask);
2446 migrate_irq_remapped_level_desc(desc);
2447 return;
2448 }
2449
2450 migrate_ioapic_irq_desc(desc, mask); 2389 migrate_ioapic_irq_desc(desc, mask);
2451} 2390}
2452static void set_ir_ioapic_affinity_irq(unsigned int irq, 2391static void set_ir_ioapic_affinity_irq(unsigned int irq,
@@ -2537,9 +2476,44 @@ static inline void irq_complete_move(struct irq_desc **descp) {}
2537#endif 2476#endif
2538 2477
2539#ifdef CONFIG_INTR_REMAP 2478#ifdef CONFIG_INTR_REMAP
2479static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
2480{
2481 int apic, pin;
2482 struct irq_pin_list *entry;
2483
2484 entry = cfg->irq_2_pin;
2485 for (;;) {
2486
2487 if (!entry)
2488 break;
2489
2490 apic = entry->apic;
2491 pin = entry->pin;
2492 io_apic_eoi(apic, pin);
2493 entry = entry->next;
2494 }
2495}
2496
2497static void
2498eoi_ioapic_irq(struct irq_desc *desc)
2499{
2500 struct irq_cfg *cfg;
2501 unsigned long flags;
2502 unsigned int irq;
2503
2504 irq = desc->irq;
2505 cfg = desc->chip_data;
2506
2507 spin_lock_irqsave(&ioapic_lock, flags);
2508 __eoi_ioapic_irq(irq, cfg);
2509 spin_unlock_irqrestore(&ioapic_lock, flags);
2510}
2511
2540static void ack_x2apic_level(unsigned int irq) 2512static void ack_x2apic_level(unsigned int irq)
2541{ 2513{
2514 struct irq_desc *desc = irq_to_desc(irq);
2542 ack_x2APIC_irq(); 2515 ack_x2APIC_irq();
2516 eoi_ioapic_irq(desc);
2543} 2517}
2544 2518
2545static void ack_x2apic_edge(unsigned int irq) 2519static void ack_x2apic_edge(unsigned int irq)