2019-04-30 10:15:31

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 00/14] Add support for TISCI Interrupt controller drivers

TI AM65x SoC based on K3 architecture introduced support for Events
which are message based interrupts with minimal latency. These events
are not compatible with regular interrupts and are valid only through
an event transport lane. An Interrupt Aggregator(INTA) is introduced
to convert these events to interrupts. INTA can also group 64 events
into a single interrupt. Now the SoC has many peripherals and a large
number of event sources (time sync or DMA), the use of events is
completely dependent on a user's specific application, which drives a
need for maximum flexibility in which event sources are used in the
system. It is also completely up to software control as to how the
events are serviced.

Because of the huge flexibility there are certain standard peripherals
(like GPIO etc)where all interrupts cannot be directly corrected to host
interrupt controller. For this purpose, Interrupt Router(INTR) is
introduced in the SoC. INTR just does a classic interrupt redirection.

So the SoC has 3 types of interrupt controllers:
- GIC500
- Interrupt Router
- Interrupt Aggregator

Below is a diagrammatic view of how SoC integration of these interrupt
controllers:(https://pastebin.ubuntu.com/p/9ngV3jdGj2/)

Device Index-x Device Index-y
| |
| |
....
\ /
\ /
\ (global events) /
+---------------------------+ +---------+
| | | |
| INTA | | GPIO |
| | | |
+---------------------------+ +---------+
| (vint) |
| |
\|/ |
+---------------------------+ |
| |<-------+
| INTR |
| |
+---------------------------+
|
|
\|/ (gic irq)
+---------------------------+
| |
| GIC |
| |
+---------------------------+

While at it, TISCI abstracts the handling of all above IRQ routes where
interrupt sources are not directly connected to host interrupt controller.
That would be configuration of Interrupt Aggregator and Interrupt Router.

This series adds support for:
- TISCI commands needed for IRQ configuration
- Interrupt Router(INTR) driver.
- Interrupt Aggregator(INTA) driver.
- Interrupt Aggregator MSI bus layer.

Marc,
As discussed offline, the firmware changes are going to come within
a day or so. These changes are tested against local binary which is
bound to release.

Boot Log: https://pastebin.ubuntu.com/p/YwprMKXdg4/

Changes since v7:
- Rebased on top of latest master.
- Each patch has respective changes mentioned.

Grygorii Strashko (1):
firmware: ti_sci: Add support to get TISCI handle using of_phandle

Lokesh Vutla (12):
firmware: ti_sci: Add support for RM core ops
firmware: ti_sci: Add support for IRQ management
firmware: ti_sci: Add helper apis to manage resources
genirq: Introduce irq_chip_{request,release}_resource_parent() apis
gpio: thunderx: Use the default parent apis for
{request,release}_resources
dt-bindings: irqchip: Introduce TISCI Interrupt router bindings
irqchip: ti-sci-intr: Add support for Interrupt Router driver
dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings
irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
soc: ti: Add MSI domain bus support for Interrupt Aggregator
irqchip: ti-sci-inta: Add msi domain support
arm64: arch_k3: Enable interrupt controller drivers

Peter Ujfalusi (1):
firmware: ti_sci: Add RM mapping table for am654

.../bindings/arm/keystone/ti,sci.txt | 3 +-
.../interrupt-controller/ti,sci-inta.txt | 66 ++
.../interrupt-controller/ti,sci-intr.txt | 82 +++
MAINTAINERS | 6 +
arch/arm64/Kconfig.platforms | 5 +
drivers/firmware/ti_sci.c | 651 ++++++++++++++++++
drivers/firmware/ti_sci.h | 102 +++
drivers/gpio/gpio-thunderx.c | 16 +-
drivers/irqchip/Kconfig | 23 +
drivers/irqchip/Makefile | 2 +
drivers/irqchip/irq-ti-sci-inta.c | 615 +++++++++++++++++
drivers/irqchip/irq-ti-sci-intr.c | 275 ++++++++
drivers/soc/ti/Kconfig | 6 +
drivers/soc/ti/Makefile | 1 +
drivers/soc/ti/ti_sci_inta_msi.c | 146 ++++
include/linux/irq.h | 2 +
include/linux/irqdomain.h | 1 +
include/linux/msi.h | 10 +
include/linux/soc/ti/ti_sci_inta_msi.h | 23 +
include/linux/soc/ti/ti_sci_protocol.h | 124 ++++
kernel/irq/chip.c | 27 +
21 files changed, 2173 insertions(+), 13 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
create mode 100644 drivers/irqchip/irq-ti-sci-inta.c
create mode 100644 drivers/irqchip/irq-ti-sci-intr.c
create mode 100644 drivers/soc/ti/ti_sci_inta_msi.c
create mode 100644 include/linux/soc/ti/ti_sci_inta_msi.h

--
2.21.0


2019-04-30 10:15:38

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 09/14] irqchip: ti-sci-intr: Add support for Interrupt Router driver

Texas Instruments' K3 generation SoCs has an IP Interrupt Router
that does allows for redirection of input interrupts to host
interrupt controller. Interrupt Router inputs are either from a
peripheral or from an Interrupt Aggregator which is another
interrupt controller.

Configuration of the interrupt router registers can only be done by
a system co-processor and the driver needs to send a message to this
co processor over TISCI protocol.

Add support for Interrupt Router driver over TISCI protocol.

Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
- Adapted driver to interrupt cells 2.

MAINTAINERS | 1 +
drivers/irqchip/Kconfig | 11 ++
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-ti-sci-intr.c | 275 ++++++++++++++++++++++++++++++
4 files changed, 288 insertions(+)
create mode 100644 drivers/irqchip/irq-ti-sci-intr.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 91b4dcfb47f4..b54a01a70f44 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15351,6 +15351,7 @@ F: Documentation/devicetree/bindings/clock/ti,sci-clk.txt
F: drivers/clk/keystone/sci-clk.c
F: drivers/reset/reset-ti-sci.c
F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
+F: drivers/irqchip/irq-ti-sci-intr.c

Texas Instruments ASoC drivers
M: Peter Ujfalusi <[email protected]>
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 5438abb1baba..4f84e7902626 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -425,6 +425,17 @@ config LS1X_IRQ
help
Support for the Loongson-1 platform Interrupt Controller.

+config TI_SCI_INTR_IRQCHIP
+ bool
+ depends on TI_SCI_PROTOCOL
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ This enables the irqchip driver support for K3 Interrupt router
+ over TI System Control Interface available on some new TI's SoCs.
+ If you wish to use interrupt router irq resources managed by the
+ TI System Controller, say Y here. Otherwise, say N.
+
endmenu

