diff mbox series

[2/2] irqchip/loongson-eiointc: simplify irq route on one eioi-node system

Message ID 20230704132108.1096940-3-maobibo@loongson.cn (mailing list archive)
State Handled Elsewhere
Headers show
Series irqchip/loongson-eiointc: use simple irq route | expand

Commit Message

Bibo Mao July 4, 2023, 1:21 p.m. UTC
Some LoongArch systems has only one eioi node such as 3A5000 machine
and qemu virt-machine. If there is only one eioi node, all cpus can
access eioi register directly; if there is multiple eioi nodes, cpus
can only access specified eioi node, so anysend or ipi need be used
to configure irq routing. IRQ routing is simple on such system with
one node, hacking method like anysend is not necessary.

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Change-Id: I351e615ab15b79a1a3a4b96943a32c0ff5df2b13
---
 drivers/irqchip/irq-loongson-eiointc.c | 71 ++++++++++++++++++++++++--
 1 file changed, 66 insertions(+), 5 deletions(-)

Comments

Bibo Mao July 6, 2023, 12:30 a.m. UTC | #1
will add simple route for embedded system like 2K500 and 2K2000 in next patch. 
-       ret = eiointc_init(priv, parent_irq, 0);
+       /*
+        * 2k0500 and 2k2000 has only one eio node
+        * set nodemap as 1 for simple irq routing
+        * what about for future embedded board more than 4 cpus??
+        */
+       ret = eiointc_init(priv, parent_irq, 1);

Regards
Bbibo Mao

