static int hyperv_irq_remapping_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { struct irq_alloc_info *info = arg; struct irq_data *irq_data; struct irq_desc *desc; int ret = 0; if (!info || info->type != X86_IRQ_ALLOC_TYPE_IOAPIC || nr_irqs > 1) return -EINVAL; ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg); if (ret < 0) return ret; irq_data = irq_domain_get_irq_data(domain, virq); if (!irq_data) { irq_domain_free_irqs_common(domain, virq, nr_irqs); return -EINVAL; } irq_data->chip = &hyperv_ir_chip; /* * If there is interrupt remapping function of IOMMU, setting irq * affinity only needs to change IRTE of IOMMU. But Hyper-V doesn't * support interrupt remapping function, setting irq affinity of IO-APIC * interrupts still needs to change IO-APIC registers. But ioapic_ * configure_entry() will ignore value of cfg->vector and cfg-> * dest_apicid when IO-APIC's parent irq domain is not the vector * domain.(See ioapic_configure_entry()) In order to setting vector * and dest_apicid to IO-APIC register, IO-APIC entry pointer is saved * in the chip_data and hyperv_irq_remapping_activate()/hyperv_ir_set_ * affinity() set vector and dest_apicid directly into IO-APIC entry. */ irq_data->chip_data = info->ioapic_entry; /* * Hypver-V IO APIC irq affinity should be in the scope of * ioapic_max_cpumask because no irq remapping support. */ desc = irq_data_to_desc(irq_data); cpumask_copy(desc->irq_common_data.affinity, &ioapic_max_cpumask); return 0; }
int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev, int virq, int nvec, msi_alloc_info_t *arg) { struct msi_domain_info *info = domain->host_data; struct msi_domain_ops *ops = info->ops; struct msi_desc *desc; int ret = 0; for_each_msi_entry(desc, dev) { /* Don't even try the multi-MSI brain damage. */ if (WARN_ON(!desc->irq || desc->nvec_used != 1)) { ret = -EINVAL; break; } if (!(desc->irq >= virq && desc->irq < (virq + nvec))) continue; ops->set_desc(arg, desc); /* Assumes the domain mutex is held! */ ret = irq_domain_alloc_irqs_hierarchy(domain, desc->irq, 1, arg); if (ret) break; irq_set_msi_desc_off(desc->irq, 0, desc); } if (ret) { /* Mop up the damage */ for_each_msi_entry(desc, dev) { if (!(desc->irq >= virq && desc->irq < (virq + nvec))) continue; irq_domain_free_irqs_common(domain, desc->irq, 1); } } return ret; }
static void hyperv_irq_remapping_free(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs) { irq_domain_free_irqs_common(domain, virq, nr_irqs); }