config SIFIVE_PLIC
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 85972ae1bd7f..fa5c865788b5 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -97,3 +97,4 @@ obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o
obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
+obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c
new file mode 100644
index 000000000000..59d51a20bbd8
--- /dev/null
+++ b/drivers/irqchip/irq-ti-sci-intr.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments' K3 Interrupt Router irqchip driver
+ *
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Lokesh Vutla <[email protected]>
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+#define TI_SCI_DEV_ID_MASK 0xffff
+#define TI_SCI_DEV_ID_SHIFT 16
+#define TI_SCI_IRQ_ID_MASK 0xffff
+#define TI_SCI_IRQ_ID_SHIFT 0
+#define HWIRQ_TO_DEVID(hwirq) (((hwirq) >> (TI_SCI_DEV_ID_SHIFT)) & \
+ (TI_SCI_DEV_ID_MASK))
+#define HWIRQ_TO_IRQID(hwirq) ((hwirq) & (TI_SCI_IRQ_ID_MASK))
+#define TO_HWIRQ(dev, index) ((((dev) & TI_SCI_DEV_ID_MASK) << \
+ TI_SCI_DEV_ID_SHIFT) | \
+ ((index) & TI_SCI_IRQ_ID_MASK))
+
+/**
+ * struct ti_sci_intr_irq_domain - Structure representing a TISCI based
+ * Interrupt Router IRQ domain.
+ * @sci: Pointer to TISCI handle
+ * @dst_irq: TISCI resource pointer representing GIC irq controller.
+ * @dst_id: TISCI device ID of the GIC irq controller.
+ * @type: Specifies the trigger type supported by this Interrupt Router
+ */
+struct ti_sci_intr_irq_domain {
+ const struct ti_sci_handle *sci;
+ struct ti_sci_resource *dst_irq;
+ u32 dst_id;
+ u32 type;
+};
+
+static struct irq_chip ti_sci_intr_irq_chip = {
+ .name = "INTR",
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_set_type = irq_chip_set_type_parent,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+};
+
+/**
+ * ti_sci_intr_irq_domain_translate() - Retrieve hwirq and type from
+ * IRQ firmware specific handler.
+ * @domain: Pointer to IRQ domain
+ * @fwspec: Pointer to IRQ specific firmware structure
+ * @hwirq: IRQ number identified by hardware
+ * @type: IRQ type
+ *
+ * Return 0 if all went ok else appropriate error.
+ */
+static int ti_sci_intr_irq_domain_translate(struct irq_domain *domain,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ struct ti_sci_intr_irq_domain *intr = domain->host_data;
+
+ if (fwspec->param_count != 2)
+ return -EINVAL;
+
+ *hwirq = TO_HWIRQ(fwspec->param[0], fwspec->param[1]);
+ *type = intr->type;
+
+ return 0;
+}
+
+/**
+ * ti_sci_intr_irq_domain_free() - Free the specified IRQs from the domain.
+ * @domain: Domain to which the irqs belong
+ * @virq: Linux virtual IRQ to be freed.
+ * @nr_irqs: Number of continuous irqs to be freed
+ */
+static void ti_sci_intr_irq_domain_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ struct ti_sci_intr_irq_domain *intr = domain->host_data;
+ struct irq_data *data, *parent_data;
+ u16 dev_id, irq_index;
+
+ parent_data = irq_domain_get_irq_data(domain->parent, virq);
+ data = irq_domain_get_irq_data(domain, virq);
+ irq_index = HWIRQ_TO_IRQID(data->hwirq);
+ dev_id = HWIRQ_TO_DEVID(data->hwirq);
+
+ intr->sci->ops.rm_irq_ops.free_irq(intr->sci, dev_id, irq_index,
+ intr->dst_id, parent_data->hwirq);
+ ti_sci_release_resource(intr->dst_irq, parent_data->hwirq);
+ irq_domain_free_irqs_parent(domain, virq, 1);
+ irq_domain_reset_irq_data(data);
+}
+
+/**
+ * ti_sci_intr_alloc_gic_irq() - Allocate GIC specific IRQ
+ * @domain: Pointer to the interrupt router IRQ domain
+ * @virq: Corresponding Linux virtual IRQ number
+ * @hwirq: Corresponding hwirq for the IRQ within this IRQ domain
+ *
+ * Returns 0 if all went well else appropriate error pointer.
+ */
+static int ti_sci_intr_alloc_gic_irq(struct irq_domain *domain,
+ unsigned int virq, u32 hwirq)
+{
+ struct ti_sci_intr_irq_domain *intr = domain->host_data;
+ struct irq_fwspec fwspec;
+ u16 dev_id, irq_index;
+ u16 dst_irq;
+ int err;
+
+ dev_id = HWIRQ_TO_DEVID(hwirq);
+ irq_index = HWIRQ_TO_IRQID(hwirq);
+
+ dst_irq = ti_sci_get_free_resource(intr->dst_irq);
+ if (dst_irq == TI_SCI_RESOURCE_NULL)
+ return -EINVAL;
+
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 3;
+ fwspec.param[0] = 0; /* SPI */
+ fwspec.param[1] = dst_irq - 32; /* SPI offset */
+ fwspec.param[2] = intr->type;
+
+ err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
+ if (err)
+ goto err_irqs;
+
+ err = intr->sci->ops.rm_irq_ops.set_irq(intr->sci, dev_id, irq_index,
+ intr->dst_id, dst_irq);
+ if (err)
+ goto err_msg;
+
+ return 0;
+
+err_msg:
+ irq_domain_free_irqs_parent(domain, virq, 1);
+err_irqs:
+ ti_sci_release_resource(intr->dst_irq, dst_irq);
+ return err;
+}
+
+/**
+ * ti_sci_intr_irq_domain_alloc() - Allocate Interrupt router IRQs
+ * @domain: Point to the interrupt router IRQ domain
+ * @virq: Corresponding Linux virtual IRQ number
+ * @nr_irqs: Continuous irqs to be allocated
+ * @data: Pointer to firmware specifier
+ *
+ * Return 0 if all went well else appropriate error value.
+ */
+static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs,
+ void *data)
+{
+ struct irq_fwspec *fwspec = data;
+ unsigned long hwirq;
+ unsigned int flags;
+ int err;
+
+ err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags);
+ if (err)
+ return err;
+
+ err = ti_sci_intr_alloc_gic_irq(domain, virq, hwirq);
+ if (err)
+ return err;
+
+ irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+ &ti_sci_intr_irq_chip, NULL);
+
+ return 0;
+}
+
+static const struct irq_domain_ops ti_sci_intr_irq_domain_ops = {
+ .free = ti_sci_intr_irq_domain_free,
+ .alloc = ti_sci_intr_irq_domain_alloc,
+ .translate = ti_sci_intr_irq_domain_translate,
+};
+
+static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
+{
+ struct irq_domain *parent_domain, *domain;
+ struct ti_sci_intr_irq_domain *intr;
+ struct device_node *parent_node;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ parent_node = of_irq_find_parent(dev_of_node(dev));
+ if (!parent_node) {
+ dev_err(dev, "Failed to get IRQ parent node\n");
+ return -ENODEV;
+ }
+
+ parent_domain = irq_find_host(parent_node);
+ if (!parent_domain) {
+ dev_err(dev, "Failed to find IRQ parent domain\n");
+ return -ENODEV;
+ }
+
+ intr = devm_kzalloc(dev, sizeof(*intr), GFP_KERNEL);
+ if (!intr)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(dev_of_node(dev), "ti,intr-trigger-type",
+ &intr->type);
+ if (ret) {
+ dev_err(dev, "missing ti,intr-trigger-type property\n");
+ return -EINVAL;
+ }
+
+ intr->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
+ if (IS_ERR(intr->sci)) {
+ ret = PTR_ERR(intr->sci);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "ti,sci read fail %d\n", ret);
+ intr->sci = NULL;
+ return ret;
+ }
+
+ ret = of_property_read_u32(dev_of_node(dev), "ti,sci-dst-id",
+ &intr->dst_id);
+ if (ret) {
+ dev_err(dev, "missing 'ti,sci-dst-id' property\n");
+ return -EINVAL;
+ }
+
+ intr->dst_irq = devm_ti_sci_get_of_resource(intr->sci, dev,
+ intr->dst_id,
+ "ti,sci-rm-range-girq");
+ if (IS_ERR(intr->dst_irq)) {
+ dev_err(dev, "Destination irq resource allocation failed\n");
+ return PTR_ERR(intr->dst_irq);
+ }
+
+ domain = irq_domain_add_hierarchy(parent_domain, 0, 0, dev_of_node(dev),
+ &ti_sci_intr_irq_domain_ops, intr);
+ if (!domain) {
+ dev_err(dev, "Failed to allocate IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id ti_sci_intr_irq_domain_of_match[] = {
+ { .compatible = "ti,sci-intr", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ti_sci_intr_irq_domain_of_match);
+
+static struct platform_driver ti_sci_intr_irq_domain_driver = {
+ .probe = ti_sci_intr_irq_domain_probe,
+ .driver = {
+ .name = "ti-sci-intr",
+ .of_match_table = ti_sci_intr_irq_domain_of_match,
+ },
+};
+module_platform_driver(ti_sci_intr_irq_domain_driver);
+
+MODULE_AUTHOR("Lokesh Vutla <lokeshvutla@ticom>");
+MODULE_DESCRIPTION("K3 Interrupt Router driver over TI SCI protocol");
+MODULE_LICENSE("GPL v2");
--
2.21.0

2019-04-30 10:15:41

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 10/14] dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings

Add the DT binding documentation for Interrupt Aggregator driver.

Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
- None
.../interrupt-controller/ti,sci-inta.txt | 66 +++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 67 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt

diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
new file mode 100644
index 000000000000..7841cb099e13
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
@@ -0,0 +1,66 @@
+Texas Instruments K3 Interrupt Aggregator
+=========================================
+
+The Interrupt Aggregator (INTA) provides a centralized machine
+which handles the termination of system events to that they can
+be coherently processed by the host(s) in the system. A maximum
+of 64 events can be mapped to a single interrupt.
+
+
+ Interrupt Aggregator
+ +-----------------------------------------+
+ | Intmap VINT |
+ | +--------------+ +------------+ |
+ m ------>| | vint | bit | | 0 |.....|63| vint0 |
+ . | +--------------+ +------------+ | +------+
+ . | . . | | HOST |
+Globalevents ------>| . . |------>| IRQ |
+ . | . . | | CTRL |
+ . | . . | +------+
+ n ------>| +--------------+ +------------+ |
+ | | vint | bit | | 0 |.....|63| vintx |
+ | +--------------+ +------------+ |
+ | |
+ +-----------------------------------------+
+
+Configuration of these Intmap registers that maps global events to vint is done
+by a system controller (like the Device Memory and Security Controller on K3
+AM654 SoC). Driver should request the system controller to get the range
+of global events and vints assigned to the requesting host. Management
+of these requested resources should be handled by driver and requests
+system controller to map specific global event to vint, bit pair.
+
+Communication between the host processor running an OS and the system
+controller happens through a protocol called TI System Control Interface
+(TISCI protocol). For more details refer:
+Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
+
+TISCI Interrupt Aggregator Node:
+-------------------------------
+- compatible: Must be "ti,sci-inta".
+- reg: Should contain registers location and length.
+- interrupt-controller: Identifies the node as an interrupt controller
+- msi-controller: Identifies the node as an MSI controller.
+- interrupt-parent: phandle of irq parent.
+- ti,sci: Phandle to TI-SCI compatible System controller node.
+- ti,sci-dev-id: TISCI device ID of the Interrupt Aggregator.
+- ti,sci-rm-range-vint: Array of TISCI subtype ids representing vints(inta
+ outputs) range within this INTA, assigned to the
+ requesting host context.
+- ti,sci-rm-range-global-event: Array of TISCI subtype ids representing the
+ global events range reaching this IA and are assigned
+ to the requesting host context.
+
+Example:
+--------
+main_udmass_inta: interrupt-controller@33d00000 {
+ compatible = "ti,sci-inta";
+ reg = <0x0 0x33d00000 0x0 0x100000>;
+ interrupt-controller;
+ msi-controller;
+ interrupt-parent = <&main_navss_intr>;
+ ti,sci = <&dmsc>;
+ ti,sci-dev-id = <179>;
+ ti,sci-rm-range-vint = <0x0>;
+ ti,sci-rm-range-global-event = <0x1>;
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index b54a01a70f44..bac5c926a6ed 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15351,6 +15351,7 @@ F: Documentation/devicetree/bindings/clock/ti,sci-clk.txt
F: drivers/clk/keystone/sci-clk.c
F: drivers/reset/reset-ti-sci.c
F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
+F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
F: drivers/irqchip/irq-ti-sci-intr.c

Texas Instruments ASoC drivers
--
2.21.0

2019-04-30 10:15:59

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 05/14] firmware: ti_sci: Add helper apis to manage resources

Each resource with in the device can be uniquely identified as defined
by TISCI. Since this is generic across the devices, resource allocation
also can be made generic instead of each client driver handling the
resource. So add helper apis to manage the resource.

Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
-None

drivers/firmware/ti_sci.c | 130 +++++++++++++++++++++++++
include/linux/soc/ti/ti_sci_protocol.h | 54 ++++++++++
2 files changed, 184 insertions(+)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 551895535767..ef93406ace1b 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -2262,6 +2262,136 @@ const struct ti_sci_handle *devm_ti_sci_get_by_phandle(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_ti_sci_get_by_phandle);

+/**
+ * ti_sci_get_free_resource() - Get a free resource from TISCI resource.
+ * @res: Pointer to the TISCI resource
+ *
+ * Return: resource num if all went ok else TI_SCI_RESOURCE_NULL.
+ */
+u16 ti_sci_get_free_resource(struct ti_sci_resource *res)
+{
+ unsigned long flags;
+ u16 set, free_bit;
+
+ raw_spin_lock_irqsave(&res->lock, flags);
+ for (set = 0; set < res->sets; set++) {
+ free_bit = find_first_zero_bit(res->desc[set].res_map,
+ res->desc[set].num);
+ if (free_bit != res->desc[set].num) {
+ set_bit(free_bit, res->desc[set].res_map);
+ raw_spin_unlock_irqrestore(&res->lock, flags);
+ return res->desc[set].start + free_bit;
+ }
+ }
+ raw_spin_unlock_irqrestore(&res->lock, flags);
+
+ return TI_SCI_RESOURCE_NULL;
+}
+EXPORT_SYMBOL_GPL(ti_sci_get_free_resource);
+
+/**
+ * ti_sci_release_resource() - Release a resource from TISCI resource.
+ * @res: Pointer to the TISCI resource
+ * @id: Resource id to be released.
+ */
+void ti_sci_release_resource(struct ti_sci_resource *res, u16 id)
+{
+ unsigned long flags;
+ u16 set;
+
+ raw_spin_lock_irqsave(&res->lock, flags);
+ for (set = 0; set < res->sets; set++) {
+ if (res->desc[set].start <= id &&
+ (res->desc[set].num + res->desc[set].start) > id)
+ clear_bit(id - res->desc[set].start,
+ res->desc[set].res_map);
+ }
+ raw_spin_unlock_irqrestore(&res->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ti_sci_release_resource);
+
+/**
+ * ti_sci_get_num_resources() - Get the number of resources in TISCI resource
+ * @res: Pointer to the TISCI resource
+ *
+ * Return: Total number of available resources.
+ */
+u32 ti_sci_get_num_resources(struct ti_sci_resource *res)
+{
+ u32 set, count = 0;
+
+ for (set = 0; set < res->sets; set++)
+ count += res->desc[set].num;
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(ti_sci_get_num_resources);
+
+/**
+ * devm_ti_sci_get_of_resource() - Get a TISCI resource assigned to a device
+ * @handle: TISCI handle
+ * @dev: Device pointer to which the resource is assigned
+ * @dev_id: TISCI device id to which the resource is assigned
+ * @of_prop: property name by which the resource are represented
+ *
+ * Return: Pointer to ti_sci_resource if all went well else appropriate
+ * error pointer.
+ */
+struct ti_sci_resource *
+devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
+ struct device *dev, u32 dev_id, char *of_prop)
+{
+ struct ti_sci_resource *res;
+ u32 resource_subtype;
+ int i, ret;
+
+ res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+ if (!res)
+ return ERR_PTR(-ENOMEM);
+
+ res->sets = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
+ sizeof(u32));
+ if (res->sets < 0) {
+ dev_err(dev, "%s resource type ids not available\n", of_prop);
+ return ERR_PTR(res->sets);
+ }
+
+ res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
+ GFP_KERNEL);
+ if (!res->desc)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < res->sets; i++) {
+ ret = of_property_read_u32_index(dev_of_node(dev), of_prop, i,
+ &resource_subtype);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
+ ret = handle->ops.rm_core_ops.get_range(handle, dev_id,
+ resource_subtype,
+ &res->desc[i].start,
+ &res->desc[i].num);
+ if (ret) {
+ dev_err(dev, "dev = %d subtype %d not allocated for this host\n",
+ dev_id, resource_subtype);
+ return ERR_PTR(ret);
+ }
+
+ dev_dbg(dev, "dev = %d, subtype = %d, start = %d, num = %d\n",
+ dev_id, resource_subtype, res->desc[i].start,
+ res->desc[i].num);
+
+ res->desc[i].res_map =
+ devm_kzalloc(dev, BITS_TO_LONGS(res->desc[i].num) *
+ sizeof(*res->desc[i].res_map), GFP_KERNEL);
+ if (!res->desc[i].res_map)
+ return ERR_PTR(-ENOMEM);
+ }
+ raw_spin_lock_init(&res->lock);
+
+ return res;
+}
+
static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
void *cmd)
{
diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h
index d0bc4123232e..568722a041bf 100644
--- a/include/linux/soc/ti/ti_sci_protocol.h
+++ b/include/linux/soc/ti/ti_sci_protocol.h
@@ -266,6 +266,33 @@ struct ti_sci_handle {
struct ti_sci_ops ops;
};

+#define TI_SCI_RESOURCE_NULL 0xffff
+
+/**
+ * struct ti_sci_resource_desc - Description of TI SCI resource instance range.
+ * @start: Start index of the resource.
+ * @num: Number of resources.
+ * @res_map: Bitmap to manage the allocation of these resources.
+ */
+struct ti_sci_resource_desc {
+ u16 start;
+ u16 num;
+ unsigned long *res_map;
+};
+
+/**
+ * struct ti_sci_resource - Structure representing a resource assigned
+ * to a device.
+ * @sets: Number of sets available from this resource type
+ * @lock: Lock to guard the res map in each set.
+ * @desc: Array of resource descriptors.
+ */
+struct ti_sci_resource {
+ u16 sets;
+ raw_spinlock_t lock;
+ struct ti_sci_resource_desc *desc;
+};
+
#if IS_ENABLED(CONFIG_TI_SCI_PROTOCOL)
const struct ti_sci_handle *ti_sci_get_handle(struct device *dev);
int ti_sci_put_handle(const struct ti_sci_handle *handle);
@@ -274,6 +301,12 @@ const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np,
const char *property);
const struct ti_sci_handle *devm_ti_sci_get_by_phandle(struct device *dev,
const char *property);
+u16 ti_sci_get_free_resource(struct ti_sci_resource *res);
+void ti_sci_release_resource(struct ti_sci_resource *res, u16 id);
+u32 ti_sci_get_num_resources(struct ti_sci_resource *res);
+struct ti_sci_resource *
+devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
+ struct device *dev, u32 dev_id, char *of_prop);

#else /* CONFIG_TI_SCI_PROTOCOL */

@@ -306,6 +339,27 @@ const struct ti_sci_handle *devm_ti_sci_get_by_phandle(struct device *dev,
{
return ERR_PTR(-EINVAL);
}
+
+static inline u16 ti_sci_get_free_resource(struct ti_sci_resource *res)
+{
+ return TI_SCI_RESOURCE_NULL;
+}
+
+static inline void ti_sci_release_resource(struct ti_sci_resource *res, u16 id)
+{
+}
+
+static inline u32 ti_sci_get_num_resources(struct ti_sci_resource *res)
+{
+ return 0;
+}
+
+static inline struct ti_sci_resource *
+devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
+ struct device *dev, u32 dev_id, char *of_prop)
+{
+ return ERR_PTR(-EINVAL);
+}
#endif /* CONFIG_TI_SCI_PROTOCOL */

#endif /* __TISCI_PROTOCOL_H */
--
2.21.0

2019-04-30 10:16:05

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 01/14] firmware: ti_sci: Add support to get TISCI handle using of_phandle

From: Grygorii Strashko <[email protected]>

TISCI has been updated to have support for Resource management(like
interrupts etc..). And there can be multiple device instances of a
resource type in a SoC. So every driver corresponding to a resource type
should get a TISCI handle so that it can make TISCI calls. And each
DT node corresponding to a device should exist under its corresponding
bus node as per the SoC architecture.

But existing apis in TISCI library assumes that all TISCI users are
child nodes of TISCI. Which is not true in the above case. So introduce
(devm_)ti_sci_get_by_phandle() apis that can be used by TISCI users
to get TISCI handle using of phandle property.

Signed-off-by: Grygorii Strashko <[email protected]>
Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
- None

drivers/firmware/ti_sci.c | 83 ++++++++++++++++++++++++++
include/linux/soc/ti/ti_sci_protocol.h | 17 ++++++
2 files changed, 100 insertions(+)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 3fbbb61012c4..852043531233 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -1764,6 +1764,89 @@ const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev)
}
EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle);

+/**
+ * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle
+ * @np: device node
+ * @property: property name containing phandle on TISCI node
+ *
+ * NOTE: The function does not track individual clients of the framework
+ * and is expected to be maintained by caller of TI SCI protocol library.
+ * ti_sci_put_handle must be balanced with successful ti_sci_get_by_phandle
+ * Return: pointer to handle if successful, else:
+ * -EPROBE_DEFER if the instance is not ready
+ * -ENODEV if the required node handler is missing
+ * -EINVAL if invalid conditions are encountered.
+ */
+const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np,
+ const char *property)
+{
+ struct ti_sci_handle *handle = NULL;
+ struct device_node *ti_sci_np;
+ struct ti_sci_info *info;
+ struct list_head *p;
+
+ if (!np) {
+ pr_err("I need a device pointer\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ ti_sci_np = of_parse_phandle(np, property, 0);
+ if (!ti_sci_np)
+ return ERR_PTR(-ENODEV);
+
+ mutex_lock(&ti_sci_list_mutex);
+ list_for_each(p, &ti_sci_list) {
+ info = list_entry(p, struct ti_sci_info, node);
+ if (ti_sci_np == info->dev->of_node) {
+ handle = &info->handle;
+ info->users++;
+ break;
+ }
+ }
+ mutex_unlock(&ti_sci_list_mutex);
+ of_node_put(ti_sci_np);
+
+ if (!handle)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return handle;
+}
+EXPORT_SYMBOL_GPL(ti_sci_get_by_phandle);
+
+/**
+ * devm_ti_sci_get_by_phandle() - Managed get handle using phandle
+ * @dev: Device pointer requesting TISCI handle
+ * @property: property name containing phandle on TISCI node
+ *
+ * NOTE: This releases the handle once the device resources are
+ * no longer needed. MUST NOT BE released with ti_sci_put_handle.
+ * The function does not track individual clients of the framework
+ * and is expected to be maintained by caller of TI SCI protocol library.
+ *
+ * Return: 0 if all went fine, else corresponding error.
+ */
+const struct ti_sci_handle *devm_ti_sci_get_by_phandle(struct device *dev,
+ const char *property)
+{
+ const struct ti_sci_handle *handle;
+ const struct ti_sci_handle **ptr;
+
+ ptr = devres_alloc(devm_ti_sci_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+ handle = ti_sci_get_by_phandle(dev_of_node(dev), property);
+
+ if (!IS_ERR(handle)) {
+ *ptr = handle;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return handle;
+}
+EXPORT_SYMBOL_GPL(devm_ti_sci_get_by_phandle);
+
static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
void *cmd)
{
diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h
index 18435e5c6364..515587e9d373 100644
--- a/include/linux/soc/ti/ti_sci_protocol.h
+++ b/include/linux/soc/ti/ti_sci_protocol.h
@@ -217,6 +217,10 @@ struct ti_sci_handle {
const struct ti_sci_handle *ti_sci_get_handle(struct device *dev);
int ti_sci_put_handle(const struct ti_sci_handle *handle);
const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev);
+const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np,
+ const char *property);
+const struct ti_sci_handle *devm_ti_sci_get_by_phandle(struct device *dev,
+ const char *property);

#else /* CONFIG_TI_SCI_PROTOCOL */

@@ -236,6 +240,19 @@ const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev)
return ERR_PTR(-EINVAL);
}

+static inline
+const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np,
+ const char *property)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline
+const struct ti_sci_handle *devm_ti_sci_get_by_phandle(struct device *dev,
+ const char *property)
+{
+ return ERR_PTR(-EINVAL);
+}
#endif /* CONFIG_TI_SCI_PROTOCOL */

