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 * Jiang Liu <jiang.liu@linux.intel.com> 7 * Convert to hierarchical irqdomain 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 #include <linux/mm.h> 14 #include <linux/interrupt.h> 15 #include <linux/pci.h> 16 #include <linux/dmar.h> 17 #include <linux/hpet.h> 18 #include <linux/msi.h> 19 #include <asm/irqdomain.h> 20 #include <asm/msidef.h> 21 #include <asm/hpet.h> 22 #include <asm/hw_irq.h> 23 #include <asm/apic.h> 24 #include <asm/irq_remapping.h> 25 26 static struct irq_domain *msi_default_domain; 27 28 static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) 29 { 30 struct irq_cfg *cfg = irqd_cfg(data); 31 32 msg->address_hi = MSI_ADDR_BASE_HI; 33 34 if (x2apic_enabled()) 35 msg->address_hi |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid); 36 37 msg->address_lo = 38 MSI_ADDR_BASE_LO | 39 ((apic->irq_dest_mode == 0) ? 40 MSI_ADDR_DEST_MODE_PHYSICAL : 41 MSI_ADDR_DEST_MODE_LOGICAL) | 42 MSI_ADDR_REDIRECTION_CPU | 43 MSI_ADDR_DEST_ID(cfg->dest_apicid); 44 45 msg->data = 46 MSI_DATA_TRIGGER_EDGE | 47 MSI_DATA_LEVEL_ASSERT | 48 MSI_DATA_DELIVERY_FIXED | 49 MSI_DATA_VECTOR(cfg->vector); 50 } 51 52 /* 53 * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, 54 * which implement the MSI or MSI-X Capability Structure. 55 */ 56 static struct irq_chip pci_msi_controller = { 57 .name = "PCI-MSI", 58 .irq_unmask = pci_msi_unmask_irq, 59 .irq_mask = pci_msi_mask_irq, 60 .irq_ack = irq_chip_ack_parent, 61 .irq_retrigger = irq_chip_retrigger_hierarchy, 62 .irq_compose_msi_msg = irq_msi_compose_msg, 63 .flags = IRQCHIP_SKIP_SET_WAKE, 64 }; 65 66 int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 67 { 68 struct irq_domain *domain; 69 struct irq_alloc_info info; 70 71 init_irq_alloc_info(&info, NULL); 72 info.type = X86_IRQ_ALLOC_TYPE_MSI; 73 info.msi_dev = dev; 74 75 domain = irq_remapping_get_irq_domain(&info); 76 if (domain == NULL) 77 domain = msi_default_domain; 78 if (domain == NULL) 79 return -ENOSYS; 80 81 return msi_domain_alloc_irqs(domain, &dev->dev, nvec); 82 } 83 84 void native_teardown_msi_irq(unsigned int irq) 85 { 86 irq_domain_free_irqs(irq, 1); 87 } 88 89 static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info, 90 msi_alloc_info_t *arg) 91 { 92 return arg->msi_hwirq; 93 } 94 95 int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec, 96 msi_alloc_info_t *arg) 97 { 98 struct pci_dev *pdev = to_pci_dev(dev); 99 struct msi_desc *desc = first_pci_msi_entry(pdev); 100 101 init_irq_alloc_info(arg, NULL); 102 arg->msi_dev = pdev; 103 if (desc->msi_attrib.is_msix) { 104 arg->type = X86_IRQ_ALLOC_TYPE_MSIX; 105 } else { 106 arg->type = X86_IRQ_ALLOC_TYPE_MSI; 107 arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS; 108 } 109 110 return 0; 111 } 112 EXPORT_SYMBOL_GPL(pci_msi_prepare); 113 114 void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) 115 { 116 arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc); 117 } 118 EXPORT_SYMBOL_GPL(pci_msi_set_desc); 119 120 static struct msi_domain_ops pci_msi_domain_ops = { 121 .get_hwirq = pci_msi_get_hwirq, 122 .msi_prepare = pci_msi_prepare, 123 .set_desc = pci_msi_set_desc, 124 }; 125 126 static struct msi_domain_info pci_msi_domain_info = { 127 .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 128 MSI_FLAG_PCI_MSIX, 129 .ops = &pci_msi_domain_ops, 130 .chip = &pci_msi_controller, 131 .handler = handle_edge_irq, 132 .handler_name = "edge", 133 }; 134 135 void __init arch_init_msi_domain(struct irq_domain *parent) 136 { 137 struct fwnode_handle *fn; 138 139 if (disable_apic) 140 return; 141 142 fn = irq_domain_alloc_named_fwnode("PCI-MSI"); 143 if (fn) { 144 msi_default_domain = 145 pci_msi_create_irq_domain(fn, &pci_msi_domain_info, 146 parent); 147 irq_domain_free_fwnode(fn); 148 } 149 if (!msi_default_domain) 150 pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n"); 151 } 152 153 #ifdef CONFIG_IRQ_REMAP 154 static struct irq_chip pci_msi_ir_controller = { 155 .name = "IR-PCI-MSI", 156 .irq_unmask = pci_msi_unmask_irq, 157 .irq_mask = pci_msi_mask_irq, 158 .irq_ack = irq_chip_ack_parent, 159 .irq_retrigger = irq_chip_retrigger_hierarchy, 160 .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent, 161 .flags = IRQCHIP_SKIP_SET_WAKE, 162 }; 163 164 static struct msi_domain_info pci_msi_ir_domain_info = { 165 .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 166 MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX, 167 .ops = &pci_msi_domain_ops, 168 .chip = &pci_msi_ir_controller, 169 .handler = handle_edge_irq, 170 .handler_name = "edge", 171 }; 172 173 struct irq_domain *arch_create_remap_msi_irq_domain(struct irq_domain *parent, 174 const char *name, int id) 175 { 176 struct fwnode_handle *fn; 177 struct irq_domain *d; 178 179 fn = irq_domain_alloc_named_id_fwnode(name, id); 180 if (!fn) 181 return NULL; 182 d = pci_msi_create_irq_domain(fn, &pci_msi_ir_domain_info, parent); 183 irq_domain_free_fwnode(fn); 184 return d; 185 } 186 #endif 187 188 #ifdef CONFIG_DMAR_TABLE 189 static void dmar_msi_write_msg(struct irq_data *data, struct msi_msg *msg) 190 { 191 dmar_msi_write(data->irq, msg); 192 } 193 194 static struct irq_chip dmar_msi_controller = { 195 .name = "DMAR-MSI", 196 .irq_unmask = dmar_msi_unmask, 197 .irq_mask = dmar_msi_mask, 198 .irq_ack = irq_chip_ack_parent, 199 .irq_set_affinity = msi_domain_set_affinity, 200 .irq_retrigger = irq_chip_retrigger_hierarchy, 201 .irq_compose_msi_msg = irq_msi_compose_msg, 202 .irq_write_msi_msg = dmar_msi_write_msg, 203 .flags = IRQCHIP_SKIP_SET_WAKE, 204 }; 205 206 static irq_hw_number_t dmar_msi_get_hwirq(struct msi_domain_info *info, 207 msi_alloc_info_t *arg) 208 { 209 return arg->dmar_id; 210 } 211 212 static int dmar_msi_init(struct irq_domain *domain, 213 struct msi_domain_info *info, unsigned int virq, 214 irq_hw_number_t hwirq, msi_alloc_info_t *arg) 215 { 216 irq_domain_set_info(domain, virq, arg->dmar_id, info->chip, NULL, 217 handle_edge_irq, arg->dmar_data, "edge"); 218 219 return 0; 220 } 221 222 static struct msi_domain_ops dmar_msi_domain_ops = { 223 .get_hwirq = dmar_msi_get_hwirq, 224 .msi_init = dmar_msi_init, 225 }; 226 227 static struct msi_domain_info dmar_msi_domain_info = { 228 .ops = &dmar_msi_domain_ops, 229 .chip = &dmar_msi_controller, 230 }; 231 232 static struct irq_domain *dmar_get_irq_domain(void) 233 { 234 static struct irq_domain *dmar_domain; 235 static DEFINE_MUTEX(dmar_lock); 236 struct fwnode_handle *fn; 237 238 mutex_lock(&dmar_lock); 239 if (dmar_domain) 240 goto out; 241 242 fn = irq_domain_alloc_named_fwnode("DMAR-MSI"); 243 if (fn) { 244 dmar_domain = msi_create_irq_domain(fn, &dmar_msi_domain_info, 245 x86_vector_domain); 246 irq_domain_free_fwnode(fn); 247 } 248 out: 249 mutex_unlock(&dmar_lock); 250 return dmar_domain; 251 } 252 253 int dmar_alloc_hwirq(int id, int node, void *arg) 254 { 255 struct irq_domain *domain = dmar_get_irq_domain(); 256 struct irq_alloc_info info; 257 258 if (!domain) 259 return -1; 260 261 init_irq_alloc_info(&info, NULL); 262 info.type = X86_IRQ_ALLOC_TYPE_DMAR; 263 info.dmar_id = id; 264 info.dmar_data = arg; 265 266 return irq_domain_alloc_irqs(domain, 1, node, &info); 267 } 268 269 void dmar_free_hwirq(int irq) 270 { 271 irq_domain_free_irqs(irq, 1); 272 } 273 #endif 274 275 /* 276 * MSI message composition 277 */ 278 #ifdef CONFIG_HPET_TIMER 279 static inline int hpet_dev_id(struct irq_domain *domain) 280 { 281 struct msi_domain_info *info = msi_get_domain_info(domain); 282 283 return (int)(long)info->data; 284 } 285 286 static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg) 287 { 288 hpet_msi_write(irq_data_get_irq_handler_data(data), msg); 289 } 290 291 static struct irq_chip hpet_msi_controller __ro_after_init = { 292 .name = "HPET-MSI", 293 .irq_unmask = hpet_msi_unmask, 294 .irq_mask = hpet_msi_mask, 295 .irq_ack = irq_chip_ack_parent, 296 .irq_set_affinity = msi_domain_set_affinity, 297 .irq_retrigger = irq_chip_retrigger_hierarchy, 298 .irq_compose_msi_msg = irq_msi_compose_msg, 299 .irq_write_msi_msg = hpet_msi_write_msg, 300 .flags = IRQCHIP_SKIP_SET_WAKE, 301 }; 302 303 static irq_hw_number_t hpet_msi_get_hwirq(struct msi_domain_info *info, 304 msi_alloc_info_t *arg) 305 { 306 return arg->hpet_index; 307 } 308 309 static int hpet_msi_init(struct irq_domain *domain, 310 struct msi_domain_info *info, unsigned int virq, 311 irq_hw_number_t hwirq, msi_alloc_info_t *arg) 312 { 313 irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); 314 irq_domain_set_info(domain, virq, arg->hpet_index, info->chip, NULL, 315 handle_edge_irq, arg->hpet_data, "edge"); 316 317 return 0; 318 } 319 320 static void hpet_msi_free(struct irq_domain *domain, 321 struct msi_domain_info *info, unsigned int virq) 322 { 323 irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT); 324 } 325 326 static struct msi_domain_ops hpet_msi_domain_ops = { 327 .get_hwirq = hpet_msi_get_hwirq, 328 .msi_init = hpet_msi_init, 329 .msi_free = hpet_msi_free, 330 }; 331 332 static struct msi_domain_info hpet_msi_domain_info = { 333 .ops = &hpet_msi_domain_ops, 334 .chip = &hpet_msi_controller, 335 }; 336 337 struct irq_domain *hpet_create_irq_domain(int hpet_id) 338 { 339 struct msi_domain_info *domain_info; 340 struct irq_domain *parent, *d; 341 struct irq_alloc_info info; 342 struct fwnode_handle *fn; 343 344 if (x86_vector_domain == NULL) 345 return NULL; 346 347 domain_info = kzalloc(sizeof(*domain_info), GFP_KERNEL); 348 if (!domain_info) 349 return NULL; 350 351 *domain_info = hpet_msi_domain_info; 352 domain_info->data = (void *)(long)hpet_id; 353 354 init_irq_alloc_info(&info, NULL); 355 info.type = X86_IRQ_ALLOC_TYPE_HPET; 356 info.hpet_id = hpet_id; 357 parent = irq_remapping_get_ir_irq_domain(&info); 358 if (parent == NULL) 359 parent = x86_vector_domain; 360 else 361 hpet_msi_controller.name = "IR-HPET-MSI"; 362 363 fn = irq_domain_alloc_named_id_fwnode(hpet_msi_controller.name, 364 hpet_id); 365 if (!fn) { 366 kfree(domain_info); 367 return NULL; 368 } 369 370 d = msi_create_irq_domain(fn, domain_info, parent); 371 irq_domain_free_fwnode(fn); 372 return d; 373 } 374 375 int hpet_assign_irq(struct irq_domain *domain, struct hpet_dev *dev, 376 int dev_num) 377 { 378 struct irq_alloc_info info; 379 380 init_irq_alloc_info(&info, NULL); 381 info.type = X86_IRQ_ALLOC_TYPE_HPET; 382 info.hpet_data = dev; 383 info.hpet_id = hpet_dev_id(domain); 384 info.hpet_index = dev_num; 385 386 return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, &info); 387 } 388 #endif 389