2024-03-16 08:22:10

by Tianyang Zhang

[permalink] [raw]
Subject: [PATCH V2] irqchip/loongson-pch-pic: Update interrupt registration policy

From: Baoqi Zhang <[email protected]>

This patch remove the fixed mapping between the 7A interrupt source
and the HT interrupt vector, and replaced it with a dynamically
allocated approach.

We introduce a mapping table in struct pch_pic, where each interrupt
source will allocate an index as a 'hwirq' from the table in the order
of application and set table value as interrupt source number. This hwirq
will be configured as its vector in the HT interrupt controller. For an
interrupt source, the validity period of the obtained hwirq will last until
the system reset

This will be more conducive to fully utilizing existing vectors to
support more devices

Signed-off-by: Baoqi Zhang <[email protected]>
Signed-off-by: Biao Dong <[email protected]>
Signed-off-by: Tianyang Zhang <[email protected]>
---
drivers/irqchip/irq-loongson-pch-pic.c | 77 ++++++++++++++++++++------
1 file changed, 59 insertions(+), 18 deletions(-)

diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c
index 63db8e2172e0..f17187641154 100644
--- a/drivers/irqchip/irq-loongson-pch-pic.c
+++ b/drivers/irqchip/irq-loongson-pch-pic.c
@@ -33,7 +33,7 @@
#define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT)
#define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
#define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)
-
+#define PIC_UNDEF_VECTOR 255
static int nr_pics;

struct pch_pic {
@@ -46,12 +46,19 @@ struct pch_pic {
u32 saved_vec_en[PIC_REG_COUNT];
u32 saved_vec_pol[PIC_REG_COUNT];
u32 saved_vec_edge[PIC_REG_COUNT];
+ u8 table[PIC_COUNT];
+ int inuse;
};

static struct pch_pic *pch_pic_priv[MAX_IO_PICS];

struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];

+static inline u8 hwirq_to_bit(struct pch_pic *priv, int hirq)
+{
+ return priv->table[hirq];
+}
+
static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
{
u32 reg;
@@ -80,45 +87,47 @@ static void pch_pic_mask_irq(struct irq_data *d)
{
struct pch_pic *priv = irq_data_get_irq_chip_data(d);

- pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq);
+ pch_pic_bitset(priv, PCH_PIC_MASK, hwirq_to_bit(priv, d->hwirq));
irq_chip_mask_parent(d);
}

static void pch_pic_unmask_irq(struct irq_data *d)
{
struct pch_pic *priv = irq_data_get_irq_chip_data(d);
+ int bit = hwirq_to_bit(priv, d->hwirq);

- writel(BIT(PIC_REG_BIT(d->hwirq)),
- priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
+ writel(BIT(PIC_REG_BIT(bit)),
+ priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);

irq_chip_unmask_parent(d);
- pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq);
+ pch_pic_bitclr(priv, PCH_PIC_MASK, bit);
}

