Re: [PATCH v4 2/2] irqchip/loongson-eiointc: Simplify irq routing on some platforms

From: bibo mao
Date: Tue Jul 18 2023 - 23:54:55 EST


Jianmin,

Thank for your reply.

OK, qemu virt-machine eiointc model will be consistent with physical machine.
And let's wait for new LoongArch irqchip in future.

Regards
Bibo Mao

在 2023/7/19 11:33, Jianmin Lv 写道:
> Hi, bibo
>
> I think the patch has been it as we discussed offline, I have no further comments. And there's no plan to update EIOPIC structure in ACPI table since new advanced feature for LoongArch irq chip will be available in future.
>
> Thanks,
> Jianmin.
>
> On 2023/7/18 下午3:01, bibo mao wrote:
>> Jianmin,
>>
>> Do you have any comments so that I can update in the next version together?
>> since you are original author of eiointc driver.
>>
>> Is it possible to add extra specific version in eiointc acpi table for
>> virt-machine in future? For specific eiointc, irq can be routed to all
>> cpus rather cpu 0-3, I do not know whether it is deserved for qemu
>> virt-machine alone.
>>
>> Regards
>> Bibo Mao
>>
>> 在 2023/7/13 11:22, Bibo Mao 写道:
>>> Some LoongArch systems have only one eiointc node such as 3A5000/2K2000
>>> and qemu virt-machine. If there is only one eiointc node, all cpus can
>>> access eiointc registers directly; if there is multiple eiointc nodes, each
>>> cpu can only access eiointc belonging to specified node group, so anysend
>>> or ipi needs to be used to configure irq routing. IRQ routing is simple on
>>> such systems with one node, hacking method like anysend is not necessary.
>>>
>>> This patch provides simpile IRQ routing method for systems with one eiointc
>>> node, and is tested on 3A5000 board and qemu virt-machine.
>>>
>>> Signed-off-by: Bibo Mao <maobibo@xxxxxxxxxxx>
>>> ---
>>>   drivers/irqchip/irq-loongson-eiointc.c | 80 ++++++++++++++++++++++++--
>>>   1 file changed, 74 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
>>> index 603d323b8f8b..e6be9d6a18c8 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 platform with only one eiointc node
>>> +     * access eiointc registers directly rather than
>>> +     * use any_send 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;
>>> @@ -238,22 +280,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 routing method on single eiointc node
>>> +     */
>>> +    if ((nr_pics == 1) && (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;
>>>   }
>>> @@ -310,6 +369,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);
>>>   @@ -319,7 +379,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);
>>>               }
>>>           }
>>> @@ -497,7 +558,14 @@ static int __init eiointc_of_init(struct device_node *of_node,
>>>       priv->node = 0;
>>>       priv->domain_handle = of_node_to_fwnode(of_node);
>>>   -    ret = eiointc_init(priv, parent_irq, 0);
>>> +    /*
>>> +     * 2k0500 and 2k2000 has only one eiointc node
>>> +     * set nodemap as 1 for simple irq routing
>>> +     *
>>> +     * Fixme: what about future embedded boards with more than 4 cpus?
>>> +     * nodemap and node need be added in dts like acpi table
>>> +     */
>>> +    ret = eiointc_init(priv, parent_irq, 1);
>>>       if (ret < 0)
>>>           goto out_free_priv;
>>>  
>