在 2023/7/4 21:21, Bibo Mao 写道:
> Some LoongArch systems has only one eioi node such as 3A5000 machine
> and qemu virt-machine. If there is only one eioi node, all cpus can
> access eioi register directly; if there is multiple eioi nodes, cpus
> can only access specified eioi node, so anysend or ipi need be used
> to configure irq routing. IRQ routing is simple on such system with
> one node, hacking method like anysend is not necessary.
> 
> Signed-off-by: Bibo Mao <maobibo@loongson.cn>
> Change-Id: I351e615ab15b79a1a3a4b96943a32c0ff5df2b13
> ---
>  drivers/irqchip/irq-loongson-eiointc.c | 71 ++++++++++++++++++++++++--
>  1 file changed, 66 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
> index 1c5a5b59f199..4759c0ae8edb 100644
> --- a/drivers/irqchip/irq-loongson-eiointc.c
> +++ b/drivers/irqchip/irq-loongson-eiointc.c
> @@ -127,6 +127,48 @@ static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *af
>  	return IRQ_SET_MASK_OK;
>  }
>  
> +static int eiointc_single_set_irq_affinity(struct irq_data *d,
> +				const struct cpumask *affinity, bool force)
> +{
> +	unsigned int cpu;
> +	unsigned long flags;
> +	uint32_t vector, regaddr, data, coremap;
> +	struct cpumask mask;
> +	struct eiointc_priv *priv = d->domain->host_data;
> +
> +	cpumask_and(&mask, affinity, cpu_online_mask);
> +	cpumask_and(&mask, &mask, &priv->cpuspan_map);
> +	if (cpumask_empty(&mask))
> +		return -EINVAL;
> +
> +	cpu = cpumask_first(&mask);
> +	vector = d->hwirq;
> +	regaddr = EIOINTC_REG_ENABLE + ((vector >> 5) << 2);
> +	data = ~BIT(vector & 0x1F);
> +	coremap = BIT(cpu_logical_map(cpu) % CORES_PER_EIO_NODE);
> +
> +	/*
> +	 * simplify for only one eio node
> +	 * access eio registers directly rather than
> +	 * use any_send hack method here
> +	 */
> +	raw_spin_lock_irqsave(&affinity_lock, flags);
> +	iocsr_write32(EIOINTC_ALL_ENABLE & data, regaddr);
> +	/*
> +	 * get irq route info for continuous 4 vectors
> +	 * and set affinity for specified vector
> +	 */
> +	data = iocsr_read32(EIOINTC_REG_ROUTE + (vector & ~3));
> +	data &=  ~(0xff << ((vector & 3) * 8));
> +	data |= coremap << ((vector & 3) * 8);
> +	iocsr_write32(data, EIOINTC_REG_ROUTE + (vector & ~3));
> +	iocsr_write32(EIOINTC_ALL_ENABLE, regaddr);
> +	raw_spin_unlock_irqrestore(&affinity_lock, flags);
> +
> +	irq_data_update_effective_affinity(d, cpumask_of(cpu));
> +	return IRQ_SET_MASK_OK;
> +}
> +
>  static int eiointc_index(int node)
>  {
>  	int i;
> @@ -237,22 +279,39 @@ static struct irq_chip eiointc_irq_chip = {
>  	.irq_set_affinity	= eiointc_set_irq_affinity,
>  };
>  
> +static struct irq_chip eiointc_irq_chipi_single = {
> +	.name			= "EIOINTC-S",
> +	.irq_ack		= eiointc_ack_irq,
> +	.irq_mask		= eiointc_mask_irq,
> +	.irq_unmask		= eiointc_unmask_irq,
> +#ifdef CONFIG_SMP
> +	.irq_set_affinity       = eiointc_single_set_irq_affinity,
> +#endif
> +};
> +
>  static int eiointc_domain_alloc(struct irq_domain *domain, unsigned int virq,
>  				unsigned int nr_irqs, void *arg)
>  {
>  	int ret;
>  	unsigned int i, type;
>  	unsigned long hwirq = 0;
> -	struct eiointc *priv = domain->host_data;
> +	struct eiointc_priv *priv = domain->host_data;
> +	struct irq_chip *chip;
>  
>  	ret = irq_domain_translate_onecell(domain, arg, &hwirq, &type);
>  	if (ret)
>  		return ret;
>  
> -	for (i = 0; i < nr_irqs; i++) {
> -		irq_domain_set_info(domain, virq + i, hwirq + i, &eiointc_irq_chip,
> +	/*
> +	 * use simple irq route method for single node eiointc
> +	 */
> +	if (nodes_weight(priv->node_map) == 1)
> +		chip = &eiointc_irq_chipi_single;
> +	else
> +		chip = &eiointc_irq_chip;
> +	for (i = 0; i < nr_irqs; i++)
> +		irq_domain_set_info(domain, virq + i, hwirq + i, chip,
>  					priv, handle_edge_irq, NULL, NULL);
> -	}
>  
>  	return 0;
>  }
> @@ -309,6 +368,7 @@ static void eiointc_resume(void)
>  	int i, j;
>  	struct irq_desc *desc;
>  	struct irq_data *irq_data;
> +	struct irq_chip *chip;
>  
>  	eiointc_router_init(0);
>  
> @@ -318,7 +378,8 @@ static void eiointc_resume(void)
>  			if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) {
>  				raw_spin_lock(&desc->lock);
>  				irq_data = irq_domain_get_irq_data(eiointc_priv[i]->eiointc_domain, irq_desc_get_irq(desc));
> -				eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0);
> +				chip = irq_data_get_irq_chip(irq_data);
> +				chip->irq_set_affinity(irq_data, irq_data->common->affinity, 0);
>  				raw_spin_unlock(&desc->lock);
>  			}
>  		}
diff mbox series

Patch

diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
index 1c5a5b59f199..4759c0ae8edb 100644
--- a/drivers/irqchip/irq-loongson-eiointc.c
+++ b/drivers/irqchip/irq-loongson-eiointc.c
@@ -127,6 +127,48 @@  static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *af
 	return IRQ_SET_MASK_OK;
 }
 
