Skip to content

Commit 0a6c8d7

Browse files
maoxiaochuanAirFortressIlikara
authored andcommitted
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
1 parent 693fe4c commit 0a6c8d7

File tree

1 file changed

+121
-44
lines changed

1 file changed

+121
-44
lines changed

drivers/gpio/gpio-loongson-irq.c

Lines changed: 121 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -116,30 +116,45 @@ static int __map_hwirq_pin(lsirq_gpio_irqpinmap_t* map, int hwirq,
116116
lsirq_gpio_priv_t* priv)
117117
{
118118
int pin;
119+
u8 irq_val, irqsta_val;
119120

120-
if (map->hwirq == hwirq)
121-
{
122-
for (pin = map->pin_start;
123-
pin < map->pin_start + map->pin_num;
124-
pin++)
125-
{
126-
// 2k300 must check irq enable
127-
if (lsirq_gpio_get_reg_irq(priv, pin) == 1 &&
128-
lsirq_gpio_get_reg_irqsta(priv, pin) == 1)
129-
return pin;
130-
}
121+
if (map->hwirq != hwirq)
122+
return -1;
123+
124+
for (pin = map->pin_start; pin < map->pin_start + map->pin_num; pin++) {
125+
/* Bounds checking */
126+
if (pin < 0 || pin >= priv->gc.ngpio)
127+
continue;
128+
129+
/* Atomic register read to avoid race condition */
130+
irq_val = lsirq_gpio_get_reg_irq(priv, pin);
131+
irqsta_val = lsirq_gpio_get_reg_irqsta(priv, pin);
132+
133+
/* 2k300 must check irq enable */
134+
if (irq_val == 1 && irqsta_val == 1)
135+
return pin;
131136
}
132137

133138
return -1;
134139
}
135140

136141
static int __map_vhwirq_pin(lsirq_gpio_priv_t* priv, int vhwirq)
137142
{
138-
return vhwirq - priv->irqd.vhwirq_base;
143+
int pin = vhwirq - priv->irqd.vhwirq_base;
144+
145+
/* Bounds checking */
146+
if (pin < 0 || pin >= priv->gc.ngpio)
147+
return -EINVAL;
148+
149+
return pin;
139150
}
140151

141152
static int __map_pin_vhwirq(lsirq_gpio_priv_t* priv, int pin)
142153
{
154+
/* Bounds checking */
155+
if (pin < 0 || pin >= priv->gc.ngpio)
156+
return -EINVAL;
157+
143158
return pin + priv->irqd.vhwirq_base;
144159
}
145160

@@ -225,7 +240,13 @@ static int mthd_lsirq_gpio_to_irq(struct gpio_chip *gc, unsigned pin)
225240
int vhwirq, rirq;
226241
lsirq_gpio_priv_t *priv = gpiochip_get_data(gc);
227242

243+
if (pin >= gc->ngpio)
244+
return -EINVAL;
245+
228246
vhwirq = __map_pin_vhwirq(priv, (int)pin);
247+
if (vhwirq < 0)
248+
return vhwirq;
249+
229250
rirq = __map_vhwirq_rirq(priv, vhwirq);
230251

231252
return rirq;
@@ -238,6 +259,9 @@ static int mthd_lsirq_gpio_irqsettype(struct irq_data *d, u32 type)
238259
int pin = __map_vhwirq_pin(priv, vhwirq);
239260
unsigned long flags;
240261

262+
if (pin < 0)
263+
return pin;
264+
241265
switch (type) {
242266
case IRQ_TYPE_EDGE_RISING:
243267
lsirq_gpio_set_reg_irq(priv, pin, 1);
@@ -283,7 +307,13 @@ static int mthd_lsirq_gpio_irqsettype(struct irq_data *d, u32 type)
283307

284308
static void mthd_lsirq_gpio_irqack(struct irq_data *d)
285309
{
286-
310+
lsirq_gpio_priv_t *priv = irq_data_get_irq_chip_data(d);
311+
int vhwirq = d->hwirq;
312+
int pin = __map_vhwirq_pin(priv, vhwirq);
313+
314+
/* Acknowledge interrupt by clearing status */
315+
if (pin >= 0)
316+
lsirq_gpio_set_reg_irqclr(priv, pin, 1);
287317
}
288318

289319
static void mthd_lsirq_gpio_irqmask(struct irq_data *d)
@@ -293,7 +323,10 @@ static void mthd_lsirq_gpio_irqmask(struct irq_data *d)
293323
int pin = __map_vhwirq_pin(priv, vhwirq);
294324
unsigned long flags;
295325

296-
// interrupt must gpio input
326+
if (pin < 0)
327+
return;
328+
329+
/* interrupt must gpio input */
297330
spin_lock_irqsave(&priv->lock, flags);
298331
lsirq_gpio_set_reg_dir(priv, pin, 1);
299332
spin_unlock_irqrestore(&priv->lock, flags);
@@ -307,23 +340,24 @@ static void mthd_lsirq_gpio_irqunmask(struct irq_data *d)
307340
int vhwirq = d->hwirq;
308341
int pin = __map_vhwirq_pin(priv, vhwirq);
309342

343+
if (pin < 0)
344+
return;
345+
310346
lsirq_gpio_set_reg_irq(priv, pin, 1);
311347
}
312348

313-
static int lsirq_gpio_gc_remove(lsirq_gpio_priv_t* priv)
314-
{
315-
struct gpio_chip* gc = &priv->gc;
316349

317-
gpiochip_remove(gc);
318-
319-
return 0;
320-
}
321350

322351
static int lsirq_gpio_gc_setup(lsirq_gpio_priv_t* priv)
323352
{
324353
struct gpio_chip* gc = &priv->gc;
325354
struct device_node *np = priv->dev->of_node;
326355

356+
if (!np) {
357+
dev_err(priv->dev, "No device node\n");
358+
return -ENODEV;
359+
}
360+
327361
of_property_read_u32(np, "ngpios", (u32 *)&gc->ngpio);
328362
of_property_read_u32(np, "gpio_base", (u32 *)&gc->base);
329363
gc->request = mthd_lsirq_gpio_request;
@@ -339,7 +373,7 @@ static int lsirq_gpio_gc_setup(lsirq_gpio_priv_t* priv)
339373
if (devm_gpiochip_add_data(priv->dev, gc, priv))
340374
{
341375
dev_err(priv->dev, "gpiochip setup fail\n");
342-
return -1;
376+
return -ENODEV;
343377
}
344378

345379
return 0;
@@ -429,6 +463,11 @@ static int lsirqd_setup(lsirq_gpio_priv_t* priv)
429463
lsirq_gpio_irqdesc_t* irqd = &priv->irqd;
430464
struct device_node *np = priv->dev->of_node;
431465

466+
if (!np) {
467+
dev_err(priv->dev, "No device node\n");
468+
return -ENODEV;
469+
}
470+
432471
of_property_read_u32(np, "loongson,vhwirq-base", (u32 *)&irqd->vhwirq_base);
433472
snprintf(irqd->name, sizeof(irqd->name), "GPIC-%s", np->name);
434473

@@ -439,7 +478,7 @@ static int lsirqd_setup(lsirq_gpio_priv_t* priv)
439478
if (irqd->nr_irqs <= 0)
440479
{
441480
dev_err(priv->dev, "IRQ Pin Map fail\n");
442-
goto err;
481+
return -ENODEV;
443482
}
444483
/*
445484
* Setup VIRQ-IRQ-MAP
@@ -450,14 +489,14 @@ static int lsirqd_setup(lsirq_gpio_priv_t* priv)
450489
0, irqd->nr_irqs, numa_node_id());
451490
if (irqd->rirq_base < 0) {
452491
dev_err(priv->dev, "Alloc IRQ fail\n");
453-
goto clear_pin_map;
492+
goto free_map;
454493
}
455494
// set ic prop
456495
irqd->ic = kzalloc(sizeof(*irqd->ic), GFP_KERNEL);
457496
if (!irqd->ic)
458497
{
459498
dev_err(priv->dev, "IRQ chip alloc fail\n");
460-
goto free_irq_desc;
499+
goto free_ic;
461500
}
462501
irqd->ic->name = irqd->name;
463502
irqd->ic->irq_ack = mthd_lsirq_gpio_irqack;
@@ -471,20 +510,18 @@ static int lsirqd_setup(lsirq_gpio_priv_t* priv)
471510
&domain_ops_gpic, priv);
472511
if (!irqd->domain) {
473512
dev_err(priv->dev, "IRQ domain add fail\n");
474-
goto free_ic;
513+
goto free_domain;
475514
}
476515
dev_info(priv->dev, "register irqnum=%d, vhwirq-base=%d, rirq-base=%d\n",
477516
irqd->nr_irqs, irqd->vhwirq_base, irqd->rirq_base);
478517
return 0;
479-
480-
free_ic:
518+
free_domain:
481519
kfree(irqd->ic);
482-
free_irq_desc:
520+
free_ic:
483521
irq_free_descs(irqd->rirq_base, irqd->nr_irqs);
484-
clear_pin_map:
522+
free_map:
485523
lsirqmap_clear(&irqd->ipm);
486-
err:
487-
return -1;
524+
return -ENODEV;
488525
}
489526

490527
static const struct of_device_id drvids_lsirq_gpio[] = {
@@ -497,37 +534,69 @@ MODULE_DEVICE_TABLE(of, drvids_lsirq_gpio);
497534
static int drv_lsirq_gpio_probe(struct platform_device *pdev)
498535
{
499536
lsirq_gpio_priv_t* priv;
500-
const struct of_device_id *of_id =
501-
of_match_device(drvids_lsirq_gpio, &pdev->dev);
537+
const struct of_device_id *of_id;
538+
539+
of_id = of_match_device(drvids_lsirq_gpio, &pdev->dev);
540+
if (!of_id) {
541+
dev_err(&pdev->dev, "No matching device ID\n");
542+
return -ENODEV;
543+
}
544+
545+
if (!of_id->data) {
546+
dev_err(&pdev->dev, "No register table data\n");
547+
return -ENODEV;
548+
}
502549

503550
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
504551
if (!priv)
505552
return -ENOMEM;
506553

507554
priv->reg = devm_platform_ioremap_resource(pdev, 0);
508555
if (IS_ERR(priv->reg))
509-
goto ioremap_fail;
556+
return PTR_ERR(priv->reg);
557+
510558
spin_lock_init(&priv->lock);
511559
priv->dev = &pdev->dev;
512560
priv->regtable = of_id->data;
513561

514562
if (lsirq_gpio_gc_setup(priv))
515-
goto gc_fail;
563+
return -ENODEV;
516564

517565
if (lsirqd_setup(priv))
518-
goto irqd_fail;
566+
return -ENODEV;
519567

520568
platform_set_drvdata(pdev, priv);
521569

522570
return 0;
571+
}
523572

524-
irqd_fail:
525-
lsirq_gpio_gc_remove(priv);
526-
gc_fail:
527-
devm_iounmap(&pdev->dev, priv->reg);
528-
ioremap_fail:
529-
devm_kfree(&pdev->dev, priv);
530-
return -1;
573+
static void drv_lsirq_gpio_remove(struct platform_device *pdev)
574+
{
575+
lsirq_gpio_priv_t *priv = platform_get_drvdata(pdev);
576+
577+
if (!priv)
578+
return;
579+
580+
/* Clean up IRQ domain and mappings */
581+
if (priv->irqd.domain) {
582+
irq_domain_remove(priv->irqd.domain);
583+
priv->irqd.domain = NULL;
584+
}
585+
586+
/* Free IRQ descriptors */
587+
if (priv->irqd.rirq_base >= 0) {
588+
irq_free_descs(priv->irqd.rirq_base, priv->irqd.nr_irqs);
589+
priv->irqd.rirq_base = -1;
590+
}
591+
592+
/* Free IRQ chip */
593+
kfree(priv->irqd.ic);
594+
priv->irqd.ic = NULL;
595+
596+
/* Clear IRQ pin mappings */
597+
lsirqmap_clear(&priv->irqd.ipm);
598+
599+
/* GPIO chip will be automatically cleaned up by devm_* */
531600
}
532601

533602
static struct platform_driver lsirq_gpio_driver = {
@@ -537,13 +606,21 @@ static struct platform_driver lsirq_gpio_driver = {
537606
.of_match_table = drvids_lsirq_gpio,
538607
},
539608
.probe = drv_lsirq_gpio_probe,
609+
.remove = drv_lsirq_gpio_remove,
540610
};
541611

542612
static int __init lsirq_gpio_init(void)
543613
{
544614
return platform_driver_register(&lsirq_gpio_driver);
545615
}
616+
617+
static void __exit lsirq_gpio_exit(void)
618+
{
619+
platform_driver_unregister(&lsirq_gpio_driver);
620+
}
621+
546622
subsys_initcall(lsirq_gpio_init);
623+
module_exit(lsirq_gpio_exit);
547624

548625
MODULE_AUTHOR("Yize Niu <niuyize@loongson.cn>");
549626
MODULE_DESCRIPTION("Loongson GPIO With IRQ Driver");

0 commit comments

Comments
 (0)