Commit 6d31b6ff authored by Marc Zyngier's avatar Marc Zyngier
Browse files

irqchip/gic-v4.1: Add VSGI allocation/teardown



Allocate per-VPE SGIs when initializing the GIC-specific part of the
VPE data structure.

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Reviewed-by: default avatarZenghui Yu <yuzenghui@huawei.com>
Link: https://lore.kernel.org/r/20200304203330.4967-15-maz@kernel.org
parent ae699ad3
Loading
Loading
Loading
Loading
+67 −1
Original line number Diff line number Diff line
@@ -92,6 +92,47 @@ static bool has_v4_1(void)
	return !!sgi_domain_ops;
}

static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
{
	char *name;
	int sgi_base;

	if (!has_v4_1())
		return 0;

	name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current));
	if (!name)
		goto err;

	vpe->fwnode = irq_domain_alloc_named_id_fwnode(name, idx);
	if (!vpe->fwnode)
		goto err;

	kfree(name);
	name = NULL;

	vpe->sgi_domain = irq_domain_create_linear(vpe->fwnode, 16,
						   sgi_domain_ops, vpe);
	if (!vpe->sgi_domain)
		goto err;

	sgi_base = __irq_domain_alloc_irqs(vpe->sgi_domain, -1, 16,
					       NUMA_NO_NODE, vpe,
					       false, NULL);
	if (sgi_base <= 0)
		goto err;

	return 0;

err:
	if (vpe->sgi_domain)
		irq_domain_remove(vpe->sgi_domain);
	if (vpe->fwnode)
		irq_domain_free_fwnode(vpe->fwnode);
	kfree(name);
	return -ENOMEM;
}

int its_alloc_vcpu_irqs(struct its_vm *vm)
{
	int vpe_base_irq, i;
@@ -118,8 +159,13 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
	if (vpe_base_irq <= 0)
		goto err;

	for (i = 0; i < vm->nr_vpes; i++)
	for (i = 0; i < vm->nr_vpes; i++) {
		int ret;
		vm->vpes[i]->irq = vpe_base_irq + i;
		ret = its_alloc_vcpu_sgis(vm->vpes[i], i);
		if (ret)
			goto err;
	}

	return 0;

@@ -132,8 +178,28 @@ err:
	return -ENOMEM;
}

static void its_free_sgi_irqs(struct its_vm *vm)
{
	int i;

	if (!has_v4_1())
		return;

	for (i = 0; i < vm->nr_vpes; i++) {
		unsigned int irq = irq_find_mapping(vm->vpes[i]->sgi_domain, 0);

		if (WARN_ON(!irq))
			continue;

		irq_domain_free_irqs(irq, 16);
		irq_domain_remove(vm->vpes[i]->sgi_domain);
		irq_domain_free_fwnode(vm->vpes[i]->fwnode);
	}
}

void its_free_vcpu_irqs(struct its_vm *vm)
{
	its_free_sgi_irqs(vm);
	irq_domain_free_irqs(vm->vpes[0]->irq, vm->nr_vpes);
	irq_domain_remove(vm->domain);
	irq_domain_free_fwnode(vm->fwnode);
+2 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ struct its_vpe {
		};
		/* GICv4.1 implementations */
		struct {
			struct fwnode_handle	*fwnode;
			struct irq_domain	*sgi_domain;
			struct {
				u8	priority;
				bool	enabled;