#endif /* __TISCI_PROTOCOL_H */
--
2.21.0

2019-04-30 10:16:11

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 12/14] soc: ti: Add MSI domain bus support for Interrupt Aggregator

With the system coprocessor managing the range allocation of the
inputs to Interrupt Aggregator, it is difficult to represent
the device IRQs from DT.

The suggestion is to use MSI in such cases where devices wants
to allocate and group interrupts dynamically.

Create a MSI domain bus layer that allocates and frees MSIs for
a device.

APIs that are implemented:
- ti_sci_inta_msi_create_irq_domain() that creates a MSI domain
- ti_sci_inta_msi_domain_alloc_irqs() that creates MSIs for the
specified device and resource.
- ti_sci_inta_msi_domain_free_irqs() frees the irqs attached to the device.
- ti_sci_inta_msi_get_virq() for getting the virq attached to a specific event.

Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
- None

MAINTAINERS | 2 +
drivers/soc/ti/Kconfig | 6 +
drivers/soc/ti/Makefile | 1 +
drivers/soc/ti/ti_sci_inta_msi.c | 146 +++++++++++++++++++++++++
include/linux/irqdomain.h | 1 +
include/linux/msi.h | 10 ++
include/linux/soc/ti/ti_sci_inta_msi.h | 23 ++++
7 files changed, 189 insertions(+)
create mode 100644 drivers/soc/ti/ti_sci_inta_msi.c
create mode 100644 include/linux/soc/ti/ti_sci_inta_msi.h

diff --git a/MAINTAINERS b/MAINTAINERS
index fff8e1589f07..469e3eb4a958 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15354,6 +15354,8 @@ F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
F: drivers/irqchip/irq-ti-sci-intr.c
F: drivers/irqchip/irq-ti-sci-inta.c
+F: include/linux/soc/ti/ti_sci_inta_msi.h
+F: drivers/soc/ti/ti_sci_inta_msi.c

Texas Instruments ASoC drivers
M: Peter Ujfalusi <[email protected]>
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index be4570baad96..82f110fe4953 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -73,4 +73,10 @@ config TI_SCI_PM_DOMAINS
called ti_sci_pm_domains. Note this is needed early in boot before
rootfs may be available.

+config TI_SCI_INTA_MSI_DOMAIN
+ bool
+ select GENERIC_MSI_IRQ_DOMAIN
+ help
+ Driver to enable Interrupt Aggregator specific MSI Domain.
+
endif # SOC_TI
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index a22edc0b258a..b3868d392d4f 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o
obj-$(CONFIG_AMX3_PM) += pm33xx.o
obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o
obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
+obj-$(CONFIG_TI_SCI_INTA_MSI_DOMAIN) += ti_sci_inta_msi.o
diff --git a/drivers/soc/ti/ti_sci_inta_msi.c b/drivers/soc/ti/ti_sci_inta_msi.c
new file mode 100644
index 000000000000..0eb9462f609e
--- /dev/null
+++ b/drivers/soc/ti/ti_sci_inta_msi.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments' K3 Interrupt Aggregator MSI bus
+ *
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Lokesh Vutla <[email protected]>
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/soc/ti/ti_sci_inta_msi.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+static void ti_sci_inta_msi_write_msg(struct irq_data *data,
+ struct msi_msg *msg)
+{
+ /* Nothing to do */
+}
+
+static void ti_sci_inta_msi_compose_msi_msg(struct irq_data *data,
+ struct msi_msg *msg)
+{
+ /* Nothing to do */
+}
+
+static void ti_sci_inta_msi_update_chip_ops(struct msi_domain_info *info)
+{
+ struct irq_chip *chip = info->chip;
+
+ if (WARN_ON(!chip))
+ return;
+
+ chip->irq_request_resources = irq_chip_request_resources_parent;
+ chip->irq_release_resources = irq_chip_release_resources_parent;
+ chip->irq_compose_msi_msg = ti_sci_inta_msi_compose_msi_msg;
+ chip->irq_write_msi_msg = ti_sci_inta_msi_write_msg;
+ chip->irq_set_type = irq_chip_set_type_parent;
+ chip->irq_unmask = irq_chip_unmask_parent;
+ chip->irq_mask = irq_chip_mask_parent;
+ chip->irq_ack = irq_chip_ack_parent;
+}
+
+struct irq_domain *ti_sci_inta_msi_create_irq_domain(struct fwnode_handle *fwnode,
+ struct msi_domain_info *info,
+ struct irq_domain *parent)
+{
+ struct irq_domain *domain;
+
+ ti_sci_inta_msi_update_chip_ops(info);
+
+ domain = msi_create_irq_domain(fwnode, info, parent);
+ if (domain)
+ irq_domain_update_bus_token(domain, DOMAIN_BUS_TI_SCI_INTA_MSI);
+
+ return domain;
+}
+EXPORT_SYMBOL_GPL(ti_sci_inta_msi_create_irq_domain);
+
+static void ti_sci_inta_msi_free_descs(struct device *dev)
+{
+ struct msi_desc *desc, *tmp;
+
+ list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) {
+ list_del(&desc->list);
+ free_msi_entry(desc);
+ }
+}
+
+static int ti_sci_inta_msi_alloc_descs(struct device *dev,
+ struct ti_sci_resource *res)
+{
+ struct msi_desc *msi_desc;
+ int set, i, count = 0;
+
+ for (set = 0; set < res->sets; set++) {
+ for (i = 0; i < res->desc[set].num; i++) {
+ msi_desc = alloc_msi_entry(dev, 1, NULL);
+ if (!msi_desc) {
+ ti_sci_inta_msi_free_descs(dev);
+ return -ENOMEM;
+ }
+
+ msi_desc->inta.dev_index = res->desc[set].start + i;
+ INIT_LIST_HEAD(&msi_desc->list);
+ list_add_tail(&msi_desc->list, dev_to_msi_list(dev));
+ count++;
+ }
+ }
+
+ return count;
+}
+
+int ti_sci_inta_msi_domain_alloc_irqs(struct device *dev,
+ struct ti_sci_resource *res)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct irq_domain *msi_domain;
+ int ret, nvec;
+
+ msi_domain = dev_get_msi_domain(dev);
+ if (!msi_domain)
+ return -EINVAL;
+
+ if (pdev->id < 0)
+ return -ENODEV;
+
+ nvec = ti_sci_inta_msi_alloc_descs(dev, res);
+ if (nvec <= 0)
+ return nvec;
+
+ ret = msi_domain_alloc_irqs(msi_domain, dev, nvec);
+ if (ret) {
+ dev_err(dev, "Failed to allocate IRQs %d\n", ret);
+ goto cleanup;
+ }
+
+ return 0;
+
+cleanup:
+ ti_sci_inta_msi_free_descs(&pdev->dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ti_sci_inta_msi_domain_alloc_irqs);
+
+void ti_sci_inta_msi_domain_free_irqs(struct device *dev)
+{
+ msi_domain_free_irqs(dev->msi_domain, dev);
+ ti_sci_inta_msi_free_descs(dev);
+}
+EXPORT_SYMBOL_GPL(ti_sci_inta_msi_domain_free_irqs);
+
+unsigned int ti_sci_inta_msi_get_virq(struct device *dev, u32 dev_index)
+{
+ struct msi_desc *desc;
+
+ for_each_msi_entry(desc, dev)
+ if (desc->inta.dev_index == dev_index)
+ return desc->irq;
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(ti_sci_inta_msi_get_virq);
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 61706b430907..07ec8b390161 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -82,6 +82,7 @@ enum irq_domain_bus_token {
DOMAIN_BUS_NEXUS,
DOMAIN_BUS_IPI,
DOMAIN_BUS_FSL_MC_MSI,
+ DOMAIN_BUS_TI_SCI_INTA_MSI,
};

/**
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 7e9b81c3b50d..7c28762851a3 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -47,6 +47,14 @@ struct fsl_mc_msi_desc {
u16 msi_index;
};

+/**
+ * ti_sci_inta_msi_desc - TISCI based INTA specific msi descriptor data
+ * @dev_index: TISCI device index
+ */
+struct ti_sci_inta_msi_desc {
+ u16 dev_index;
+};
+
/**
* struct msi_desc - Descriptor structure for MSI based interrupts
* @list: List head for management
@@ -68,6 +76,7 @@ struct fsl_mc_msi_desc {
* @mask_base: [PCI MSI-X] Mask register base address
* @platform: [platform] Platform device specific msi descriptor data
* @fsl_mc: [fsl-mc] FSL MC device specific msi descriptor data
+ * @inta: [INTA] TISCI based INTA specific msi descriptor data
*/
struct msi_desc {
/* Shared device/bus type independent data */
@@ -106,6 +115,7 @@ struct msi_desc {
*/
struct platform_msi_desc platform;
struct fsl_mc_msi_desc fsl_mc;
+ struct ti_sci_inta_msi_desc inta;
};
};

diff --git a/include/linux/soc/ti/ti_sci_inta_msi.h b/include/linux/soc/ti/ti_sci_inta_msi.h
new file mode 100644
index 000000000000..11fb5048f5f6
--- /dev/null
+++ b/include/linux/soc/ti/ti_sci_inta_msi.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Texas Instruments' K3 TI SCI INTA MSI helper
+ *
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Lokesh Vutla <[email protected]>
+ */
+
+#ifndef __INCLUDE_LINUX_TI_SCI_INTA_MSI_H
+#define __INCLUDE_LINUX_TI_SCI_INTA_MSI_H
+
+#include <linux/msi.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+struct irq_domain
+*ti_sci_inta_msi_create_irq_domain(struct fwnode_handle *fwnode,
+ struct msi_domain_info *info,
+ struct irq_domain *parent);
+int ti_sci_inta_msi_domain_alloc_irqs(struct device *dev,
+ struct ti_sci_resource *res);
+unsigned int ti_sci_inta_msi_get_virq(struct device *dev, u32 index);
+void ti_sci_inta_msi_domain_free_irqs(struct device *dev);
+#endif /* __INCLUDE_LINUX_IRQCHIP_TI_SCI_INTA_H */
--
2.21.0

2019-04-30 10:16:25

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 11/14] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver

Texas Instruments' K3 generation SoCs has an IP Interrupt Aggregator
which is an interrupt controller that does the following:
- Converts events to interrupts that can be understood by
an interrupt router.
- Allows for multiplexing of events to interrupts.

Configuration of the interrupt aggregator registers can only be done by
a system co-processor and the driver needs to send a message to this
co processor over TISCI protocol. This patch adds support for Interrupt
Aggregator irqdomain.

Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
- Update ti_sci_inta_set_type() to handle unsupported trigger types
- Guarded entire allocation and free of irqs with vint_mutex because of the
race condition that can happen while allocation and free.
https://patchwork.kernel.org/patch/10910145/
- Dropped event_mutex
- Update ack_irq to not clear the event if we know down event is expected.

MAINTAINERS | 1 +
drivers/irqchip/Kconfig | 11 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-ti-sci-inta.c | 577 ++++++++++++++++++++++++++++++
4 files changed, 590 insertions(+)
create mode 100644 drivers/irqchip/irq-ti-sci-inta.c

diff --git a/MAINTAINERS b/MAINTAINERS
index bac5c926a6ed..fff8e1589f07 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15353,6 +15353,7 @@ F: drivers/reset/reset-ti-sci.c
F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
F: drivers/irqchip/irq-ti-sci-intr.c
+F: drivers/irqchip/irq-ti-sci-inta.c

Texas Instruments ASoC drivers
M: Peter Ujfalusi <[email protected]>
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4f84e7902626..7c84a71bcd88 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -436,6 +436,17 @@ config TI_SCI_INTR_IRQCHIP
If you wish to use interrupt router irq resources managed by the
TI System Controller, say Y here. Otherwise, say N.

+config TI_SCI_INTA_IRQCHIP
+ bool
+ depends on TI_SCI_PROTOCOL
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ This enables the irqchip driver support for K3 Interrupt aggregator
+ over TI System Control Interface available on some new TI's SoCs.
+ If you wish to use interrupt aggregator irq resources managed by the
+ TI System Controller, say Y here. Otherwise, say N.
+
endmenu

