gpio:fix crash when irq map fail

[    1.112617] Warning: unable to open an initial console.
[    1.128648] Waiting for root device /dev/mmcblk0p1...
[   11.439784] gpio gpiochip0: Static allocation of GPIO base is deprecated, use dynamic allocation.
[   11.449431] gpio-lsirq 16104000.gpio: IRQ Pin Map fail
[   11.459605] gpio-lsirq 16104000.gpio: probe with driver gpio-lsirq failed with error -1
[   11.467761] Unhandled kernel unaligned access[#1]:
[   11.472606] CPU: 0 UID: 0 PID: 79 Comm: kworker/u4:2 Not tainted 6.12.0.lsgd #1
[   11.479994] Hardware name: Loongson LS2K300/LS2K300-PAI, BIOS 2022.04-v2.0.0-00572-gfaaca55a 04/01/2022
[   11.489483] Workqueue: events_unbound deferred_probe_work_func
[   11.495394] pc 90000000008683a8 ra 9000000000868398 tp 9000000006954000 sp 9000000006957b60
[   11.503832] a0 9000000001860338 a1 90000000066a0230 a2 9000000006957b98 a3 0000000000000004
[   11.512267] a4 00000000000000b4 a5 0000000000000040 a6 0000000000000000 a7 9000000006018410
[   11.520703] t0 0000000000000122 t1 9000000001860240 t2 90000000068b2f40 t3 0000000000000000
[   11.529137] t4 900000000618a658 t5 900000000618a658 t6 90000000009f0eb4 t7 90000000009f1154
[   11.537571] t8 0000000000000000 u0 006f6970672e3030 s9 90000000066ce500 s0 9000000006c1d440
[   11.546005] s1 9000000006c1e400 s2 9000000001860240 s3 9000000001860338 s4 0000000000000003
[   11.554440] s5 90000000013ea000 s6 90000000066ce4c0 s7 90000000013f2000 s8 90000000060e5e80
[   11.562874]    ra: 9000000000868398 gpiochip_remove+0x44/0xd4
[   11.568693]   ERA: 90000000008683a8 gpiochip_remove+0x54/0xd4
[   11.574504]  CRMD: 000000b0 (PLV0 -IE -DA +PG DACF=CC DACM=CC -WE)
[   11.580774]  PRMD: 00000004 (PPLV0 +PIE -PWE)
[   11.585182]  EUEN: 00000000 (-FPE -SXE -ASXE -BTE)
[   11.590033]  ECFG: 00071c1d (LIE=0,2-4,10-12 VS=7)
[   11.594882] ESTAT: 00090000 [ALE] (IS= ECode=9 EsubCode=0)
[   11.600428]  BADV: 0000000000000122
[   11.603946]  PRID: 0014a030 (Loongson-64bit, )
[   11.608431] Modules linked in:
[   11.611512] Process kworker/u4:2 (pid: 79, threadinfo=(____ptrval____), task=(____ptrval____))
[   11.620213] Stack : 9000000006196ca0 9000000006957b98 900000000618a410 90000000066d7b40
[   11.628313]         90000000066a0200 90000000009f276c 90000000013ea000 90000000066d7420
[   11.636412]         90000000066a0200 db47c55fde642c00 90000000013ea000 90000000009ec89c
[   11.644510]         90000000013ea000 0000000000000000 9000000001860e00 0000000000000001
[   11.652608]         900000000618a410 90000000009ebae8 900000000618a410 90000000009ec3e8
[   11.660707]         900000000618a410 0000000000000003 900000000618a410 9000000001860e00
[   11.668805]         900000000618a410 90000000009ec63c 900000000618a410 9000000001860e00
[   11.676904]         9000000001c91e18 90000000009ec7fc 9000000001860e00 900000000618a410
[   11.685002]         9000000006957d18 9000000001860e00 0000000000000001 90000000009ec968
[   11.693100]         90000000013ea000 9000000006957d18 900000000608f800 9000000006957cb8
[   11.701199]         ...
[   11.703668] Call Trace:
[   11.703675] [<90000000008683a8>] gpiochip_remove+0x54/0xd4
[   11.711688] [<90000000009f2768>] devres_release_all+0xb4/0x12c
[   11.717594] [<90000000009ebae4>] device_unbind_cleanup+0x10/0x5c
[   11.723667] [<90000000009ec3e4>] really_probe+0x1e0/0x3ac
[   11.729126] [<90000000009ec638>] __driver_probe_device+0x88/0x160
[   11.735285] [<90000000009ec7f8>] driver_probe_device+0x34/0xd8
[   11.741181] [<90000000009ec964>] __device_attach_driver+0xc8/0x178
[   11.747430] [<90000000009e9d7c>] bus_for_each_drv+0x8c/0xf0
[   11.753073] [<90000000009ecda8>] __device_attach+0xa4/0x1b4
[   11.758705] [<90000000009eaf60>] bus_probe_device+0xa8/0xd0
[   11.764339] [<90000000009eb5f4>] deferred_probe_work_func+0x9c/0xf0
[   11.770674] [<9000000000259084>] process_one_work+0x178/0x2f4
[   11.776492] [<9000000000259fa0>] worker_thread+0x390/0x4c8
[   11.782041] [<9000000000261028>] kthread+0x104/0x114
[   11.787066] [<9000000000f1c764>] ret_from_kernel_thread+0x28/0x48
[   11.793229] [<9000000000221024>] ret_from_kernel_thread_asm+0xc/0x88
[   11.799654]
[   11.801153] Code: 28cd630c  00150344  29c021ac <2700018d> 0284880c  29cd630c  5789441a  02c04324  56f96fe8
[   11.811031]
[   11.812564] ---[ end trace 0000000000000000 ]---
[  119.451577] random: crng init done
This commit is contained in:
maoxiaochuan
2025-11-20 16:56:46 +08:00
parent f9d47373c9
commit ed8ea729ee
+121 -44
View File
@@ -116,18 +116,23 @@ static int __map_hwirq_pin(lsirq_gpio_irqpinmap_t* map, int hwirq,
lsirq_gpio_priv_t* priv)
{
int pin;
u8 irq_val, irqsta_val;
if (map->hwirq == hwirq)
{
for (pin = map->pin_start;
pin < map->pin_start + map->pin_num;
pin++)
{
// 2k300 must check irq enable
if (lsirq_gpio_get_reg_irq(priv, pin) == 1 &&
lsirq_gpio_get_reg_irqsta(priv, pin) == 1)
return pin;
}
if (map->hwirq != hwirq)
return -1;
for (pin = map->pin_start; pin < map->pin_start + map->pin_num; pin++) {
/* Bounds checking */
if (pin < 0 || pin >= priv->gc.ngpio)
continue;
/* Atomic register read to avoid race condition */
irq_val = lsirq_gpio_get_reg_irq(priv, pin);
irqsta_val = lsirq_gpio_get_reg_irqsta(priv, pin);
/* 2k300 must check irq enable */
if (irq_val == 1 && irqsta_val == 1)
return pin;
}
return -1;
@@ -135,11 +140,21 @@ static int __map_hwirq_pin(lsirq_gpio_irqpinmap_t* map, int hwirq,
static int __map_vhwirq_pin(lsirq_gpio_priv_t* priv, int vhwirq)
{
return vhwirq - priv->irqd.vhwirq_base;
int pin = vhwirq - priv->irqd.vhwirq_base;
/* Bounds checking */
if (pin < 0 || pin >= priv->gc.ngpio)
return -EINVAL;
return pin;
}
static int __map_pin_vhwirq(lsirq_gpio_priv_t* priv, int pin)
{
/* Bounds checking */
if (pin < 0 || pin >= priv->gc.ngpio)
return -EINVAL;
return pin + priv->irqd.vhwirq_base;
}
@@ -225,7 +240,13 @@ static int mthd_lsirq_gpio_to_irq(struct gpio_chip *gc, unsigned pin)
int vhwirq, rirq;
lsirq_gpio_priv_t *priv = gpiochip_get_data(gc);
if (pin >= gc->ngpio)
return -EINVAL;
vhwirq = __map_pin_vhwirq(priv, (int)pin);
if (vhwirq < 0)
return vhwirq;
rirq = __map_vhwirq_rirq(priv, vhwirq);
return rirq;
@@ -238,6 +259,9 @@ static int mthd_lsirq_gpio_irqsettype(struct irq_data *d, u32 type)
int pin = __map_vhwirq_pin(priv, vhwirq);
unsigned long flags;
if (pin < 0)
return pin;
switch (type) {
case IRQ_TYPE_EDGE_RISING:
lsirq_gpio_set_reg_irq(priv, pin, 1);
@@ -283,7 +307,13 @@ static int mthd_lsirq_gpio_irqsettype(struct irq_data *d, u32 type)
static void mthd_lsirq_gpio_irqack(struct irq_data *d)
{
lsirq_gpio_priv_t *priv = irq_data_get_irq_chip_data(d);
int vhwirq = d->hwirq;
int pin = __map_vhwirq_pin(priv, vhwirq);
/* Acknowledge interrupt by clearing status */
if (pin >= 0)
lsirq_gpio_set_reg_irqclr(priv, pin, 1);
}
static void mthd_lsirq_gpio_irqmask(struct irq_data *d)
@@ -293,7 +323,10 @@ static void mthd_lsirq_gpio_irqmask(struct irq_data *d)
int pin = __map_vhwirq_pin(priv, vhwirq);
unsigned long flags;
// interrupt must gpio input
if (pin < 0)
return;
/* interrupt must gpio input */
spin_lock_irqsave(&priv->lock, flags);
lsirq_gpio_set_reg_dir(priv, pin, 1);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -307,23 +340,24 @@ static void mthd_lsirq_gpio_irqunmask(struct irq_data *d)
int vhwirq = d->hwirq;
int pin = __map_vhwirq_pin(priv, vhwirq);
if (pin < 0)
return;
lsirq_gpio_set_reg_irq(priv, pin, 1);
}
static int lsirq_gpio_gc_remove(lsirq_gpio_priv_t* priv)
{
struct gpio_chip* gc = &priv->gc;
gpiochip_remove(gc);
return 0;
}
static int lsirq_gpio_gc_setup(lsirq_gpio_priv_t* priv)
{
struct gpio_chip* gc = &priv->gc;
struct device_node *np = priv->dev->of_node;
if (!np) {
dev_err(priv->dev, "No device node\n");
return -ENODEV;
}
of_property_read_u32(np, "ngpios", (u32 *)&gc->ngpio);
of_property_read_u32(np, "gpio_base", (u32 *)&gc->base);
gc->request = mthd_lsirq_gpio_request;
@@ -339,7 +373,7 @@ static int lsirq_gpio_gc_setup(lsirq_gpio_priv_t* priv)
if (devm_gpiochip_add_data(priv->dev, gc, priv))
{
dev_err(priv->dev, "gpiochip setup fail\n");
return -1;
return -ENODEV;
}
return 0;
@@ -429,6 +463,11 @@ static int lsirqd_setup(lsirq_gpio_priv_t* priv)
lsirq_gpio_irqdesc_t* irqd = &priv->irqd;
struct device_node *np = priv->dev->of_node;
if (!np) {
dev_err(priv->dev, "No device node\n");
return -ENODEV;
}
of_property_read_u32(np, "loongson,vhwirq-base", (u32 *)&irqd->vhwirq_base);
snprintf(irqd->name, sizeof(irqd->name), "GPIC-%s", np->name);
@@ -439,7 +478,7 @@ static int lsirqd_setup(lsirq_gpio_priv_t* priv)
if (irqd->nr_irqs <= 0)
{
dev_err(priv->dev, "IRQ Pin Map fail\n");
goto err;
return -ENODEV;
}
/*
* Setup VIRQ-IRQ-MAP
@@ -450,14 +489,14 @@ static int lsirqd_setup(lsirq_gpio_priv_t* priv)
0, irqd->nr_irqs, numa_node_id());
if (irqd->rirq_base < 0) {
dev_err(priv->dev, "Alloc IRQ fail\n");
goto clear_pin_map;
goto free_map;
}
// set ic prop
irqd->ic = kzalloc(sizeof(*irqd->ic), GFP_KERNEL);
if (!irqd->ic)
{
dev_err(priv->dev, "IRQ chip alloc fail\n");
goto free_irq_desc;
goto free_ic;
}
irqd->ic->name = irqd->name;
irqd->ic->irq_ack = mthd_lsirq_gpio_irqack;
@@ -471,20 +510,18 @@ static int lsirqd_setup(lsirq_gpio_priv_t* priv)
&domain_ops_gpic, priv);
if (!irqd->domain) {
dev_err(priv->dev, "IRQ domain add fail\n");
goto free_ic;
goto free_domain;
}
dev_info(priv->dev, "register irqnum=%d, vhwirq-base=%d, rirq-base=%d\n",
irqd->nr_irqs, irqd->vhwirq_base, irqd->rirq_base);
return 0;
free_ic:
free_domain:
kfree(irqd->ic);
free_irq_desc:
free_ic:
irq_free_descs(irqd->rirq_base, irqd->nr_irqs);
clear_pin_map:
free_map:
lsirqmap_clear(&irqd->ipm);
err:
return -1;
return -ENODEV;
}
static const struct of_device_id drvids_lsirq_gpio[] = {
@@ -497,8 +534,18 @@ MODULE_DEVICE_TABLE(of, drvids_lsirq_gpio);
static int drv_lsirq_gpio_probe(struct platform_device *pdev)
{
lsirq_gpio_priv_t* priv;
const struct of_device_id *of_id =
of_match_device(drvids_lsirq_gpio, &pdev->dev);
const struct of_device_id *of_id;
of_id = of_match_device(drvids_lsirq_gpio, &pdev->dev);
if (!of_id) {
dev_err(&pdev->dev, "No matching device ID\n");
return -ENODEV;
}
if (!of_id->data) {
dev_err(&pdev->dev, "No register table data\n");
return -ENODEV;
}
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -506,28 +553,50 @@ static int drv_lsirq_gpio_probe(struct platform_device *pdev)
priv->reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->reg))
goto ioremap_fail;
return PTR_ERR(priv->reg);
spin_lock_init(&priv->lock);
priv->dev = &pdev->dev;
priv->regtable = of_id->data;
if (lsirq_gpio_gc_setup(priv))
goto gc_fail;
return -ENODEV;
if (lsirqd_setup(priv))
goto irqd_fail;
return -ENODEV;
platform_set_drvdata(pdev, priv);
return 0;
}
irqd_fail:
lsirq_gpio_gc_remove(priv);
gc_fail:
devm_iounmap(&pdev->dev, priv->reg);
ioremap_fail:
devm_kfree(&pdev->dev, priv);
return -1;
static void drv_lsirq_gpio_remove(struct platform_device *pdev)
{
lsirq_gpio_priv_t *priv = platform_get_drvdata(pdev);
if (!priv)
return;
/* Clean up IRQ domain and mappings */
if (priv->irqd.domain) {
irq_domain_remove(priv->irqd.domain);
priv->irqd.domain = NULL;
}
/* Free IRQ descriptors */
if (priv->irqd.rirq_base >= 0) {
irq_free_descs(priv->irqd.rirq_base, priv->irqd.nr_irqs);
priv->irqd.rirq_base = -1;
}
/* Free IRQ chip */
kfree(priv->irqd.ic);
priv->irqd.ic = NULL;
/* Clear IRQ pin mappings */
lsirqmap_clear(&priv->irqd.ipm);
/* GPIO chip will be automatically cleaned up by devm_* */
}
static struct platform_driver lsirq_gpio_driver = {
@@ -537,13 +606,21 @@ static struct platform_driver lsirq_gpio_driver = {
.of_match_table = drvids_lsirq_gpio,
},
.probe = drv_lsirq_gpio_probe,
.remove = drv_lsirq_gpio_remove,
};
static int __init lsirq_gpio_init(void)
{
return platform_driver_register(&lsirq_gpio_driver);
}
static void __exit lsirq_gpio_exit(void)
{
platform_driver_unregister(&lsirq_gpio_driver);
}
subsys_initcall(lsirq_gpio_init);
module_exit(lsirq_gpio_exit);
MODULE_AUTHOR("Yize Niu <niuyize@loongson.cn>");
MODULE_DESCRIPTION("Loongson GPIO With IRQ Driver");