Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

x86/hyperv: Switch to msi_create_parent_irq_domain()

Move away from the legacy MSI domain setup, switch to use
msi_create_parent_irq_domain().

While doing the conversion, I noticed that hv_irq_compose_msi_msg() is
doing more than it is supposed to (composing message content). The
interrupt allocation bits should be moved into hv_msi_domain_alloc().
However, I have no hardware to test this change, therefore I leave a TODO
note.

Signed-off-by: Nam Cao <namcao@linutronix.de>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Nam Cao and committed by
Wei Liu
4691db07 c5eebe07

+77 -35
+76 -35
arch/x86/hyperv/irqdomain.c
··· 11 11 #include <linux/pci.h> 12 12 #include <linux/irq.h> 13 13 #include <linux/export.h> 14 + #include <linux/irqchip/irq-msi-lib.h> 14 15 #include <asm/mshyperv.h> 15 16 16 17 static int hv_map_interrupt(union hv_device_id device_id, bool level, ··· 290 289 (void)hv_unmap_msi_interrupt(dev, &old_entry); 291 290 } 292 291 293 - static void hv_msi_free_irq(struct irq_domain *domain, 294 - struct msi_domain_info *info, unsigned int virq) 295 - { 296 - struct irq_data *irqd = irq_get_irq_data(virq); 297 - struct msi_desc *desc; 298 - 299 - if (!irqd) 300 - return; 301 - 302 - desc = irq_data_get_msi_desc(irqd); 303 - if (!desc || !desc->irq || WARN_ON_ONCE(!dev_is_pci(desc->dev))) 304 - return; 305 - 306 - hv_teardown_msi_irq(to_pci_dev(desc->dev), irqd); 307 - } 308 - 309 292 /* 310 293 * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, 311 294 * which implement the MSI or MSI-X Capability Structure. 312 295 */ 313 296 static struct irq_chip hv_pci_msi_controller = { 314 297 .name = "HV-PCI-MSI", 315 - .irq_unmask = pci_msi_unmask_irq, 316 - .irq_mask = pci_msi_mask_irq, 317 298 .irq_ack = irq_chip_ack_parent, 318 - .irq_retrigger = irq_chip_retrigger_hierarchy, 319 299 .irq_compose_msi_msg = hv_irq_compose_msi_msg, 320 - .irq_set_affinity = msi_domain_set_affinity, 321 - .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MOVE_DEFERRED, 300 + .irq_set_affinity = irq_chip_set_affinity_parent, 322 301 }; 323 302 324 - static struct msi_domain_ops pci_msi_domain_ops = { 325 - .msi_free = hv_msi_free_irq, 326 - .msi_prepare = pci_msi_prepare, 303 + static bool hv_init_dev_msi_info(struct device *dev, struct irq_domain *domain, 304 + struct irq_domain *real_parent, struct msi_domain_info *info) 305 + { 306 + struct irq_chip *chip = info->chip; 307 + 308 + if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info)) 309 + return false; 310 + 311 + chip->flags |= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MOVE_DEFERRED; 312 + 313 + info->ops->msi_prepare = pci_msi_prepare; 314 + 315 + return true; 316 + } 317 + 318 + #define HV_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | MSI_FLAG_PCI_MSIX) 319 + #define HV_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS) 320 + 321 + static struct msi_parent_ops hv_msi_parent_ops = { 322 + .supported_flags = HV_MSI_FLAGS_SUPPORTED, 323 + .required_flags = HV_MSI_FLAGS_REQUIRED, 324 + .bus_select_token = DOMAIN_BUS_NEXUS, 325 + .bus_select_mask = MATCH_PCI_MSI, 326 + .chip_flags = MSI_CHIP_FLAG_SET_ACK, 327 + .prefix = "HV-", 328 + .init_dev_msi_info = hv_init_dev_msi_info, 327 329 }; 328 330 329 - static struct msi_domain_info hv_pci_msi_domain_info = { 330 - .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 331 - MSI_FLAG_PCI_MSIX, 332 - .ops = &pci_msi_domain_ops, 333 - .chip = &hv_pci_msi_controller, 334 - .handler = handle_edge_irq, 335 - .handler_name = "edge", 331 + static int hv_msi_domain_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, 332 + void *arg) 333 + { 334 + /* 335 + * TODO: The allocation bits of hv_irq_compose_msi_msg(), i.e. everything except 336 + * entry_to_msi_msg() should be in here. 337 + */ 338 + 339 + int ret; 340 + 341 + ret = irq_domain_alloc_irqs_parent(d, virq, nr_irqs, arg); 342 + if (ret) 343 + return ret; 344 + 345 + for (int i = 0; i < nr_irqs; ++i) { 346 + irq_domain_set_info(d, virq + i, 0, &hv_pci_msi_controller, NULL, 347 + handle_edge_irq, NULL, "edge"); 348 + } 349 + return 0; 350 + } 351 + 352 + static void hv_msi_domain_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs) 353 + { 354 + for (int i = 0; i < nr_irqs; ++i) { 355 + struct irq_data *irqd = irq_domain_get_irq_data(d, virq); 356 + struct msi_desc *desc; 357 + 358 + desc = irq_data_get_msi_desc(irqd); 359 + if (!desc || !desc->irq || WARN_ON_ONCE(!dev_is_pci(desc->dev))) 360 + continue; 361 + 362 + hv_teardown_msi_irq(to_pci_dev(desc->dev), irqd); 363 + } 364 + irq_domain_free_irqs_top(d, virq, nr_irqs); 365 + } 366 + 367 + static const struct irq_domain_ops hv_msi_domain_ops = { 368 + .select = msi_lib_irq_domain_select, 369 + .alloc = hv_msi_domain_alloc, 370 + .free = hv_msi_domain_free, 336 371 }; 337 372 338 373 struct irq_domain * __init hv_create_pci_msi_domain(void) 339 374 { 340 375 struct irq_domain *d = NULL; 341 - struct fwnode_handle *fn; 342 376 343 - fn = irq_domain_alloc_named_fwnode("HV-PCI-MSI"); 344 - if (fn) 345 - d = pci_msi_create_irq_domain(fn, &hv_pci_msi_domain_info, x86_vector_domain); 377 + struct irq_domain_info info = { 378 + .fwnode = irq_domain_alloc_named_fwnode("HV-PCI-MSI"), 379 + .ops = &hv_msi_domain_ops, 380 + .parent = x86_vector_domain, 381 + }; 382 + 383 + if (info.fwnode) 384 + d = msi_create_parent_irq_domain(&info, &hv_msi_parent_ops); 346 385 347 386 /* No point in going further if we can't get an irq domain */ 348 387 BUG_ON(!d);
+1
drivers/hv/Kconfig
··· 10 10 select X86_HV_CALLBACK_VECTOR if X86 11 11 select OF_EARLY_FLATTREE if OF 12 12 select SYSFB if EFI && !HYPERV_VTL_MODE 13 + select IRQ_MSI_LIB if X86 13 14 help 14 15 Select this option to run Linux as a Hyper-V client operating 15 16 system.