static int pch_pic_set_type(struct irq_data *d, unsigned int type)
{
struct pch_pic *priv = irq_data_get_irq_chip_data(d);
+ int bit = hwirq_to_bit(priv, d->hwirq);
int ret = 0;

switch (type) {
case IRQ_TYPE_EDGE_RISING:
- pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
- pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
+ pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
+ pch_pic_bitclr(priv, PCH_PIC_POL, bit);
irq_set_handler_locked(d, handle_edge_irq);
break;
case IRQ_TYPE_EDGE_FALLING:
- pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
- pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
+ pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
+ pch_pic_bitset(priv, PCH_PIC_POL, bit);
irq_set_handler_locked(d, handle_edge_irq);
break;
case IRQ_TYPE_LEVEL_HIGH:
- pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
- pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
+ pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
+ pch_pic_bitclr(priv, PCH_PIC_POL, bit);
irq_set_handler_locked(d, handle_level_irq);
break;
case IRQ_TYPE_LEVEL_LOW:
- pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
- pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
+ pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
+ pch_pic_bitset(priv, PCH_PIC_POL, bit);
irq_set_handler_locked(d, handle_level_irq);
break;
default:
@@ -133,11 +142,12 @@ static void pch_pic_ack_irq(struct irq_data *d)
{
unsigned int reg;
struct pch_pic *priv = irq_data_get_irq_chip_data(d);
+ int bit = hwirq_to_bit(priv, d->hwirq);

- reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4);
- if (reg & BIT(PIC_REG_BIT(d->hwirq))) {
- writel(BIT(PIC_REG_BIT(d->hwirq)),
- priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
+ reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(bit) * 4);
+ if (reg & BIT(PIC_REG_BIT(bit))) {
+ writel(BIT(PIC_REG_BIT(bit)),
+ priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
}
irq_chip_ack_parent(d);
}
@@ -159,6 +169,8 @@ static int pch_pic_domain_translate(struct irq_domain *d,
{
struct pch_pic *priv = d->host_data;
struct device_node *of_node = to_of_node(fwspec->fwnode);
+ unsigned long flags;
+ int i;

if (of_node) {
if (fwspec->param_count < 2)
@@ -171,6 +183,27 @@ static int pch_pic_domain_translate(struct irq_domain *d,
return -EINVAL;

*hwirq = fwspec->param[0] - priv->gsi_base;
+
+ raw_spin_lock_irqsave(&priv->pic_lock, flags);
+ /* Check pic-table to confirm if the hwirq has been assigned */
+ for (i = 0; i < priv->inuse; i++) {
+ if (priv->table[i] == *hwirq) {
+ *hwirq = i;
+ break;
+ }
+ }
+ if (i == priv->inuse) {
+ /* Assign a new hwirq in pic-table */
+ if (priv->inuse >= PIC_COUNT) {
+ pr_err("pch-pic domain has no free vectors\n");
+ raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
+ return -EINVAL;
+ }
+ priv->table[priv->inuse] = *hwirq;
+ *hwirq = priv->inuse++;
+ }
+ raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
+
if (fwspec->param_count > 1)
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
else
@@ -194,6 +227,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
if (err)
return err;

+ /* Write vector ID */
+ writeb(priv->ht_vec_base + hwirq, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, hwirq)));
+
parent_fwspec.fwnode = domain->parent->fwnode;
parent_fwspec.param_count = 1;
parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
@@ -222,7 +258,7 @@ static void pch_pic_reset(struct pch_pic *priv)

for (i = 0; i < PIC_COUNT; i++) {
/* Write vector ID */
- writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
+ writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, i)));
/* Hardcode route to HT0 Lo */
writeb(1, priv->base + PCH_INT_ROUTE(i));
}
@@ -284,6 +320,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
u32 gsi_base)
{
struct pch_pic *priv;
+ int i;

priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -294,6 +331,10 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
if (!priv->base)
goto free_priv;

+ priv->inuse = 0;
+ for (i = 0; i < PIC_COUNT; i++)
+ priv->table[i] = PIC_UNDEF_VECTOR;
+
priv->ht_vec_base = vec_base;
priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
priv->gsi_base = gsi_base;
--
2.20.1



2024-03-16 14:03:42

by Christophe JAILLET

[permalink] [raw]
Subject: Re: [PATCH V2] irqchip/loongson-pch-pic: Update interrupt registration policy

Le 16/03/2024 à 09:21, Tianyang Zhang a écrit :
> From: Baoqi Zhang <[email protected]>
>
> This patch remove the fixed mapping between the 7A interrupt source
> and the HT interrupt vector, and replaced it with a dynamically
> allocated approach.
>
> We introduce a mapping table in struct pch_pic, where each interrupt
> source will allocate an index as a 'hwirq' from the table in the order
> of application and set table value as interrupt source number. This hwirq
> will be configured as its vector in the HT interrupt controller. For an
> interrupt source, the validity period of the obtained hwirq will last until
> the system reset
>
> This will be more conducive to fully utilizing existing vectors to
> support more devices
>
> Signed-off-by: Baoqi Zhang <[email protected]>
> Signed-off-by: Biao Dong <[email protected]>
> Signed-off-by: Tianyang Zhang <[email protected]>
> ---
> drivers/irqchip/irq-loongson-pch-pic.c | 77 ++++++++++++++++++++------
> 1 file changed, 59 insertions(+), 18 deletions(-)
>

..

> @@ -171,6 +183,27 @@ static int pch_pic_domain_translate(struct irq_domain *d,
> return -EINVAL;
>
> *hwirq = fwspec->param[0] - priv->gsi_base;
> +
> + raw_spin_lock_irqsave(&priv->pic_lock, flags);
> + /* Check pic-table to confirm if the hwirq has been assigned */
> + for (i = 0; i < priv->inuse; i++) {
> + if (priv->table[i] == *hwirq) {
> + *hwirq = i;
> + break;
> + }
> + }
> + if (i == priv->inuse) {
> + /* Assign a new hwirq in pic-table */
> + if (priv->inuse >= PIC_COUNT) {
> + pr_err("pch-pic domain has no free vectors\n");
> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
> + return -EINVAL;
> + }
> + priv->table[priv->inuse] = *hwirq;
> + *hwirq = priv->inuse++;
> + }
> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);

Hi,

not sure if it helps or if this is a hot path, but, IIUC, taking the
lock could be avoided with some code reordering and 'inuse' being an
atomic_t.

IIUC, the lock is only needed to protect 'inuse' and 'table' is never
modified afterwards.

Somehing like:

> + int cur_inuse;
...
> + cur_inuse = atomic_read(&priv->inuse);
> + /* Check pic-table to confirm if the hwirq has been assigned */
> + for (i = 0; i < cur_inuse; i++) {
> + if (priv->table[i] == *hwirq) {
> + *hwirq = i;
> + break;
> + }
> + }
> + if (i == cur_inuse) {
> + /* Assign a new hwirq in pic-table */
> + if (cur_inuse >= PIC_COUNT) {
> + pr_err("pch-pic domain has no free vectors\n");
> + return -EINVAL;
> + }
> + priv->table[cur_inuse] = *hwirq;
> + *hwirq = atomic_inc_return(&priv->inuse);
> + }


> +
> if (fwspec->param_count > 1)
> *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
> else
> @@ -194,6 +227,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
> if (err)
> return err;
>
> + /* Write vector ID */
> + writeb(priv->ht_vec_base + hwirq, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, hwirq)));
> +
> parent_fwspec.fwnode = domain->parent->fwnode;
> parent_fwspec.param_count = 1;
> parent_fwspec.param[0] = hwirq + priv->ht_vec_base;

..


2024-03-18 11:18:43

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH V2] irqchip/loongson-pch-pic: Update interrupt registration policy

On Sat, Mar 16 2024 at 15:03, Christophe JAILLET wrote:
> Le 16/03/2024 à 09:21, Tianyang Zhang a écrit :
>> @@ -171,6 +183,27 @@ static int pch_pic_domain_translate(struct irq_domain *d,
>> return -EINVAL;
>>
>> *hwirq = fwspec->param[0] - priv->gsi_base;
>> +
>> + raw_spin_lock_irqsave(&priv->pic_lock, flags);
>> + /* Check pic-table to confirm if the hwirq has been assigned */
>> + for (i = 0; i < priv->inuse; i++) {
>> + if (priv->table[i] == *hwirq) {
>> + *hwirq = i;
>> + break;
>> + }
>> + }
>> + if (i == priv->inuse) {
>> + /* Assign a new hwirq in pic-table */
>> + if (priv->inuse >= PIC_COUNT) {
>> + pr_err("pch-pic domain has no free vectors\n");
>> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
>> + return -EINVAL;
>> + }
>> + priv->table[priv->inuse] = *hwirq;
>> + *hwirq = priv->inuse++;
>> + }
>> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
>
> Hi,
>
> not sure if it helps or if this is a hot path, but, IIUC, taking the
> lock could be avoided with some code reordering and 'inuse' being an
> atomic_t.

It's the translate and setup path, so nothing to optimize here.

2024-03-18 14:36:07

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH V2] irqchip/loongson-pch-pic: Update interrupt registration policy

Hi, Tianyang,