config SIFIVE_PLIC
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index fa5c865788b5..8a33013da953 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -98,3 +98,4 @@ obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
+obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
new file mode 100644
index 000000000000..87e0abe0041f
--- /dev/null
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -0,0 +1,577 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments' K3 Interrupt Aggregator irqchip driver
+ *
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Lokesh Vutla <[email protected]>
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/msi.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include <asm-generic/msi.h>
+
+#define TI_SCI_DEV_ID_MASK 0xffff
+#define TI_SCI_DEV_ID_SHIFT 16
+#define TI_SCI_IRQ_ID_MASK 0xffff
+#define TI_SCI_IRQ_ID_SHIFT 0
+#define HWIRQ_TO_DEVID(hwirq) (((hwirq) >> (TI_SCI_DEV_ID_SHIFT)) & \
+ (TI_SCI_DEV_ID_MASK))
+#define HWIRQ_TO_IRQID(hwirq) ((hwirq) & (TI_SCI_IRQ_ID_MASK))
+
+#define MAX_EVENTS_PER_VINT 64
+#define VINT_ENABLE_SET_OFFSET 0x0
+#define VINT_ENABLE_CLR_OFFSET 0x8
+#define VINT_STATUS_OFFSET 0x18
+
+/**
+ * struct ti_sci_inta_event_desc - Description of an event coming to
+ * Interrupt Aggregator. This serves
+ * as a mapping table for global event,
+ * hwirq and vint bit.
+ * @global_event: Global event number corresponding to this event
+ * @hwirq: Hwirq of the incoming interrupt
+ * @vint_bit: Corresponding vint bit to which this event is attached.
+ */
+struct ti_sci_inta_event_desc {
+ u16 global_event;
+ u32 hwirq;
+ u8 vint_bit;
+};
+
+/**
+ * struct ti_sci_inta_vint_desc - Description of a virtual interrupt coming out
+ * of Interrupt Aggregator.
+ * @domain: Pointer to IRQ domain to which this vint belongs.
+ * @list: List entry for the vint list
+ * @event_map: Bitmap to manage the allocation of events to vint.
+ * @events: Array of event descriptors assigned to this vint.
+ * @parent_virq: Linux IRQ number that gets attached to parent
+ * @vint_id: TISCI vint ID
+ */
+struct ti_sci_inta_vint_desc {
+ struct irq_domain *domain;
+ struct list_head list;
+ DECLARE_BITMAP(event_map, MAX_EVENTS_PER_VINT);
+ struct ti_sci_inta_event_desc events[MAX_EVENTS_PER_VINT];
+ unsigned int parent_virq;
+ u16 vint_id;
+};
+
+/**
+ * struct ti_sci_inta_irq_domain - Structure representing a TISCI based
+ * Interrupt Aggregator IRQ domain.
+ * @sci: Pointer to TISCI handle
+ * @vint: TISCI resource pointer representing IA inerrupts.
+ * @global_event: TISCI resource pointer representing global events.
+ * @vint_list: List of the vints active in the system
+ * @vint_mutex: Mutex to protect vint_list
+ * @base: Base address of the memory mapped IO registers
+ * @pdev: Pointer to platform device.
+ */
+struct ti_sci_inta_irq_domain {
+ const struct ti_sci_handle *sci;
+ struct ti_sci_resource *vint;
+ struct ti_sci_resource *global_event;
+ struct list_head vint_list;
+ /* Mutex to protect vint list */
+ struct mutex vint_mutex;
+ void __iomem *base;
+ struct platform_device *pdev;
+};
+
+#define to_vint_desc(e, i) container_of(e, struct ti_sci_inta_vint_desc, \
+ events[i])
+
+/**
+ * ti_sci_inta_irq_handler() - Chained IRQ handler for the vint irqs
+ * @desc: Pointer to irq_desc corresponding to the irq
+ */
+static void ti_sci_inta_irq_handler(struct irq_desc *desc)
+{
+ struct ti_sci_inta_vint_desc *vint_desc;
+ struct ti_sci_inta_irq_domain *inta;
+ struct irq_domain *domain;
+ unsigned int virq, bit;
+ unsigned long val;
+
+ vint_desc = irq_desc_get_handler_data(desc);
+ domain = vint_desc->domain;
+ inta = domain->host_data;
+
+ chained_irq_enter(irq_desc_get_chip(desc), desc);
+
+ val = readq_relaxed(inta->base + vint_desc->vint_id * 0x1000 +
+ VINT_STATUS_OFFSET);
+
+ for_each_set_bit(bit, &val, MAX_EVENTS_PER_VINT) {
+ virq = irq_find_mapping(domain, vint_desc->events[bit].hwirq);
+ if (virq)
+ generic_handle_irq(virq);
+ }
+
+ chained_irq_exit(irq_desc_get_chip(desc), desc);
+}
+
+/**
+ * ti_sci_inta_alloc_parent_irq() - Allocate parent irq to Interrupt aggregator
+ * @domain: IRQ domain corresponding to Interrupt Aggregator
+ *
+ * Return 0 if all went well else corresponding error value.
+ */
+static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_domain *domain)
+{
+ struct ti_sci_inta_irq_domain *inta = domain->host_data;
+ struct ti_sci_inta_vint_desc *vint_desc;
+ struct irq_fwspec parent_fwspec;
+ unsigned int parent_virq;
+ u16 vint_id;
+
+ vint_id = ti_sci_get_free_resource(inta->vint);
+ if (vint_id == TI_SCI_RESOURCE_NULL)
+ return ERR_PTR(-EINVAL);
+
+ vint_desc = kzalloc(sizeof(*vint_desc), GFP_KERNEL);
+ if (!vint_desc)
+ return ERR_PTR(-ENOMEM);
+
+ vint_desc->domain = domain;
+ vint_desc->vint_id = vint_id;
+ INIT_LIST_HEAD(&vint_desc->list);
+
+ parent_fwspec.fwnode = of_node_to_fwnode(of_irq_find_parent(dev_of_node(&inta->pdev->dev)));
+ parent_fwspec.param_count = 2;
+ parent_fwspec.param[0] = inta->pdev->id;
+ parent_fwspec.param[1] = vint_desc->vint_id;
+
+ parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
+ if (parent_virq <= 0) {
+ kfree(vint_desc);
+ return ERR_PTR(parent_virq);
+ }
+ vint_desc->parent_virq = parent_virq;
+
+ list_add_tail(&vint_desc->list, &inta->vint_list);
+ irq_set_chained_handler_and_data(vint_desc->parent_virq,
+ ti_sci_inta_irq_handler, vint_desc);
+
+ return vint_desc;
+}
+
+/**
+ * ti_sci_inta_alloc_event() - Attach an event to a IA vint.
+ * @vint_desc: Pointer to vint_desc to which the event gets attached
+ * @free_bit: Bit inside vint to which event gets attached
+ * @hwirq: hwirq of the input event
+ *
+ * Return event_desc pointer if all went ok else appropriate error value.
+ */
+static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_event(struct ti_sci_inta_vint_desc *vint_desc,
+ u16 free_bit,
+ u32 hwirq)
+{
+ struct ti_sci_inta_irq_domain *inta = vint_desc->domain->host_data;
+ struct ti_sci_inta_event_desc *event_desc;
+ u16 dev_id, dev_index;
+ int err;
+
+ dev_id = HWIRQ_TO_DEVID(hwirq);
+ dev_index = HWIRQ_TO_IRQID(hwirq);
+
+ event_desc = &vint_desc->events[free_bit];
+ event_desc->hwirq = hwirq;
+ event_desc->vint_bit = free_bit;
+ event_desc->global_event = ti_sci_get_free_resource(inta->global_event);
+ if (event_desc->global_event == TI_SCI_RESOURCE_NULL)
+ return ERR_PTR(-EINVAL);
+
+ err = inta->sci->ops.rm_irq_ops.set_event_map(inta->sci,
+ dev_id, dev_index,
+ inta->pdev->id,
+ vint_desc->vint_id,
+ event_desc->global_event,
+ free_bit);
+ if (err)
+ goto free_global_event;
+
+ return event_desc;
+free_global_event:
+ ti_sci_release_resource(inta->global_event, event_desc->global_event);
+ return ERR_PTR(err);
+}
+
+/**
+ * ti_sci_inta_alloc_irq() - Allocate an irq within INTA domain
+ * @domain: irq_domain pointer corresponding to INTA
+ * @hwirq: hwirq of the input event
+ *
+ * Note: Allocation happens in the following manner:
+ * - Find a free bit available in any of the vints available in the list.
+ * - If not found, allocate a vint from the vint pool
+ * - Attach the free bit to input hwirq.
+ * Return event_desc if all went ok else appropriate error value.
+ */
+static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_irq(struct irq_domain *domain,
+ u32 hwirq)
+{
+ struct ti_sci_inta_irq_domain *inta = domain->host_data;
+ struct ti_sci_inta_vint_desc *vint_desc = NULL;
+ struct ti_sci_inta_event_desc *event_desc;
+ u16 free_bit;
+
+ mutex_lock(&inta->vint_mutex);
+ list_for_each_entry(vint_desc, &inta->vint_list, list) {
+ free_bit = find_first_zero_bit(vint_desc->event_map,
+ MAX_EVENTS_PER_VINT);
+ if (free_bit != MAX_EVENTS_PER_VINT) {
+ set_bit(free_bit, vint_desc->event_map);
+ goto alloc_event;
+ }
+ }
+
+ /* No free bits available. Allocate a new vint */
+ vint_desc = ti_sci_inta_alloc_parent_irq(domain);
+ if (IS_ERR(vint_desc)) {
+ mutex_unlock(&inta->vint_mutex);
+ return ERR_PTR(PTR_ERR(vint_desc));
+ }
+
+ free_bit = find_first_zero_bit(vint_desc->event_map,
+ MAX_EVENTS_PER_VINT);
+ set_bit(free_bit, vint_desc->event_map);
+
+alloc_event:
+ event_desc = ti_sci_inta_alloc_event(vint_desc, free_bit, hwirq);
+ if (IS_ERR(event_desc))
+ clear_bit(free_bit, vint_desc->event_map);
+
+ mutex_unlock(&inta->vint_mutex);
+ return event_desc;
+}
+
+/**
+ * ti_sci_inta_free_parent_irq() - Free a parent irq to INTA
+ * @inta: Pointer to inta domain.
+ * @vint_desc: Pointer to vint_desc that needs to be freed.
+ */
+static void ti_sci_inta_free_parent_irq(struct ti_sci_inta_irq_domain *inta,
+ struct ti_sci_inta_vint_desc *vint_desc)
+{
+ if (find_first_bit(vint_desc->event_map, MAX_EVENTS_PER_VINT) == MAX_EVENTS_PER_VINT) {
+ list_del(&vint_desc->list);
+ ti_sci_release_resource(inta->vint, vint_desc->vint_id);
+ irq_dispose_mapping(vint_desc->parent_virq);
+ kfree(vint_desc);
+ }
+}
+
+/**
+ * ti_sci_inta_free_irq() - Free an IRQ within INTA domain
+ * @event_desc: Pointer to event_desc that needs to be freed.
+ * @hwirq: Hwirq number within INTA domain that needs to be freed
+ */
+static void ti_sci_inta_free_irq(struct ti_sci_inta_event_desc *event_desc,
+ u32 hwirq)
+{
+ struct ti_sci_inta_vint_desc *vint_desc;
+ struct ti_sci_inta_irq_domain *inta;
+
+ vint_desc = to_vint_desc(event_desc, event_desc->vint_bit);
+ inta = vint_desc->domain->host_data;
+ /* free event irq */
+ mutex_lock(&inta->vint_mutex);
+ inta->sci->ops.rm_irq_ops.free_event_map(inta->sci,
+ HWIRQ_TO_DEVID(hwirq),
+ HWIRQ_TO_IRQID(hwirq),
+ inta->pdev->id,
+ vint_desc->vint_id,
+ event_desc->global_event,
+ event_desc->vint_bit);
+
+ clear_bit(event_desc->vint_bit, vint_desc->event_map);
+ ti_sci_release_resource(inta->global_event, event_desc->global_event);
+ event_desc->global_event = TI_SCI_RESOURCE_NULL;
+ event_desc->hwirq = 0;
+
+ ti_sci_inta_free_parent_irq(inta, vint_desc);
+ mutex_unlock(&inta->vint_mutex);
+}
+
+/**
+ * ti_sci_inta_request_resources() - Allocate resources for input irq
+ * @data: Pointer to corresponding irq_data
+ *
+ * Note: This is the core api where the actual allocation happens for input
+ * hwirq. This allocation involves creating a parent irq for vint.
+ * If this is done in irq_domain_ops.alloc() then a deadlock is reached
+ * for allocation. So this allocation is being done in request_resources()
+ *
+ * Return: 0 if all went well else corresponding error.
+ */
+static int ti_sci_inta_request_resources(struct irq_data *data)
+{
+ struct ti_sci_inta_event_desc *event_desc;
+
+ event_desc = ti_sci_inta_alloc_irq(data->domain, data->hwirq);
+ if (IS_ERR(event_desc))
+ return PTR_ERR(event_desc);
+
+ data->chip_data = event_desc;
+
+ return 0;
+}
+
+/**
+ * ti_sci_inta_release_resources - Release resources for input irq
+ * @data: Pointer to corresponding irq_data
+ *
+ * Note: Corresponding to request_resources(), all the unmapping and deletion
+ * of parent vint irqs happens in this api.
+ */
+static void ti_sci_inta_release_resources(struct irq_data *data)
+{
+ struct ti_sci_inta_event_desc *event_desc;
+
+ event_desc = irq_data_get_irq_chip_data(data);
+ ti_sci_inta_free_irq(event_desc, data->hwirq);
+}
+
+/**
+ * ti_sci_inta_manage_event() - Control the event based on the offset
+ * @data: Pointer to corresponding irq_data
+ * @offset: register offset using which event is controlled.
+ */
+static void ti_sci_inta_manage_event(struct irq_data *data, u32 offset)
+{
+ struct ti_sci_inta_event_desc *event_desc;
+ struct ti_sci_inta_vint_desc *vint_desc;
+ struct ti_sci_inta_irq_domain *inta;
+
+ event_desc = irq_data_get_irq_chip_data(data);
+ vint_desc = to_vint_desc(event_desc, event_desc->vint_bit);
+ inta = data->domain->host_data;
+
+ writeq_relaxed(BIT(event_desc->vint_bit),
+ inta->base + vint_desc->vint_id * 0x1000 + offset);
+}
+
+/**
+ * ti_sci_inta_mask_irq() - Mask an event
+ * @data: Pointer to corresponding irq_data
+ */
+static void ti_sci_inta_mask_irq(struct irq_data *data)
+{
+ ti_sci_inta_manage_event(data, VINT_ENABLE_CLR_OFFSET);
+}
+
+/**
+ * ti_sci_inta_unmask_irq() - Unmask an event
+ * @data: Pointer to corresponding irq_data
+ */
+static void ti_sci_inta_unmask_irq(struct irq_data *data)
+{
+ ti_sci_inta_manage_event(data, VINT_ENABLE_SET_OFFSET);
+}
+
+/**
+ * ti_sci_inta_ack_irq() - Ack an event
+ * @data: Pointer to corresponding irq_data
+ */
+static void ti_sci_inta_ack_irq(struct irq_data *data)
+{
+ /*
+ * Do not clear the event if hardware is capable of sending
+ * a down event.
+ */
+ if (irqd_get_trigger_type(data) != IRQF_TRIGGER_HIGH)
+ ti_sci_inta_manage_event(data, VINT_STATUS_OFFSET);
+}
+
+static int ti_sci_inta_set_affinity(struct irq_data *d,
+ const struct cpumask *mask_val, bool force)
+{
+ return -EINVAL;
+}
+
+/**
+ * ti_sci_inta_set_type() - Update the trigger type of the irq.
+ * @data: Pointer to corresponding irq_data
+ * @type: Trigger type as specified by user
+ *
+ * Note: This updates the handle_irq callback for level msi.
+ *
+ * Return 0 if all went well else appropriate error.
+ */
+static int ti_sci_inta_set_type(struct irq_data *data, unsigned int type)
+{
+ /*
+ * .alloc default sets handle_edge_irq. But if the user specifies
+ * that IRQ is level MSI, then update the handle to handle_level_irq
+ */
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQF_TRIGGER_HIGH:
+ irq_set_handler_locked(data, handle_level_irq);
+ return 0;
+ case IRQF_TRIGGER_RISING:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+static struct irq_chip ti_sci_inta_irq_chip = {
+ .name = "INTA",
+ .irq_ack = ti_sci_inta_ack_irq,
+ .irq_mask = ti_sci_inta_mask_irq,
+ .irq_set_type = ti_sci_inta_set_type,
+ .irq_unmask = ti_sci_inta_unmask_irq,
+ .irq_set_affinity = ti_sci_inta_set_affinity,
+ .irq_request_resources = ti_sci_inta_request_resources,
+ .irq_release_resources = ti_sci_inta_release_resources,
+};
+
+/**
+ * ti_sci_inta_irq_domain_free() - Free an IRQ from the IRQ domain
+ * @domain: Domain to which the irqs belong
+ * @virq: base linux virtual IRQ to be freed.
+ * @nr_irqs: Number of continuous irqs to be freed
+ */
+static void ti_sci_inta_irq_domain_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ struct irq_data *data = irq_domain_get_irq_data(domain, virq);
+
+ irq_domain_reset_irq_data(data);
+}
+
+/**
+ * ti_sci_inta_irq_domain_alloc() - Allocate Interrupt aggregator IRQs
+ * @domain: Point to the interrupt aggregator IRQ domain
+ * @virq: Corresponding Linux virtual IRQ number
+ * @nr_irqs: Continuous irqs to be allocated
+ * @data: Pointer to firmware specifier
+ *
+ * No actual allocation happens here.
+ *
+ * Return 0 if all went well else appropriate error value.
+ */
+static int ti_sci_inta_irq_domain_alloc(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs,
+ void *data)
+{
+ msi_alloc_info_t *arg = data;
+
+ irq_domain_set_info(domain, virq, arg->hwirq, &ti_sci_inta_irq_chip,
+ NULL, handle_edge_irq, NULL, NULL);
+
+ return 0;
+}
+
+static const struct irq_domain_ops ti_sci_inta_irq_domain_ops = {
+ .free = ti_sci_inta_irq_domain_free,
+ .alloc = ti_sci_inta_irq_domain_alloc,
+};
+
+static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
+{
+ struct irq_domain *parent_domain, *domain;
+ struct device_node *parent_node, *node;
+ struct ti_sci_inta_irq_domain *inta;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret;
+
+ node = dev_of_node(dev);
+ parent_node = of_irq_find_parent(node);
+ if (!parent_node) {
+ dev_err(dev, "Failed to get IRQ parent node\n");
+ return -ENODEV;
+ }
+
+ parent_domain = irq_find_host(parent_node);
+ if (!parent_domain)
+ return -EPROBE_DEFER;
+
+ inta = devm_kzalloc(dev, sizeof(*inta), GFP_KERNEL);
+ if (!inta)
+ return -ENOMEM;
+
+ inta->pdev = pdev;
+ inta->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
+ if (IS_ERR(inta->sci)) {
+ ret = PTR_ERR(inta->sci);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "ti,sci read fail %d\n", ret);
+ inta->sci = NULL;
+ return ret;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", &pdev->id);
+ if (ret) {
+ dev_err(dev, "missing 'ti,sci-dev-id' property\n");
+ return -EINVAL;
+ }
+
+ inta->vint = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
+ "ti,sci-rm-range-vint");
+ if (IS_ERR(inta->vint)) {
+ dev_err(dev, "VINT resource allocation failed\n");
+ return PTR_ERR(inta->vint);
+ }
+
+ inta->global_event = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
+ "ti,sci-rm-range-global-event");
+ if (IS_ERR(inta->global_event)) {
+ dev_err(dev, "Global event resource allocation failed\n");
+ return PTR_ERR(inta->global_event);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ inta->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(inta->base))
+ return -ENODEV;
+
+ domain = irq_domain_add_linear(dev_of_node(dev),
+ ti_sci_get_num_resources(inta->vint),
+ &ti_sci_inta_irq_domain_ops, inta);
+ if (!domain) {
+ dev_err(dev, "Failed to allocate IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&inta->vint_list);
+ mutex_init(&inta->vint_mutex);
+
+ return 0;
+}
+
+static const struct of_device_id ti_sci_inta_irq_domain_of_match[] = {
+ { .compatible = "ti,sci-inta", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ti_sci_inta_irq_domain_of_match);
+
+static struct platform_driver ti_sci_inta_irq_domain_driver = {
+ .probe = ti_sci_inta_irq_domain_probe,
+ .driver = {
+ .name = "ti-sci-inta",
+ .of_match_table = ti_sci_inta_irq_domain_of_match,
+ },
+};
+module_platform_driver(ti_sci_inta_irq_domain_driver);
+
+MODULE_AUTHOR("Lokesh Vutla <lokeshvutla@ticom>");
+MODULE_DESCRIPTION("K3 Interrupt Aggregator driver over TI SCI protocol");
+MODULE_LICENSE("GPL v2");
--
2.21.0

2019-04-30 10:16:35

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 03/14] firmware: ti_sci: Add support for IRQ management

TISCI abstracts the handling of IRQ routes where interrupt sources
are not directly connected to host interrupt controller. Add support
for the set of TISCI commands for requesting and releasing IRQs.

Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
- Updated to latest system firmware version for not tracking INTR configuration
coming from INTA.

drivers/firmware/ti_sci.c | 245 +++++++++++++++++++++++++
drivers/firmware/ti_sci.h | 60 ++++++
include/linux/soc/ti/ti_sci_protocol.h | 26 +++
3 files changed, 331 insertions(+)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 503195223c09..4ccdf9a53648 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -1765,6 +1765,245 @@ int ti_sci_cmd_get_resource_range_from_shost(const struct ti_sci_handle *handle,
range_start, range_num);
}

