Skip to content

Commit bcdd75c

Browse files
chenhuacaiMarc Zyngier
authored andcommitted
irqchip/loongson-pch-pic: Add ACPI init support
PCH-PIC/PCH-MSI stands for "Interrupt Controller" that described in Section 5 of "Loongson 7A1000 Bridge User Manual". For more information please refer Documentation/loongarch/irq-chip-model.rst. Co-developed-by: Jianmin Lv <lvjianmin@loongson.cn> Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/1658314292-35346-9-git-send-email-lvjianmin@loongson.cn
1 parent ee73f14 commit bcdd75c

File tree

5 files changed

+151
-36
lines changed

5 files changed

+151
-36
lines changed

arch/loongarch/include/asm/irq.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ int pch_lpc_acpi_init(struct irq_domain *parent,
116116
struct acpi_madt_lpc_pic *acpi_pchlpc);
117117
struct irq_domain *pch_msi_acpi_init(struct irq_domain *parent,
118118
struct acpi_madt_msi_pic *acpi_pchmsi);
119-
struct irq_domain *pch_pic_acpi_init(struct irq_domain *parent,
119+
int pch_pic_acpi_init(struct irq_domain *parent,
120120
struct acpi_madt_bio_pic *acpi_pchpic);
121+
int find_pch_pic(u32 gsi);
121122

122123
extern struct acpi_madt_lio_pic *acpi_liointc;
123124
extern struct acpi_madt_eio_pic *acpi_eiointc[MAX_IO_PICS];
@@ -131,7 +132,7 @@ extern struct irq_domain *cpu_domain;
131132
extern struct irq_domain *liointc_domain;
132133
extern struct fwnode_handle *pch_lpc_handle;
133134
extern struct irq_domain *pch_msi_domain[MAX_IO_PICS];
134-
extern struct irq_domain *pch_pic_domain[MAX_IO_PICS];
135+
extern struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
135136

136137
extern irqreturn_t loongson3_ipi_interrupt(int irq, void *dev);
137138

arch/loongarch/kernel/irq.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ EXPORT_PER_CPU_SYMBOL(irq_stat);
2828
struct irq_domain *cpu_domain;
2929
struct irq_domain *liointc_domain;
3030
struct irq_domain *pch_msi_domain[MAX_IO_PICS];
31-
struct irq_domain *pch_pic_domain[MAX_IO_PICS];
3231

3332
struct acpi_vector_group pch_group[MAX_IO_PICS];
3433
struct acpi_vector_group msi_group[MAX_IO_PICS];

arch/mips/include/asm/mach-loongson64/irq.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#define NR_MIPS_CPU_IRQS 8
88
#define NR_MAX_CHAINED_IRQS 40 /* Chained IRQs means those not directly used by devices */
99
#define NR_IRQS (NR_IRQS_LEGACY + NR_MIPS_CPU_IRQS + NR_MAX_CHAINED_IRQS + 256)
10-
10+
#define MAX_IO_PICS 1
1111
#define MIPS_CPU_IRQ_BASE NR_IRQS_LEGACY
1212

1313
#include <asm/mach-generic/irq.h>

drivers/irqchip/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ config LOONGSON_HTVEC
574574

575575
config LOONGSON_PCH_PIC
576576
bool "Loongson PCH PIC Controller"
577-
depends on MACH_LOONGSON64 || COMPILE_TEST
577+
depends on MACH_LOONGSON64
578578
default MACH_LOONGSON64
579579
select IRQ_DOMAIN_HIERARCHY
580580
select IRQ_FASTEOI_HIERARCHY_HANDLERS

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

Lines changed: 146 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,40 @@
3333
#define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
3434
#define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)
3535

36+
static int nr_pics;
37+
3638
struct pch_pic {
3739
void __iomem *base;
3840
struct irq_domain *pic_domain;
3941
u32 ht_vec_base;
4042
raw_spinlock_t pic_lock;
43+
u32 vec_count;
44+
u32 gsi_base;
4145
};
4246

47+
static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
48+
49+
struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
50+
51+
int find_pch_pic(u32 gsi)
52+
{
53+
int i;
54+
55+
/* Find the PCH_PIC that manages this GSI. */
56+
for (i = 0; i < MAX_IO_PICS; i++) {
57+
struct pch_pic *priv = pch_pic_priv[i];
58+
59+
if (!priv)
60+
return -1;
61+
62+
if (gsi >= priv->gsi_base && gsi < (priv->gsi_base + priv->vec_count))
63+
return i;
64+
}
65+
66+
pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
67+
return -1;
68+
}
69+
4370
static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
4471
{
4572
u32 reg;
@@ -139,6 +166,28 @@ static struct irq_chip pch_pic_irq_chip = {
139166
.irq_set_type = pch_pic_set_type,
140167
};
141168

169+
static int pch_pic_domain_translate(struct irq_domain *d,
170+
struct irq_fwspec *fwspec,
171+
unsigned long *hwirq,
172+
unsigned int *type)
173+
{
174+
struct pch_pic *priv = d->host_data;
175+
struct device_node *of_node = to_of_node(fwspec->fwnode);
176+
177+
if (fwspec->param_count < 1)
178+
return -EINVAL;
179+
180+
if (of_node) {
181+
*hwirq = fwspec->param[0] + priv->ht_vec_base;
182+
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
183+
} else {
184+
*hwirq = fwspec->param[0] - priv->gsi_base;
185+
*type = IRQ_TYPE_NONE;
186+
}
187+
188+
return 0;
189+
}
190+
142191
static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
143192
unsigned int nr_irqs, void *arg)
144193
{
@@ -149,13 +198,13 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
149198
struct irq_fwspec parent_fwspec;
150199
struct pch_pic *priv = domain->host_data;
151200

152-
err = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
201+
err = pch_pic_domain_translate(domain, fwspec, &hwirq, &type);
153202
if (err)
154203
return err;
155204

156205
parent_fwspec.fwnode = domain->parent->fwnode;
157206
parent_fwspec.param_count = 1;
158-
parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
207+
parent_fwspec.param[0] = hwirq;
159208

160209
err = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
161210
if (err)
@@ -170,7 +219,7 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
170219
}
171220

172221
static const struct irq_domain_ops pch_pic_domain_ops = {
173-
.translate = irq_domain_translate_twocell,
222+
.translate = pch_pic_domain_translate,
174223
.alloc = pch_pic_alloc,
175224
.free = irq_domain_free_irqs_parent,
176225
};
@@ -180,7 +229,7 @@ static void pch_pic_reset(struct pch_pic *priv)
180229
int i;
181230

182231
for (i = 0; i < PIC_COUNT; i++) {
183-
/* Write vectored ID */
232+
/* Write vector ID */
184233
writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
185234
/* Hardcode route to HT0 Lo */
186235
writeb(1, priv->base + PCH_INT_ROUTE(i));
@@ -198,50 +247,37 @@ static void pch_pic_reset(struct pch_pic *priv)
198247
}
199248
}
200249