On Sat, Mar 16, 2024 at 4:22 PM Tianyang Zhang
<[email protected]> wrote:
>
> From: Baoqi Zhang <[email protected]>
>
> This patch remove the fixed mapping between the 7A interrupt source
> and the HT interrupt vector, and replaced it with a dynamically
> allocated approach.
Use LS7A instead of 7A here.

>
> We introduce a mapping table in struct pch_pic, where each interrupt
> source will allocate an index as a 'hwirq' from the table in the order
> of application and set table value as interrupt source number. This hwirq
> will be configured as its vector in the HT interrupt controller. For an
> interrupt source, the validity period of the obtained hwirq will last until
> the system reset
Missing a . at the end.

>
> This will be more conducive to fully utilizing existing vectors to
> support more devices
>
> Signed-off-by: Baoqi Zhang <[email protected]>
> Signed-off-by: Biao Dong <[email protected]>
> Signed-off-by: Tianyang Zhang <[email protected]>
> ---
> drivers/irqchip/irq-loongson-pch-pic.c | 77 ++++++++++++++++++++------
> 1 file changed, 59 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c
> index 63db8e2172e0..f17187641154 100644
> --- a/drivers/irqchip/irq-loongson-pch-pic.c
> +++ b/drivers/irqchip/irq-loongson-pch-pic.c
> @@ -33,7 +33,7 @@
> #define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT)
> #define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
> #define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)
> -
> +#define PIC_UNDEF_VECTOR 255
Keep a new line after the macro, please.

Huacai