+static int eiointc_single_set_irq_affinity(struct irq_data *d,
+				const struct cpumask *affinity, bool force)
+{
+	unsigned int cpu;
+	unsigned long flags;
+	uint32_t vector, regaddr, data, coremap;
+	struct cpumask mask;
+	struct eiointc_priv *priv = d->domain->host_data;
+
+	cpumask_and(&mask, affinity, cpu_online_mask);
+	cpumask_and(&mask, &mask, &priv->cpuspan_map);
+	if (cpumask_empty(&mask))
+		return -EINVAL;
+
+	cpu = cpumask_first(&mask);
+	vector = d->hwirq;
+	regaddr = EIOINTC_REG_ENABLE + ((vector >> 5) << 2);
+	data = ~BIT(vector & 0x1F);
+	coremap = BIT(cpu_logical_map(cpu) % CORES_PER_EIO_NODE);
+
+	/*
+	 * simplify for only one eio node
+	 * access eio registers directly rather than
+	 * use any_send hack method here
+	 */
+	raw_spin_lock_irqsave(&affinity_lock, flags);
+	iocsr_write32(EIOINTC_ALL_ENABLE & data, regaddr);
+	/*
+	 * get irq route info for continuous 4 vectors
+	 * and set affinity for specified vector
+	 */
+	data = iocsr_read32(EIOINTC_REG_ROUTE + (vector & ~3));
+	data &=  ~(0xff << ((vector & 3) * 8));
+	data |= coremap << ((vector & 3) * 8);
+	iocsr_write32(data, EIOINTC_REG_ROUTE + (vector & ~3));
+	iocsr_write32(EIOINTC_ALL_ENABLE, regaddr);
+	raw_spin_unlock_irqrestore(&affinity_lock, flags);
+
+	irq_data_update_effective_affinity(d, cpumask_of(cpu));
+	return IRQ_SET_MASK_OK;
+}
+
 static int eiointc_index(int node)
 {
 	int i;
@@ -237,22 +279,39 @@  static struct irq_chip eiointc_irq_chip = {
 	.irq_set_affinity	= eiointc_set_irq_affinity,
 };
 
+static struct irq_chip eiointc_irq_chipi_single = {
+	.name			= "EIOINTC-S",
+	.irq_ack		= eiointc_ack_irq,
+	.irq_mask		= eiointc_mask_irq,
+	.irq_unmask		= eiointc_unmask_irq,
+#ifdef CONFIG_SMP
+	.irq_set_affinity       = eiointc_single_set_irq_affinity,
+#endif
+};
+
 static int eiointc_domain_alloc(struct irq_domain *domain, unsigned int virq,
 				unsigned int nr_irqs, void *arg)
 {
 	int ret;
 	unsigned int i, type;
 	unsigned long hwirq = 0;
-	struct eiointc *priv = domain->host_data;
+	struct eiointc_priv *priv = domain->host_data;
+	struct irq_chip *chip;
 
 	ret = irq_domain_translate_onecell(domain, arg, &hwirq, &type);
 	if (ret)
 		return ret;
 
-	for (i = 0; i < nr_irqs; i++) {
-		irq_domain_set_info(domain, virq + i, hwirq + i, &eiointc_irq_chip,
+	/*
+	 * use simple irq route method for single node eiointc
+	 */
+	if (nodes_weight(priv->node_map) == 1)
+		chip = &eiointc_irq_chipi_single;
+	else
+		chip = &eiointc_irq_chip;
+	for (i = 0; i < nr_irqs; i++)
+		irq_domain_set_info(domain, virq + i, hwirq + i, chip,
 					priv, handle_edge_irq, NULL, NULL);
-	}
 
 	return 0;
 }
@@ -309,6 +368,7 @@  static void eiointc_resume(void)
 	int i, j;
 	struct irq_desc *desc;
 	struct irq_data *irq_data;
+	struct irq_chip *chip;
 
 	eiointc_router_init(0);
 
@@ -318,7 +378,8 @@  static void eiointc_resume(void)
 			if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) {
 				raw_spin_lock(&desc->lock);
 				irq_data = irq_domain_get_irq_data(eiointc_priv[i]->eiointc_domain, irq_desc_get_irq(desc));
-				eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0);
+				chip = irq_data_get_irq_chip(irq_data);
+				chip->irq_set_affinity(irq_data, irq_data->common->affinity, 0);
 				raw_spin_unlock(&desc->lock);
 			}
 		}