Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
Arquivo: msi.c Projeto: mkrufky/linux
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;
}
Exemplo n.º 3
0
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);
}