201-
static int pch_pic_of_init(struct device_node *node,
202-
struct device_node *parent)
250+
static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
251+
struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
252+
u32 gsi_base)
203253
{
204254
struct pch_pic *priv;
205-
struct irq_domain *parent_domain;
206-
int err;
207255

208256
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
209257
if (!priv)
210258
return -ENOMEM;
211259

212260
raw_spin_lock_init(&priv->pic_lock);
213-
priv->base = of_iomap(node, 0);
214-
if (!priv->base) {
215-
err = -ENOMEM;
261+
priv->base = ioremap(addr, size);
262+
if (!priv->base)
216263
goto free_priv;
217-
}
218264

219-
parent_domain = irq_find_host(parent);
220-
if (!parent_domain) {
221-
pr_err("Failed to find the parent domain\n");
222-
err = -ENXIO;
223-
goto iounmap_base;
224-
}
225-
226-
if (of_property_read_u32(node, "loongson,pic-base-vec",
227-
&priv->ht_vec_base)) {
228-
pr_err("Failed to determine pic-base-vec\n");
229-
err = -EINVAL;
230-
goto iounmap_base;
231-
}
265+
priv->ht_vec_base = vec_base;
266+
priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
267+
priv->gsi_base = gsi_base;
232268

233269
priv->pic_domain = irq_domain_create_hierarchy(parent_domain, 0,
234-
PIC_COUNT,
235-
of_node_to_fwnode(node),
236-
&pch_pic_domain_ops,
237-
priv);
270+
priv->vec_count, domain_handle,
271+
&pch_pic_domain_ops, priv);
272+
238273
if (!priv->pic_domain) {
239274
pr_err("Failed to create IRQ domain\n");
240-
err = -ENOMEM;
241275
goto iounmap_base;
242276
}
243277