+/**
+ * ti_sci_manage_irq() - Helper api to configure/release the irq route between
+ * the requested source and destination
+ * @handle: Pointer to TISCI handle.
+ * @valid_params: Bit fields defining the validity of certain params
+ * @src_id: Device ID of the IRQ source
+ * @src_index: IRQ source index within the source device
+ * @dst_id: Device ID of the IRQ destination
+ * @dst_host_irq: IRQ number of the destination device
+ * @ia_id: Device ID of the IA, if the IRQ flows through this IA
+ * @vint: Virtual interrupt to be used within the IA
+ * @global_event: Global event number to be used for the requesting event
+ * @vint_status_bit: Virtual interrupt status bit to be used for the event
+ * @s_host: Secondary host ID to which the irq/event is being
+ * requested for.
+ * @type: Request type irq set or release.
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_manage_irq(const struct ti_sci_handle *handle,
+ u32 valid_params, u16 src_id, u16 src_index,
+ u16 dst_id, u16 dst_host_irq, u16 ia_id, u16 vint,
+ u16 global_event, u8 vint_status_bit, u8 s_host,
+ u16 type)
+{
+ struct ti_sci_msg_req_manage_irq *req;
+ struct ti_sci_msg_hdr *resp;
+ struct ti_sci_xfer *xfer;
+ struct ti_sci_info *info;
+ struct device *dev;
+ int ret = 0;
+
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ if (!handle)
+ return -EINVAL;
+
+ info = handle_to_ti_sci_info(handle);
+ dev = info->dev;
+
+ xfer = ti_sci_get_one_xfer(info, type, TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+ sizeof(*req), sizeof(*resp));
+ if (IS_ERR(xfer)) {
+ ret = PTR_ERR(xfer);
+ dev_err(dev, "Message alloc failed(%d)\n", ret);
+ return ret;
+ }
+ req = (struct ti_sci_msg_req_manage_irq *)xfer->xfer_buf;
+ req->valid_params = valid_params;
+ req->src_id = src_id;
+ req->src_index = src_index;
+ req->dst_id = dst_id;
+ req->dst_host_irq = dst_host_irq;
+ req->ia_id = ia_id;
+ req->vint = vint;
+ req->global_event = global_event;
+ req->vint_status_bit = vint_status_bit;
+ req->secondary_host = s_host;
+
+ ret = ti_sci_do_xfer(info, xfer);
+ if (ret) {
+ dev_err(dev, "Mbox send fail %d\n", ret);
+ goto fail;
+ }
+
+ resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
+
+ ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV;
+
+fail:
+ ti_sci_put_one_xfer(&info->minfo, xfer);
+
+ return ret;
+}
+
+/**
+ * ti_sci_set_irq() - Helper api to configure the irq route between the
+ * requested source and destination
+ * @handle: Pointer to TISCI handle.
+ * @valid_params: Bit fields defining the validity of certain params
+ * @src_id: Device ID of the IRQ source
+ * @src_index: IRQ source index within the source device
+ * @dst_id: Device ID of the IRQ destination
+ * @dst_host_irq: IRQ number of the destination device
+ * @ia_id: Device ID of the IA, if the IRQ flows through this IA
+ * @vint: Virtual interrupt to be used within the IA
+ * @global_event: Global event number to be used for the requesting event
+ * @vint_status_bit: Virtual interrupt status bit to be used for the event
+ * @s_host: Secondary host ID to which the irq/event is being
+ * requested for.
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_set_irq(const struct ti_sci_handle *handle, u32 valid_params,
+ u16 src_id, u16 src_index, u16 dst_id,
+ u16 dst_host_irq, u16 ia_id, u16 vint,
+ u16 global_event, u8 vint_status_bit, u8 s_host)
+{
+ pr_debug("%s: IRQ set with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
+ __func__, valid_params, src_id, src_index,
+ dst_id, dst_host_irq, ia_id, vint, global_event,
+ vint_status_bit);
+
+ return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
+ dst_id, dst_host_irq, ia_id, vint,
+ global_event, vint_status_bit, s_host,
+ TI_SCI_MSG_SET_IRQ);
+}
+
+/**
+ * ti_sci_free_irq() - Helper api to free the irq route between the
+ * requested source and destination
+ * @handle: Pointer to TISCI handle.
+ * @valid_params: Bit fields defining the validity of certain params
+ * @src_id: Device ID of the IRQ source
+ * @src_index: IRQ source index within the source device
+ * @dst_id: Device ID of the IRQ destination
+ * @dst_host_irq: IRQ number of the destination device
+ * @ia_id: Device ID of the IA, if the IRQ flows through this IA
+ * @vint: Virtual interrupt to be used within the IA
+ * @global_event: Global event number to be used for the requesting event
+ * @vint_status_bit: Virtual interrupt status bit to be used for the event
+ * @s_host: Secondary host ID to which the irq/event is being
+ * requested for.
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_free_irq(const struct ti_sci_handle *handle, u32 valid_params,
+ u16 src_id, u16 src_index, u16 dst_id,
+ u16 dst_host_irq, u16 ia_id, u16 vint,
+ u16 global_event, u8 vint_status_bit, u8 s_host)
+{
+ pr_debug("%s: IRQ release with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
+ __func__, valid_params, src_id, src_index,
+ dst_id, dst_host_irq, ia_id, vint, global_event,
+ vint_status_bit);
+
+ return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
+ dst_id, dst_host_irq, ia_id, vint,
+ global_event, vint_status_bit, s_host,
+ TI_SCI_MSG_FREE_IRQ);
+}
+
+/**
+ * ti_sci_cmd_set_irq() - Configure a host irq route between the requested
+ * source and destination.
+ * @handle: Pointer to TISCI handle.
+ * @src_id: Device ID of the IRQ source
+ * @src_index: IRQ source index within the source device
+ * @dst_id: Device ID of the IRQ destination
+ * @dst_host_irq: IRQ number of the destination device
+ * @vint_irq: Boolean specifying if this interrupt belongs to
+ * Interrupt Aggregator.
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_set_irq(const struct ti_sci_handle *handle, u16 src_id,
+ u16 src_index, u16 dst_id, u16 dst_host_irq)
+{
+ u32 valid_params = MSG_FLAG_DST_ID_VALID | MSG_FLAG_DST_HOST_IRQ_VALID;
+
+ return ti_sci_set_irq(handle, valid_params, src_id, src_index, dst_id,
+ dst_host_irq, 0, 0, 0, 0, 0);
+}
+
+/**
+ * ti_sci_cmd_set_event_map() - Configure an event based irq route between the
+ * requested source and Interrupt Aggregator.
+ * @handle: Pointer to TISCI handle.
+ * @src_id: Device ID of the IRQ source
+ * @src_index: IRQ source index within the source device
+ * @ia_id: Device ID of the IA, if the IRQ flows through this IA
+ * @vint: Virtual interrupt to be used within the IA
+ * @global_event: Global event number to be used for the requesting event
+ * @vint_status_bit: Virtual interrupt status bit to be used for the event
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_set_event_map(const struct ti_sci_handle *handle,
+ u16 src_id, u16 src_index, u16 ia_id,
+ u16 vint, u16 global_event,
+ u8 vint_status_bit)
+{
+ u32 valid_params = MSG_FLAG_IA_ID_VALID | MSG_FLAG_VINT_VALID |
+ MSG_FLAG_GLB_EVNT_VALID |
+ MSG_FLAG_VINT_STS_BIT_VALID;
+
+ return ti_sci_set_irq(handle, valid_params, src_id, src_index, 0, 0,
+ ia_id, vint, global_event, vint_status_bit, 0);
+}
+
+/**
+ * ti_sci_cmd_free_irq() - Free a host irq route between the between the
+ * requested source and destination.
+ * @handle: Pointer to TISCI handle.
+ * @src_id: Device ID of the IRQ source
+ * @src_index: IRQ source index within the source device
+ * @dst_id: Device ID of the IRQ destination
+ * @dst_host_irq: IRQ number of the destination device
+ * @vint_irq: Boolean specifying if this interrupt belongs to
+ * Interrupt Aggregator.
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_free_irq(const struct ti_sci_handle *handle, u16 src_id,
+ u16 src_index, u16 dst_id, u16 dst_host_irq)
+{
+ u32 valid_params = MSG_FLAG_DST_ID_VALID | MSG_FLAG_DST_HOST_IRQ_VALID;
+
+ return ti_sci_free_irq(handle, valid_params, src_id, src_index, dst_id,
+ dst_host_irq, 0, 0, 0, 0, 0);
+}
+
+/**
+ * ti_sci_cmd_free_event_map() - Free an event map between the requested source
+ * and Interrupt Aggregator.
+ * @handle: Pointer to TISCI handle.
+ * @src_id: Device ID of the IRQ source
+ * @src_index: IRQ source index within the source device
+ * @ia_id: Device ID of the IA, if the IRQ flows through this IA
+ * @vint: Virtual interrupt to be used within the IA
+ * @global_event: Global event number to be used for the requesting event
+ * @vint_status_bit: Virtual interrupt status bit to be used for the event
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_free_event_map(const struct ti_sci_handle *handle,
+ u16 src_id, u16 src_index, u16 ia_id,
+ u16 vint, u16 global_event,
+ u8 vint_status_bit)
+{
+ u32 valid_params = MSG_FLAG_IA_ID_VALID |
+ MSG_FLAG_VINT_VALID | MSG_FLAG_GLB_EVNT_VALID |
+ MSG_FLAG_VINT_STS_BIT_VALID;
+
+ return ti_sci_free_irq(handle, valid_params, src_id, src_index, 0, 0,
+ ia_id, vint, global_event, vint_status_bit, 0);
+}
+
/*
* ti_sci_setup_ops() - Setup the operations structures
* @info: pointer to TISCI pointer
@@ -1776,6 +2015,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
struct ti_sci_dev_ops *dops = &ops->dev_ops;
struct ti_sci_clk_ops *cops = &ops->clk_ops;
struct ti_sci_rm_core_ops *rm_core_ops = &ops->rm_core_ops;
+ struct ti_sci_rm_irq_ops *iops = &ops->rm_irq_ops;

core_ops->reboot_device = ti_sci_cmd_core_reboot;

@@ -1810,6 +2050,11 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
rm_core_ops->get_range = ti_sci_cmd_get_resource_range;
rm_core_ops->get_range_from_shost =
ti_sci_cmd_get_resource_range_from_shost;
+
+ iops->set_irq = ti_sci_cmd_set_irq;
+ iops->set_event_map = ti_sci_cmd_set_event_map;
+ iops->free_irq = ti_sci_cmd_free_irq;
+ iops->free_event_map = ti_sci_cmd_free_event_map;
}

/**
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index a043c4762791..4983827151bf 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -38,6 +38,10 @@
/* Resource Management Requests */
#define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500

