Skip to content

Commit cfd00b7

Browse files
committed
Merge tag 'soc_fsl-6.20-1' of https://git.kernel.org/pub/scm/linux/kernel/git/chleroy/linux into soc/drivers
FSL SOC Changes for 6.20 Freescale Management Complex: - Convert fsl-mc bus to bus callbacks - Fix a use-after-free - Drop redundant error messages - Fix ressources release on some error path Freescale QUICC Engine: - Add an interrupt controller for IO Ports - Use scoped for-each OF child loop * tag 'soc_fsl-6.20-1' of https://git.kernel.org/pub/scm/linux/kernel/git/chleroy/linux: bus: fsl-mc: fix an error handling in fsl_mc_device_add() soc: fsl: qe: qe_ports_ic: Consolidate chained IRQ handler install/remove dt-bindings: soc: fsl: qe: Add an interrupt controller for QUICC Engine Ports soc: fsl: qe: Add an interrupt controller for QUICC Engine Ports soc: fsl: qe: Simplify with scoped for each OF child loop bus: fsl-mc: fix use-after-free in driver_override_show() bus: fsl-mc: Convert to bus callbacks bus: fsl-mc: Drop error message in probe function Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2 parents 1b65492 + 52f527d commit cfd00b7

5 files changed

Lines changed: 233 additions & 63 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/interrupt-controller/fsl,qe-ports-ic.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: Freescale QUICC Engine I/O Ports Interrupt Controller
8+
9+
maintainers:
10+
- Christophe Leroy (CS GROUP) <chleroy@kernel.org>
11+
12+
properties:
13+
compatible:
14+
enum:
15+
- fsl,mpc8323-qe-ports-ic
16+
17+
reg:
18+
maxItems: 1
19+
20+
interrupt-controller: true
21+
22+
'#address-cells':
23+
const: 0
24+
25+
'#interrupt-cells':
26+
const: 1
27+
28+
interrupts:
29+
maxItems: 1
30+
31+
required:
32+
- compatible
33+
- reg
34+
- interrupt-controller
35+
- '#address-cells'
36+
- '#interrupt-cells'
37+
- interrupts
38+
39+
additionalProperties: false
40+
41+
examples:
42+
- |
43+
interrupt-controller@c00 {
44+
compatible = "fsl,mpc8323-qe-ports-ic";
45+
reg = <0xc00 0x18>;
46+
interrupt-controller;
47+
#address-cells = <0>;
48+
#interrupt-cells = <1>;
49+
interrupts = <74 0x8>;
50+
interrupt-parent = <&ipic>;
51+
};

drivers/bus/fsl-mc/fsl-mc-bus.c

Lines changed: 38 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,35 @@ static int fsl_mc_bus_uevent(const struct device *dev, struct kobj_uevent_env *e
137137
return 0;
138138
}
139139