> static int nr_pics;
>
> struct pch_pic {
> @@ -46,12 +46,19 @@ struct pch_pic {
> u32 saved_vec_en[PIC_REG_COUNT];
> u32 saved_vec_pol[PIC_REG_COUNT];
> u32 saved_vec_edge[PIC_REG_COUNT];
> + u8 table[PIC_COUNT];
> + int inuse;
> };
>
> static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
>
> struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
>
> +static inline u8 hwirq_to_bit(struct pch_pic *priv, int hirq)
> +{
> + return priv->table[hirq];
> +}
> +
> static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
> {
> u32 reg;
> @@ -80,45 +87,47 @@ static void pch_pic_mask_irq(struct irq_data *d)
> {
> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>
> - pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq);
> + pch_pic_bitset(priv, PCH_PIC_MASK, hwirq_to_bit(priv, d->hwirq));
> irq_chip_mask_parent(d);
> }
>
> static void pch_pic_unmask_irq(struct irq_data *d)
> {
> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
> + int bit = hwirq_to_bit(priv, d->hwirq);
>
> - writel(BIT(PIC_REG_BIT(d->hwirq)),
> - priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
> + writel(BIT(PIC_REG_BIT(bit)),
> + priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
>
> irq_chip_unmask_parent(d);
> - pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq);
> + pch_pic_bitclr(priv, PCH_PIC_MASK, bit);
> }
>
> static int pch_pic_set_type(struct irq_data *d, unsigned int type)
> {
> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
> + int bit = hwirq_to_bit(priv, d->hwirq);
> int ret = 0;
>
> switch (type) {
> case IRQ_TYPE_EDGE_RISING:
> - pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
> - pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
> + pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
> + pch_pic_bitclr(priv, PCH_PIC_POL, bit);
> irq_set_handler_locked(d, handle_edge_irq);
> break;
> case IRQ_TYPE_EDGE_FALLING:
> - pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
> - pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
> + pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
> + pch_pic_bitset(priv, PCH_PIC_POL, bit);
> irq_set_handler_locked(d, handle_edge_irq);
> break;
> case IRQ_TYPE_LEVEL_HIGH:
> - pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
> - pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
> + pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
> + pch_pic_bitclr(priv, PCH_PIC_POL, bit);
> irq_set_handler_locked(d, handle_level_irq);
> break;
> case IRQ_TYPE_LEVEL_LOW:
> - pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
> - pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
> + pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
> + pch_pic_bitset(priv, PCH_PIC_POL, bit);
> irq_set_handler_locked(d, handle_level_irq);
> break;
> default:
> @@ -133,11 +142,12 @@ static void pch_pic_ack_irq(struct irq_data *d)
> {
> unsigned int reg;
> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
> + int bit = hwirq_to_bit(priv, d->hwirq);
>
> - reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4);
> - if (reg & BIT(PIC_REG_BIT(d->hwirq))) {
> - writel(BIT(PIC_REG_BIT(d->hwirq)),
> - priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
> + reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(bit) * 4);
> + if (reg & BIT(PIC_REG_BIT(bit))) {
> + writel(BIT(PIC_REG_BIT(bit)),
> + priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
> }
> irq_chip_ack_parent(d);
> }
> @@ -159,6 +169,8 @@ static int pch_pic_domain_translate(struct irq_domain *d,
> {
> struct pch_pic *priv = d->host_data;
> struct device_node *of_node = to_of_node(fwspec->fwnode);
> + unsigned long flags;
> + int i;
>
> if (of_node) {
> if (fwspec->param_count < 2)
> @@ -171,6 +183,27 @@ static int pch_pic_domain_translate(struct irq_domain *d,
> return -EINVAL;
>
> *hwirq = fwspec->param[0] - priv->gsi_base;
> +
> + raw_spin_lock_irqsave(&priv->pic_lock, flags);
> + /* Check pic-table to confirm if the hwirq has been assigned */
> + for (i = 0; i < priv->inuse; i++) {
> + if (priv->table[i] == *hwirq) {
> + *hwirq = i;
> + break;
> + }
> + }
> + if (i == priv->inuse) {
> + /* Assign a new hwirq in pic-table */
> + if (priv->inuse >= PIC_COUNT) {
> + pr_err("pch-pic domain has no free vectors\n");
> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
> + return -EINVAL;
> + }
> + priv->table[priv->inuse] = *hwirq;
> + *hwirq = priv->inuse++;
> + }
> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
> +
> if (fwspec->param_count > 1)
> *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
> else
> @@ -194,6 +227,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
> if (err)
> return err;
>
> + /* Write vector ID */
> + writeb(priv->ht_vec_base + hwirq, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, hwirq)));
> +
> parent_fwspec.fwnode = domain->parent->fwnode;
> parent_fwspec.param_count = 1;
> parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
> @@ -222,7 +258,7 @@ static void pch_pic_reset(struct pch_pic *priv)
>
> for (i = 0; i < PIC_COUNT; i++) {
> /* Write vector ID */
> - writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
> + writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, i)));
> /* Hardcode route to HT0 Lo */
> writeb(1, priv->base + PCH_INT_ROUTE(i));
> }
> @@ -284,6 +320,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
> u32 gsi_base)
> {
> struct pch_pic *priv;
> + int i;
>
> priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> if (!priv)
> @@ -294,6 +331,10 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
> if (!priv->base)
> goto free_priv;
>
> + priv->inuse = 0;
> + for (i = 0; i < PIC_COUNT; i++)
> + priv->table[i] = PIC_UNDEF_VECTOR;
> +
> priv->ht_vec_base = vec_base;
> priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
> priv->gsi_base = gsi_base;
> --
> 2.20.1
>
>

2024-03-19 11:19:34

by Tianyang Zhang

[permalink] [raw]
Subject: Re: [PATCH V2] irqchip/loongson-pch-pic: Update interrupt registration policy

Hi, Huacai

Thanks for your suggestions and corrections. I will make the
modifications as required

and provide the next version of the patch as soon as possible

Tianyang

在 2024/3/18 下午10:35, Huacai Chen 写道:
> Hi, Tianyang,
>
> On Sat, Mar 16, 2024 at 4:22 PM Tianyang Zhang
> <[email protected]> wrote:
>> From: Baoqi Zhang <[email protected]>
>>
>> This patch remove the fixed mapping between the 7A interrupt source
>> and the HT interrupt vector, and replaced it with a dynamically
>> allocated approach.
> Use LS7A instead of 7A here.
>
>> We introduce a mapping table in struct pch_pic, where each interrupt
>> source will allocate an index as a 'hwirq' from the table in the order
>> of application and set table value as interrupt source number. This hwirq
>> will be configured as its vector in the HT interrupt controller. For an
>> interrupt source, the validity period of the obtained hwirq will last until
>> the system reset
> Missing a . at the end.
>
>> This will be more conducive to fully utilizing existing vectors to
>> support more devices
>>
>> Signed-off-by: Baoqi Zhang <[email protected]>
>> Signed-off-by: Biao Dong <[email protected]>
>> Signed-off-by: Tianyang Zhang <[email protected]>
>> ---
>> drivers/irqchip/irq-loongson-pch-pic.c | 77 ++++++++++++++++++++------
>> 1 file changed, 59 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c
>> index 63db8e2172e0..f17187641154 100644
>> --- a/drivers/irqchip/irq-loongson-pch-pic.c
>> +++ b/drivers/irqchip/irq-loongson-pch-pic.c
>> @@ -33,7 +33,7 @@
>> #define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT)
>> #define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
>> #define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)
>> -
>> +#define PIC_UNDEF_VECTOR 255
> Keep a new line after the macro, please.
>
> Huacai
>
>> static int nr_pics;
>>
>> struct pch_pic {
>> @@ -46,12 +46,19 @@ struct pch_pic {
>> u32 saved_vec_en[PIC_REG_COUNT];
>> u32 saved_vec_pol[PIC_REG_COUNT];
>> u32 saved_vec_edge[PIC_REG_COUNT];
>> + u8 table[PIC_COUNT];
>> + int inuse;
>> };
>>
>> static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
>>
>> struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
>>
>> +static inline u8 hwirq_to_bit(struct pch_pic *priv, int hirq)
>> +{
>> + return priv->table[hirq];
>> +}
>> +
>> static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
>> {
>> u32 reg;
>> @@ -80,45 +87,47 @@ static void pch_pic_mask_irq(struct irq_data *d)
>> {
>> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>>
>> - pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq);
>> + pch_pic_bitset(priv, PCH_PIC_MASK, hwirq_to_bit(priv, d->hwirq));
>> irq_chip_mask_parent(d);
>> }
>>
>> static void pch_pic_unmask_irq(struct irq_data *d)
>> {
>> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>> + int bit = hwirq_to_bit(priv, d->hwirq);
>>
>> - writel(BIT(PIC_REG_BIT(d->hwirq)),
>> - priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
>> + writel(BIT(PIC_REG_BIT(bit)),
>> + priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
>>
>> irq_chip_unmask_parent(d);
>> - pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq);
>> + pch_pic_bitclr(priv, PCH_PIC_MASK, bit);
>> }
>>
>> static int pch_pic_set_type(struct irq_data *d, unsigned int type)
>> {
>> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>> + int bit = hwirq_to_bit(priv, d->hwirq);
>> int ret = 0;
>>
>> switch (type) {
>> case IRQ_TYPE_EDGE_RISING:
>> - pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
>> - pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
>> + pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
>> + pch_pic_bitclr(priv, PCH_PIC_POL, bit);
>> irq_set_handler_locked(d, handle_edge_irq);
>> break;
>> case IRQ_TYPE_EDGE_FALLING:
>> - pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
>> - pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
>> + pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
>> + pch_pic_bitset(priv, PCH_PIC_POL, bit);
>> irq_set_handler_locked(d, handle_edge_irq);
>> break;
>> case IRQ_TYPE_LEVEL_HIGH:
>> - pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
>> - pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
>> + pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
>> + pch_pic_bitclr(priv, PCH_PIC_POL, bit);
>> irq_set_handler_locked(d, handle_level_irq);
>> break;
>> case IRQ_TYPE_LEVEL_LOW:
>> - pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
>> - pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
>> + pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
>> + pch_pic_bitset(priv, PCH_PIC_POL, bit);
>> irq_set_handler_locked(d, handle_level_irq);
>> break;
>> default:
>> @@ -133,11 +142,12 @@ static void pch_pic_ack_irq(struct irq_data *d)
>> {
>> unsigned int reg;
>> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>> + int bit = hwirq_to_bit(priv, d->hwirq);
>>
>> - reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4);
>> - if (reg & BIT(PIC_REG_BIT(d->hwirq))) {
>> - writel(BIT(PIC_REG_BIT(d->hwirq)),
>> - priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
>> + reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(bit) * 4);
>> + if (reg & BIT(PIC_REG_BIT(bit))) {
>> + writel(BIT(PIC_REG_BIT(bit)),
>> + priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
>> }
>> irq_chip_ack_parent(d);
>> }
>> @@ -159,6 +169,8 @@ static int pch_pic_domain_translate(struct irq_domain *d,
>> {
>> struct pch_pic *priv = d->host_data;
>> struct device_node *of_node = to_of_node(fwspec->fwnode);
>> + unsigned long flags;
>> + int i;
>>
>> if (of_node) {
>> if (fwspec->param_count < 2)
>> @@ -171,6 +183,27 @@ static int pch_pic_domain_translate(struct irq_domain *d,
>> return -EINVAL;
>>
>> *hwirq = fwspec->param[0] - priv->gsi_base;
>> +
>> + raw_spin_lock_irqsave(&priv->pic_lock, flags);
>> + /* Check pic-table to confirm if the hwirq has been assigned */
>> + for (i = 0; i < priv->inuse; i++) {
>> + if (priv->table[i] == *hwirq) {
>> + *hwirq = i;
>> + break;
>> + }
>> + }
>> + if (i == priv->inuse) {
>> + /* Assign a new hwirq in pic-table */
>> + if (priv->inuse >= PIC_COUNT) {
>> + pr_err("pch-pic domain has no free vectors\n");
>> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
>> + return -EINVAL;
>> + }
>> + priv->table[priv->inuse] = *hwirq;
>> + *hwirq = priv->inuse++;
>> + }
>> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
>> +
>> if (fwspec->param_count > 1)
>> *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
>> else
>> @@ -194,6 +227,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
>> if (err)
>> return err;
>>
>> + /* Write vector ID */
>> + writeb(priv->ht_vec_base + hwirq, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, hwirq)));
>> +
>> parent_fwspec.fwnode = domain->parent->fwnode;
>> parent_fwspec.param_count = 1;
>> parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
>> @@ -222,7 +258,7 @@ static void pch_pic_reset(struct pch_pic *priv)
>>
>> for (i = 0; i < PIC_COUNT; i++) {
>> /* Write vector ID */
>> - writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
>> + writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, i)));
>> /* Hardcode route to HT0 Lo */
>> writeb(1, priv->base + PCH_INT_ROUTE(i));
>> }
>> @@ -284,6 +320,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
>> u32 gsi_base)
>> {
>> struct pch_pic *priv;
>> + int i;
>>
>> priv = kzalloc(sizeof(*priv), GFP_KERNEL);
>> if (!priv)
>> @@ -294,6 +331,10 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
>> if (!priv->base)
>> goto free_priv;
>>
>> + priv->inuse = 0;
>> + for (i = 0; i < PIC_COUNT; i++)
>> + priv->table[i] = PIC_UNDEF_VECTOR;
>> +
>> priv->ht_vec_base = vec_base;
>> priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
>> priv->gsi_base = gsi_base;
>> --
>> 2.20.1
>>
>>


2024-03-19 11:26:42

by Tianyang Zhang

[permalink] [raw]
Subject: Re: [PATCH V2] irqchip/loongson-pch-pic: Update interrupt registration policy

Hi Christophe

This part of the code is not a hotspot path. In fact, it may only be
executed once at startup,

so some optimizations that we consider extreme can be omitted

Tianyang

在 2024/3/16 下午10:03, Christophe JAILLET 写道:
> Le 16/03/2024 à 09:21, Tianyang Zhang a écrit :
>> From: Baoqi Zhang <[email protected]>
>>
>> This patch remove the fixed mapping between the 7A interrupt source
>> and the HT interrupt vector, and replaced it with a dynamically
>> allocated approach.
>>
>> We introduce a mapping table in struct pch_pic, where each interrupt
>> source will allocate an index as a 'hwirq' from the table in the order
>> of application and set table value as interrupt source number. This
>> hwirq
>> will be configured as its vector in the HT interrupt controller. For an
>> interrupt source, the validity period of the obtained hwirq will last
>> until
>> the system reset
>>
>> This will be more conducive to fully utilizing existing vectors to
>> support more devices
>>
>> Signed-off-by: Baoqi Zhang <[email protected]>
>> Signed-off-by: Biao Dong <[email protected]>
>> Signed-off-by: Tianyang Zhang <[email protected]>
>> ---
>>   drivers/irqchip/irq-loongson-pch-pic.c | 77 ++++++++++++++++++++------
>>   1 file changed, 59 insertions(+), 18 deletions(-)
>>
>
> ...
>
>> @@ -171,6 +183,27 @@ static int pch_pic_domain_translate(struct
>> irq_domain *d,
>>               return -EINVAL;
>>             *hwirq = fwspec->param[0] - priv->gsi_base;
>> +
>> +        raw_spin_lock_irqsave(&priv->pic_lock, flags);
>> +        /* Check pic-table to confirm if the hwirq has been assigned */
>> +        for (i = 0; i < priv->inuse; i++) {
>> +            if (priv->table[i] == *hwirq) {
>> +                *hwirq = i;
>> +                break;
>> +            }
>> +        }
>> +        if (i == priv->inuse) {
>> +            /* Assign a new hwirq in pic-table */
>> +            if (priv->inuse >= PIC_COUNT) {
>> +                pr_err("pch-pic domain has no free vectors\n");
>> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
>> +                return -EINVAL;
>> +            }
>> +            priv->table[priv->inuse] = *hwirq;
>> +            *hwirq = priv->inuse++;
>> +        }
>> +        raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
>
> Hi,
>
> not sure if it helps or if this is a hot path, but, IIUC, taking the
> lock could be avoided with some code reordering and 'inuse' being an
> atomic_t.
>
> IIUC, the lock is only needed to protect 'inuse' and 'table' is never
> modified afterwards.
>
> Somehing like:
>
> > +        int cur_inuse;
>         ...
> > +        cur_inuse = atomic_read(&priv->inuse);
> > +        /* Check pic-table to confirm if the hwirq has been
> assigned */
> > +        for (i = 0; i < cur_inuse; i++) {
> > +            if (priv->table[i] == *hwirq) {
> > +                *hwirq = i;
> > +                break;
> > +            }
> > +        }
> > +        if (i == cur_inuse) {
> > +            /* Assign a new hwirq in pic-table */
> > +            if (cur_inuse >= PIC_COUNT) {
> > +                pr_err("pch-pic domain has no free vectors\n");
> > +                return -EINVAL;
> > +            }
> > +            priv->table[cur_inuse] = *hwirq;
> > +            *hwirq = atomic_inc_return(&priv->inuse);
> > +        }
>
>
>> +
>>           if (fwspec->param_count > 1)
>>               *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
>>           else
>> @@ -194,6 +227,9 @@ static int pch_pic_alloc(struct irq_domain
>> *domain, unsigned int virq,
>>       if (err)
>>           return err;
>>   +    /* Write vector ID */
>> +    writeb(priv->ht_vec_base + hwirq, priv->base +
>> PCH_INT_HTVEC(hwirq_to_bit(priv, hwirq)));
>> +
>>       parent_fwspec.fwnode = domain->parent->fwnode;
>>       parent_fwspec.param_count = 1;
>>       parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
>
> ...


2024-03-21 06:11:01

by Binbin Zhou

[permalink] [raw]
Subject: Re: [PATCH v2] irqchip/loongson-pch-pic: Update interrupt registration policy

Hi Tianyang:

On 2024/3/16 16:21, Tianyang Zhang wrote:
> From: Baoqi Zhang <[email protected]>
>
> This patch remove the fixed mapping between the 7A interrupt source
> and the HT interrupt vector, and replaced it with a dynamically
> allocated approach.
>
> We introduce a mapping table in struct pch_pic, where each interrupt
> source will allocate an index as a 'hwirq' from the table in the order
> of application and set table value as interrupt source number. This hwirq
> will be configured as its vector in the HT interrupt controller. For an
> interrupt source, the validity period of the obtained hwirq will last until
> the system reset
>
> This will be more conducive to fully utilizing existing vectors to
> support more devices
>
> Signed-off-by: Baoqi Zhang <[email protected]>
> Signed-off-by: Biao Dong <[email protected]>
> Signed-off-by: Tianyang Zhang <[email protected]>
> ---
> drivers/irqchip/irq-loongson-pch-pic.c | 77 ++++++++++++++++++++------
> 1 file changed, 59 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c
> index 63db8e2172e0..f17187641154 100644
> --- a/drivers/irqchip/irq-loongson-pch-pic.c
> +++ b/drivers/irqchip/irq-loongson-pch-pic.c
> @@ -33,7 +33,7 @@
> #define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT)
> #define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
> #define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)
> -
> +#define PIC_UNDEF_VECTOR 255
> static int nr_pics;
>
> struct pch_pic {
> @@ -46,12 +46,19 @@ struct pch_pic {
> u32 saved_vec_en[PIC_REG_COUNT];
> u32 saved_vec_pol[PIC_REG_COUNT];
> u32 saved_vec_edge[PIC_REG_COUNT];
> + u8 table[PIC_COUNT];
> + int inuse;
> };
>
> static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
>
> struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
>
> +static inline u8 hwirq_to_bit(struct pch_pic *priv, int hirq)
> +{
> + return priv->table[hirq];
> +}
> +
> static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
> {
> u32 reg;
> @@ -80,45 +87,47 @@ static void pch_pic_mask_irq(struct irq_data *d)
> {
> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>
> - pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq);
> + pch_pic_bitset(priv, PCH_PIC_MASK, hwirq_to_bit(priv, d->hwirq));
> irq_chip_mask_parent(d);
> }
>
> static void pch_pic_unmask_irq(struct irq_data *d)
> {
> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
> + int bit = hwirq_to_bit(priv, d->hwirq);
>
> - writel(BIT(PIC_REG_BIT(d->hwirq)),
> - priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
> + writel(BIT(PIC_REG_BIT(bit)),
> + priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
>
> irq_chip_unmask_parent(d);
> - pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq);
> + pch_pic_bitclr(priv, PCH_PIC_MASK, bit);
> }
>
> static int pch_pic_set_type(struct irq_data *d, unsigned int type)
> {
> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
> + int bit = hwirq_to_bit(priv, d->hwirq);
> int ret = 0;
>
> switch (type) {
> case IRQ_TYPE_EDGE_RISING:
> - pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
> - pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
> + pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
> + pch_pic_bitclr(priv, PCH_PIC_POL, bit);
> irq_set_handler_locked(d, handle_edge_irq);
> break;
> case IRQ_TYPE_EDGE_FALLING:
> - pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
> - pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
> + pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
> + pch_pic_bitset(priv, PCH_PIC_POL, bit);
> irq_set_handler_locked(d, handle_edge_irq);
> break;
> case IRQ_TYPE_LEVEL_HIGH:
> - pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
> - pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
> + pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
> + pch_pic_bitclr(priv, PCH_PIC_POL, bit);
> irq_set_handler_locked(d, handle_level_irq);
> break;
> case IRQ_TYPE_LEVEL_LOW:
> - pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
> - pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
> + pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
> + pch_pic_bitset(priv, PCH_PIC_POL, bit);
> irq_set_handler_locked(d, handle_level_irq);
> break;
> default:
> @@ -133,11 +142,12 @@ static void pch_pic_ack_irq(struct irq_data *d)
> {
> unsigned int reg;
> struct pch_pic *priv = irq_data_get_irq_chip_data(d);
> + int bit = hwirq_to_bit(priv, d->hwirq);
>
> - reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4);
> - if (reg & BIT(PIC_REG_BIT(d->hwirq))) {
> - writel(BIT(PIC_REG_BIT(d->hwirq)),
> - priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
> + reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(bit) * 4);
> + if (reg & BIT(PIC_REG_BIT(bit))) {
> + writel(BIT(PIC_REG_BIT(bit)),
> + priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
> }
> irq_chip_ack_parent(d);
> }
> @@ -159,6 +169,8 @@ static int pch_pic_domain_translate(struct irq_domain *d,
> {
> struct pch_pic *priv = d->host_data;
> struct device_node *of_node = to_of_node(fwspec->fwnode);
> + unsigned long flags;
> + int i;
>
> if (of_node) {
> if (fwspec->param_count < 2)
> @@ -171,6 +183,27 @@ static int pch_pic_domain_translate(struct irq_domain *d,
> return -EINVAL;
>
> *hwirq = fwspec->param[0] - priv->gsi_base;
> +
> + raw_spin_lock_irqsave(&priv->pic_lock, flags);
> + /* Check pic-table to confirm if the hwirq has been assigned */
> + for (i = 0; i < priv->inuse; i++) {
> + if (priv->table[i] == *hwirq) {
> + *hwirq = i;
> + break;
> + }
> + }
> + if (i == priv->inuse) {
> + /* Assign a new hwirq in pic-table */
> + if (priv->inuse >= PIC_COUNT) {
> + pr_err("pch-pic domain has no free vectors\n");
> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
> + return -EINVAL;
> + }
> + priv->table[priv->inuse] = *hwirq;
> + *hwirq = priv->inuse++;
> + }
> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
> +

The patch fails the test on LS2K2000+FDT and does not boot the system
properly.

The reason the test fails is that this part of the priv->table[]
initialization is needed for FDT as well, so I think it needs to be put
after the whole judgment, at the end of the function.


Thanks.

Binbin

> if (fwspec->param_count > 1)
> *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
> else
> @@ -194,6 +227,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
> if (err)
> return err;
>
> + /* Write vector ID */
> + writeb(priv->ht_vec_base + hwirq, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, hwirq)));
> +
> parent_fwspec.fwnode = domain->parent->fwnode;
> parent_fwspec.param_count = 1;
> parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
> @@ -222,7 +258,7 @@ static void pch_pic_reset(struct pch_pic *priv)
>
> for (i = 0; i < PIC_COUNT; i++) {
> /* Write vector ID */
> - writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
> + writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, i)));
> /* Hardcode route to HT0 Lo */
> writeb(1, priv->base + PCH_INT_ROUTE(i));
> }
> @@ -284,6 +320,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
> u32 gsi_base)
> {
> struct pch_pic *priv;
> + int i;
>
> priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> if (!priv)
> @@ -294,6 +331,10 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
> if (!priv->base)
> goto free_priv;
>
> + priv->inuse = 0;
> + for (i = 0; i < PIC_COUNT; i++)
> + priv->table[i] = PIC_UNDEF_VECTOR;
> +
> priv->ht_vec_base = vec_base;
> priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
> priv->gsi_base = gsi_base;
>


2024-03-22 10:16:38

by Tianyang Zhang

[permalink] [raw]
Subject: Re: [PATCH v2] irqchip/loongson-pch-pic: Update interrupt registration policy

Hi,Binbin

Thank you for pointing out the problems in this patch. We will adjust
the scheme after the test

Thanks again

在 2024/3/21 下午2:10, Binbin Zhou 写道:
> Hi Tianyang:
>
> On 2024/3/16 16:21, Tianyang Zhang wrote:
>> From: Baoqi Zhang <[email protected]>
>>
>> This patch remove the fixed mapping between the 7A interrupt source
>> and the HT interrupt vector, and replaced it with a dynamically
>> allocated approach.
>>
>> We introduce a mapping table in struct pch_pic, where each interrupt
>> source will allocate an index as a 'hwirq' from the table in the order
>> of application and set table value as interrupt source number. This
>> hwirq
>> will be configured as its vector in the HT interrupt controller. For an
>> interrupt source, the validity period of the obtained hwirq will last
>> until
>> the system reset
>>
>> This will be more conducive to fully utilizing existing vectors to
>> support more devices
>>
>> Signed-off-by: Baoqi Zhang <[email protected]>
>> Signed-off-by: Biao Dong <[email protected]>
>> Signed-off-by: Tianyang Zhang <[email protected]>
>> ---
>>   drivers/irqchip/irq-loongson-pch-pic.c | 77 ++++++++++++++++++++------
>>   1 file changed, 59 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-loongson-pch-pic.c
>> b/drivers/irqchip/irq-loongson-pch-pic.c
>> index 63db8e2172e0..f17187641154 100644
>> --- a/drivers/irqchip/irq-loongson-pch-pic.c
>> +++ b/drivers/irqchip/irq-loongson-pch-pic.c
>> @@ -33,7 +33,7 @@
>>   #define PIC_COUNT        (PIC_COUNT_PER_REG * PIC_REG_COUNT)
>>   #define PIC_REG_IDX(irq_id)    ((irq_id) / PIC_COUNT_PER_REG)
>>   #define PIC_REG_BIT(irq_id)    ((irq_id) % PIC_COUNT_PER_REG)
>> -
>> +#define PIC_UNDEF_VECTOR    255
>>   static int nr_pics;
>>     struct pch_pic {
>> @@ -46,12 +46,19 @@ struct pch_pic {
>>       u32            saved_vec_en[PIC_REG_COUNT];
>>       u32            saved_vec_pol[PIC_REG_COUNT];
>>       u32            saved_vec_edge[PIC_REG_COUNT];
>> +    u8            table[PIC_COUNT];
>> +    int            inuse;
>>   };
>>     static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
>>     struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
>>   +static inline u8 hwirq_to_bit(struct pch_pic *priv, int hirq)
>> +{
>> +    return priv->table[hirq];
>> +}
>> +
>>   static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
>>   {
>>       u32 reg;
>> @@ -80,45 +87,47 @@ static void pch_pic_mask_irq(struct irq_data *d)
>>   {
>>       struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>>   -    pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq);
>> +    pch_pic_bitset(priv, PCH_PIC_MASK, hwirq_to_bit(priv, d->hwirq));
>>       irq_chip_mask_parent(d);
>>   }
>>     static void pch_pic_unmask_irq(struct irq_data *d)
>>   {
>>       struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>> +    int bit = hwirq_to_bit(priv, d->hwirq);
>>   -    writel(BIT(PIC_REG_BIT(d->hwirq)),
>> -            priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
>> +    writel(BIT(PIC_REG_BIT(bit)),
>> +            priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
>>         irq_chip_unmask_parent(d);
>> -    pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq);
>> +    pch_pic_bitclr(priv, PCH_PIC_MASK, bit);
>>   }
>>     static int pch_pic_set_type(struct irq_data *d, unsigned int type)
>>   {
>>       struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>> +    int bit = hwirq_to_bit(priv, d->hwirq);
>>       int ret = 0;
>>         switch (type) {
>>       case IRQ_TYPE_EDGE_RISING:
>> -        pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
>> -        pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
>> +        pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
>> +        pch_pic_bitclr(priv, PCH_PIC_POL, bit);
>>           irq_set_handler_locked(d, handle_edge_irq);
>>           break;
>>       case IRQ_TYPE_EDGE_FALLING:
>> -        pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
>> -        pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
>> +        pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
>> +        pch_pic_bitset(priv, PCH_PIC_POL, bit);
>>           irq_set_handler_locked(d, handle_edge_irq);
>>           break;
>>       case IRQ_TYPE_LEVEL_HIGH:
>> -        pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
>> -        pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
>> +        pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
>> +        pch_pic_bitclr(priv, PCH_PIC_POL, bit);
>>           irq_set_handler_locked(d, handle_level_irq);
>>           break;
>>       case IRQ_TYPE_LEVEL_LOW:
>> -        pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
>> -        pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
>> +        pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
>> +        pch_pic_bitset(priv, PCH_PIC_POL, bit);
>>           irq_set_handler_locked(d, handle_level_irq);
>>           break;
>>       default:
>> @@ -133,11 +142,12 @@ static void pch_pic_ack_irq(struct irq_data *d)
>>   {
>>       unsigned int reg;
>>       struct pch_pic *priv = irq_data_get_irq_chip_data(d);
>> +    int bit = hwirq_to_bit(priv, d->hwirq);
>>   -    reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq)
>> * 4);
>> -    if (reg & BIT(PIC_REG_BIT(d->hwirq))) {
>> -        writel(BIT(PIC_REG_BIT(d->hwirq)),
>> -            priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
>> +    reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(bit) * 4);
>> +    if (reg & BIT(PIC_REG_BIT(bit))) {
>> +        writel(BIT(PIC_REG_BIT(bit)),
>> +            priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
>>       }
>>       irq_chip_ack_parent(d);
>>   }
>> @@ -159,6 +169,8 @@ static int pch_pic_domain_translate(struct
>> irq_domain *d,
>>   {
>>       struct pch_pic *priv = d->host_data;
>>       struct device_node *of_node = to_of_node(fwspec->fwnode);
>> +    unsigned long flags;
>> +    int i;
>>         if (of_node) {
>>           if (fwspec->param_count < 2)
>> @@ -171,6 +183,27 @@ static int pch_pic_domain_translate(struct
>> irq_domain *d,
>>               return -EINVAL;
>>             *hwirq = fwspec->param[0] - priv->gsi_base;
>> +
>> +        raw_spin_lock_irqsave(&priv->pic_lock, flags);
>> +        /* Check pic-table to confirm if the hwirq has been assigned */
>> +        for (i = 0; i < priv->inuse; i++) {
>> +            if (priv->table[i] == *hwirq) {
>> +                *hwirq = i;
>> +                break;
>> +            }
>> +        }
>> +        if (i == priv->inuse) {
>> +            /* Assign a new hwirq in pic-table */
>> +            if (priv->inuse >= PIC_COUNT) {
>> +                pr_err("pch-pic domain has no free vectors\n");
>> + raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
>> +                return -EINVAL;
>> +            }
>> +            priv->table[priv->inuse] = *hwirq;
>> +            *hwirq = priv->inuse++;
>> +        }
>> +        raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
>> +
>
> The patch fails the test on LS2K2000+FDT and does not boot the system
> properly.
>
> The reason the test fails is that this part of the priv->table[]
> initialization is needed for FDT as well, so I think it needs to be
> put after the whole judgment, at the end of the function.
>
>
> Thanks.
>
> Binbin
>
>>           if (fwspec->param_count > 1)
>>               *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
>>           else
>> @@ -194,6 +227,9 @@ static int pch_pic_alloc(struct irq_domain
>> *domain, unsigned int virq,
>>       if (err)
>>           return err;
>>   +    /* Write vector ID */
>> +    writeb(priv->ht_vec_base + hwirq, priv->base +
>> PCH_INT_HTVEC(hwirq_to_bit(priv, hwirq)));
>> +
>>       parent_fwspec.fwnode = domain->parent->fwnode;
>>       parent_fwspec.param_count = 1;
>>       parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
>> @@ -222,7 +258,7 @@ static void pch_pic_reset(struct pch_pic *priv)
>>         for (i = 0; i < PIC_COUNT; i++) {
>>           /* Write vector ID */
>> -        writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
>> +        writeb(priv->ht_vec_base + i, priv->base +
>> PCH_INT_HTVEC(hwirq_to_bit(priv, i)));
>>           /* Hardcode route to HT0 Lo */
>>           writeb(1, priv->base + PCH_INT_ROUTE(i));
>>       }
>> @@ -284,6 +320,7 @@ static int pch_pic_init(phys_addr_t addr,
>> unsigned long size, int vec_base,
>>               u32 gsi_base)
>>   {
>>       struct pch_pic *priv;
>> +    int i;
>>         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
>>       if (!priv)
>> @@ -294,6 +331,10 @@ static int pch_pic_init(phys_addr_t addr,
>> unsigned long size, int vec_base,
>>       if (!priv->base)
>>           goto free_priv;
>>   +    priv->inuse = 0;
>> +    for (i = 0; i < PIC_COUNT; i++)
>> +        priv->table[i] = PIC_UNDEF_VECTOR;
>> +
>>       priv->ht_vec_base = vec_base;
>>       priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
>>       priv->gsi_base = gsi_base;
>>