+/* IRQ requests */
+#define TI_SCI_MSG_SET_IRQ 0x1000
+#define TI_SCI_MSG_FREE_IRQ 0x1001
+
/**
* struct ti_sci_msg_hdr - Generic Message Header for All messages and responses
* @type: Type of messages: One of TI_SCI_MSG* values
@@ -503,4 +507,60 @@ struct ti_sci_msg_resp_get_resource_range {
u16 range_num;
} __packed;

+/**
+ * struct ti_sci_msg_req_manage_irq - Request to configure/release the route
+ * between the dev and the host.
+ * @hdr: Generic Header
+ * @valid_params: Bit fields defining the validity of interrupt source
+ * parameters. If a bit is not set, then corresponding
+ * field is not valid and will not be used for route set.
+ * Bit field definitions:
+ * 0 - Valid bit for @dst_id
+ * 1 - Valid bit for @dst_host_irq
+ * 2 - Valid bit for @ia_id
+ * 3 - Valid bit for @vint
+ * 4 - Valid bit for @global_event
+ * 5 - Valid bit for @vint_status_bit_index
+ * 31 - Valid bit for @secondary_host
+ * @src_id: IRQ source peripheral ID.
+ * @src_index: IRQ source index within the peripheral
+ * @dst_id: IRQ Destination ID. Based on the architecture it can be
+ * IRQ controller or host processor ID.
+ * @dst_host_irq: IRQ number of the destination host IRQ controller
+ * @ia_id: Device ID of the interrupt aggregator in which the
+ * vint resides.
+ * @vint: Virtual interrupt number if the interrupt route
+ * is through an interrupt aggregator.
+ * @global_event: Global event that is to be mapped to interrupt
+ * aggregator virtual interrupt status bit.
+ * @vint_status_bit: Virtual interrupt status bit if the interrupt route
+ * utilizes an interrupt aggregator status bit.
+ * @secondary_host: Host ID of the IRQ destination computing entity. This is
+ * required only when destination host id is different
+ * from ti sci interface host id.
+ *
+ * Request type is TI_SCI_MSG_SET/RELEASE_IRQ.
+ * Response is generic ACK / NACK message.
+ */
+struct ti_sci_msg_req_manage_irq {
+ struct ti_sci_msg_hdr hdr;
+#define MSG_FLAG_DST_ID_VALID TI_SCI_MSG_FLAG(0)
+#define MSG_FLAG_DST_HOST_IRQ_VALID TI_SCI_MSG_FLAG(1)
+#define MSG_FLAG_IA_ID_VALID TI_SCI_MSG_FLAG(2)
+#define MSG_FLAG_VINT_VALID TI_SCI_MSG_FLAG(3)
+#define MSG_FLAG_GLB_EVNT_VALID TI_SCI_MSG_FLAG(4)
+#define MSG_FLAG_VINT_STS_BIT_VALID TI_SCI_MSG_FLAG(5)
+#define MSG_FLAG_SHOST_VALID TI_SCI_MSG_FLAG(31)
+ u32 valid_params;
+ u16 src_id;
+ u16 src_index;
+ u16 dst_id;
+ u16 dst_host_irq;
+ u16 ia_id;
+ u16 vint;
+ u16 global_event;
+ u8 vint_status_bit;
+ u8 secondary_host;
+} __packed;
+
#endif /* __TI_SCI_H */
diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h
index 0c92a922db6a..d0bc4123232e 100644
--- a/include/linux/soc/ti/ti_sci_protocol.h
+++ b/include/linux/soc/ti/ti_sci_protocol.h
@@ -217,17 +217,43 @@ struct ti_sci_rm_core_ops {
u16 *range_start, u16 *range_num);
};

+/**
+ * struct ti_sci_rm_irq_ops: IRQ management operations
+ * @set_irq: Set an IRQ route between the requested source
+ * and destination
+ * @set_event_map: Set an Event based peripheral irq to Interrupt
+ * Aggregator.
+ * @free_irq: Free an an IRQ route between the requested source
+ * destination.
+ * @free_event_map: Free an event based peripheral irq to Interrupt
+ * Aggregator.
+ */
+struct ti_sci_rm_irq_ops {
+ int (*set_irq)(const struct ti_sci_handle *handle, u16 src_id,
+ u16 src_index, u16 dst_id, u16 dst_host_irq);
+ int (*set_event_map)(const struct ti_sci_handle *handle, u16 src_id,
+ u16 src_index, u16 ia_id, u16 vint,
+ u16 global_event, u8 vint_status_bit);
+ int (*free_irq)(const struct ti_sci_handle *handle, u16 src_id,
+ u16 src_index, u16 dst_id, u16 dst_host_irq);
+ int (*free_event_map)(const struct ti_sci_handle *handle, u16 src_id,
+ u16 src_index, u16 ia_id, u16 vint,
+ u16 global_event, u8 vint_status_bit);
+};
+
/**
* struct ti_sci_ops - Function support for TI SCI
* @dev_ops: Device specific operations
* @clk_ops: Clock specific operations
* @rm_core_ops: Resource management core operations.
+ * @rm_irq_ops: IRQ management specific operations
*/
struct ti_sci_ops {
struct ti_sci_core_ops core_ops;
struct ti_sci_dev_ops dev_ops;
struct ti_sci_clk_ops clk_ops;
struct ti_sci_rm_core_ops rm_core_ops;
+ struct ti_sci_rm_irq_ops rm_irq_ops;
};

