Skip to content

Commit 0230873

Browse files
chenhuacaiMarc Zyngier
authored andcommitted
irqchip/loongson-pch-msi: 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-10-git-send-email-lvjianmin@loongson.cn
1 parent bcdd75c commit 0230873

File tree

4 files changed

+96
-46
lines changed

4 files changed

+96
-46
lines changed

arch/loongarch/include/asm/irq.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,20 @@ struct irq_domain *htvec_acpi_init(struct irq_domain *parent,
114114
struct acpi_madt_ht_pic *acpi_htvec);
115115
int pch_lpc_acpi_init(struct irq_domain *parent,
116116
struct acpi_madt_lpc_pic *acpi_pchlpc);
117-
struct irq_domain *pch_msi_acpi_init(struct irq_domain *parent,
117+
#if IS_ENABLED(CONFIG_LOONGSON_PCH_MSI)
118+
int pch_msi_acpi_init(struct irq_domain *parent,
118119
struct acpi_madt_msi_pic *acpi_pchmsi);
120+
#else
121+
static inline int pch_msi_acpi_init(struct irq_domain *parent,
122+
struct acpi_madt_msi_pic *acpi_pchmsi)
123+
{
124+
return 0;
125+
}
126+
#endif
119127
int pch_pic_acpi_init(struct irq_domain *parent,
120128
struct acpi_madt_bio_pic *acpi_pchpic);
121129
int find_pch_pic(u32 gsi);
130+
struct fwnode_handle *get_pch_msi_handle(int pci_segment);
122131

123132
extern struct acpi_madt_lio_pic *acpi_liointc;
124133
extern struct acpi_madt_eio_pic *acpi_eiointc[MAX_IO_PICS];
@@ -131,7 +140,6 @@ extern struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS];
131140
extern struct irq_domain *cpu_domain;
132141
extern struct irq_domain *liointc_domain;
133142
extern struct fwnode_handle *pch_lpc_handle;
134-
extern struct irq_domain *pch_msi_domain[MAX_IO_PICS];
135143
extern struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
136144

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

arch/loongarch/kernel/irq.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ EXPORT_PER_CPU_SYMBOL(irq_stat);
2727

2828
struct irq_domain *cpu_domain;
2929
struct irq_domain *liointc_domain;
30-
struct irq_domain *pch_msi_domain[MAX_IO_PICS];
3130

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

drivers/irqchip/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ config LOONGSON_PCH_PIC
583583

584584
config LOONGSON_PCH_MSI
585585
bool "Loongson PCH MSI Controller"
586-
depends on MACH_LOONGSON64 || COMPILE_TEST
586+
depends on MACH_LOONGSON64
587587
depends on PCI
588588
default MACH_LOONGSON64
589589
select IRQ_DOMAIN_HIERARCHY

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

Lines changed: 85 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <linux/pci.h>
1616
#include <linux/slab.h>
1717

