Commit 234a557e authored by Baoqi Zhang's avatar Baoqi Zhang Committed by Thomas Gleixner

irqchip/loongson-pch-pic: Update interrupt registration policy

The current code is using a fixed mapping between the LS7A interrupt source
and the HT interrupt vector. This prevents the utilization of the full
interrupt vector space and therefore limits the number of interrupt source
in a system.

Replace the fixed mapping with a dynamic mapping which allocates a
vector when an interrupt source is set up. This avoids that unused
sources prevent vectors from being used for other devices.

Introduce a mapping table in struct pch_pic, where each interrupt source
will allocate an index as a 'hwirq' number from the table in the order of
application and set table value as interrupt source number. This hwirq
number will be configured as vector in the HT interrupt controller. For an
interrupt source, the validity period of the obtained hwirq will last until
the system reset.
Co-developed-by: default avatarBiao Dong <dongbiao@loongson.cn>
Signed-off-by: default avatarBiao Dong <dongbiao@loongson.cn>
Co-developed-by: default avatarTianyang Zhang <zhangtianyang@loongson.cn>
Signed-off-by: default avatarTianyang Zhang <zhangtianyang@loongson.cn>
Signed-off-by: default avatarBaoqi Zhang <zhangbaoqi@loongson.cn>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20240422093830.27212-1-zhangtianyang@loongson.cn
parent bb58c1ba
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT) #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_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
#define PIC_REG_BIT(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; static int nr_pics;
...@@ -46,12 +47,19 @@ struct pch_pic { ...@@ -46,12 +47,19 @@ struct pch_pic {
u32 saved_vec_en[PIC_REG_COUNT]; u32 saved_vec_en[PIC_REG_COUNT];
u32 saved_vec_pol[PIC_REG_COUNT]; u32 saved_vec_pol[PIC_REG_COUNT];
u32 saved_vec_edge[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]; static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
struct fwnode_handle *pch_pic_handle[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) static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
{ {
u32 reg; u32 reg;
...@@ -80,45 +88,47 @@ static void pch_pic_mask_irq(struct irq_data *d) ...@@ -80,45 +88,47 @@ static void pch_pic_mask_irq(struct irq_data *d)
{ {
struct pch_pic *priv = irq_data_get_irq_chip_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); irq_chip_mask_parent(d);
} }
static void pch_pic_unmask_irq(struct irq_data *d) static void pch_pic_unmask_irq(struct irq_data *d)
{ {
struct pch_pic *priv = irq_data_get_irq_chip_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)), writel(BIT(PIC_REG_BIT(bit)),
priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4); priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
irq_chip_unmask_parent(d); 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) static int pch_pic_set_type(struct irq_data *d, unsigned int type)
{ {
struct pch_pic *priv = irq_data_get_irq_chip_data(d); struct pch_pic *priv = irq_data_get_irq_chip_data(d);
int bit = hwirq_to_bit(priv, d->hwirq);
int ret = 0; int ret = 0;
switch (type) { switch (type) {
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq); pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq); pch_pic_bitclr(priv, PCH_PIC_POL, bit);
irq_set_handler_locked(d, handle_edge_irq); irq_set_handler_locked(d, handle_edge_irq);
break; break;
case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_FALLING:
pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq); pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq); pch_pic_bitset(priv, PCH_PIC_POL, bit);
irq_set_handler_locked(d, handle_edge_irq); irq_set_handler_locked(d, handle_edge_irq);
break; break;
case IRQ_TYPE_LEVEL_HIGH: case IRQ_TYPE_LEVEL_HIGH:
pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq); pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq); pch_pic_bitclr(priv, PCH_PIC_POL, bit);
irq_set_handler_locked(d, handle_level_irq); irq_set_handler_locked(d, handle_level_irq);
break; break;
case IRQ_TYPE_LEVEL_LOW: case IRQ_TYPE_LEVEL_LOW:
pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq); pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq); pch_pic_bitset(priv, PCH_PIC_POL, bit);
irq_set_handler_locked(d, handle_level_irq); irq_set_handler_locked(d, handle_level_irq);
break; break;
default: default:
...@@ -133,11 +143,12 @@ static void pch_pic_ack_irq(struct irq_data *d) ...@@ -133,11 +143,12 @@ static void pch_pic_ack_irq(struct irq_data *d)
{ {
unsigned int reg; unsigned int reg;
struct pch_pic *priv = irq_data_get_irq_chip_data(d); 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); reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(bit) * 4);
if (reg & BIT(PIC_REG_BIT(d->hwirq))) { if (reg & BIT(PIC_REG_BIT(bit))) {
writel(BIT(PIC_REG_BIT(d->hwirq)), writel(BIT(PIC_REG_BIT(bit)),
priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4); priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
} }
irq_chip_ack_parent(d); irq_chip_ack_parent(d);
} }
...@@ -159,6 +170,8 @@ static int pch_pic_domain_translate(struct irq_domain *d, ...@@ -159,6 +170,8 @@ static int pch_pic_domain_translate(struct irq_domain *d,
{ {
struct pch_pic *priv = d->host_data; struct pch_pic *priv = d->host_data;
struct device_node *of_node = to_of_node(fwspec->fwnode); struct device_node *of_node = to_of_node(fwspec->fwnode);
unsigned long flags;
int i;
if (of_node) { if (of_node) {
if (fwspec->param_count < 2) if (fwspec->param_count < 2)
...@@ -171,12 +184,33 @@ static int pch_pic_domain_translate(struct irq_domain *d, ...@@ -171,12 +184,33 @@ static int pch_pic_domain_translate(struct irq_domain *d,
return -EINVAL; return -EINVAL;
*hwirq = fwspec->param[0] - priv->gsi_base; *hwirq = fwspec->param[0] - priv->gsi_base;
if (fwspec->param_count > 1) if (fwspec->param_count > 1)
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
else else
*type = IRQ_TYPE_NONE; *type = IRQ_TYPE_NONE;
} }
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);
return 0; return 0;
} }
...@@ -194,6 +228,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq, ...@@ -194,6 +228,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
if (err) if (err)
return 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.fwnode = domain->parent->fwnode;
parent_fwspec.param_count = 1; parent_fwspec.param_count = 1;
parent_fwspec.param[0] = hwirq + priv->ht_vec_base; parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
...@@ -222,7 +259,7 @@ static void pch_pic_reset(struct pch_pic *priv) ...@@ -222,7 +259,7 @@ static void pch_pic_reset(struct pch_pic *priv)
for (i = 0; i < PIC_COUNT; i++) { for (i = 0; i < PIC_COUNT; i++) {
/* Write vector ID */ /* 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 */ /* Hardcode route to HT0 Lo */
writeb(1, priv->base + PCH_INT_ROUTE(i)); writeb(1, priv->base + PCH_INT_ROUTE(i));
} }
...@@ -284,6 +321,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, ...@@ -284,6 +321,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
u32 gsi_base) u32 gsi_base)
{ {
struct pch_pic *priv; struct pch_pic *priv;
int i;
priv = kzalloc(sizeof(*priv), GFP_KERNEL); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
...@@ -294,6 +332,10 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, ...@@ -294,6 +332,10 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
if (!priv->base) if (!priv->base)
goto free_priv; 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->ht_vec_base = vec_base;
priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1; priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
priv->gsi_base = gsi_base; priv->gsi_base = gsi_base;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment