diff options
| -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 | ||
