diff options
author | Jiang Liu <jiang.liu@linux.intel.com> | 2014-10-27 04:12:02 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2014-12-16 08:08:17 -0500 |
commit | 443809828cb5ee0eae09060aa8d4b42b79dd4e0b (patch) | |
tree | 834d204734b505fc30b33b64830fcdf1d297463e | |
parent | 849d3569bbaf2dfdea41a6073bc0e25a0578c380 (diff) |
x86, irq: Move PCI MSI related code from io_apic.c into msi.c
Create arch/x86/kernel/apic/msi.c to host MSI related code,
preparing for enabling hierarchy irqdomain.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: Grant Likely <grant.likely@linaro.org>
Cc: Prarit Bhargava <prarit@redhat.com>
Link: http://lkml.kernel.org/r/1414397531-28254-12-git-send-email-jiang.liu@linux.intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/include/asm/io_apic.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/pci.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/apic/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 272 | ||||
-rw-r--r-- | arch/x86/kernel/apic/msi.c | 286 |
5 files changed, 290 insertions, 276 deletions
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 0db2b7037e4b..bdd45c25023a 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h | |||
@@ -148,9 +148,6 @@ extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *, | |||
148 | struct io_apic_irq_attr *); | 148 | struct io_apic_irq_attr *); |
149 | extern void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg); | 149 | extern void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg); |
150 | 150 | ||
151 | extern void native_compose_msi_msg(struct pci_dev *pdev, | ||
152 | unsigned int irq, unsigned int dest, | ||
153 | struct msi_msg *msg, u8 hpet_id); | ||
154 | extern void native_eoi_ioapic_pin(int apic, int pin, int vector); | 151 | extern void native_eoi_ioapic_pin(int apic, int pin, int vector); |
155 | 152 | ||
156 | extern int save_ioapic_entries(void); | 153 | extern int save_ioapic_entries(void); |
@@ -261,7 +258,6 @@ static inline void disable_ioapic_support(void) { } | |||
261 | #define native_io_apic_print_entries NULL | 258 | #define native_io_apic_print_entries NULL |
262 | #define native_ioapic_set_affinity NULL | 259 | #define native_ioapic_set_affinity NULL |
263 | #define native_setup_ioapic_entry NULL | 260 | #define native_setup_ioapic_entry NULL |
264 | #define native_compose_msi_msg NULL | ||
265 | #define native_eoi_ioapic_pin NULL | 261 | #define native_eoi_ioapic_pin NULL |
266 | #endif | 262 | #endif |
267 | 263 | ||
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 0892ea0e683f..4e370a5d8117 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h | |||
@@ -96,12 +96,15 @@ extern void pci_iommu_alloc(void); | |||
96 | #ifdef CONFIG_PCI_MSI | 96 | #ifdef CONFIG_PCI_MSI |
97 | /* implemented in arch/x86/kernel/apic/io_apic. */ | 97 | /* implemented in arch/x86/kernel/apic/io_apic. */ |
98 | struct msi_desc; | 98 | struct msi_desc; |
99 | void native_compose_msi_msg(struct pci_dev *pdev, unsigned int irq, | ||
100 | unsigned int dest, struct msi_msg *msg, u8 hpet_id); | ||
99 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); | 101 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); |
100 | void native_teardown_msi_irq(unsigned int irq); | 102 | void native_teardown_msi_irq(unsigned int irq); |
101 | void native_restore_msi_irqs(struct pci_dev *dev); | 103 | void native_restore_msi_irqs(struct pci_dev *dev); |
102 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | 104 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, |
103 | unsigned int irq_base, unsigned int irq_offset); | 105 | unsigned int irq_base, unsigned int irq_offset); |
104 | #else | 106 | #else |
107 | #define native_compose_msi_msg NULL | ||
105 | #define native_setup_msi_irqs NULL | 108 | #define native_setup_msi_irqs NULL |
106 | #define native_teardown_msi_irq NULL | 109 | #define native_teardown_msi_irq NULL |
107 | #endif | 110 | #endif |
diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile index 84299e5d10dc..aac300750f0e 100644 --- a/arch/x86/kernel/apic/Makefile +++ b/arch/x86/kernel/apic/Makefile | |||
@@ -6,6 +6,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o ipi.o vector.o | |||
6 | obj-y += hw_nmi.o | 6 | obj-y += hw_nmi.o |
7 | 7 | ||
8 | obj-$(CONFIG_X86_IO_APIC) += io_apic.o | 8 | obj-$(CONFIG_X86_IO_APIC) += io_apic.o |
9 | obj-$(CONFIG_PCI_MSI) += msi.o | ||
9 | obj-$(CONFIG_SMP) += ipi.o | 10 | obj-$(CONFIG_SMP) += ipi.o |
10 | 11 | ||
11 | ifeq ($(CONFIG_X86_64),y) | 12 | ifeq ($(CONFIG_X86_64),y) |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 677044df2d7a..653fe211e4ca 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -32,15 +32,12 @@ | |||
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/syscore_ops.h> | 33 | #include <linux/syscore_ops.h> |
34 | #include <linux/irqdomain.h> | 34 | #include <linux/irqdomain.h> |
35 | #include <linux/msi.h> | ||
36 | #include <linux/htirq.h> | 35 | #include <linux/htirq.h> |
37 | #include <linux/freezer.h> | 36 | #include <linux/freezer.h> |
38 | #include <linux/kthread.h> | 37 | #include <linux/kthread.h> |
39 | #include <linux/jiffies.h> /* time_after() */ | 38 | #include <linux/jiffies.h> /* time_after() */ |
40 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
41 | #include <linux/bootmem.h> | 40 | #include <linux/bootmem.h> |
42 | #include <linux/dmar.h> | ||
43 | #include <linux/hpet.h> | ||
44 | 41 | ||
45 | #include <asm/idle.h> | 42 | #include <asm/idle.h> |
46 | #include <asm/io.h> | 43 | #include <asm/io.h> |
@@ -52,11 +49,9 @@ | |||
52 | #include <asm/dma.h> | 49 | #include <asm/dma.h> |
53 | #include <asm/timer.h> | 50 | #include <asm/timer.h> |
54 | #include <asm/i8259.h> | 51 | #include <asm/i8259.h> |
55 | #include <asm/msidef.h> | ||
56 | #include <asm/hypertransport.h> | 52 | #include <asm/hypertransport.h> |
57 | #include <asm/setup.h> | 53 | #include <asm/setup.h> |
58 | #include <asm/irq_remapping.h> | 54 | #include <asm/irq_remapping.h> |
59 | #include <asm/hpet.h> | ||
60 | #include <asm/hw_irq.h> | 55 | #include <asm/hw_irq.h> |
61 | 56 | ||
62 | #include <asm/apic.h> | 57 | #include <asm/apic.h> |
@@ -2456,273 +2451,6 @@ static int __init ioapic_init_ops(void) | |||
2456 | device_initcall(ioapic_init_ops); | 2451 | device_initcall(ioapic_init_ops); |
2457 | 2452 | ||
2458 | /* | 2453 | /* |
2459 | * MSI message composition | ||
2460 | */ | ||
2461 | void native_compose_msi_msg(struct pci_dev *pdev, | ||
2462 | unsigned int irq, unsigned int dest, | ||
2463 | struct msi_msg *msg, u8 hpet_id) | ||
2464 | { | ||
2465 | struct irq_cfg *cfg = irq_cfg(irq); | ||
2466 | |||
2467 | msg->address_hi = MSI_ADDR_BASE_HI; | ||
2468 | |||
2469 | if (x2apic_enabled()) | ||
2470 | msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest); | ||
2471 | |||
2472 | msg->address_lo = | ||
2473 | MSI_ADDR_BASE_LO | | ||
2474 | ((apic->irq_dest_mode == 0) ? | ||
2475 | MSI_ADDR_DEST_MODE_PHYSICAL: | ||
2476 | MSI_ADDR_DEST_MODE_LOGICAL) | | ||
2477 | ((apic->irq_delivery_mode != dest_LowestPrio) ? | ||
2478 | MSI_ADDR_REDIRECTION_CPU: | ||
2479 | MSI_ADDR_REDIRECTION_LOWPRI) | | ||
2480 | MSI_ADDR_DEST_ID(dest); | ||
2481 | |||
2482 | msg->data = | ||
2483 | MSI_DATA_TRIGGER_EDGE | | ||
2484 | MSI_DATA_LEVEL_ASSERT | | ||
2485 | ((apic->irq_delivery_mode != dest_LowestPrio) ? | ||
2486 | MSI_DATA_DELIVERY_FIXED: | ||
2487 | MSI_DATA_DELIVERY_LOWPRI) | | ||
2488 | MSI_DATA_VECTOR(cfg->vector); | ||
2489 | } | ||
2490 | |||
2491 | #ifdef CONFIG_PCI_MSI | ||
2492 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, | ||
2493 | struct msi_msg *msg, u8 hpet_id) | ||
2494 | { | ||
2495 | struct irq_cfg *cfg; | ||
2496 | int err; | ||
2497 | unsigned dest; | ||
2498 | |||
2499 | if (disable_apic) | ||
2500 | return -ENXIO; | ||
2501 | |||
2502 | cfg = irq_cfg(irq); | ||
2503 | err = assign_irq_vector(irq, cfg, apic->target_cpus()); | ||
2504 | if (err) | ||
2505 | return err; | ||
2506 | |||
2507 | err = apic->cpu_mask_to_apicid_and(cfg->domain, | ||
2508 | apic->target_cpus(), &dest); | ||
2509 | if (err) | ||
2510 | return err; | ||
2511 | |||
2512 | x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id); | ||
2513 | |||
2514 | return 0; | ||
2515 | } | ||
2516 | |||
2517 | static int | ||
2518 | msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) | ||
2519 | { | ||
2520 | struct irq_cfg *cfg = data->chip_data; | ||
2521 | struct msi_msg msg; | ||
2522 | unsigned int dest; | ||
2523 | int ret; | ||
2524 | |||
2525 | ret = apic_set_affinity(data, mask, &dest); | ||
2526 | if (ret) | ||
2527 | return ret; | ||
2528 | |||
2529 | __get_cached_msi_msg(data->msi_desc, &msg); | ||
2530 | |||
2531 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
2532 | msg.data |= MSI_DATA_VECTOR(cfg->vector); | ||
2533 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
2534 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
2535 | |||
2536 | __pci_write_msi_msg(data->msi_desc, &msg); | ||
2537 | |||
2538 | return IRQ_SET_MASK_OK_NOCOPY; | ||
2539 | } | ||
2540 | |||
2541 | /* | ||
2542 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, | ||
2543 | * which implement the MSI or MSI-X Capability Structure. | ||
2544 | */ | ||
2545 | static struct irq_chip msi_chip = { | ||
2546 | .name = "PCI-MSI", | ||
2547 | .irq_unmask = pci_msi_unmask_irq, | ||
2548 | .irq_mask = pci_msi_mask_irq, | ||
2549 | .irq_ack = apic_ack_edge, | ||
2550 | .irq_set_affinity = msi_set_affinity, | ||
2551 | .irq_retrigger = apic_retrigger_irq, | ||
2552 | .flags = IRQCHIP_SKIP_SET_WAKE, | ||
2553 | }; | ||
2554 | |||
2555 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | ||
2556 | unsigned int irq_base, unsigned int irq_offset) | ||
2557 | { | ||
2558 | struct irq_chip *chip = &msi_chip; | ||
2559 | struct msi_msg msg; | ||
2560 | unsigned int irq = irq_base + irq_offset; | ||
2561 | int ret; | ||
2562 | |||
2563 | ret = msi_compose_msg(dev, irq, &msg, -1); | ||
2564 | if (ret < 0) | ||
2565 | return ret; | ||
2566 | |||
2567 | irq_set_msi_desc_off(irq_base, irq_offset, msidesc); | ||
2568 | |||
2569 | /* | ||
2570 | * MSI-X message is written per-IRQ, the offset is always 0. | ||
2571 | * MSI message denotes a contiguous group of IRQs, written for 0th IRQ. | ||
2572 | */ | ||
2573 | if (!irq_offset) | ||
2574 | pci_write_msi_msg(irq, &msg); | ||
2575 | |||
2576 | setup_remapped_irq(irq, irq_cfg(irq), chip); | ||
2577 | |||
2578 | irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); | ||
2579 | |||
2580 | dev_printk(KERN_DEBUG, &dev->dev, "irq %d for MSI/MSI-X\n", irq); | ||
2581 | |||
2582 | return 0; | ||
2583 | } | ||
2584 | |||
2585 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
2586 | { | ||
2587 | struct msi_desc *msidesc; | ||
2588 | unsigned int irq; | ||
2589 | int node, ret; | ||
2590 | |||
2591 | /* Multiple MSI vectors only supported with interrupt remapping */ | ||
2592 | if (type == PCI_CAP_ID_MSI && nvec > 1) | ||
2593 | return 1; | ||
2594 | |||
2595 | node = dev_to_node(&dev->dev); | ||
2596 | |||
2597 | list_for_each_entry(msidesc, &dev->msi_list, list) { | ||
2598 | irq = irq_alloc_hwirq(node); | ||
2599 | if (!irq) | ||
2600 | return -ENOSPC; | ||
2601 | |||
2602 | ret = setup_msi_irq(dev, msidesc, irq, 0); | ||
2603 | if (ret < 0) { | ||
2604 | irq_free_hwirq(irq); | ||
2605 | return ret; | ||
2606 | } | ||
2607 | |||
2608 | } | ||
2609 | return 0; | ||
2610 | } | ||
2611 | |||
2612 | void native_teardown_msi_irq(unsigned int irq) | ||
2613 | { | ||
2614 | irq_free_hwirq(irq); | ||
2615 | } | ||
2616 | |||
2617 | #ifdef CONFIG_DMAR_TABLE | ||
2618 | static int | ||
2619 | dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, | ||
2620 | bool force) | ||
2621 | { | ||
2622 | struct irq_cfg *cfg = data->chip_data; | ||
2623 | unsigned int dest, irq = data->irq; | ||
2624 | struct msi_msg msg; | ||
2625 | int ret; | ||
2626 | |||
2627 | ret = apic_set_affinity(data, mask, &dest); | ||
2628 | if (ret) | ||
2629 | return ret; | ||
2630 | |||
2631 | dmar_msi_read(irq, &msg); | ||
2632 | |||
2633 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
2634 | msg.data |= MSI_DATA_VECTOR(cfg->vector); | ||
2635 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
2636 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
2637 | msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest); | ||
2638 | |||
2639 | dmar_msi_write(irq, &msg); | ||
2640 | |||
2641 | return IRQ_SET_MASK_OK_NOCOPY; | ||
2642 | } | ||
2643 | |||
2644 | static struct irq_chip dmar_msi_type = { | ||
2645 | .name = "DMAR_MSI", | ||
2646 | .irq_unmask = dmar_msi_unmask, | ||
2647 | .irq_mask = dmar_msi_mask, | ||
2648 | .irq_ack = apic_ack_edge, | ||
2649 | .irq_set_affinity = dmar_msi_set_affinity, | ||
2650 | .irq_retrigger = apic_retrigger_irq, | ||
2651 | .flags = IRQCHIP_SKIP_SET_WAKE, | ||
2652 | }; | ||
2653 | |||
2654 | int arch_setup_dmar_msi(unsigned int irq) | ||
2655 | { | ||
2656 | int ret; | ||
2657 | struct msi_msg msg; | ||
2658 | |||
2659 | ret = msi_compose_msg(NULL, irq, &msg, -1); | ||
2660 | if (ret < 0) | ||
2661 | return ret; | ||
2662 | dmar_msi_write(irq, &msg); | ||
2663 | irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq, | ||
2664 | "edge"); | ||
2665 | return 0; | ||
2666 | } | ||
2667 | #endif | ||
2668 | |||
2669 | #ifdef CONFIG_HPET_TIMER | ||
2670 | |||
2671 | static int hpet_msi_set_affinity(struct irq_data *data, | ||
2672 | const struct cpumask *mask, bool force) | ||
2673 | { | ||
2674 | struct irq_cfg *cfg = data->chip_data; | ||
2675 | struct msi_msg msg; | ||
2676 | unsigned int dest; | ||
2677 | int ret; | ||
2678 | |||
2679 | ret = apic_set_affinity(data, mask, &dest); | ||
2680 | if (ret) | ||
2681 | return ret; | ||
2682 | |||
2683 | hpet_msi_read(data->handler_data, &msg); | ||
2684 | |||
2685 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
2686 | msg.data |= MSI_DATA_VECTOR(cfg->vector); | ||
2687 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
2688 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
2689 | |||
2690 | hpet_msi_write(data->handler_data, &msg); | ||
2691 | |||
2692 | return IRQ_SET_MASK_OK_NOCOPY; | ||
2693 | } | ||
2694 | |||
2695 | static struct irq_chip hpet_msi_type = { | ||
2696 | .name = "HPET_MSI", | ||
2697 | .irq_unmask = hpet_msi_unmask, | ||
2698 | .irq_mask = hpet_msi_mask, | ||
2699 | .irq_ack = apic_ack_edge, | ||
2700 | .irq_set_affinity = hpet_msi_set_affinity, | ||
2701 | .irq_retrigger = apic_retrigger_irq, | ||
2702 | .flags = IRQCHIP_SKIP_SET_WAKE, | ||
2703 | }; | ||
2704 | |||
2705 | int default_setup_hpet_msi(unsigned int irq, unsigned int id) | ||
2706 | { | ||
2707 | struct irq_chip *chip = &hpet_msi_type; | ||
2708 | struct msi_msg msg; | ||
2709 | int ret; | ||
2710 | |||
2711 | ret = msi_compose_msg(NULL, irq, &msg, id); | ||
2712 | if (ret < 0) | ||
2713 | return ret; | ||
2714 | |||
2715 | hpet_msi_write(irq_get_handler_data(irq), &msg); | ||
2716 | irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); | ||
2717 | setup_remapped_irq(irq, irq_cfg(irq), chip); | ||
2718 | |||
2719 | irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); | ||
2720 | return 0; | ||
2721 | } | ||
2722 | #endif | ||
2723 | |||
2724 | #endif /* CONFIG_PCI_MSI */ | ||
2725 | /* | ||
2726 | * Hypertransport interrupt support | 2454 | * Hypertransport interrupt support |
2727 | */ | 2455 | */ |
2728 | #ifdef CONFIG_HT_IRQ | 2456 | #ifdef CONFIG_HT_IRQ |
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c new file mode 100644 index 000000000000..ddb28f1dab4d --- /dev/null +++ b/arch/x86/kernel/apic/msi.c | |||
@@ -0,0 +1,286 @@ | |||
1 | /* | ||
2 | * Support of MSI, HPET and DMAR interrupts. | ||
3 | * | ||
4 | * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo | ||
5 | * Moved from arch/x86/kernel/apic/io_apic.c. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/dmar.h> | ||
15 | #include <linux/hpet.h> | ||
16 | #include <linux/msi.h> | ||
17 | #include <asm/msidef.h> | ||
18 | #include <asm/hpet.h> | ||
19 | #include <asm/hw_irq.h> | ||
20 | #include <asm/apic.h> | ||
21 | #include <asm/irq_remapping.h> | ||
22 | |||
23 | void native_compose_msi_msg(struct pci_dev *pdev, | ||
24 | unsigned int irq, unsigned int dest, | ||
25 | struct msi_msg *msg, u8 hpet_id) | ||
26 | { | ||
27 | struct irq_cfg *cfg = irq_cfg(irq); | ||
28 | |||
29 | msg->address_hi = MSI_ADDR_BASE_HI; | ||
30 | |||
31 | if (x2apic_enabled()) | ||
32 | msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest); | ||
33 | |||
34 | msg->address_lo = | ||
35 | MSI_ADDR_BASE_LO | | ||
36 | ((apic->irq_dest_mode == 0) ? | ||
37 | MSI_ADDR_DEST_MODE_PHYSICAL : | ||
38 | MSI_ADDR_DEST_MODE_LOGICAL) | | ||
39 | ((apic->irq_delivery_mode != dest_LowestPrio) ? | ||
40 | MSI_ADDR_REDIRECTION_CPU : | ||
41 | MSI_ADDR_REDIRECTION_LOWPRI) | | ||
42 | MSI_ADDR_DEST_ID(dest); | ||
43 | |||
44 | msg->data = | ||
45 | MSI_DATA_TRIGGER_EDGE | | ||
46 | MSI_DATA_LEVEL_ASSERT | | ||
47 | ((apic->irq_delivery_mode != dest_LowestPrio) ? | ||
48 | MSI_DATA_DELIVERY_FIXED : | ||
49 | MSI_DATA_DELIVERY_LOWPRI) | | ||
50 | MSI_DATA_VECTOR(cfg->vector); | ||
51 | } | ||
52 | |||
53 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, | ||
54 | struct msi_msg *msg, u8 hpet_id) | ||
55 | { | ||
56 | struct irq_cfg *cfg; | ||
57 | int err; | ||
58 | unsigned dest; | ||
59 | |||
60 | if (disable_apic) | ||
61 | return -ENXIO; | ||
62 | |||
63 | cfg = irq_cfg(irq); | ||
64 | err = assign_irq_vector(irq, cfg, apic->target_cpus()); | ||
65 | if (err) | ||
66 | return err; | ||
67 | |||
68 | err = apic->cpu_mask_to_apicid_and(cfg->domain, | ||
69 | apic->target_cpus(), &dest); | ||
70 | if (err) | ||
71 | return err; | ||
72 | |||
73 | x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int | ||
79 | msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) | ||
80 | { | ||
81 | struct irq_cfg *cfg = data->chip_data; | ||
82 | struct msi_msg msg; | ||
83 | unsigned int dest; | ||
84 | int ret; | ||
85 | |||
86 | ret = apic_set_affinity(data, mask, &dest); | ||
87 | if (ret) | ||
88 | return ret; | ||
89 | |||
90 | __get_cached_msi_msg(data->msi_desc, &msg); | ||
91 | |||
92 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
93 | msg.data |= MSI_DATA_VECTOR(cfg->vector); | ||
94 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
95 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
96 | |||
97 | __pci_write_msi_msg(data->msi_desc, &msg); | ||
98 | |||
99 | return IRQ_SET_MASK_OK_NOCOPY; | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, | ||
104 | * which implement the MSI or MSI-X Capability Structure. | ||
105 | */ | ||
106 | static struct irq_chip msi_chip = { | ||
107 | .name = "PCI-MSI", | ||
108 | .irq_unmask = pci_msi_unmask_irq, | ||
109 | .irq_mask = pci_msi_mask_irq, | ||
110 | .irq_ack = apic_ack_edge, | ||
111 | .irq_set_affinity = msi_set_affinity, | ||
112 | .irq_retrigger = apic_retrigger_irq, | ||
113 | .flags = IRQCHIP_SKIP_SET_WAKE, | ||
114 | }; | ||
115 | |||
116 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | ||
117 | unsigned int irq_base, unsigned int irq_offset) | ||
118 | { | ||
119 | struct irq_chip *chip = &msi_chip; | ||
120 | struct msi_msg msg; | ||
121 | unsigned int irq = irq_base + irq_offset; | ||
122 | int ret; | ||
123 | |||
124 | ret = msi_compose_msg(dev, irq, &msg, -1); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
128 | irq_set_msi_desc_off(irq_base, irq_offset, msidesc); | ||
129 | |||
130 | /* | ||
131 | * MSI-X message is written per-IRQ, the offset is always 0. | ||
132 | * MSI message denotes a contiguous group of IRQs, written for 0th IRQ. | ||
133 | */ | ||
134 | if (!irq_offset) | ||
135 | pci_write_msi_msg(irq, &msg); | ||
136 | |||
137 | setup_remapped_irq(irq, irq_cfg(irq), chip); | ||
138 | |||
139 | irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); | ||
140 | |||
141 | dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", irq); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
147 | { | ||
148 | struct msi_desc *msidesc; | ||
149 | unsigned int irq; | ||
150 | int node, ret; | ||
151 | |||
152 | /* Multiple MSI vectors only supported with interrupt remapping */ | ||
153 | if (type == PCI_CAP_ID_MSI && nvec > 1) | ||
154 | return 1; | ||
155 | |||
156 | node = dev_to_node(&dev->dev); | ||
157 | |||
158 | list_for_each_entry(msidesc, &dev->msi_list, list) { | ||
159 | irq = irq_alloc_hwirq(node); | ||
160 | if (!irq) | ||
161 | return -ENOSPC; | ||
162 | |||
163 | ret = setup_msi_irq(dev, msidesc, irq, 0); | ||
164 | if (ret < 0) { | ||
165 | irq_free_hwirq(irq); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | void native_teardown_msi_irq(unsigned int irq) | ||
174 | { | ||
175 | irq_free_hwirq(irq); | ||
176 | } | ||
177 | |||
178 | #ifdef CONFIG_DMAR_TABLE | ||
179 | static int | ||
180 | dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, | ||
181 | bool force) | ||
182 | { | ||
183 | struct irq_cfg *cfg = data->chip_data; | ||
184 | unsigned int dest, irq = data->irq; | ||
185 | struct msi_msg msg; | ||
186 | int ret; | ||
187 | |||
188 | ret = apic_set_affinity(data, mask, &dest); | ||
189 | if (ret) | ||
190 | return ret; | ||
191 | |||
192 | dmar_msi_read(irq, &msg); | ||
193 | |||
194 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
195 | msg.data |= MSI_DATA_VECTOR(cfg->vector); | ||
196 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
197 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
198 | msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest); | ||
199 | |||
200 | dmar_msi_write(irq, &msg); | ||
201 | |||
202 | return IRQ_SET_MASK_OK_NOCOPY; | ||
203 | } | ||
204 | |||
205 | static struct irq_chip dmar_msi_type = { | ||
206 | .name = "DMAR_MSI", | ||
207 | .irq_unmask = dmar_msi_unmask, | ||
208 | .irq_mask = dmar_msi_mask, | ||
209 | .irq_ack = apic_ack_edge, | ||
210 | .irq_set_affinity = dmar_msi_set_affinity, | ||
211 | .irq_retrigger = apic_retrigger_irq, | ||
212 | .flags = IRQCHIP_SKIP_SET_WAKE, | ||
213 | }; | ||
214 | |||
215 | int arch_setup_dmar_msi(unsigned int irq) | ||
216 | { | ||
217 | int ret; | ||
218 | struct msi_msg msg; | ||
219 | |||
220 | ret = msi_compose_msg(NULL, irq, &msg, -1); | ||
221 | if (ret < 0) | ||
222 | return ret; | ||
223 | dmar_msi_write(irq, &msg); | ||
224 | irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq, | ||
225 | "edge"); | ||
226 | return 0; | ||
227 | } | ||
228 | #endif | ||
229 | |||
230 | /* | ||
231 | * MSI message composition | ||
232 | */ | ||
233 | #ifdef CONFIG_HPET_TIMER | ||
234 | |||
235 | static int hpet_msi_set_affinity(struct irq_data *data, | ||
236 | const struct cpumask *mask, bool force) | ||
237 | { | ||
238 | struct irq_cfg *cfg = data->chip_data; | ||
239 | struct msi_msg msg; | ||
240 | unsigned int dest; | ||
241 | int ret; | ||
242 | |||
243 | ret = apic_set_affinity(data, mask, &dest); | ||
244 | if (ret) | ||
245 | return ret; | ||
246 | |||
247 | hpet_msi_read(data->handler_data, &msg); | ||
248 | |||
249 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
250 | msg.data |= MSI_DATA_VECTOR(cfg->vector); | ||
251 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
252 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
253 | |||
254 | hpet_msi_write(data->handler_data, &msg); | ||
255 | |||
256 | return IRQ_SET_MASK_OK_NOCOPY; | ||
257 | } | ||
258 | |||
259 | static struct irq_chip hpet_msi_type = { | ||
260 | .name = "HPET_MSI", | ||
261 | .irq_unmask = hpet_msi_unmask, | ||
262 | .irq_mask = hpet_msi_mask, | ||
263 | .irq_ack = apic_ack_edge, | ||
264 | .irq_set_affinity = hpet_msi_set_affinity, | ||
265 | .irq_retrigger = apic_retrigger_irq, | ||
266 | .flags = IRQCHIP_SKIP_SET_WAKE, | ||
267 | }; | ||
268 | |||
269 | int default_setup_hpet_msi(unsigned int irq, unsigned int id) | ||
270 | { | ||
271 | struct irq_chip *chip = &hpet_msi_type; | ||
272 | struct msi_msg msg; | ||
273 | int ret; | ||
274 | |||
275 | ret = msi_compose_msg(NULL, irq, &msg, id); | ||
276 | if (ret < 0) | ||
277 | return ret; | ||
278 | |||
279 | hpet_msi_write(irq_get_handler_data(irq), &msg); | ||
280 | irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); | ||
281 | setup_remapped_irq(irq, irq_cfg(irq), chip); | ||
282 | |||
283 | irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); | ||
284 | return 0; | ||
285 | } | ||
286 | #endif | ||