18+
static int nr_pics;
19+
1820
struct pch_msi_data {
1921
struct mutex msi_map_lock;
2022
phys_addr_t doorbell;
@@ -23,6 +25,8 @@ struct pch_msi_data {
2325
unsigned long *msi_map;
2426
};
2527

28+
static struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
29+
2630
static void pch_msi_mask_msi_irq(struct irq_data *d)
2731
{
2832
pci_msi_mask_irq(d);
@@ -154,12 +158,12 @@ static const struct irq_domain_ops pch_msi_middle_domain_ops = {
154158
};
155159

156160
static int pch_msi_init_domains(struct pch_msi_data *priv,
157-
struct device_node *node,
158-
struct irq_domain *parent)
161+
struct irq_domain *parent,
162+
struct fwnode_handle *domain_handle)
159163
{
160164
struct irq_domain *middle_domain, *msi_domain;
161165

162-
middle_domain = irq_domain_create_linear(of_node_to_fwnode(node),
166+
middle_domain = irq_domain_create_linear(domain_handle,
163167
priv->num_irqs,
164168
&pch_msi_middle_domain_ops,
165169
priv);
@@ -171,7 +175,7 @@ static int pch_msi_init_domains(struct pch_msi_data *priv,
171175
middle_domain->parent = parent;
172176
irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS);
173177

174-
msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node),
178+
msi_domain = pci_msi_create_irq_domain(domain_handle,
175179
&pch_msi_domain_info,
176180
middle_domain);
177181
if (!msi_domain) {
@@ -183,68 +187,107 @@ static int pch_msi_init_domains(struct pch_msi_data *priv,
183187
return 0;
184188
}
185189

186-
static int pch_msi_init(struct device_node *node,
187-
struct device_node *parent)
190+
static int pch_msi_init(phys_addr_t msg_address, int irq_base, int irq_count,
191+
struct irq_domain *parent_domain, struct fwnode_handle *domain_handle)
188192
{
189-
struct pch_msi_data *priv;
190-
struct irq_domain *parent_domain;
191-
struct resource res;
192193
int ret;
193-
194-
parent_domain = irq_find_host(parent);
195-
if (!parent_domain) {
196-
pr_err("Failed to find the parent domain\n");
197-
return -ENXIO;
198-
}
194+
struct pch_msi_data *priv;
199195

200196
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
201197
if (!priv)
202198
return -ENOMEM;
203199

204200
mutex_init(&priv->msi_map_lock);
205201

206-
ret = of_address_to_resource(node, 0, &res);
207-
if (ret) {
208-
pr_err("Failed to allocate resource\n");
209-
goto err_priv;
210-
}
211-
212-
priv->doorbell = res.start;
213-
214-
if (of_property_read_u32(node, "loongson,msi-base-vec",
215-
&priv->irq_first)) {
216-
pr_err("Unable to parse MSI vec base\n");
217-
ret = -EINVAL;
218-
goto err_priv;
219-
}
220-
221-
if (of_property_read_u32(node, "loongson,msi-num-vecs",
222-
&priv->num_irqs)) {
223-
pr_err("Unable to parse MSI vec number\n");
224-
ret = -EINVAL;
225-
goto err_priv;
226-
}
202+
priv->doorbell = msg_address;
203+
priv->irq_first = irq_base;
204+
priv->num_irqs = irq_count;
227205

228206
priv->msi_map = bitmap_zalloc(priv->num_irqs, GFP_KERNEL);
229-
if (!priv->msi_map) {
230-
ret = -ENOMEM;
207+
if (!priv->msi_map)
231208
goto err_priv;
232-
}
233209

234210
pr_debug("Registering %d MSIs, starting at %d\n",
235211
priv->num_irqs, priv->irq_first);
236212

237-
ret = pch_msi_init_domains(priv, node, parent_domain);
213+
ret = pch_msi_init_domains(priv, parent_domain, domain_handle);
238214
if (ret)
239215
goto err_map;
240216

217+
pch_msi_handle[nr_pics++] = domain_handle;
241218
return 0;
242219

243220
err_map:
244221
bitmap_free(priv->msi_map);
245222
err_priv:
246223
kfree(priv);
247-
return ret;
224+
225+
return -EINVAL;
226+
}
227+
228+
#ifdef CONFIG_OF
229+
static int pch_msi_of_init(struct device_node *node, struct device_node *parent)
230+
{
231+
int err;
232+
int irq_base, irq_count;
233+
struct resource res;
234+
struct irq_domain *parent_domain;
235+
236+
parent_domain = irq_find_host(parent);
237+
if (!parent_domain) {
238+
pr_err("Failed to find the parent domain\n");
239+
return -ENXIO;
240+
}
241+
242+
if (of_address_to_resource(node, 0, &res)) {
243+
pr_err("Failed to allocate resource\n");
244+
return -EINVAL;
245+
}
246+
247+
if (of_property_read_u32(node, "loongson,msi-base-vec", &irq_base)) {
248+
pr_err("Unable to parse MSI vec base\n");
249+
return -EINVAL;
250+
}
251+
252+
if (of_property_read_u32(node, "loongson,msi-num-vecs", &irq_count)) {
253+
pr_err("Unable to parse MSI vec number\n");
254+
return -EINVAL;
255+
}
256+
257+
err = pch_msi_init(res.start, irq_base, irq_count, parent_domain, of_node_to_fwnode(node));
258+
if (err < 0)
259+
return err;
260+
261+
return 0;
248262
}
249263

250-
IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_msi_init);
264+
IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_msi_of_init);
265+
#endif
266+
267+
#ifdef CONFIG_ACPI
268+
struct fwnode_handle *get_pch_msi_handle(int pci_segment)
269+
{
270+
int i;
271+
272+
for (i = 0; i < MAX_IO_PICS; i++) {
273+
if (msi_group[i].pci_segment == pci_segment)
274+
return pch_msi_handle[i];
275+
}
276+
return NULL;
277+
}
278+
279+
int __init pch_msi_acpi_init(struct irq_domain *parent,
280+
struct acpi_madt_msi_pic *acpi_pchmsi)
281+
{
282+
int ret;
283+
struct fwnode_handle *domain_handle;
284+
285+
domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_pchmsi);
286+
ret = pch_msi_init(acpi_pchmsi->msg_address, acpi_pchmsi->start,
287+
acpi_pchmsi->count, parent, domain_handle);
288+
if (ret < 0)
289+
irq_domain_free_fwnode(domain_handle);
290+
291+
return ret;
292+
}
293+
#endif

0 commit comments

Comments
 (0)