/**
--
2.21.0

2019-04-30 10:16:51

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 08/14] dt-bindings: irqchip: Introduce TISCI Interrupt router bindings

Add the DT binding documentation for Interrupt router driver.

Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
- Changes interrupt cells to 2.

.../interrupt-controller/ti,sci-intr.txt | 82 +++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 83 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt

diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
new file mode 100644
index 000000000000..1a8718f8855d
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
@@ -0,0 +1,82 @@
+Texas Instruments K3 Interrupt Router
+=====================================
+
+The Interrupt Router (INTR) module provides a mechanism to mux M
+interrupt inputs to N interrupt outputs, where all M inputs are selectable
+to be driven per N output. An Interrupt Router can either handle edge triggered
+or level triggered interrupts and that is fixed in hardware.
+
+ Interrupt Router
+ +----------------------+
+ | Inputs Outputs |
+ +-------+ | +------+ +-----+ |
+ | GPIO |----------->| | irq0 | | 0 | | Host IRQ
+ +-------+ | +------+ +-----+ | controller
+ | . . | +-------+
+ +-------+ | . . |----->| IRQ |
+ | INTA |----------->| . . | +-------+
+ +-------+ | . +-----+ |
+ | +------+ | N | |
+ | | irqM | +-----+ |
+ | +------+ |
+ | |
+ +----------------------+
+
+There is one register per output (MUXCNTL_N) that controls the selection.
+Configuration of these MUXCNTL_N registers is done by a system controller
+(like the Device Memory and Security Controller on K3 AM654 SoC). System
+controller will keep track of the used and unused registers within the Router.
+Driver should request the system controller to get the range of GIC IRQs
+assigned to the requesting hosts. It is the drivers responsibility to keep
+track of Host IRQs.
+
+Communication between the host processor running an OS and the system
+controller happens through a protocol called TI System Control Interface
+(TISCI protocol). For more details refer:
+Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
+
+TISCI Interrupt Router Node:
+----------------------------
+Required Properties:
+- compatible: Must be "ti,sci-intr".
+- ti,intr-trigger-type: Should be one of the following:
+ 1: If intr supports edge triggered interrupts.
+ 4: If intr supports level triggered interrupts.
+- interrupt-controller: Identifies the node as an interrupt controller
+- #interrupt-cells: Specifies the number of cells needed to encode an
+ interrupt source. The value should be 2.
+ First cell should contain the TISCI device ID of source
+ Second cell should contain the interrupt source offset
+ within the device.
+- ti,sci: Phandle to TI-SCI compatible System controller node.
+- ti,sci-dst-id: TISCI device ID of the destination IRQ controller.
+- ti,sci-rm-range-girq: Array of TISCI subtype ids representing the host irqs
+ assigned to this interrupt router. Each subtype id
+ corresponds to a range of host irqs.
+
+For more details on TISCI IRQ resource management refer:
+http://downloads.ti.com/tisci/esd/latest/2_tisci_msgs/rm/rm_irq.html
+
+Example:
+--------
+The following example demonstrates both interrupt router node and the consumer
+node(main gpio) on the AM654 SoC:
+
+main_intr: interrupt-controller0 {
+ compatible = "ti,sci-intr";
+ ti,intr-trigger-type = <1>;
+ interrupt-controller;
+ interrupt-parent = <&gic500>;
+ #interrupt-cells = <2>;
+ ti,sci = <&dmsc>;
+ ti,sci-dst-id = <56>;
+ ti,sci-rm-range-girq = <0x1>;
+};
+
+main_gpio0: gpio@600000 {
+ ...
+ interrupt-parent = <&main_intr>;
+ interrupts = <57 256>, <57 257>, <57 258>,
+ <57 259>, <57 260>, <57 261>;
+ ...
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 5c38f21aee78..91b4dcfb47f4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15350,6 +15350,7 @@ F: Documentation/devicetree/bindings/reset/ti,sci-reset.txt
F: Documentation/devicetree/bindings/clock/ti,sci-clk.txt
F: drivers/clk/keystone/sci-clk.c
F: drivers/reset/reset-ti-sci.c
+F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt

Texas Instruments ASoC drivers
M: Peter Ujfalusi <[email protected]>
--
2.21.0

2019-04-30 10:17:22

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 07/14] gpio: thunderx: Use the default parent apis for {request,release}_resources

thunderx_gpio_irq_{request,release}_resources apis are trying to
{request,release} resources on parent interrupt. There are default
apis doing the same. Use the default parent apis instead of writing
the same code snippet.

Cc: [email protected]
Cc: Linus Walleij <[email protected]>
Acked-by: Linus Walleij <[email protected]>
Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
- None

drivers/gpio/gpio-thunderx.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c
index 1306722faa5a..715371b5102a 100644
--- a/drivers/gpio/gpio-thunderx.c
+++ b/drivers/gpio/gpio-thunderx.c
@@ -363,22 +363,16 @@ static int thunderx_gpio_irq_request_resources(struct irq_data *data)
{
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
struct thunderx_gpio *txgpio = txline->txgpio;
- struct irq_data *parent_data = data->parent_data;
int r;

r = gpiochip_lock_as_irq(&txgpio->chip, txline->line);
if (r)
return r;

- if (parent_data && parent_data->chip->irq_request_resources) {
- r = parent_data->chip->irq_request_resources(parent_data);
- if (r)
- goto error;
- }
+ r = irq_chip_request_resources_parent(data);
+ if (r)
+ gpiochip_unlock_as_irq(&txgpio->chip, txline->line);

- return 0;
-error:
- gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
return r;
}

@@ -386,10 +380,8 @@ static void thunderx_gpio_irq_release_resources(struct irq_data *data)
{
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
struct thunderx_gpio *txgpio = txline->txgpio;
- struct irq_data *parent_data = data->parent_data;

- if (parent_data && parent_data->chip->irq_release_resources)
- parent_data->chip->irq_release_resources(parent_data);
+ irq_chip_release_resources_parent(data);

gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
}
--
2.21.0

2019-04-30 10:17:26

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 14/14] arm64: arch_k3: Enable interrupt controller drivers

Select the TISCI Interrupt Router, Aggregator drivers and all its
dependencies for TI's SoCs based on K3 architecture.

Suggested-by: Marc Zyngier <[email protected]>
Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
-None

arch/arm64/Kconfig.platforms | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index b5ca9c50876d..ab9cac8235b3 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -82,6 +82,11 @@ config ARCH_EXYNOS
config ARCH_K3
bool "Texas Instruments Inc. K3 multicore SoC architecture"
select PM_GENERIC_DOMAINS if PM
+ select MAILBOX
+ select TI_MESSAGE_MANAGER
+ select TI_SCI_PROTOCOL
+ select TI_SCI_INTR_IRQCHIP
+ select TI_SCI_INTA_IRQCHIP
help
This enables support for Texas Instruments' K3 multicore SoC
architecture.
--
2.21.0

2019-04-30 10:17:31

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 13/14] irqchip: ti-sci-inta: Add msi domain support

Add a msi domain that is child to the INTA domain. Clients
uses the INTA msi bus layer to allocate irqs in this
msi domain.

Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes sinece v7:
-None

drivers/irqchip/Kconfig | 1 +
drivers/irqchip/irq-ti-sci-inta.c | 40 ++++++++++++++++++++++++++++++-
2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 7c84a71bcd88..1fab40487d63 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -441,6 +441,7 @@ config TI_SCI_INTA_IRQCHIP
depends on TI_SCI_PROTOCOL
select IRQ_DOMAIN
select IRQ_DOMAIN_HIERARCHY
+ select TI_SCI_INTA_MSI_DOMAIN
help
This enables the irqchip driver support for K3 Interrupt aggregator
over TI System Control Interface available on some new TI's SoCs.
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
index 87e0abe0041f..011b60a49e3f 100644
--- a/drivers/irqchip/irq-ti-sci-inta.c
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -18,6 +18,7 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/irqchip/chained_irq.h>
+#include <linux/soc/ti/ti_sci_inta_msi.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include <asm-generic/msi.h>

@@ -28,6 +29,9 @@
#define HWIRQ_TO_DEVID(hwirq) (((hwirq) >> (TI_SCI_DEV_ID_SHIFT)) & \
(TI_SCI_DEV_ID_MASK))
#define HWIRQ_TO_IRQID(hwirq) ((hwirq) & (TI_SCI_IRQ_ID_MASK))
+#define TO_HWIRQ(dev, index) ((((dev) & TI_SCI_DEV_ID_MASK) << \
+ TI_SCI_DEV_ID_SHIFT) | \
+ ((index) & TI_SCI_IRQ_ID_MASK))

#define MAX_EVENTS_PER_VINT 64
#define VINT_ENABLE_SET_OFFSET 0x0
@@ -484,9 +488,34 @@ static const struct irq_domain_ops ti_sci_inta_irq_domain_ops = {
.alloc = ti_sci_inta_irq_domain_alloc,
};

+static struct irq_chip ti_sci_inta_msi_irq_chip = {
+ .name = "MSI-INTA",
+ .flags = IRQCHIP_SUPPORTS_LEVEL_MSI,
+};
+
+static void ti_sci_inta_msi_set_desc(msi_alloc_info_t *arg,
+ struct msi_desc *desc)
+{
+ struct platform_device *pdev = to_platform_device(desc->dev);
+
+ arg->desc = desc;
+ arg->hwirq = TO_HWIRQ(pdev->id, desc->inta.dev_index);
+}
+
+static struct msi_domain_ops ti_sci_inta_msi_ops = {
+ .set_desc = ti_sci_inta_msi_set_desc,
+};
+
+static struct msi_domain_info ti_sci_inta_msi_domain_info = {
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_LEVEL_CAPABLE),
+ .ops = &ti_sci_inta_msi_ops,
+ .chip = &ti_sci_inta_msi_irq_chip,
+};
+
static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
{
- struct irq_domain *parent_domain, *domain;
+ struct irq_domain *parent_domain, *domain, *msi_domain;
struct device_node *parent_node, *node;
struct ti_sci_inta_irq_domain *inta;
struct device *dev = &pdev->dev;
@@ -551,6 +580,15 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
return -ENOMEM;
}

+ msi_domain = ti_sci_inta_msi_create_irq_domain(of_node_to_fwnode(node),
+ &ti_sci_inta_msi_domain_info,
+ domain);
+ if (!msi_domain) {
+ irq_domain_remove(domain);
+ dev_err(dev, "Failed to allocate msi domain\n");
+ return -ENOMEM;
+ }
+
INIT_LIST_HEAD(&inta->vint_list);
mutex_init(&inta->vint_mutex);

--
2.21.0

2019-04-30 10:17:53

by Lokesh Vutla

[permalink] [raw]
Subject: [PATCH v8 04/14] firmware: ti_sci: Add RM mapping table for am654

From: Peter Ujfalusi <[email protected]>

Add the resource mapping table for AM654 SoC as defined in
http://downloads.ti.com/tisci/esd/latest/5_soc_doc/am6x/resasg_types.html
Introduce a new compatible for AM654 "ti,am654-sci" for using
this resource map table.

Reviewed-by: Rob Herring <[email protected]>
Acked-by: Tony Lindgren <[email protected]>
Signed-off-by: Peter Ujfalusi <[email protected]>
Signed-off-by: Lokesh Vutla <[email protected]>
---
Changes since v7:
- None
.../bindings/arm/keystone/ti,sci.txt | 3 ++-
drivers/firmware/ti_sci.c | 23 +++++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/arm/keystone/ti,sci.txt b/Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
index b56a02c10ae6..6f0cd31c1520 100644
--- a/Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
+++ b/Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
@@ -24,7 +24,8 @@ relationship between the TI-SCI parent node to the child node.

Required properties:
-------------------
-- compatible: should be "ti,k2g-sci"
+- compatible: should be "ti,k2g-sci" for TI 66AK2G SoC
+ should be "ti,am654-sci" for for TI AM654 SoC
- mbox-names:
"rx" - Mailbox corresponding to receive path
"tx" - Mailbox corresponding to transmit path
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 4ccdf9a53648..551895535767 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -2282,10 +2282,33 @@ static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
/* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
.max_msgs = 20,
.max_msg_size = 64,
+ .rm_type_map = NULL,
+};
+
+static struct ti_sci_rm_type_map ti_sci_am654_rm_type_map[] = {
+ {.dev_id = 56, .type = 0x00b}, /* GIC_IRQ */
+ {.dev_id = 179, .type = 0x000}, /* MAIN_NAV_UDMASS_IA0 */
+ {.dev_id = 187, .type = 0x009}, /* MAIN_NAV_RA */
+ {.dev_id = 188, .type = 0x006}, /* MAIN_NAV_UDMAP */
+ {.dev_id = 194, .type = 0x007}, /* MCU_NAV_UDMAP */
+ {.dev_id = 195, .type = 0x00a}, /* MCU_NAV_RA */
+ {.dev_id = 0, .type = 0x000}, /* end of table */
+};
+
+/* Description for AM654 */
+static const struct ti_sci_desc ti_sci_pmmc_am654_desc = {
+ .default_host_id = 12,
+ /* Conservative duration */
+ .max_rx_timeout_ms = 10000,
+ /* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
+ .max_msgs = 20,
+ .max_msg_size = 60,
+ .rm_type_map = ti_sci_am654_rm_type_map,
};

static const struct of_device_id ti_sci_of_match[] = {
{.compatible = "ti,k2g-sci", .data = &ti_sci_pmmc_k2g_desc},
+ {.compatible = "ti,am654-sci", .data = &ti_sci_pmmc_am654_desc},
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, ti_sci_of_match);
--
2.21.0

2019-04-30 12:02:15

by Nishanth Menon

[permalink] [raw]
Subject: Re: [PATCH v8 00/14] Add support for TISCI Interrupt controller drivers

On 15:42-20190430, Lokesh Vutla wrote:
[...]
> Changes since v7:
> - Rebased on top of latest master.
> - Each patch has respective changes mentioned.
>
> Grygorii Strashko (1):
> firmware: ti_sci: Add support to get TISCI handle using of_phandle
>
> Lokesh Vutla (12):
> firmware: ti_sci: Add support for RM core ops
> firmware: ti_sci: Add support for IRQ management
> firmware: ti_sci: Add helper apis to manage resources
> genirq: Introduce irq_chip_{request,release}_resource_parent() apis
> gpio: thunderx: Use the default parent apis for
> {request,release}_resources
> dt-bindings: irqchip: Introduce TISCI Interrupt router bindings
> irqchip: ti-sci-intr: Add support for Interrupt Router driver
> dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings
> irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
> soc: ti: Add MSI domain bus support for Interrupt Aggregator
> irqchip: ti-sci-inta: Add msi domain support
> arm64: arch_k3: Enable interrupt controller drivers
>
> Peter Ujfalusi (1):
> firmware: ti_sci: Add RM mapping table for am654
>

For patches 1..5 (Firmware patches):

Acked-by: Nishanth Menon <[email protected]>

--
Regards,
Nishanth Menon

2019-04-30 22:26:53

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v8 10/14] dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings

On Tue, 30 Apr 2019 15:42:26 +0530, Lokesh Vutla wrote:
> Add the DT binding documentation for Interrupt Aggregator driver.
>
> Signed-off-by: Lokesh Vutla <[email protected]>
> ---
> Changes since v7:
> - None
> .../interrupt-controller/ti,sci-inta.txt | 66 +++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 67 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
>

Reviewed-by: Rob Herring <[email protected]>

2019-04-30 22:27:36

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v8 08/14] dt-bindings: irqchip: Introduce TISCI Interrupt router bindings

On Tue, 30 Apr 2019 15:42:24 +0530, Lokesh Vutla wrote:
> Add the DT binding documentation for Interrupt router driver.
>
> Signed-off-by: Lokesh Vutla <[email protected]>
> ---
> Changes since v7:
> - Changes interrupt cells to 2.
>
> .../interrupt-controller/ti,sci-intr.txt | 82 +++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 83 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
>

Reviewed-by: Rob Herring <[email protected]>

2019-05-01 11:59:55

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH v8 00/14] Add support for TISCI Interrupt controller drivers

On 30/04/2019 11:12, Lokesh Vutla wrote:
> TI AM65x SoC based on K3 architecture introduced support for Events
> which are message based interrupts with minimal latency. These events
> are not compatible with regular interrupts and are valid only through
> an event transport lane. An Interrupt Aggregator(INTA) is introduced
> to convert these events to interrupts. INTA can also group 64 events
> into a single interrupt. Now the SoC has many peripherals and a large
> number of event sources (time sync or DMA), the use of events is
> completely dependent on a user's specific application, which drives a
> need for maximum flexibility in which event sources are used in the
> system. It is also completely up to software control as to how the
> events are serviced.
>
> Because of the huge flexibility there are certain standard peripherals
> (like GPIO etc)where all interrupts cannot be directly corrected to host
> interrupt controller. For this purpose, Interrupt Router(INTR) is
> introduced in the SoC. INTR just does a classic interrupt redirection.
>
> So the SoC has 3 types of interrupt controllers:
> - GIC500
> - Interrupt Router
> - Interrupt Aggregator
>
> Below is a diagrammatic view of how SoC integration of these interrupt
> controllers:(https://pastebin.ubuntu.com/p/9ngV3jdGj2/)
>
> Device Index-x Device Index-y
> | |
> | |
> ....
> \ /
> \ /
> \ (global events) /
> +---------------------------+ +---------+
> | | | |
> | INTA | | GPIO |
> | | | |
> +---------------------------+ +---------+
> | (vint) |
> | |
> \|/ |
> +---------------------------+ |
> | |<-------+
> | INTR |
> | |
> +---------------------------+
> |
> |
> \|/ (gic irq)
> +---------------------------+
> | |
> | GIC |
> | |
> +---------------------------+
>
> While at it, TISCI abstracts the handling of all above IRQ routes where
> interrupt sources are not directly connected to host interrupt controller.
> That would be configuration of Interrupt Aggregator and Interrupt Router.
>
> This series adds support for:
> - TISCI commands needed for IRQ configuration
> - Interrupt Router(INTR) driver.
> - Interrupt Aggregator(INTA) driver.
> - Interrupt Aggregator MSI bus layer.
>
> Marc,
> As discussed offline, the firmware changes are going to come within
> a day or so. These changes are tested against local binary which is
> bound to release.
>
> Boot Log: https://pastebin.ubuntu.com/p/YwprMKXdg4/
>
> Changes since v7:
> - Rebased on top of latest master.
> - Each patch has respective changes mentioned.
>
> Grygorii Strashko (1):
> firmware: ti_sci: Add support to get TISCI handle using of_phandle
>
> Lokesh Vutla (12):
> firmware: ti_sci: Add support for RM core ops
> firmware: ti_sci: Add support for IRQ management
> firmware: ti_sci: Add helper apis to manage resources
> genirq: Introduce irq_chip_{request,release}_resource_parent() apis
> gpio: thunderx: Use the default parent apis for
> {request,release}_resources
> dt-bindings: irqchip: Introduce TISCI Interrupt router bindings
> irqchip: ti-sci-intr: Add support for Interrupt Router driver
> dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings
> irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
> soc: ti: Add MSI domain bus support for Interrupt Aggregator
> irqchip: ti-sci-inta: Add msi domain support
> arm64: arch_k3: Enable interrupt controller drivers
>
> Peter Ujfalusi (1):
> firmware: ti_sci: Add RM mapping table for am654
>
> .../bindings/arm/keystone/ti,sci.txt | 3 +-
> .../interrupt-controller/ti,sci-inta.txt | 66 ++
> .../interrupt-controller/ti,sci-intr.txt | 82 +++
> MAINTAINERS | 6 +
> arch/arm64/Kconfig.platforms | 5 +
> drivers/firmware/ti_sci.c | 651 ++++++++++++++++++
> drivers/firmware/ti_sci.h | 102 +++
> drivers/gpio/gpio-thunderx.c | 16 +-
> drivers/irqchip/Kconfig | 23 +
> drivers/irqchip/Makefile | 2 +
> drivers/irqchip/irq-ti-sci-inta.c | 615 +++++++++++++++++
> drivers/irqchip/irq-ti-sci-intr.c | 275 ++++++++
> drivers/soc/ti/Kconfig | 6 +
> drivers/soc/ti/Makefile | 1 +
> drivers/soc/ti/ti_sci_inta_msi.c | 146 ++++
> include/linux/irq.h | 2 +
> include/linux/irqdomain.h | 1 +
> include/linux/msi.h | 10 +
> include/linux/soc/ti/ti_sci_inta_msi.h | 23 +
> include/linux/soc/ti/ti_sci_protocol.h | 124 ++++
> kernel/irq/chip.c | 27 +
> 21 files changed, 2173 insertions(+), 13 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
> create mode 100644 drivers/irqchip/irq-ti-sci-inta.c
> create mode 100644 drivers/irqchip/irq-ti-sci-intr.c
> create mode 100644 drivers/soc/ti/ti_sci_inta_msi.c
> create mode 100644 include/linux/soc/ti/ti_sci_inta_msi.h

Lokesh,

Thanks for having respun this quickly.

I've applied the first 13 patches to irqchip-next (after tidying up some
of the commit messages). I've left the last patch for armsoc to take,
unless you guys insist on me taking it.

If nothing horrible appears in -next tomorrow, I'll send the 5.2 PR with
this series.

Hopefully we won't see more of this madness any time soon... :-/

Thanks,

M.
--
Jazz is not dead. It just smells funny...

2019-05-01 13:25:51

by Lokesh Vutla

[permalink] [raw]
Subject: Re: [PATCH v8 00/14] Add support for TISCI Interrupt controller drivers

Hi Marc,

On 01/05/19 5:28 PM, Marc Zyngier wrote:
> On 30/04/2019 11:12, Lokesh Vutla wrote:
>> TI AM65x SoC based on K3 architecture introduced support for Events
>> which are message based interrupts with minimal latency. These events
>> are not compatible with regular interrupts and are valid only through
>> an event transport lane. An Interrupt Aggregator(INTA) is introduced
>> to convert these events to interrupts. INTA can also group 64 events
>> into a single interrupt. Now the SoC has many peripherals and a large
>> number of event sources (time sync or DMA), the use of events is
>> completely dependent on a user's specific application, which drives a
>> need for maximum flexibility in which event sources are used in the
>> system. It is also completely up to software control as to how the
>> events are serviced.
>>
>> Because of the huge flexibility there are certain standard peripherals
>> (like GPIO etc)where all interrupts cannot be directly corrected to host
>> interrupt controller. For this purpose, Interrupt Router(INTR) is
>> introduced in the SoC. INTR just does a classic interrupt redirection.
>>
>> So the SoC has 3 types of interrupt controllers:
>> - GIC500
>> - Interrupt Router
>> - Interrupt Aggregator
>>
>> Below is a diagrammatic view of how SoC integration of these interrupt
>> controllers:(https://pastebin.ubuntu.com/p/9ngV3jdGj2/)
>>
>> Device Index-x Device Index-y
>> | |
>> | |
>> ....
>> \ /
>> \ /
>> \ (global events) /
>> +---------------------------+ +---------+
>> | | | |
>> | INTA | | GPIO |
>> | | | |
>> +---------------------------+ +---------+
>> | (vint) |
>> | |
>> \|/ |
>> +---------------------------+ |
>> | |<-------+
>> | INTR |
>> | |
>> +---------------------------+
>> |
>> |
>> \|/ (gic irq)
>> +---------------------------+
>> | |
>> | GIC |
>> | |
>> +---------------------------+
>>
>> While at it, TISCI abstracts the handling of all above IRQ routes where
>> interrupt sources are not directly connected to host interrupt controller.
>> That would be configuration of Interrupt Aggregator and Interrupt Router.
>>
>> This series adds support for:
>> - TISCI commands needed for IRQ configuration
>> - Interrupt Router(INTR) driver.
>> - Interrupt Aggregator(INTA) driver.
>> - Interrupt Aggregator MSI bus layer.
>>
>> Marc,
>> As discussed offline, the firmware changes are going to come within
>> a day or so. These changes are tested against local binary which is
>> bound to release.
>>
>> Boot Log: https://pastebin.ubuntu.com/p/YwprMKXdg4/
>>
>> Changes since v7:
>> - Rebased on top of latest master.
>> - Each patch has respective changes mentioned.
>>
>> Grygorii Strashko (1):
>> firmware: ti_sci: Add support to get TISCI handle using of_phandle
>>
>> Lokesh Vutla (12):
>> firmware: ti_sci: Add support for RM core ops
>> firmware: ti_sci: Add support for IRQ management
>> firmware: ti_sci: Add helper apis to manage resources
>> genirq: Introduce irq_chip_{request,release}_resource_parent() apis
>> gpio: thunderx: Use the default parent apis for
>> {request,release}_resources
>> dt-bindings: irqchip: Introduce TISCI Interrupt router bindings
>> irqchip: ti-sci-intr: Add support for Interrupt Router driver
>> dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings
>> irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
>> soc: ti: Add MSI domain bus support for Interrupt Aggregator
>> irqchip: ti-sci-inta: Add msi domain support
>> arm64: arch_k3: Enable interrupt controller drivers
>>
>> Peter Ujfalusi (1):
>> firmware: ti_sci: Add RM mapping table for am654
>>
>> .../bindings/arm/keystone/ti,sci.txt | 3 +-
>> .../interrupt-controller/ti,sci-inta.txt | 66 ++
>> .../interrupt-controller/ti,sci-intr.txt | 82 +++
>> MAINTAINERS | 6 +
>> arch/arm64/Kconfig.platforms | 5 +
>> drivers/firmware/ti_sci.c | 651 ++++++++++++++++++
>> drivers/firmware/ti_sci.h | 102 +++
>> drivers/gpio/gpio-thunderx.c | 16 +-
>> drivers/irqchip/Kconfig | 23 +
>> drivers/irqchip/Makefile | 2 +
>> drivers/irqchip/irq-ti-sci-inta.c | 615 +++++++++++++++++
>> drivers/irqchip/irq-ti-sci-intr.c | 275 ++++++++
>> drivers/soc/ti/Kconfig | 6 +
>> drivers/soc/ti/Makefile | 1 +
>> drivers/soc/ti/ti_sci_inta_msi.c | 146 ++++
>> include/linux/irq.h | 2 +
>> include/linux/irqdomain.h | 1 +
>> include/linux/msi.h | 10 +
>> include/linux/soc/ti/ti_sci_inta_msi.h | 23 +
>> include/linux/soc/ti/ti_sci_protocol.h | 124 ++++
>> kernel/irq/chip.c | 27 +
>> 21 files changed, 2173 insertions(+), 13 deletions(-)
>> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
>> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
>> create mode 100644 drivers/irqchip/irq-ti-sci-inta.c
>> create mode 100644 drivers/irqchip/irq-ti-sci-intr.c
>> create mode 100644 drivers/soc/ti/ti_sci_inta_msi.c
>> create mode 100644 include/linux/soc/ti/ti_sci_inta_msi.h
>
> Lokesh,
>
> Thanks for having respun this quickly.
>
> I've applied the first 13 patches to irqchip-next (after tidying up some
> of the commit messages). I've left the last patch for armsoc to take,
> unless you guys insist on me taking it.

I prefer if everything goes as a single bundle, unless arm-soc maintainers
object. Want to start posting DT nodes.

>
> If nothing horrible appears in -next tomorrow, I'll send the 5.2 PR with
> this series.

Awesome.

>
> Hopefully we won't see more of this madness any time soon... :-/

IRQCHIP is one part of it. Fun is yet to start with DMA.

Thanks and regards,
Lokesh

2019-05-01 13:46:18

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH v8 00/14] Add support for TISCI Interrupt controller drivers

On Wed, 01 May 2019 14:23:41 +0100,
Lokesh Vutla <[email protected]> wrote:
>
> Hi Marc,

[...]

> > Lokesh,
> >
> > Thanks for having respun this quickly.
> >
> > I've applied the first 13 patches to irqchip-next (after tidying up some
> > of the commit messages). I've left the last patch for armsoc to take,
> > unless you guys insist on me taking it.
>
> I prefer if everything goes as a single bundle, unless arm-soc maintainers
> object. Want to start posting DT nodes.

Santosh, Tony: what do you prefer? I don't care either way, but I need
a word from either of you.

>
> >
> > If nothing horrible appears in -next tomorrow, I'll send the 5.2 PR with
> > this series.
>
> Awesome.
>
> >
> > Hopefully we won't see more of this madness any time soon... :-/
>
> IRQCHIP is one part of it. Fun is yet to start with DMA.

Great. Oh well, I guess Robin and Christoph will enjoy the ride!

Thanks,

M.

--
Jazz is not dead, it just smell funny.

2019-05-01 14:06:14

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH v8 00/14] Add support for TISCI Interrupt controller drivers

* Marc Zyngier <[email protected]> [190501 13:45]:
> On Wed, 01 May 2019 14:23:41 +0100,
> Lokesh Vutla <[email protected]> wrote:
> >
> > Hi Marc,
>
> [...]
>
> > > Lokesh,
> > >
> > > Thanks for having respun this quickly.
> > >
> > > I've applied the first 13 patches to irqchip-next (after tidying up some
> > > of the commit messages). I've left the last patch for armsoc to take,
> > > unless you guys insist on me taking it.
> >
> > I prefer if everything goes as a single bundle, unless arm-soc maintainers
> > object. Want to start posting DT nodes.
>
> Santosh, Tony: what do you prefer? I don't care either way, but I need
> a word from either of you.

Best to keep the series together IMO, and it's a tiny patch unlikely
to conflict with anything. Here's an ack from me for patch 14 from me:

Acked-by: Tony Lindgren <[email protected]>

2019-05-01 14:33:17

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH v8 00/14] Add support for TISCI Interrupt controller drivers

On 01/05/2019 15:04, Tony Lindgren wrote:
> * Marc Zyngier <[email protected]> [190501 13:45]:
>> On Wed, 01 May 2019 14:23:41 +0100,
>> Lokesh Vutla <[email protected]> wrote:
>>>
>>> Hi Marc,
>>
>> [...]
>>
>>>> Lokesh,
>>>>
>>>> Thanks for having respun this quickly.
>>>>
>>>> I've applied the first 13 patches to irqchip-next (after tidying up some
>>>> of the commit messages). I've left the last patch for armsoc to take,
>>>> unless you guys insist on me taking it.
>>>
>>> I prefer if everything goes as a single bundle, unless arm-soc maintainers
>>> object. Want to start posting DT nodes.
>>
>> Santosh, Tony: what do you prefer? I don't care either way, but I need
>> a word from either of you.
>
> Best to keep the series together IMO, and it's a tiny patch unlikely
> to conflict with anything. Here's an ack from me for patch 14 from me:
>
> Acked-by: Tony Lindgren <[email protected]>

Cheers Tony. Applied and pushed out.

M.
--
Jazz is not dead. It just smells funny...

2020-03-10 23:28:40

by Tim Harvey

[permalink] [raw]
Subject: Re: [PATCH v8 07/14] gpio: thunderx: Use the default parent apis for {request,release}_resources

On Tue, Apr 30, 2019 at 3:14 AM Lokesh Vutla <[email protected]> wrote:
>
> thunderx_gpio_irq_{request,release}_resources apis are trying to
> {request,release} resources on parent interrupt. There are default
> apis doing the same. Use the default parent apis instead of writing
> the same code snippet.
>
> Cc: [email protected]
> Cc: Linus Walleij <[email protected]>
> Acked-by: Linus Walleij <[email protected]>
> Signed-off-by: Lokesh Vutla <[email protected]>
> ---
> Changes since v7:
> - None
>
> drivers/gpio/gpio-thunderx.c | 16 ++++------------
> 1 file changed, 4 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c
> index 1306722faa5a..715371b5102a 100644
> --- a/drivers/gpio/gpio-thunderx.c
> +++ b/drivers/gpio/gpio-thunderx.c
> @@ -363,22 +363,16 @@ static int thunderx_gpio_irq_request_resources(struct irq_data *data)
> {
> struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
> struct thunderx_gpio *txgpio = txline->txgpio;
> - struct irq_data *parent_data = data->parent_data;
> int r;
>
> r = gpiochip_lock_as_irq(&txgpio->chip, txline->line);
> if (r)
> return r;
>
> - if (parent_data && parent_data->chip->irq_request_resources) {
> - r = parent_data->chip->irq_request_resources(parent_data);
> - if (r)
> - goto error;
> - }
> + r = irq_chip_request_resources_parent(data);
> + if (r)
> + gpiochip_unlock_as_irq(&txgpio->chip, txline->line);

Lokesh,

This patch breaks irq resources for thunderx-gpio as
parent_data->chip->irq_request_resources is undefined thus your new
irq_chip_request_resources_parent() returns -ENOSYS causing this
function to return an error where as before it would happily return 0.

Is the following the correct fix or should we qualify
data->parent_data->chip->irq_request_resources before calling
irq_chip_request_resources_parent() in thunderx-gpio?

diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index b3fa2d8..b2435ecb 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -1525,7 +1525,7 @@ int irq_chip_request_resources_parent(struct
irq_data *data)
if (data->chip->irq_request_resources)
return data->chip->irq_request_resources(data);

- return -ENOSYS;
+ return 0;
}
EXPORT_SYMBOL_GPL(irq_chip_request_resources_parent);

Regards,

Tim

2020-03-11 04:58:59

by Lokesh Vutla

[permalink] [raw]
Subject: Re: [PATCH v8 07/14] gpio: thunderx: Use the default parent apis for {request,release}_resources

Hi Tim,

On 11/03/20 4:57 AM, Tim Harvey wrote:
> On Tue, Apr 30, 2019 at 3:14 AM Lokesh Vutla <[email protected]> wrote:
>>
>> thunderx_gpio_irq_{request,release}_resources apis are trying to
>> {request,release} resources on parent interrupt. There are default
>> apis doing the same. Use the default parent apis instead of writing
>> the same code snippet.
>>
>> Cc: [email protected]
>> Cc: Linus Walleij <[email protected]>
>> Acked-by: Linus Walleij <[email protected]>
>> Signed-off-by: Lokesh Vutla <[email protected]>
>> ---
>> Changes since v7:
>> - None
>>
>> drivers/gpio/gpio-thunderx.c | 16 ++++------------
>> 1 file changed, 4 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c
>> index 1306722faa5a..715371b5102a 100644
>> --- a/drivers/gpio/gpio-thunderx.c
>> +++ b/drivers/gpio/gpio-thunderx.c
>> @@ -363,22 +363,16 @@ static int thunderx_gpio_irq_request_resources(struct irq_data *data)
>> {
>> struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
>> struct thunderx_gpio *txgpio = txline->txgpio;
>> - struct irq_data *parent_data = data->parent_data;
>> int r;
>>
>> r = gpiochip_lock_as_irq(&txgpio->chip, txline->line);
>> if (r)
>> return r;
>>
>> - if (parent_data && parent_data->chip->irq_request_resources) {
>> - r = parent_data->chip->irq_request_resources(parent_data);
>> - if (r)
>> - goto error;
>> - }
>> + r = irq_chip_request_resources_parent(data);
>> + if (r)
>> + gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
>
> Lokesh,
>
> This patch breaks irq resources for thunderx-gpio as
> parent_data->chip->irq_request_resources is undefined thus your new
> irq_chip_request_resources_parent() returns -ENOSYS causing this
> function to return an error where as before it would happily return 0.

Returning -ENOSYS is the right behaviour. If the parent doesn't have the
resources, child driver should not hook it at all.

>
> Is the following the correct fix or should we qualify
> data->parent_data->chip->irq_request_resources before calling
> irq_chip_request_resources_parent() in thunderx-gpio?

If there are no parent resources why should thunderx-gpio request parent
resources at all?

Thanks and regards,
Lokesh

2020-03-11 15:44:24

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v8 07/14] gpio: thunderx: Use the default parent apis for {request,release}_resources

Tim,

Tim Harvey <[email protected]> writes:
> On Tue, Apr 30, 2019 at 3:14 AM Lokesh Vutla <[email protected]> wrote:
>> - if (parent_data && parent_data->chip->irq_request_resources) {
>> - r = parent_data->chip->irq_request_resources(parent_data);
>> - if (r)
>> - goto error;
>> - }
>> + r = irq_chip_request_resources_parent(data);
>> + if (r)
>> + gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
>
> This patch breaks irq resources for thunderx-gpio as
> parent_data->chip->irq_request_resources is undefined thus your new
> irq_chip_request_resources_parent() returns -ENOSYS causing this
> function to return an error where as before it would happily return 0.
>
> Is the following the correct fix or should we qualify
> data->parent_data->chip->irq_request_resources before calling
> irq_chip_request_resources_parent() in thunderx-gpio?

You are not supposed to fiddle with parent data at all. Just because C
allows you is no excuse to violate abstractions in the first place.

irq_chip_request_resources_parent() rightfully returns -ENOSYS when it
can't request a resource from the parent chip because that chip does not
have anything to offer.

It's up to the caller to do something sensible with the return code. If
your chip is happy with the parent not providing it then handle
-ENOSYS. None of the chip callbacks should return -ENOSYS. If one does
then that wants to be fixed.

Thanks,

tglx


2020-03-11 16:10:53

by Tim Harvey

[permalink] [raw]
Subject: Re: [PATCH v8 07/14] gpio: thunderx: Use the default parent apis for {request,release}_resources

On Wed, Mar 11, 2020 at 8:43 AM Thomas Gleixner <[email protected]> wrote:
>
> Tim,
>
> Tim Harvey <[email protected]> writes:
> > On Tue, Apr 30, 2019 at 3:14 AM Lokesh Vutla <[email protected]> wrote:
> >> - if (parent_data && parent_data->chip->irq_request_resources) {
> >> - r = parent_data->chip->irq_request_resources(parent_data);
> >> - if (r)
> >> - goto error;
> >> - }
> >> + r = irq_chip_request_resources_parent(data);
> >> + if (r)
> >> + gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
> >
> > This patch breaks irq resources for thunderx-gpio as
> > parent_data->chip->irq_request_resources is undefined thus your new
> > irq_chip_request_resources_parent() returns -ENOSYS causing this
> > function to return an error where as before it would happily return 0.
> >
> > Is the following the correct fix or should we qualify
> > data->parent_data->chip->irq_request_resources before calling
> > irq_chip_request_resources_parent() in thunderx-gpio?
>
> You are not supposed to fiddle with parent data at all. Just because C
> allows you is no excuse to violate abstractions in the first place.
>
> irq_chip_request_resources_parent() rightfully returns -ENOSYS when it
> can't request a resource from the parent chip because that chip does not
> have anything to offer.
>
> It's up to the caller to do something sensible with the return code. If
> your chip is happy with the parent not providing it then handle
> -ENOSYS. None of the chip callbacks should return -ENOSYS. If one does
> then that wants to be fixed.
>

Ok, makes sense. Thank you and Lokesh for the feedback. I just
submitted a patch to fix the thunderx-gpio breakage.

Best Regards,

Tim