Skip to content

Commit 234a557

Browse files
zhangbaoqi-lsKAGA-KOKO
authored andcommitted
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: Biao Dong <dongbiao@loongson.cn> Signed-off-by: Biao Dong <dongbiao@loongson.cn> Co-developed-by: Tianyang Zhang <zhangtianyang@loongson.cn> Signed-off-by: Tianyang Zhang <zhangtianyang@loongson.cn> Signed-off-by: Baoqi Zhang <zhangbaoqi@loongson.cn> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/r/20240422093830.27212-1-zhangtianyang@loongson.cn
1 parent bb58c1b commit 234a557

1 file changed

Lines changed: 59 additions & 17 deletions

File tree

drivers/irqchip/irq-loongson-pch-pic.c

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT)
3434
#define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
3535
#define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)
36+
#define PIC_UNDEF_VECTOR 255
3637

3738
static int nr_pics;
3839

@@ -46,12 +47,19 @@ struct pch_pic {
4647
u32 saved_vec_en[PIC_REG_COUNT];
4748
u32 saved_vec_pol[PIC_REG_COUNT];
4849
u32 saved_vec_edge[PIC_REG_COUNT];
50+
u8 table[PIC_COUNT];
51+
int inuse;
4952
};
5053

5154
static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
5255

5356
struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
5457

58+
static inline u8 hwirq_to_bit(struct pch_pic *priv, int hirq)
59+
{
60+
return priv->table[hirq];
61+
}
62+
5563
static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
5664
{
5765
u32 reg;
@@ -80,45 +88,47 @@ static void pch_pic_mask_irq(struct irq_data *d)
8088
{
8189
struct pch_pic *priv = irq_data_get_irq_chip_data(d);
8290

83-
pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq);
91+
pch_pic_bitset(priv, PCH_PIC_MASK, hwirq_to_bit(priv, d->hwirq));
8492
irq_chip_mask_parent(d);
8593
}
8694

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

91-
writel(BIT(PIC_REG_BIT(d->hwirq)),
92-
priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
100+
writel(BIT(PIC_REG_BIT(bit)),
101+
priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
93102

94103
irq_chip_unmask_parent(d);
95-
pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq);
104+
pch_pic_bitclr(priv, PCH_PIC_MASK, bit);
96105
}
97106

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

103113
switch (type) {
104114
case IRQ_TYPE_EDGE_RISING:
105-
pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
106-
pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
115+
pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
116+
pch_pic_bitclr(priv, PCH_PIC_POL, bit);
107117
irq_set_handler_locked(d, handle_edge_irq);
108118
break;
109119
case IRQ_TYPE_EDGE_FALLING:
110-
pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
111-
pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
120+
pch_pic_bitset(priv, PCH_PIC_EDGE, bit);
121+
pch_pic_bitset(priv, PCH_PIC_POL, bit);
112122
irq_set_handler_locked(d, handle_edge_irq);
113123
break;
114124
case IRQ_TYPE_LEVEL_HIGH:
115-
pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
116-
pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
125+
pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
126+
pch_pic_bitclr(priv, PCH_PIC_POL, bit);
117127
irq_set_handler_locked(d, handle_level_irq);
118128
break;
119129
case IRQ_TYPE_LEVEL_LOW:
120-
pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
121-
pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
130+
pch_pic_bitclr(priv, PCH_PIC_EDGE, bit);
131+
pch_pic_bitset(priv, PCH_PIC_POL, bit);
122132
irq_set_handler_locked(d, handle_level_irq);
123133
break;
124134
default:
@@ -133,11 +143,12 @@ static void pch_pic_ack_irq(struct irq_data *d)
133143
{
134144
unsigned int reg;
135145
struct pch_pic *priv = irq_data_get_irq_chip_data(d);
146+
int bit = hwirq_to_bit(priv, d->hwirq);
136147

137-
reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4);
138-
if (reg & BIT(PIC_REG_BIT(d->hwirq))) {
139-
writel(BIT(PIC_REG_BIT(d->hwirq)),
140-
priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
148+
reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(bit) * 4);
149+
if (reg & BIT(PIC_REG_BIT(bit))) {
150+
writel(BIT(PIC_REG_BIT(bit)),
151+
priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4);
141152
}
142153
irq_chip_ack_parent(d);
143154
}
@@ -159,6 +170,8 @@ static int pch_pic_domain_translate(struct irq_domain *d,
159170
{
160171
struct pch_pic *priv = d->host_data;
161172
struct device_node *of_node = to_of_node(fwspec->fwnode);
173+
unsigned long flags;
174+
int i;
162175

163176
if (of_node) {
164177
if (fwspec->param_count < 2)
@@ -171,12 +184,33 @@ static int pch_pic_domain_translate(struct irq_domain *d,
171184
return -EINVAL;
172185

173186
*hwirq = fwspec->param[0] - priv->gsi_base;
187+
174188
if (fwspec->param_count > 1)
175189
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
176190
else
177191
*type = IRQ_TYPE_NONE;
178192
}
179193

194+
raw_spin_lock_irqsave(&priv->pic_lock, flags);
195+
/* Check pic-table to confirm if the hwirq has been assigned */
196+
for (i = 0; i < priv->inuse; i++) {
197+
if (priv->table[i] == *hwirq) {
198+
*hwirq = i;
199+
break;
200+
}
201+
}
202+
if (i == priv->inuse) {
203+
/* Assign a new hwirq in pic-table */
204+
if (priv->inuse >= PIC_COUNT) {
205+
pr_err("pch-pic domain has no free vectors\n");
206+
raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
207+
return -EINVAL;
208+
}
209+
priv->table[priv->inuse] = *hwirq;
210+
*hwirq = priv->inuse++;
211+
}
212+
raw_spin_unlock_irqrestore(&priv->pic_lock, flags);
213+
180214
return 0;
181215
}
182216

@@ -194,6 +228,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
194228
if (err)
195229
return err;
196230

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

223260
for (i = 0; i < PIC_COUNT; i++) {
224261
/* Write vector ID */
225-
writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
262+
writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, i)));
226263
/* Hardcode route to HT0 Lo */
227264
writeb(1, priv->base + PCH_INT_ROUTE(i));
228265
}
@@ -284,6 +321,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
284321
u32 gsi_base)
285322
{
286323
struct pch_pic *priv;
324+
int i;
287325

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

335+
priv->inuse = 0;
336+
for (i = 0; i < PIC_COUNT; i++)
337+
priv->table[i] = PIC_UNDEF_VECTOR;
338+
297339
priv->ht_vec_base = vec_base;
298340
priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
299341
priv->gsi_base = gsi_base;

0 commit comments

Comments
 (0)