mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 16:16:15 -04:00
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: Elliot Berman <eberman@codeaurora.org>
This commit is contained in:
parent
28cf0d0908
commit
f7c7a20027
6 changed files with 69 additions and 22 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 @@ out:
|
|||
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))
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -183,6 +183,9 @@ int hh_rm_register_notifier(struct notifier_block *nb);
|
|||
int hh_rm_unregister_notifier(struct notifier_block *nb);
|
||||
|
||||
/* Client APIs for IRQ management */
|
||||
int hh_rm_virq_to_irq(u32 virq, u32 type);
|
||||
int hh_rm_irq_to_virq(int irq, u32 *virq);
|
||||
|
||||
int hh_rm_vm_irq_accept(hh_virq_handle_t virq_handle, int virq);
|
||||
int hh_rm_vm_irq_lend_notify(hh_vmid_t vmid, int virq, int label,
|
||||
hh_virq_handle_t *virq_handle);
|
||||
|
|
@ -227,6 +230,7 @@ int hh_rm_mem_lend(u8 mem_type, u8 flags, hh_label_t label,
|
|||
int hh_rm_mem_notify(hh_memparcel_handle_t handle, u8 flags,
|
||||
hh_label_t mem_info_tag,
|
||||
struct hh_notify_vmid_desc *vmid_desc);
|
||||
|
||||
#else
|
||||
/* RM client register notifications APIs */
|
||||
static inline int hh_rm_register_notifier(struct notifier_block *nb)
|
||||
|
|
@ -240,6 +244,16 @@ static inline int hh_rm_unregister_notifier(struct notifier_block *nb)
|
|||
}
|
||||
|
||||
/* Client APIs for IRQ management */
|
||||
static inline int hh_rm_virq_to_irq(u32 virq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int hh_rm_irq_to_virq(int irq, u32 *virq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int hh_rm_vm_irq_accept(hh_virq_handle_t virq_handle, int virq)
|
||||
{
|
||||
return -EINVAL;
|
||||
|
|
|
|||
Loading…
Reference in a new issue