244278
pch_pic_reset(priv);
279+
pch_pic_handle[nr_pics] = domain_handle;
280+
pch_pic_priv[nr_pics++] = priv;
245281

246282
return 0;
247283

@@ -250,7 +286,86 @@ static int pch_pic_of_init(struct device_node *node,
250286
free_priv:
251287
kfree(priv);
252288

253-
return err;
289+
return -EINVAL;
290+
}
291+
292+
#ifdef CONFIG_OF
293+
294+
static int pch_pic_of_init(struct device_node *node,
295+
struct device_node *parent)
296+
{
297+
int err, vec_base;
298+
struct resource res;
299+
struct irq_domain *parent_domain;
300+
301+
if (of_address_to_resource(node, 0, &res))
302+
return -EINVAL;
303+
304+
parent_domain = irq_find_host(parent);
305+
if (!parent_domain) {
306+
pr_err("Failed to find the parent domain\n");
307+
return -ENXIO;
308+
}
309+
310+
if (of_property_read_u32(node, "loongson,pic-base-vec", &vec_base)) {
311+
pr_err("Failed to determine pic-base-vec\n");
312+
return -EINVAL;
313+
}
314+
315+
err = pch_pic_init(res.start, resource_size(&res), vec_base,
316+
parent_domain, of_node_to_fwnode(node), 0);
317+
if (err < 0)
318+
return err;
319+
320+
return 0;
254321
}
255322

256323
IRQCHIP_DECLARE(pch_pic, "loongson,pch-pic-1.0", pch_pic_of_init);
324+
325+
#endif
326+
327+
#ifdef CONFIG_ACPI
328+
static int __init
329+
pch_lpc_parse_madt(union acpi_subtable_headers *header,
330+
const unsigned long end)
331+
{
332+
struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header;
333+
334+
return pch_lpc_acpi_init(pch_pic_priv[0]->pic_domain, pchlpc_entry);
335+
}
336+
337+
static int __init acpi_cascade_irqdomain_init(void)
338+
{
339+
acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC,
340+
pch_lpc_parse_madt, 0);
341+
return 0;
342+
}
343+
344+
int __init pch_pic_acpi_init(struct irq_domain *parent,
345+
struct acpi_madt_bio_pic *acpi_pchpic)
346+
{
347+
int ret, vec_base;
348+
struct fwnode_handle *domain_handle;
349+
350+
vec_base = acpi_pchpic->gsi_base - GSI_MIN_PCH_IRQ;
351+
352+
domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_pchpic);
353+
if (!domain_handle) {
354+
pr_err("Unable to allocate domain handle\n");
355+
return -ENOMEM;
356+
}
357+
358+
ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size,
359+
vec_base, parent, domain_handle, acpi_pchpic->gsi_base);
360+
361+
if (ret < 0) {
362+
irq_domain_free_fwnode(domain_handle);
363+
return ret;
364+
}
365+
366+
if (acpi_pchpic->id == 0)
367+
acpi_cascade_irqdomain_init();
368+
369+
return ret;
370+
}
371+
#endif

0 commit comments

Comments
 (0)