mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
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 -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQTH/wu6mIr0ZW+Vui/dkHAmvKvPUwUCaX2wKAAKCRDdkHAmvKvP U8ZEAQCjVUaUt+nRVvd+/WzZy+dh4vT9r1FJeV4MtHSTfvSM+QD+P5eiz0RIvCAZ 0++CD7UTnPvpxlUMXX08cJRPLmgr1wA= =GjGO -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmmC+EIACgkQmmx57+YA GNnEtw/+Ov7AKkw2FpZYkpXhvzvIGvVy5HdAM4DbscedQF2qD/8Pr+tWcrM4avjW qIRvK1uAS1TSNWszze9htXd7CoHCViOuA0CUuIKp4Q1YO18fOW+eN3+uYNM0ylfg BNhY4u31EWS6F+tST30+W1eR1Oj5RfVZp2jXMKLeqjjb6qINQ4Gc3Mge+jXTbI47 M+imsNKwMMM/tDK4HNYiU7L52Y9Oo3UdnTH4LEgj7AvIQ2cZDW6n0PJUnlDAJjFJ dy7/BSZ9zdaxf8779Ma/0obJd67EIhDSEiW81hKaEp1xKhSdpwqlDkU3QKDmWAIh IbtlM8bl+5LK7tm7Olb7Zp4LC8N+2LZz3bR3kZlAlCVPK5ZVx5/23JFCHwHK+1hR nJklyChfYrN0zF3zFUvKWu77CRDEwwYH9hFNE2fa8XszMx1aH8FqxraYGqJwZpqj 9K4gexlJ/4HK477wFgyZN65mMIt0zbr9K024cY2f/HF3OvcmvM9HQs23iUcaTJO8 4D/b+BzwEo2aJxdvO+W7/6vqIyk3k7wPGQbO9DQMsL+jmVJ6xM1dH0UMjjEvzDUF E6RLigZtEzKGmg+EoM2YIIz456hqtX0Osct5irA5kLw8NX5UJN6po1u9xZAVWTW3 kYIZklaZ3Fc9AbRyFdf6w5//xRcCIzfsbXQiu5UFgHtbFZn5f7E= =+uwq -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
cfd00b7e26
5 changed files with 233 additions and 63 deletions
|
|
@ -0,0 +1,51 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interrupt-controller/fsl,qe-ports-ic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale QUICC Engine I/O Ports Interrupt Controller
|
||||
|
||||
maintainers:
|
||||
- Christophe Leroy (CS GROUP) <chleroy@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,mpc8323-qe-ports-ic
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
'#address-cells':
|
||||
const: 0
|
||||
|
||||
'#interrupt-cells':
|
||||
const: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupt-controller
|
||||
- '#address-cells'
|
||||
- '#interrupt-cells'
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
interrupt-controller@c00 {
|
||||
compatible = "fsl,mpc8323-qe-ports-ic";
|
||||
reg = <0xc00 0x18>;
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupts = <74 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
};
|
||||
|
|
@ -137,6 +137,35 @@ static int fsl_mc_bus_uevent(const struct device *dev, struct kobj_uevent_env *e
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_mc_probe(struct device *dev)
|
||||
{
|
||||
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
|
||||
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
|
||||
|
||||
if (mc_drv->probe)
|
||||
return mc_drv->probe(mc_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fsl_mc_remove(struct device *dev)
|
||||
{
|
||||
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
|
||||
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
|
||||
|
||||
if (mc_drv->remove)
|
||||
mc_drv->remove(mc_dev);
|
||||
}
|
||||
|
||||
static void fsl_mc_shutdown(struct device *dev)
|
||||
{
|
||||
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
|
||||
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
|
||||
|
||||
if (dev->driver && mc_drv->shutdown)
|
||||
mc_drv->shutdown(mc_dev);
|
||||
}
|
||||
|
||||
static int fsl_mc_dma_configure(struct device *dev)
|
||||
{
|
||||
const struct device_driver *drv = READ_ONCE(dev->driver);
|
||||
|
|
@ -202,8 +231,12 @@ static ssize_t driver_override_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
|
||||
ssize_t len;
|
||||
|
||||
return sysfs_emit(buf, "%s\n", mc_dev->driver_override);
|
||||
device_lock(dev);
|
||||
len = sysfs_emit(buf, "%s\n", mc_dev->driver_override);
|
||||
device_unlock(dev);
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR_RW(driver_override);
|
||||
|
||||
|
|
@ -314,6 +347,9 @@ const struct bus_type fsl_mc_bus_type = {
|
|||
.name = "fsl-mc",
|
||||
.match = fsl_mc_bus_match,
|
||||
.uevent = fsl_mc_bus_uevent,
|
||||
.probe = fsl_mc_probe,
|
||||
.remove = fsl_mc_remove,
|
||||
.shutdown = fsl_mc_shutdown,
|
||||
.dma_configure = fsl_mc_dma_configure,
|
||||
.dma_cleanup = fsl_mc_dma_cleanup,
|
||||
.dev_groups = fsl_mc_dev_groups,
|
||||
|
|
@ -434,42 +470,6 @@ static const struct device_type *fsl_mc_get_device_type(const char *type)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int fsl_mc_driver_probe(struct device *dev)
|
||||
{
|
||||
struct fsl_mc_driver *mc_drv;
|
||||
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
|
||||
int error;
|
||||
|
||||
mc_drv = to_fsl_mc_driver(dev->driver);
|
||||
|
||||
error = mc_drv->probe(mc_dev);
|
||||
if (error < 0) {
|
||||
if (error != -EPROBE_DEFER)
|
||||
dev_err(dev, "%s failed: %d\n", __func__, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_mc_driver_remove(struct device *dev)
|
||||
{
|
||||
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
|
||||
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
|
||||
|
||||
mc_drv->remove(mc_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fsl_mc_driver_shutdown(struct device *dev)
|
||||
{
|
||||
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
|
||||
struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
|
||||
|
||||
mc_drv->shutdown(mc_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* __fsl_mc_driver_register - registers a child device driver with the
|
||||
* MC bus
|
||||
|
|
@ -486,15 +486,6 @@ int __fsl_mc_driver_register(struct fsl_mc_driver *mc_driver,
|
|||
mc_driver->driver.owner = owner;
|
||||
mc_driver->driver.bus = &fsl_mc_bus_type;
|
||||
|
||||
if (mc_driver->probe)
|
||||
mc_driver->driver.probe = fsl_mc_driver_probe;
|
||||
|
||||
if (mc_driver->remove)
|
||||
mc_driver->driver.remove = fsl_mc_driver_remove;
|
||||
|
||||
if (mc_driver->shutdown)
|
||||
mc_driver->driver.shutdown = fsl_mc_driver_shutdown;
|
||||
|
||||
error = driver_register(&mc_driver->driver);
|
||||
if (error < 0) {
|
||||
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,
|
|||
return 0;
|
||||
|
||||
error_cleanup_dev:
|
||||
kfree(mc_dev->regions);
|
||||
if (mc_bus)
|
||||
kfree(mc_bus);
|
||||
else
|
||||
kfree(mc_dev);
|
||||
put_device(&mc_dev->dev);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
|
|||
obj-$(CONFIG_UCC_FAST) += ucc_fast.o
|
||||
obj-$(CONFIG_QE_TDM) += qe_tdm.o
|
||||
obj-$(CONFIG_QE_USB) += usb.o
|
||||
obj-$(CONFIG_QE_GPIO) += gpio.o
|
||||
obj-$(CONFIG_QE_GPIO) += gpio.o qe_ports_ic.o
|
||||
|
|
|
|||
141
drivers/soc/fsl/qe/qe_ports_ic.c
Normal file
141
drivers/soc/fsl/qe/qe_ports_ic.c
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* QUICC ENGINE I/O Ports Interrupt Controller
|
||||
*
|
||||
* Copyright (c) 2025 Christophe Leroy CS GROUP France (christophe.leroy@csgroup.eu)
|
||||
*/
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* QE IC registers offset */
|
||||
#define CEPIER 0x0c
|
||||
#define CEPIMR 0x10
|
||||
#define CEPICR 0x14
|
||||
|
||||
struct qepic_data {
|
||||
void __iomem *reg;
|
||||
struct irq_domain *host;
|
||||
};
|
||||
|
||||
static void qepic_mask(struct irq_data *d)
|
||||
{
|
||||
struct qepic_data *data = irq_data_get_irq_chip_data(d);
|
||||
|
||||
clrbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void qepic_unmask(struct irq_data *d)
|
||||
{
|
||||
struct qepic_data *data = irq_data_get_irq_chip_data(d);
|
||||
|
||||
setbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void qepic_end(struct irq_data *d)
|
||||
{
|
||||
struct qepic_data *data = irq_data_get_irq_chip_data(d);
|
||||
|
||||
out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static int qepic_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
{
|
||||
struct qepic_data *data = irq_data_get_irq_chip_data(d);
|
||||
unsigned int vec = (unsigned int)irqd_to_hwirq(d);
|
||||
|
||||
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
setbits32(data->reg + CEPICR, 1 << (31 - vec));
|
||||
return 0;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
case IRQ_TYPE_NONE:
|
||||
clrbits32(data->reg + CEPICR, 1 << (31 - vec));
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct irq_chip qepic = {
|
||||
.name = "QEPIC",
|
||||
.irq_mask = qepic_mask,
|
||||
.irq_unmask = qepic_unmask,
|
||||
.irq_eoi = qepic_end,
|
||||
.irq_set_type = qepic_set_type,
|
||||
};
|
||||
|
||||
static int qepic_get_irq(struct irq_desc *desc)
|
||||
{
|
||||
struct qepic_data *data = irq_desc_get_handler_data(desc);
|
||||
u32 event = in_be32(data->reg + CEPIER);
|
||||
|
||||
if (!event)
|
||||
return -1;
|
||||
|
||||
return irq_find_mapping(data->host, 32 - ffs(event));
|
||||
}
|
||||
|
||||
static void qepic_cascade(struct irq_desc *desc)
|
||||
{
|
||||
generic_handle_irq(qepic_get_irq(desc));
|
||||
}
|
||||
|
||||
static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
|
||||
{
|
||||
irq_set_chip_data(virq, h->host_data);
|
||||
irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops qepic_host_ops = {
|
||||
.map = qepic_host_map,
|
||||
};
|
||||
|
||||
static int qepic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct qepic_data *data;
|
||||
int irq;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->reg = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(data->reg))
|
||||
return PTR_ERR(data->reg);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
data->host = irq_domain_add_linear(dev->of_node, 32, &qepic_host_ops, data);
|
||||
if (!data->host)
|
||||
return -ENODEV;
|
||||
|
||||
irq_set_chained_handler_and_data(irq, qepic_cascade, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id qepic_match[] = {
|
||||
{
|
||||
.compatible = "fsl,mpc8323-qe-ports-ic",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver qepic_driver = {
|
||||
.driver = {
|
||||
.name = "qe_ports_ic",
|
||||
.of_match_table = qepic_match,
|
||||
},
|
||||
.probe = qepic_probe,
|
||||
};
|
||||
|
||||
static int __init qepic_init(void)
|
||||
{
|
||||
return platform_driver_register(&qepic_driver);
|
||||
}
|
||||
arch_initcall(qepic_init);
|
||||
|
|
@ -1284,31 +1284,26 @@ static unsigned int qmc_nb_chans(struct qmc *qmc)
|
|||
|
||||
static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
|
||||
{
|
||||
struct device_node *chan_np;
|
||||
struct qmc_chan *chan;
|
||||
const char *mode;
|
||||
u32 chan_id;
|
||||
u64 ts_mask;
|
||||
int ret;
|
||||
|
||||
for_each_available_child_of_node(np, chan_np) {
|
||||
for_each_available_child_of_node_scoped(np, chan_np) {
|
||||
ret = of_property_read_u32(chan_np, "reg", &chan_id);
|
||||
if (ret) {
|
||||
dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np);
|
||||
of_node_put(chan_np);
|
||||
return ret;
|
||||
}
|
||||
if (chan_id > 63) {
|
||||
dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np);
|
||||
of_node_put(chan_np);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL);
|
||||
if (!chan) {
|
||||
of_node_put(chan_np);
|
||||
if (!chan)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chan->id = chan_id;
|
||||
spin_lock_init(&chan->ts_lock);
|
||||
|
|
@ -1319,7 +1314,6 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
|
|||
if (ret) {
|
||||
dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n",
|
||||
chan_np);
|
||||
of_node_put(chan_np);
|
||||
return ret;
|
||||
}
|
||||
chan->tx_ts_mask_avail = ts_mask;
|
||||
|
|
@ -1329,7 +1323,6 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
|
|||
if (ret) {
|
||||
dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n",
|
||||
chan_np);
|
||||
of_node_put(chan_np);
|
||||
return ret;
|
||||
}
|
||||
chan->rx_ts_mask_avail = ts_mask;
|
||||
|
|
@ -1340,7 +1333,6 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
|
|||
if (ret && ret != -EINVAL) {
|
||||
dev_err(qmc->dev, "%pOF: failed to read fsl,operational-mode\n",
|
||||
chan_np);
|
||||
of_node_put(chan_np);
|
||||
return ret;
|
||||
}
|
||||
if (!strcmp(mode, "transparent")) {
|
||||
|
|
@ -1350,7 +1342,6 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
|
|||
} else {
|
||||
dev_err(qmc->dev, "%pOF: Invalid fsl,operational-mode (%s)\n",
|
||||
chan_np, mode);
|
||||
of_node_put(chan_np);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue