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 = irqd_cfg(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 = irqd_cfg(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 = irqd_cfg(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 287