lkml.org 
[lkml]   [2023]   [Mar]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Date
Subject[PATCH RFC v2 1/2] irqchip: irq-ti-sci-inta: Allocates VINTs at probe
Simplify driver by allocating all VINTs at probe instead of
allocating on IRQ request. This will allow dedicating few VINTs as
direct IRQs without aggregation in future.

Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
---
drivers/irqchip/irq-ti-sci-inta.c | 144 +++++-----
1 file changed, 67 insertions(+), 77 deletions(-)

diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
index a6ecc53d055c..a3a22edbe0f0 100644
--- a/drivers/irqchip/irq-ti-sci-inta.c
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -96,6 +96,7 @@ struct ti_sci_inta_vint_desc {
* device identifier in place of the source device
* identifier to let sysfw know where it has to program the
* Global Event number.
+ * @num_vints: Number of VINT lines allocated to this IA.
*/
struct ti_sci_inta_irq_domain {
const struct ti_sci_handle *sci;
@@ -110,6 +111,7 @@ struct ti_sci_inta_irq_domain {

int unmapped_cnt;
u16 *unmapped_dev_ids;
+ int num_vints;
};

#define to_vint_desc(e, i) container_of(e, struct ti_sci_inta_vint_desc, \
@@ -197,12 +199,12 @@ static int ti_sci_inta_xlate_irq(struct ti_sci_inta_irq_domain *inta,
}

/**
- * ti_sci_inta_alloc_parent_irq() - Allocate parent irq to Interrupt aggregator
+ * ti_sci_inta_alloc_parent_irqs() - Allocate parent irqs to Interrupt aggregator
* @domain: IRQ domain corresponding to Interrupt Aggregator
*
* Return 0 if all went well else corresponding error value.
*/
-static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_domain *domain)
+static int ti_sci_inta_alloc_parent_irqs(struct irq_domain *domain)
{
struct ti_sci_inta_irq_domain *inta = domain->host_data;
struct ti_sci_inta_vint_desc *vint_desc;
@@ -211,61 +213,69 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
unsigned int parent_virq;
int p_hwirq, ret;
u16 vint_id;
+ int i;

- vint_id = ti_sci_get_free_resource(inta->vint);
- if (vint_id == TI_SCI_RESOURCE_NULL)
- return ERR_PTR(-EINVAL);
-
- p_hwirq = ti_sci_inta_xlate_irq(inta, vint_id);
- if (p_hwirq < 0) {
- ret = p_hwirq;
- goto free_vint;
- }
+ parent_node = of_irq_find_parent(dev_of_node(&inta->pdev->dev));
+ parent_fwspec.fwnode = of_node_to_fwnode(parent_node);

- vint_desc = kzalloc(sizeof(*vint_desc), GFP_KERNEL);
- if (!vint_desc) {
- ret = -ENOMEM;
- goto free_vint;
- }
+ for (i = 0; i < inta->num_vints; i++) {
+ vint_id = ti_sci_get_free_resource(inta->vint);
+ if (vint_id == TI_SCI_RESOURCE_NULL)
+ break;

- vint_desc->domain = domain;
- vint_desc->vint_id = vint_id;
- INIT_LIST_HEAD(&vint_desc->list);
+ p_hwirq = ti_sci_inta_xlate_irq(inta, vint_id);
+ if (p_hwirq < 0) {
+ ret = p_hwirq;
+ goto free_vint;
+ }

- parent_node = of_irq_find_parent(dev_of_node(&inta->pdev->dev));
- parent_fwspec.fwnode = of_node_to_fwnode(parent_node);
+ vint_desc = kzalloc(sizeof(*vint_desc), GFP_KERNEL);
+ if (!vint_desc) {
+ ret = -ENOMEM;
+ goto free_vint;
+ }

- if (of_device_is_compatible(parent_node, "arm,gic-v3")) {
- /* Parent is GIC */
- parent_fwspec.param_count = 3;
- parent_fwspec.param[0] = 0;
- parent_fwspec.param[1] = p_hwirq - 32;
- parent_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
- } else {
- /* Parent is Interrupt Router */
- parent_fwspec.param_count = 1;
- parent_fwspec.param[0] = p_hwirq;
- }
+ INIT_LIST_HEAD(&vint_desc->list);
+ vint_desc->domain = domain;
+ vint_desc->vint_id = vint_id;
+
+ if (of_device_is_compatible(parent_node, "arm,gic-v3")) {
+ /* Parent is GIC */
+ parent_fwspec.param_count = 3;
+ parent_fwspec.param[0] = 0;
+ parent_fwspec.param[1] = p_hwirq - 32;
+ parent_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
+ } else {
+ /* Parent is Interrupt Router */
+ parent_fwspec.param_count = 1;
+ parent_fwspec.param[0] = p_hwirq;
+ }

- parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
- if (parent_virq == 0) {
- dev_err(&inta->pdev->dev, "Parent IRQ allocation failed\n");
- ret = -EINVAL;
- goto free_vint_desc;
+ parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
+ if (parent_virq == 0) {
+ dev_dbg(&inta->pdev->dev, "Parent IRQ allocation failed\n");
+ /*
+ * Certain versions of firmwares don't have
+ * enough INTR lines allocated to match number
+ * of VINTs, hence don't error out to maintain
+ * backward compatibility.
+ */
+ ret = 0;
+ goto free_vint_desc;
+ }
+ vint_desc->parent_virq = parent_virq;

+ list_add_tail(&vint_desc->list, &inta->vint_list);
+ irq_set_chained_handler_and_data(vint_desc->parent_virq,
+ ti_sci_inta_irq_handler, vint_desc);
}
- vint_desc->parent_virq = parent_virq;

- list_add_tail(&vint_desc->list, &inta->vint_list);
- irq_set_chained_handler_and_data(vint_desc->parent_virq,
- ti_sci_inta_irq_handler, vint_desc);
-
- return vint_desc;
+ return 0;
free_vint_desc:
kfree(vint_desc);
free_vint:
ti_sci_release_resource(inta->vint, vint_id);
- return ERR_PTR(ret);
+ return ret;
}

/**
@@ -335,22 +345,14 @@ static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_irq(struct irq_domain *d
MAX_EVENTS_PER_VINT);
if (free_bit != MAX_EVENTS_PER_VINT) {
set_bit(free_bit, vint_desc->event_map);
- goto alloc_event;
+ break;
}
}
-
- /* No free bits available. Allocate a new vint */
- vint_desc = ti_sci_inta_alloc_parent_irq(domain);
- if (IS_ERR(vint_desc)) {
- event_desc = ERR_CAST(vint_desc);
+ if (free_bit == MAX_EVENTS_PER_VINT) {
+ event_desc = NULL;
goto unlock;
}

- free_bit = find_first_zero_bit(vint_desc->event_map,
- MAX_EVENTS_PER_VINT);
- set_bit(free_bit, vint_desc->event_map);
-
-alloc_event:
event_desc = ti_sci_inta_alloc_event(vint_desc, free_bit, hwirq);
if (IS_ERR(event_desc))
clear_bit(free_bit, vint_desc->event_map);
@@ -360,22 +362,6 @@ static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_irq(struct irq_domain *d
return event_desc;
}

-/**
- * ti_sci_inta_free_parent_irq() - Free a parent irq to INTA
- * @inta: Pointer to inta domain.
- * @vint_desc: Pointer to vint_desc that needs to be freed.
- */
-static void ti_sci_inta_free_parent_irq(struct ti_sci_inta_irq_domain *inta,
- struct ti_sci_inta_vint_desc *vint_desc)
-{
- if (find_first_bit(vint_desc->event_map, MAX_EVENTS_PER_VINT) == MAX_EVENTS_PER_VINT) {
- list_del(&vint_desc->list);
- ti_sci_release_resource(inta->vint, vint_desc->vint_id);
- irq_dispose_mapping(vint_desc->parent_virq);
- kfree(vint_desc);
- }
-}
-
/**
* ti_sci_inta_free_irq() - Free an IRQ within INTA domain
* @event_desc: Pointer to event_desc that needs to be freed.
@@ -405,7 +391,6 @@ static void ti_sci_inta_free_irq(struct ti_sci_inta_event_desc *event_desc,
event_desc->global_event = TI_SCI_RESOURCE_NULL;
event_desc->hwirq = 0;

- ti_sci_inta_free_parent_irq(inta, vint_desc);
mutex_unlock(&inta->vint_mutex);
}

@@ -414,8 +399,7 @@ static void ti_sci_inta_free_irq(struct ti_sci_inta_event_desc *event_desc,
* @data: Pointer to corresponding irq_data
*
* Note: This is the core api where the actual allocation happens for input
- * hwirq. This allocation involves creating a parent irq for vint.
- * If this is done in irq_domain_ops.alloc() then a deadlock is reached
+ * hwirq. If this is done in irq_domain_ops.alloc() then a deadlock is reached
* for allocation. So this allocation is being done in request_resources()
*
* Return: 0 if all went well else corresponding error.
@@ -437,8 +421,7 @@ static int ti_sci_inta_request_resources(struct irq_data *data)
* ti_sci_inta_release_resources - Release resources for input irq
* @data: Pointer to corresponding irq_data
*
- * Note: Corresponding to request_resources(), all the unmapping and deletion
- * of parent vint irqs happens in this api.
+ * Note: Corresponding to request_resources(), release event mapping
*/
static void ti_sci_inta_release_resources(struct irq_data *data)
{
@@ -701,8 +684,9 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
if (ret)
return ret;

+ inta->num_vints = ti_sci_get_num_resources(inta->vint);
domain = irq_domain_add_linear(dev_of_node(dev),
- ti_sci_get_num_resources(inta->vint),
+ inta->num_vints,
&ti_sci_inta_irq_domain_ops, inta);
if (!domain) {
dev_err(dev, "Failed to allocate IRQ domain\n");
@@ -721,6 +705,12 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&inta->vint_list);
mutex_init(&inta->vint_mutex);

+ ret = ti_sci_inta_alloc_parent_irqs(domain);
+ if (ret) {
+ irq_domain_remove(msi_domain);
+ irq_domain_remove(domain);
+ }
+
dev_info(dev, "Interrupt Aggregator domain %d created\n", inta->ti_sci_id);

return 0;
--
2.40.0

\
 
 \ /
  Last update: 2023-03-27 17:06    [W:0.058 / U:1.236 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site