140+
static int fsl_mc_probe(struct device *dev)
141+
{
142+
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
143+
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
144+
145+
if (mc_drv->probe)
146+
return mc_drv->probe(mc_dev);
147+
148+
return 0;
149+
}
150+
151+
static void fsl_mc_remove(struct device *dev)
152+
{
153+
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
154+
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
155+
156+
if (mc_drv->remove)
157+
mc_drv->remove(mc_dev);
158+
}
159+
160+
static void fsl_mc_shutdown(struct device *dev)
161+
{
162+
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
163+
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
164+
165+
if (dev->driver && mc_drv->shutdown)
166+
mc_drv->shutdown(mc_dev);
167+
}
168+
140169
static int fsl_mc_dma_configure(struct device *dev)
141170
{
142171
const struct device_driver *drv = READ_ONCE(dev->driver);
@@ -202,8 +231,12 @@ static ssize_t driver_override_show(struct device *dev,
202231
struct device_attribute *attr, char *buf)
203232
{
204233
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
234+
ssize_t len;
205235

206-
return sysfs_emit(buf, "%s\n", mc_dev->driver_override);
236+
device_lock(dev);
237+
len = sysfs_emit(buf, "%s\n", mc_dev->driver_override);
238+
device_unlock(dev);
239+
return len;
207240
}
208241
static DEVICE_ATTR_RW(driver_override);
209242

@@ -314,6 +347,9 @@ const struct bus_type fsl_mc_bus_type = {
314347
.name = "fsl-mc",
315348
.match = fsl_mc_bus_match,
316349
.uevent = fsl_mc_bus_uevent,
350+
.probe = fsl_mc_probe,
351+
.remove = fsl_mc_remove,
352+
.shutdown = fsl_mc_shutdown,
317353
.dma_configure = fsl_mc_dma_configure,
318354
.dma_cleanup = fsl_mc_dma_cleanup,
319355
.dev_groups = fsl_mc_dev_groups,
@@ -434,42 +470,6 @@ static const struct device_type *fsl_mc_get_device_type(const char *type)
434470
return NULL;
435471
}
436472

437-
static int fsl_mc_driver_probe(struct device *dev)
438-
{
439-
struct fsl_mc_driver *mc_drv;
440-
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
441-
int error;
442-
443-
mc_drv = to_fsl_mc_driver(dev->driver);
444-
445-
error = mc_drv->probe(mc_dev);
446-
if (error < 0) {
447-
if (error != -EPROBE_DEFER)
448-
dev_err(dev, "%s failed: %d\n", __func__, error);
449-
return error;
450-
}
451-
452-
return 0;
453-
}
454-
455-
static int fsl_mc_driver_remove(struct device *dev)
456-
{
457-
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
458-
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
459-
460-
mc_drv->remove(mc_dev);
461-
462-
return 0;
463-
}
464-
465-
static void fsl_mc_driver_shutdown(struct device *dev)
466-
{
467-
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
468-
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
469-
470-
mc_drv->shutdown(mc_dev);
471-
}
472-
473473
/*
474474
* __fsl_mc_driver_register - registers a child device driver with the
475475
* MC bus
@@ -486,15 +486,6 @@ int __fsl_mc_driver_register(struct fsl_mc_driver *mc_driver,
486486
mc_driver->driver.owner = owner;
487487
mc_driver->driver.bus = &fsl_mc_bus_type;
488488

489-
if (mc_driver->probe)
490-
mc_driver->driver.probe = fsl_mc_driver_probe;
491-
492-
if (mc_driver->remove)
493-
mc_driver->driver.remove = fsl_mc_driver_remove;
494-
495-
if (mc_driver->shutdown)
496-
mc_driver->driver.shutdown = fsl_mc_driver_shutdown;
497-
498489
error = driver_register(&mc_driver->driver);
499490
if (error < 0) {
500491
pr_err("driver_register() failed for %s: %d\n",
@@ -905,11 +896,7 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
905896
return 0;
906897

907898
error_cleanup_dev:
908-
kfree(mc_dev->regions);
909-
if (mc_bus)
910-
kfree(mc_bus);
911-
else
912-
kfree(mc_dev);
899+
put_device(&mc_dev->dev);
913900

914901
return error;
915902
}

drivers/soc/fsl/qe/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
1111
obj-$(CONFIG_UCC_FAST) += ucc_fast.o
1212
obj-$(CONFIG_QE_TDM) += qe_tdm.o
1313
obj-$(CONFIG_QE_USB) += usb.o
14-
obj-$(CONFIG_QE_GPIO) += gpio.o
14+
obj-$(CONFIG_QE_GPIO) += gpio.o qe_ports_ic.o

drivers/soc/fsl/qe/qe_ports_ic.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* QUICC ENGINE I/O Ports Interrupt Controller
4+
*
5+
* Copyright (c) 2025 Christophe Leroy CS GROUP France (christophe.leroy@csgroup.eu)
6+
*/
7+
8+
#include <linux/irq.h>
9+
#include <linux/irqdomain.h>
10+
#include <linux/platform_device.h>
11+
12+
/* QE IC registers offset */
13+
#define CEPIER 0x0c
14+
#define CEPIMR 0x10
15+
#define CEPICR 0x14
16+
17+
struct qepic_data {
18+
void __iomem *reg;
19+
struct irq_domain *host;
20+
};
21+
22+
static void qepic_mask(struct irq_data *d)
23+
{
24+
struct qepic_data *data = irq_data_get_irq_chip_data(d);
25+
26+
clrbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
27+
}
28+
29+
static void qepic_unmask(struct irq_data *d)
30+
{
31+
struct qepic_data *data = irq_data_get_irq_chip_data(d);
32+
33+
setbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
34+
}
35+
36+
static void qepic_end(struct irq_data *d)
37+
{
38+
struct qepic_data *data = irq_data_get_irq_chip_data(d);
39+
40+
out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d)));
41+
}
42+
43+
static int qepic_set_type(struct irq_data *d, unsigned int flow_type)
44+
{
45+
struct qepic_data *data = irq_data_get_irq_chip_data(d);
46+
unsigned int vec = (unsigned int)irqd_to_hwirq(d);
47+
48+
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
49+
case IRQ_TYPE_EDGE_FALLING:
50+
setbits32(data->reg + CEPICR, 1 << (31 - vec));
51+
return 0;
52+
case IRQ_TYPE_EDGE_BOTH:
53+
case IRQ_TYPE_NONE:
54+
clrbits32(data->reg + CEPICR, 1 << (31 - vec));
55+
return 0;
56+
}
57+
return -EINVAL;
58+
}
59+
60+
static struct irq_chip qepic = {
61+
.name = "QEPIC",
62+
.irq_mask = qepic_mask,
63+
.irq_unmask = qepic_unmask,
64+
.irq_eoi = qepic_end,
65+
.irq_set_type = qepic_set_type,
66+
};
67+
68+
static int qepic_get_irq(struct irq_desc *desc)
69+
{
70+
struct qepic_data *data = irq_desc_get_handler_data(desc);
71+
u32 event = in_be32(data->reg + CEPIER);
72+
73+
if (!event)
74+
return -1;
75+
76+
return irq_find_mapping(data->host, 32 - ffs(event));
77+
}
78+
79+
static void qepic_cascade(struct irq_desc *desc)
80+
{
81+
generic_handle_irq(qepic_get_irq(desc));
82+
}
83+
84+
static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
85+
{
86+
irq_set_chip_data(virq, h->host_data);
87+
irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq);
88+
return 0;
89+
}
90+
91+
static const struct irq_domain_ops qepic_host_ops = {
92+
.map = qepic_host_map,
93+
};
94+
95+
static int qepic_probe(struct platform_device *pdev)
96+
{
97+
struct device *dev = &pdev->dev;
98+
struct qepic_data *data;
99+
int irq;
100+
101+
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
102+
if (!data)
103+
return -ENOMEM;
104+
105+
data->reg = devm_platform_ioremap_resource(pdev, 0);
106+
if (IS_ERR(data->reg))
107+
return PTR_ERR(data->reg);
108+
109+
irq = platform_get_irq(pdev, 0);
110+
if (irq < 0)
111+
return irq;
112+
113+
data->host = irq_domain_add_linear(dev->of_node, 32, &qepic_host_ops, data);
114+
if (!data->host)
115+
return -ENODEV;
116+
117+
irq_set_chained_handler_and_data(irq, qepic_cascade, data);
118+
119+
return 0;
120+
}
121+
122+
static const struct of_device_id qepic_match[] = {
123+
{
124+
.compatible = "fsl,mpc8323-qe-ports-ic",
125+
},
126+
{},
127+
};
128+
129+
static struct platform_driver qepic_driver = {
130+
.driver = {
131+
.name = "qe_ports_ic",
132+
.of_match_table = qepic_match,
133+
},
134+
.probe = qepic_probe,
135+
};
136+
137+
static int __init qepic_init(void)
138+
{
139+
return platform_driver_register(&qepic_driver);
140+
}
141+
arch_initcall(qepic_init);

