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

Commit 6d688f04 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "haven: irq: Support lending from other domains"

parents abc354e6 f7c7a200
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