Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7c7a200 authored by Elliot Berman's avatar Elliot Berman Committed by Gerrit - the friendly Code Review server
Browse files

haven: irq: Support lending from other domains



Client drivers may lend IRQs with knowledge of only their GPIO interrupt
number, which would not directly have an underlying GIC hwirq. Thus,
tweak RM's understanding of IRQs to be aware of IRQ domains. Now, the
irq backed by GPIO will be translated to GIC domain.

Change-Id: I191d9e072b14f4501f5bbeb5d5263f50e0eef8c1
Signed-off-by: default avatarElliot Berman <eberman@codeaurora.org>
parent 28cf0d09
Loading
Loading
Loading
Loading
+7 −12
Original line number Diff line number Diff line
@@ -141,17 +141,14 @@ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name,
	int ret, virq;
	unsigned long flags;
	struct hh_irq_entry *entry;
	struct irq_data *irq_data;

	if (label >= HH_IRQ_LABEL_MAX || !on_release)
		return -EINVAL;

	entry = &hh_irq_entries[label];

	irq_data = irq_get_irq_data(irq);
	if (!irq_data)
	if (hh_rm_irq_to_virq(irq, &virq))
		return -EINVAL;
	virq = irq_data->hwirq;

	spin_lock_irqsave(&hh_irq_lend_lock, flags);
	if (entry->state != HH_IRQ_STATE_NONE) {
@@ -245,17 +242,18 @@ EXPORT_SYMBOL(hh_irq_wait_for_lend);
 * hh_irq_accept: Register to receive interrupts with a lent vIRQ
 * @label: vIRQ high-level label
 * @irq: Linux IRQ# to associate vIRQ with. If don't care, use -1
 * @type: IRQ flags to use when allowing RM to choose the IRQ. If irq parameter
 *        is specified, then type is unused.
 *
 * Returns the Linux IRQ# that vIRQ was registered to on success.
 * Returns <0 on error
 * This function is not thread-safe w.r.t. IRQ lend state. Do not race with
 * with hh_irq_release or another hh_irq_accept with same label.
 */
int hh_irq_accept(enum hh_irq_label label, int irq)
int hh_irq_accept(enum hh_irq_label label, int irq, int type)
{
	struct hh_irq_entry *entry;
	const struct irq_data *irq_data;
	int virq;
	u32 virq;

	if (label >= HH_IRQ_LABEL_MAX)
		return -EINVAL;
@@ -266,10 +264,8 @@ int hh_irq_accept(enum hh_irq_label label, int irq)
		return -EINVAL;

	if (irq != -1) {
		irq_data = irq_get_irq_data(irq);
		if (!irq_data)
		if (hh_rm_irq_to_virq(irq, &virq))
			return -EINVAL;
		virq = irq_data->hwirq;
	} else
		virq = -1;

@@ -278,8 +274,7 @@ int hh_irq_accept(enum hh_irq_label label, int irq)
		return virq;

	if (irq == -1)
		irq = hh_rm_virq_to_linux_irq(virq - 32, GIC_SPI,
					      IRQ_TYPE_LEVEL_HIGH);
		irq = hh_rm_virq_to_irq(virq, type);

	return irq;
}
+47 −7
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ static DEFINE_MUTEX(hh_rm_send_lock);

static DEFINE_IDA(hh_rm_free_virq_ida);
static struct device_node *hh_rm_intc;
static struct irq_domain *hh_rm_irq_domain;
static u32 hh_rm_base_virq;

SRCU_NOTIFIER_HEAD_STATIC(hh_rm_notifier);
@@ -624,19 +625,54 @@ void *hh_rm_call(hh_rm_msgid_t message_id,
	return ret;
}

int hh_rm_virq_to_linux_irq(u32 virq, u32 type, u32 trigger)
/**
 * hh_rm_virq_to_irq: Get a Linux IRQ from a Haven-compatible vIRQ
 * @virq: Haven-compatible vIRQ
 * @type: IRQ trigger type (IRQ_TYPE_EDGE_RISING)
 *
 * Returns the mapped Linux IRQ# at Haven's IRQ domain (i.e. GIC SPI)
 */
int hh_rm_virq_to_irq(u32 virq, u32 type)
{
	struct irq_fwspec fwspec = {};

	if (virq < 32 || virq >= GIC_V3_SPI_MAX) {
		pr_warn("%s: expecting an SPI from RM, but got GIC IRQ %d\n",
			__func__, virq);
	}

	fwspec.fwnode = of_node_to_fwnode(hh_rm_intc);
	fwspec.param_count = 3;
	fwspec.param[0] = type;
	fwspec.param[1] = virq;
	fwspec.param[2] = trigger;
	fwspec.param[0] = GIC_SPI;
	fwspec.param[1] = virq - 32;
	fwspec.param[2] = type;

	return irq_create_fwspec_mapping(&fwspec);
}
EXPORT_SYMBOL(hh_rm_virq_to_linux_irq);
EXPORT_SYMBOL(hh_rm_virq_to_irq);

/**
 * hh_rm_irq_to_virq: Get a Haven-compatible vIRQ from a Linux IRQ
 * @irq: Linux-assigned IRQ#
 * @virq: out value where Haven-compatible vIRQ is stored
 *
 * Returns 0 upon success, -EINVAL if the Linux IRQ could not be mapped to
 * a Haven vIRQ (i.e., the IRQ does not correspond to any GIC-level IRQ)
 */
int hh_rm_irq_to_virq(int irq, u32 *virq)
{
	struct irq_data *irq_data;

	irq_data = irq_domain_get_irq_data(hh_rm_irq_domain, irq);
	if (!irq_data)
		return -EINVAL;

	if (virq)
		*virq = irq_data->hwirq;

	return 0;
}
EXPORT_SYMBOL(hh_rm_irq_to_virq);

static int hh_rm_get_irq(struct hh_vm_get_hyp_res_resp_entry *res_entry)
{
@@ -673,8 +709,7 @@ static int hh_rm_get_irq(struct hh_vm_get_hyp_res_resp_entry *res_entry)
		return -EINVAL;
	}

	return hh_rm_virq_to_linux_irq(virq - 32, GIC_SPI,
				       IRQ_TYPE_EDGE_RISING);
	return hh_rm_virq_to_irq(virq, IRQ_TYPE_EDGE_RISING);

err:
	ida_free(&hh_rm_free_virq_ida, virq - 32);
@@ -838,6 +873,11 @@ static int hh_rm_drv_probe(struct platform_device *pdev)
		dev_err(dev, "Failed to get the IRQ parent node\n");
		return -ENXIO;
	}
	hh_rm_irq_domain = irq_find_host(hh_rm_intc);
	if (!hh_rm_irq_domain) {
		dev_err(dev, "Failed to get IRQ domain associated with RM\n");
		return -ENXIO;
	}

	hh_rm_msgq_desc = hh_msgq_register(HH_MSGQ_LABEL_RM);
	if (IS_ERR_OR_NULL(hh_rm_msgq_desc))
+0 −1
Original line number Diff line number Diff line
@@ -281,7 +281,6 @@ struct hh_mem_notify_req_payload {
/* End Message ID headers */

/* Common function declerations */
int hh_rm_virq_to_linux_irq(u32 virq, u32 type, u32 trigger);
int hh_update_vm_prop_table(enum hh_vm_names vm_name,
			struct hh_vm_property *vm_prop);
void *hh_rm_call(hh_rm_msgid_t message_id,
+0 −1
Original line number Diff line number Diff line
@@ -373,7 +373,6 @@ static int hh_rm_vm_irq_release(hh_virq_handle_t virq_handle)

	return ret;
}
EXPORT_SYMBOL(hh_rm_vm_irq_release);

/**
 * hh_rm_vm_irq_release_notify: Release IRQ back to a VM and notify that it has
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ int hh_irq_reclaim(enum hh_irq_label label);

int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name,
			 hh_irq_handle_fn on_lend, void *data);
int hh_irq_accept(enum hh_irq_label label, int hw_irq);
int hh_irq_accept(enum hh_irq_label label, int irq, int type);
int hh_irq_release(enum hh_irq_label label);

#endif
Loading