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