linux/arch/ia64/kernel/msi_ia64.c
<<
>>
Prefs
   1/*
   2 * MSI hooks for standard x86 apic
   3 */
   4
   5#include <linux/pci.h>
   6#include <linux/irq.h>
   7#include <linux/msi.h>
   8#include <linux/dmar.h>
   9#include <asm/smp.h>
  10#include <asm/msidef.h>
  11
  12static struct irq_chip  ia64_msi_chip;
  13
  14#ifdef CONFIG_SMP
  15static int ia64_set_msi_irq_affinity(struct irq_data *idata,
  16                                     const cpumask_t *cpu_mask, bool force)
  17{
  18        struct msi_msg msg;
  19        u32 addr, data;
  20        int cpu = first_cpu(*cpu_mask);
  21        unsigned int irq = idata->irq;
  22
  23        if (!cpu_online(cpu))
  24                return -1;
  25
  26        if (irq_prepare_move(irq, cpu))
  27                return -1;
  28
  29        get_cached_msi_msg(irq, &msg);
  30
  31        addr = msg.address_lo;
  32        addr &= MSI_ADDR_DEST_ID_MASK;
  33        addr |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
  34        msg.address_lo = addr;
  35
  36        data = msg.data;
  37        data &= MSI_DATA_VECTOR_MASK;
  38        data |= MSI_DATA_VECTOR(irq_to_vector(irq));
  39        msg.data = data;
  40
  41        write_msi_msg(irq, &msg);
  42        cpumask_copy(idata->affinity, cpumask_of(cpu));
  43
  44        return 0;
  45}
  46#endif /* CONFIG_SMP */
  47
  48int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
  49{
  50        struct msi_msg  msg;
  51        unsigned long   dest_phys_id;
  52        int     irq, vector;
  53        cpumask_t mask;
  54
  55        irq = create_irq();
  56        if (irq < 0)
  57                return irq;
  58
  59        irq_set_msi_desc(irq, desc);
  60        cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
  61        dest_phys_id = cpu_physical_id(first_cpu(mask));
  62        vector = irq_to_vector(irq);
  63
  64        msg.address_hi = 0;
  65        msg.address_lo =
  66                MSI_ADDR_HEADER |
  67                MSI_ADDR_DEST_MODE_PHYS |
  68                MSI_ADDR_REDIRECTION_CPU |
  69                MSI_ADDR_DEST_ID_CPU(dest_phys_id);
  70
  71        msg.data =
  72                MSI_DATA_TRIGGER_EDGE |
  73                MSI_DATA_LEVEL_ASSERT |
  74                MSI_DATA_DELIVERY_FIXED |
  75                MSI_DATA_VECTOR(vector);
  76
  77        write_msi_msg(irq, &msg);
  78        irq_set_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
  79
  80        return 0;
  81}
  82
  83void ia64_teardown_msi_irq(unsigned int irq)
  84{
  85        destroy_irq(irq);
  86}
  87
  88static void ia64_ack_msi_irq(struct irq_data *data)
  89{
  90        irq_complete_move(data->irq);
  91        irq_move_irq(data);
  92        ia64_eoi();
  93}
  94
  95static int ia64_msi_retrigger_irq(struct irq_data *data)
  96{
  97        unsigned int vector = irq_to_vector(data->irq);
  98        ia64_resend_irq(vector);
  99
 100        return 1;
 101}
 102
 103/*
 104 * Generic ops used on most IA64 platforms.
 105 */
 106static struct irq_chip ia64_msi_chip = {
 107        .name                   = "PCI-MSI",
 108        .irq_mask               = mask_msi_irq,
 109        .irq_unmask             = unmask_msi_irq,
 110        .irq_ack                = ia64_ack_msi_irq,
 111#ifdef CONFIG_SMP
 112        .irq_set_affinity       = ia64_set_msi_irq_affinity,
 113#endif
 114        .irq_retrigger          = ia64_msi_retrigger_irq,
 115};
 116
 117
 118int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 119{
 120        if (platform_setup_msi_irq)
 121                return platform_setup_msi_irq(pdev, desc);
 122
 123        return ia64_setup_msi_irq(pdev, desc);
 124}
 125
 126void arch_teardown_msi_irq(unsigned int irq)
 127{
 128        if (platform_teardown_msi_irq)
 129                return platform_teardown_msi_irq(irq);
 130
 131        return ia64_teardown_msi_irq(irq);
 132}
 133
 134#ifdef CONFIG_INTEL_IOMMU
 135#ifdef CONFIG_SMP
 136static int dmar_msi_set_affinity(struct irq_data *data,
 137                                 const struct cpumask *mask, bool force)
 138{
 139        unsigned int irq = data->irq;
 140        struct irq_cfg *cfg = irq_cfg + irq;
 141        struct msi_msg msg;
 142        int cpu = cpumask_first(mask);
 143
 144        if (!cpu_online(cpu))
 145                return -1;
 146
 147        if (irq_prepare_move(irq, cpu))
 148                return -1;
 149
 150        dmar_msi_read(irq, &msg);
 151
 152        msg.data &= ~MSI_DATA_VECTOR_MASK;
 153        msg.data |= MSI_DATA_VECTOR(cfg->vector);
 154        msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
 155        msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
 156
 157        dmar_msi_write(irq, &msg);
 158        cpumask_copy(data->affinity, mask);
 159
 160        return 0;
 161}
 162#endif /* CONFIG_SMP */
 163
 164static struct irq_chip dmar_msi_type = {
 165        .name = "DMAR_MSI",
 166        .irq_unmask = dmar_msi_unmask,
 167        .irq_mask = dmar_msi_mask,
 168        .irq_ack = ia64_ack_msi_irq,
 169#ifdef CONFIG_SMP
 170        .irq_set_affinity = dmar_msi_set_affinity,
 171#endif
 172        .irq_retrigger = ia64_msi_retrigger_irq,
 173};
 174
 175static int
 176msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
 177{
 178        struct irq_cfg *cfg = irq_cfg + irq;
 179        unsigned dest;
 180        cpumask_t mask;
 181
 182        cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
 183        dest = cpu_physical_id(first_cpu(mask));
 184
 185        msg->address_hi = 0;
 186        msg->address_lo =
 187                MSI_ADDR_HEADER |
 188                MSI_ADDR_DEST_MODE_PHYS |
 189                MSI_ADDR_REDIRECTION_CPU |
 190                MSI_ADDR_DEST_ID_CPU(dest);
 191
 192        msg->data =
 193                MSI_DATA_TRIGGER_EDGE |
 194                MSI_DATA_LEVEL_ASSERT |
 195                MSI_DATA_DELIVERY_FIXED |
 196                MSI_DATA_VECTOR(cfg->vector);
 197        return 0;
 198}
 199
 200int arch_setup_dmar_msi(unsigned int irq)
 201{
 202        int ret;
 203        struct msi_msg msg;
 204
 205        ret = msi_compose_msg(NULL, irq, &msg);
 206        if (ret < 0)
 207                return ret;
 208        dmar_msi_write(irq, &msg);
 209        irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
 210                                      "edge");
 211        return 0;
 212}
 213#endif /* CONFIG_INTEL_IOMMU */
 214
 215