drivers/soc/fsl/qe/qmc.c

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,31 +1284,26 @@ static unsigned int qmc_nb_chans(struct qmc *qmc)
12841284

12851285
static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
12861286
{
1287-
struct device_node *chan_np;
12881287
struct qmc_chan *chan;
12891288
const char *mode;
12901289
u32 chan_id;
12911290
u64 ts_mask;
12921291
int ret;
12931292

1294-
for_each_available_child_of_node(np, chan_np) {
1293+
for_each_available_child_of_node_scoped(np, chan_np) {
12951294
ret = of_property_read_u32(chan_np, "reg", &chan_id);
12961295
if (ret) {
12971296
dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np);
1298-
of_node_put(chan_np);
12991297
return ret;
13001298
}
13011299
if (chan_id > 63) {
13021300
dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np);
1303-
of_node_put(chan_np);
13041301
return -EINVAL;
13051302
}
13061303

13071304
chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL);
1308-
if (!chan) {
1309-
of_node_put(chan_np);
1305+
if (!chan)
13101306
return -ENOMEM;
1311-
}
13121307

13131308
chan->id = chan_id;
13141309
spin_lock_init(&chan->ts_lock);
@@ -1319,7 +1314,6 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
13191314
if (ret) {
13201315
dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n",
13211316
chan_np);
1322-
of_node_put(chan_np);
13231317
return ret;
13241318
}
13251319
chan->tx_ts_mask_avail = ts_mask;
@@ -1329,7 +1323,6 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
13291323
if (ret) {
13301324
dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n",
13311325
chan_np);
1332-
of_node_put(chan_np);
13331326
return ret;
13341327
}
13351328
chan->rx_ts_mask_avail = ts_mask;
@@ -1340,7 +1333,6 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
13401333
if (ret && ret != -EINVAL) {
13411334
dev_err(qmc->dev, "%pOF: failed to read fsl,operational-mode\n",
13421335
chan_np);
1343-
of_node_put(chan_np);
13441336
return ret;
13451337
}
13461338
if (!strcmp(mode, "transparent")) {
@@ -1350,7 +1342,6 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
13501342
} else {
13511343
dev_err(qmc->dev, "%pOF: Invalid fsl,operational-mode (%s)\n",
13521344
chan_np, mode);
1353-
of_node_put(chan_np);
13541345
return -EINVAL;
13551346
}
13561347

0 commit comments

Comments
 (0)