linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/13] Add support for TISCI irqchip drivers
@ 2018-12-27  6:08 Lokesh Vutla
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                   ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:08 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

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) and Interrupt Aggregator(INTA) drivers

Changes since v3:
- Fix documentation for Interrupt Router driver
- Rebased on top of latest next.
- Fully tested with DMA(using out of tree patches)
- Fixed a build error with allmodconfig

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

Lokesh Vutla (11):
  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
  dt-bindings: irqchip: Introduce TISCI Interrupt router bindings
  irqchip: ti-sci-intr: Add support for Interrupt Router driver
  genirq/msi: Add support for allocating single MSI for a device
  genirq/msi: Add support for .msi_unprepare callback
  soc: ti: Add MSI domain support for K3 Interrupt Aggregator
  dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings
  irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
  soc: ti: am6: 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      |  74 ++
 .../interrupt-controller/ti,sci-intr.txt      |  85 ++
 MAINTAINERS                                   |   4 +
 drivers/firmware/ti_sci.c                     | 848 ++++++++++++++++++
 drivers/firmware/ti_sci.h                     | 102 +++
 drivers/irqchip/Kconfig                       |  23 +
 drivers/irqchip/Makefile                      |   2 +
 drivers/irqchip/irq-ti-sci-inta.c             | 561 ++++++++++++
 drivers/irqchip/irq-ti-sci-intr.c             | 310 +++++++
 drivers/soc/ti/Kconfig                        |  11 +
 drivers/soc/ti/Makefile                       |   1 +
 drivers/soc/ti/k3_inta_msi.c                  | 193 ++++
 include/linux/irqdomain.h                     |   1 +
 include/linux/msi.h                           |  12 +
 include/linux/soc/ti/k3_inta_msi.h            |  22 +
 include/linux/soc/ti/ti_sci_protocol.h        | 169 ++++
 kernel/irq/msi.c                              |  72 +-
 18 files changed, 2470 insertions(+), 23 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/k3_inta_msi.c
 create mode 100644 include/linux/soc/ti/k3_inta_msi.h

-- 
2.19.2


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle
  2018-12-27  6:08 [PATCH v4 00/13] Add support for TISCI irqchip drivers Lokesh Vutla
@ 2018-12-27  6:13 ` Lokesh Vutla
  2018-12-27  6:13   ` [PATCH v4 02/13] firmware: ti_sci: Add support for RM core ops Lokesh Vutla
                     ` (11 more replies)
  2019-01-02 11:58 ` [PATCH v4 00/13] Add support for TISCI irqchip drivers Peter Ujfalusi
  2019-01-11 10:28 ` Lokesh Vutla
  2 siblings, 12 replies; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

From: Grygorii Strashko <grygorii.strashko@ti.com>

TISCI has been updated to have support for Resource management(likes
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 <grygorii.strashko@ti.com>
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
 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 69ed1464175c..f0cafa8a2ee9 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -1781,6 +1781,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
+ * @propname:	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
+ * @propname:	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.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 02/13] firmware: ti_sci: Add support for RM core ops
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2018-12-27  6:13   ` [PATCH v4 03/13] firmware: ti_sci: Add support for IRQ management Lokesh Vutla
                     ` (10 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

TISCI provides support for getting the resources(IRQ, RING etc..)
assigned to a specific device. These resources can be handled by
the client and in turn sends TISCI cmd to configure the resources.

It is very important that client should keep track on usage of these
resources.

Add support for TISCI commands to get resource ranges.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
 drivers/firmware/ti_sci.c              | 170 +++++++++++++++++++++++++
 drivers/firmware/ti_sci.h              |  42 ++++++
 include/linux/soc/ti/ti_sci_protocol.h |  27 ++++
 3 files changed, 239 insertions(+)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index f0cafa8a2ee9..a2a099b8f62a 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -64,6 +64,22 @@ struct ti_sci_xfers_info {
 	spinlock_t xfer_lock;
 };
 
+/**
+ * struct ti_sci_rm_type_map - Structure representing TISCI Resource
+ *				management representation of dev_ids.
+ * @dev_id:	TISCI device ID
+ * @type:	Corresponding id as identified by TISCI RM.
+ *
+ * Note: This is used only as a work around for using RM range apis
+ *	for AM654 SoC. For future SoCs dev_id will be used as type
+ *	for RM range APIs. In order to maintain ABI backward compatibility
+ *	type is not being changed for AM654 SoC.
+ */
+struct ti_sci_rm_type_map {
+	u32 dev_id;
+	u16 type;
+};
+
 /**
  * struct ti_sci_desc - Description of SoC integration
  * @default_host_id:	Host identifier representing the compute entity
@@ -71,12 +87,14 @@ struct ti_sci_xfers_info {
  * @max_msgs: Maximum number of messages that can be pending
  *		  simultaneously in the system
  * @max_msg_size: Maximum size of data per message that can be handled.
+ * @rm_type_map: RM resource type mapping structure.
  */
 struct ti_sci_desc {
 	u8 default_host_id;
 	int max_rx_timeout_ms;
 	int max_msgs;
 	int max_msg_size;
+	struct ti_sci_rm_type_map *rm_type_map;
 };
 
 /**
@@ -1617,6 +1635,153 @@ static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle)
 	return ret;
 }
 
+static int ti_sci_get_resource_type(struct ti_sci_info *info, u16 dev_id,
+				    u16 *type)
+{
+	struct ti_sci_rm_type_map *rm_type_map = info->desc->rm_type_map;
+	bool found = false;
+	int i;
+
+	/* If map is not provided then assume dev_id is used as type */
+	if (!rm_type_map) {
+		*type = dev_id;
+		return 0;
+	}
+
+	for (i = 0; rm_type_map[i].dev_id; i++) {
+		if (rm_type_map[i].dev_id == dev_id) {
+			*type = rm_type_map[i].type;
+			found = true;
+			break;
+		}
+	}
+
+	if (!found)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * ti_sci_get_resource_range - Helper to get a range of resources assigned
+ *			       to a host. Resource is uniquely identified by
+ *			       type and subtype.
+ * @handle:		Pointer to TISCI handle.
+ * @dev_id:		TISCI device ID.
+ * @subtype:		Resource assignment subtype that is being requested
+ *			from the given device.
+ * @s_host:		Host processor ID to which the resources are allocated
+ * @range_start:	Start index of the resource range
+ * @range_num:		Number of resources in the range
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
+				     u32 dev_id, u8 subtype, u8 s_host,
+				     u16 *range_start, u16 *range_num)
+{
+	struct ti_sci_msg_resp_get_resource_range *resp;
+	struct ti_sci_msg_req_get_resource_range *req;
+	struct ti_sci_xfer *xfer;
+	struct ti_sci_info *info;
+	struct device *dev;
+	u16 type;
+	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, TI_SCI_MSG_GET_RESOURCE_RANGE,
+				   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;
+	}
+
+	ret = ti_sci_get_resource_type(info, dev_id, &type);
+	if (ret) {
+		dev_err(dev, "rm type lookup failed for %u\n", dev_id);
+		goto fail;
+	}
+
+	req = (struct ti_sci_msg_req_get_resource_range *)xfer->xfer_buf;
+	req->secondary_host = s_host;
+	req->type = type & MSG_RM_RESOURCE_TYPE_MASK;
+	req->subtype = subtype & MSG_RM_RESOURCE_SUBTYPE_MASK;
+
+	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_resp_get_resource_range *)xfer->xfer_buf;
+
+	if (!ti_sci_is_response_ack(resp)) {
+		ret = -ENODEV;
+	} else if (!resp->range_start && !resp->range_num) {
+		ret = -ENODEV;
+	} else {
+		*range_start = resp->range_start;
+		*range_num = resp->range_num;
+	};
+
+fail:
+	ti_sci_put_one_xfer(&info->minfo, xfer);
+
+	return ret;
+}
+
+/**
+ * ti_sci_cmd_get_resource_range - Get a range of resources assigned to host
+ *				   that is same as ti sci interface host.
+ * @handle:		Pointer to TISCI handle.
+ * @dev_id:		TISCI device ID.
+ * @subtype:		Resource assignment subtype that is being requested
+ *			from the given device.
+ * @range_start:	Start index of the resource range
+ * @range_num:		Number of resources in the range
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_get_resource_range(const struct ti_sci_handle *handle,
+					 u32 dev_id, u8 subtype,
+					 u16 *range_start, u16 *range_num)
+{
+	return ti_sci_get_resource_range(handle, dev_id, subtype,
+					 TI_SCI_IRQ_SECONDARY_HOST_INVALID,
+					 range_start, range_num);
+}
+
+/**
+ * ti_sci_cmd_get_resource_range_from_shost - Get a range of resources
+ *					      assigned to a specified host.
+ * @handle:		Pointer to TISCI handle.
+ * @dev_id:		TISCI device ID.
+ * @subtype:		Resource assignment subtype that is being requested
+ *			from the given device.
+ * @s_host:		Host processor ID to which the resources are allocated
+ * @range_start:	Start index of the resource range
+ * @range_num:		Number of resources in the range
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static
+int ti_sci_cmd_get_resource_range_from_shost(const struct ti_sci_handle *handle,
+					     u32 dev_id, u8 subtype, u8 s_host,
+					     u16 *range_start, u16 *range_num)
+{
+	return ti_sci_get_resource_range(handle, dev_id, subtype, s_host,
+					 range_start, range_num);
+}
+
 /*
  * ti_sci_setup_ops() - Setup the operations structures
  * @info:	pointer to TISCI pointer
@@ -1627,6 +1792,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
 	struct ti_sci_core_ops *core_ops = &ops->core_ops;
 	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;
 
 	core_ops->reboot_device = ti_sci_cmd_core_reboot;
 
@@ -1657,6 +1823,10 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
 	cops->get_best_match_freq = ti_sci_cmd_clk_get_match_freq;
 	cops->set_freq = ti_sci_cmd_clk_set_freq;
 	cops->get_freq = ti_sci_cmd_clk_get_freq;
+
+	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;
 }
 
 /**
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index 12bf316b68df..a043c4762791 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -35,6 +35,9 @@
 #define TI_SCI_MSG_QUERY_CLOCK_FREQ	0x010d
 #define TI_SCI_MSG_GET_CLOCK_FREQ	0x010e
 
+/* Resource Management Requests */
+#define TI_SCI_MSG_GET_RESOURCE_RANGE	0x1500
+
 /**
  * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses
  * @type:	Type of messages: One of TI_SCI_MSG* values
@@ -461,4 +464,43 @@ struct ti_sci_msg_resp_get_clock_freq {
 	u64 freq_hz;
 } __packed;
 
+#define TI_SCI_IRQ_SECONDARY_HOST_INVALID	0xff
+
+/**
+ * struct ti_sci_msg_req_get_resource_range - Request to get a host's assigned
+ *					      range of resources.
+ * @hdr:		Generic Header
+ * @type:		Unique resource assignment type
+ * @subtype:		Resource assignment subtype within the resource type.
+ * @secondary_host:	Host processing entity to which the resources are
+ *			allocated. This is required only when the destination
+ *			host id id different from ti sci interface host id,
+ *			else TI_SCI_IRQ_SECONDARY_HOST_INVALID can be passed.
+ *
+ * Request type is TI_SCI_MSG_GET_RESOURCE_RANGE. Responded with requested
+ * resource range which is of type TI_SCI_MSG_GET_RESOURCE_RANGE.
+ */
+struct ti_sci_msg_req_get_resource_range {
+	struct ti_sci_msg_hdr hdr;
+#define MSG_RM_RESOURCE_TYPE_MASK	GENMASK(9, 0)
+#define MSG_RM_RESOURCE_SUBTYPE_MASK	GENMASK(5, 0)
+	u16 type;
+	u8 subtype;
+	u8 secondary_host;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_get_resource_range - Response to resource get range.
+ * @hdr:		Generic Header
+ * @range_start:	Start index of the resource range.
+ * @range_num:		Number of resources in the range.
+ *
+ * Response to request TI_SCI_MSG_GET_RESOURCE_RANGE.
+ */
+struct ti_sci_msg_resp_get_resource_range {
+	struct ti_sci_msg_hdr hdr;
+	u16 range_start;
+	u16 range_num;
+} __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 515587e9d373..0c92a922db6a 100644
--- a/include/linux/soc/ti/ti_sci_protocol.h
+++ b/include/linux/soc/ti/ti_sci_protocol.h
@@ -192,15 +192,42 @@ struct ti_sci_clk_ops {
 			u64 *current_freq);
 };
 
+/**
+ * struct ti_sci_rm_core_ops - Resource management core operations
+ * @get_range:		Get a range of resources belonging to ti sci host.
+ * @get_rage_from_shost:	Get a range of resources belonging to
+ *				specified host id.
+ *			- s_host: Host processing entity to which the
+ *				  resources are allocated
+ *
+ * NOTE: for these functions, all the parameters are consolidated and defined
+ * as below:
+ * - handle:	Pointer to TISCI handle as retrieved by *ti_sci_get_handle
+ * - dev_id:	TISCI device ID.
+ * - subtype:	Resource assignment subtype that is being requested
+ *		from the given device.
+ * - range_start:	Start index of the resource range
+ * - range_end:		Number of resources in the range
+ */
+struct ti_sci_rm_core_ops {
+	int (*get_range)(const struct ti_sci_handle *handle, u32 dev_id,
+			 u8 subtype, u16 *range_start, u16 *range_num);
+	int (*get_range_from_shost)(const struct ti_sci_handle *handle,
+				    u32 dev_id, u8 subtype, u8 s_host,
+				    u16 *range_start, u16 *range_num);
+};
+
 /**
  * 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.
  */
 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;
 };
 
 /**
-- 
2.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 03/13] firmware: ti_sci: Add support for IRQ management
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
  2018-12-27  6:13   ` [PATCH v4 02/13] firmware: ti_sci: Add support for RM core ops Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2018-12-27  6:13   ` [PATCH v4 04/13] firmware: ti_sci: Add RM mapping table for am654 Lokesh Vutla
                     ` (9 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

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

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
 drivers/firmware/ti_sci.c              | 446 +++++++++++++++++++++++++
 drivers/firmware/ti_sci.h              |  60 ++++
 include/linux/soc/ti/ti_sci_protocol.h |  77 +++++
 3 files changed, 583 insertions(+)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index a2a099b8f62a..987bfb29475c 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -1782,6 +1782,439 @@ 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
+ * @dt_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
+ * @dt_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
+ * @dt_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_direct_irq() - Configure a non-event based direct 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
+ * @dt_host_irq:	IRQ number of the destination device
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_set_direct_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_irq() - Configure an event based 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
+ * @dt_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
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_set_event_irq(const struct ti_sci_handle *handle,
+				    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)
+{
+	u32 valid_params = MSG_FLAG_DST_ID_VALID |
+			   MSG_FLAG_DST_HOST_IRQ_VALID | 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, dst_id,
+			      dst_host_irq, ia_id, vint, global_event,
+			      vint_status_bit, 0);
+}
+
+/**
+ * ti_sci_cmd_set_direct_irq_from_shost() - Configure a non-event based direct
+ *					    irq route between the source and
+ *					    destination belonging to a
+ *					    specified host.
+ * @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
+ * @dt_host_irq:	IRQ number of the destination device
+ * @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_cmd_set_direct_irq_from_shost(const struct ti_sci_handle *handle,
+					 u16 src_id, u16 src_index, u16 dst_id,
+					 u16 dst_host_irq, u8 s_host)
+{
+	u32 valid_params = MSG_FLAG_DST_ID_VALID | MSG_FLAG_DST_HOST_IRQ_VALID |
+			   MSG_FLAG_SHOST_VALID;
+
+	return ti_sci_set_irq(handle, valid_params, src_id, src_index,
+			      dst_id, dst_host_irq, 0, 0, 0, 0, s_host);
+}
+
+/**
+ * ti_sci_cmd_set_event_irq_from_shost() - Configure an event based irq
+ *					   route between the source and
+ *					   destination belonging to a
+ *					   specified host.
+ * @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
+ * @dt_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_cmd_set_event_irq_from_shost(const struct ti_sci_handle *handle,
+					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)
+{
+	u32 valid_params = MSG_FLAG_DST_ID_VALID |
+			   MSG_FLAG_DST_HOST_IRQ_VALID | MSG_FLAG_IA_ID_VALID |
+			   MSG_FLAG_VINT_VALID | MSG_FLAG_GLB_EVNT_VALID |
+			   MSG_FLAG_VINT_STS_BIT_VALID | MSG_FLAG_SHOST_VALID;
+
+	return ti_sci_set_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_cmd_set_event_irq_to_poll() - Configure an event based irq
+ *					in polling mode
+ * @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
+ * @dt_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_cmd_set_event_irq_to_poll(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_direct_irq() - Free a non-event based direct 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
+ * @dt_host_irq:	IRQ number of the destination device
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_free_direct_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_irq() - Free an event based 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
+ * @dt_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
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_free_event_irq(const struct ti_sci_handle *handle,
+				     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)
+{
+	u32 valid_params = MSG_FLAG_DST_ID_VALID |
+			   MSG_FLAG_DST_HOST_IRQ_VALID | 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,
+			       dst_id, dst_host_irq, ia_id, vint,
+			       global_event, vint_status_bit, 0);
+}
+
+/**
+ * ti_sci_cmd_free_direct_irq_from_shost() - Free a non-event based direct irq
+ *					     route between the source and
+ *					     destination belonging to a
+ *					     specified host.
+ * @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
+ * @dt_host_irq:	IRQ number of the destination device
+ * @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_cmd_free_direct_irq_from_shost(const struct ti_sci_handle *handle,
+					  u16 src_id, u16 src_index, u16 dst_id,
+					  u16 dst_host_irq, u8 s_host)
+{
+	u32 valid_params = MSG_FLAG_DST_ID_VALID | MSG_FLAG_DST_HOST_IRQ_VALID |
+			   MSG_FLAG_SHOST_VALID;
+
+	return ti_sci_free_irq(handle, valid_params, src_id, src_index,
+			       dst_id, dst_host_irq, 0, 0, 0, 0, s_host);
+}
+
+/**
+ * ti_sci_cmd_free_event_irq_from_shost() - Free an event based irq
+ *					    route between the source and
+ *					    destination belonging to a
+ *					    specified host.
+ * @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
+ * @dt_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_cmd_free_event_irq_from_shost(const struct ti_sci_handle *handle,
+					 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)
+{
+	u32 valid_params = MSG_FLAG_DST_ID_VALID |
+			   MSG_FLAG_DST_HOST_IRQ_VALID | MSG_FLAG_IA_ID_VALID |
+			   MSG_FLAG_VINT_VALID | MSG_FLAG_GLB_EVNT_VALID |
+			   MSG_FLAG_VINT_STS_BIT_VALID | MSG_FLAG_SHOST_VALID;
+
+	return ti_sci_free_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_cmd_free_event_irq_to_poll() - Free an event based irq
+ *					 in polling mode
+ * @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
+ * @dt_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_cmd_free_event_irq_to_poll(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
@@ -1793,6 +2226,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;
 
@@ -1827,6 +2261,18 @@ 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_direct_irq = ti_sci_cmd_set_direct_irq;
+	iops->set_event_irq = ti_sci_cmd_set_event_irq;
+	iops->set_direct_irq_from_shost = ti_sci_cmd_set_direct_irq_from_shost;
+	iops->set_event_irq_from_shost = ti_sci_cmd_set_event_irq_from_shost;
+	iops->set_event_irq_to_poll = ti_sci_cmd_set_event_irq_to_poll;
+	iops->free_direct_irq = ti_sci_cmd_free_direct_irq;
+	iops->free_event_irq = ti_sci_cmd_free_event_irq;
+	iops->free_direct_irq_from_shost =
+					ti_sci_cmd_free_direct_irq_from_shost;
+	iops->free_event_irq_from_shost = ti_sci_cmd_free_event_irq_from_shost;
+	iops->free_event_irq_to_poll = ti_sci_cmd_free_event_irq_to_poll;
 }
 
 /**
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..6d17580839dc 100644
--- a/include/linux/soc/ti/ti_sci_protocol.h
+++ b/include/linux/soc/ti/ti_sci_protocol.h
@@ -217,17 +217,94 @@ struct ti_sci_rm_core_ops {
 				    u16 *range_start, u16 *range_num);
 };
 
+/**
+ * struct ti_sci_rm_irq_ops: IRQ management operations
+ * @set_direct_irq:		Set Non-event Sourced direct irq to destination
+ *				host(same host as ti sci interface id).
+ * @set_event_irq:		Set Event based peripheral irq to destination
+ *				host(same host as ti sci interface id).
+ * @set_direct_irq_from_shost:	Set Non-event Sourced direct irq to a
+ *				specified destination host.
+ * @set_event_irq_from_shost:	Set Event based peripheral irq to a
+ *				specified destination host.
+ * @set_event_irq_to_poll:	Set Event based peripheral irq to polling mode.
+ *				vint_status_bit is used for polling.
+ * @free_direct_irq:		Free a non-event sourced direct irq to
+ *				destination host(same as ti sci interface id)
+ * @free_event_irq:		Free an event based peripheral irq to
+ *				destination host(same as ti sci interface id)
+ * @free_direct_irq_from_shost:	Free non-event based direct irq from a
+ *				specified destination host.
+ * @free_event_irq_from_shost:	Free event based peripheral irq from a
+ *				specified destination host.
+ * @free_event_irq_to_poll:	Free an event based peripheral irq that is
+ *				configured in polling mode.
+ *
+ * NOTE: for these functions, all the parameters are consolidated and defined
+ * as below:
+ * - handle:	Pointer to TISCI handle as retrieved by *ti_sci_get_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.
+ * - 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.
+ */
+struct ti_sci_rm_irq_ops {
+	int (*set_direct_irq)(const struct ti_sci_handle *handle, u16 src_id,
+			      u16 src_index, u16 dst_id, u16 dst_host_irq);
+	int (*set_event_irq)(const struct ti_sci_handle *handle, 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);
+	int (*set_direct_irq_from_shost)(const struct ti_sci_handle *handle,
+					 u16 src_id, u16 src_index, u16 dst_id,
+					 u16 dst_host_irq, u8 s_host);
+	int (*set_event_irq_from_shost)(const struct ti_sci_handle *handle,
+					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);
+	int (*set_event_irq_to_poll)(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_direct_irq)(const struct ti_sci_handle *handle, u16 src_id,
+			       u16 src_index, u16 dst_id, u16 dst_host_irq);
+	int (*free_event_irq)(const struct ti_sci_handle *handle, 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);
+	int (*free_direct_irq_from_shost)(const struct ti_sci_handle *handle,
+					  u16 src_id, u16 src_index, u16 dst_id,
+					  u16 dst_host_irq, u8 s_host);
+	int (*free_event_irq_from_shost)(const struct ti_sci_handle *handle,
+					 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);
+	int (*free_event_irq_to_poll)(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.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 04/13] firmware: ti_sci: Add RM mapping table for am654
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
  2018-12-27  6:13   ` [PATCH v4 02/13] firmware: ti_sci: Add support for RM core ops Lokesh Vutla
  2018-12-27  6:13   ` [PATCH v4 03/13] firmware: ti_sci: Add support for IRQ management Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2018-12-27  6:13   ` [PATCH v4 05/13] firmware: ti_sci: Add helper apis to manage resources Lokesh Vutla
                     ` (8 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

From: Peter Ujfalusi <peter.ujfalusi@ti.com>

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 <robh@kernel.org>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
 .../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 987bfb29475c..c2f0815edab6 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -2500,10 +2500,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.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 05/13] firmware: ti_sci: Add helper apis to manage resources
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                     ` (2 preceding siblings ...)
  2018-12-27  6:13   ` [PATCH v4 04/13] firmware: ti_sci: Add RM mapping table for am654 Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2018-12-27 16:15     ` Nishanth Menon
  2018-12-27  6:13   ` [PATCH v4 06/13] dt-bindings: irqchip: Introduce TISCI Interrupt router bindings Lokesh Vutla
                     ` (7 subsequent siblings)
  11 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

Each resource with in the device can be uniquely identified
by a type and subtype 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 <lokeshvutla@ti.com>
---
 drivers/firmware/ti_sci.c              | 126 +++++++++++++++++++++++++
 include/linux/soc/ti/ti_sci_protocol.h |  48 ++++++++++
 2 files changed, 174 insertions(+)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index c2f0815edab6..b6804c214be9 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -2480,6 +2480,132 @@ 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
+ */
+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);
+
+/**
+ * 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
+ * @of_prop:	property name by which the resource are represented
+ *
+ * Note: This function expects of_prop to be in the form of tuples
+ *	<type, subtype>. Allocates and initializes ti_sci_resource structure
+ *	for each of_prop. Client driver can directly call
+ *	ti_sci_(get_free, release)_resource apis for handling the resource.
+ *
+ * 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;
+	u16 resource_type;
+	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);
+
+	ret = ti_sci_get_resource_type(handle_to_ti_sci_info(handle), dev_id,
+				       &resource_type);
+	if (ret) {
+		dev_err(dev, "No valid resource type for %u\n", dev_id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	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, "type %d subtype %d not allocated for host %d\n",
+				resource_type, resource_subtype,
+				handle_to_ti_sci_info(handle)->host_id);
+			return ERR_PTR(ret);
+		}
+
+		dev_dbg(dev, "res type = %d, subtype = %d, start = %d, num = %d\n",
+			resource_type, 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;
+}
+EXPORT_SYMBOL_GPL(devm_ti_sci_get_of_resource);
+
 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 6d17580839dc..2a1a41a17295 100644
--- a/include/linux/soc/ti/ti_sci_protocol.h
+++ b/include/linux/soc/ti/ti_sci_protocol.h
@@ -317,6 +317,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);
@@ -325,6 +352,11 @@ 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);
+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 */
 
@@ -357,6 +389,22 @@ 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 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.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 06/13] dt-bindings: irqchip: Introduce TISCI Interrupt router bindings
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                     ` (3 preceding siblings ...)
  2018-12-27  6:13   ` [PATCH v4 05/13] firmware: ti_sci: Add helper apis to manage resources Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2018-12-27  6:13   ` [PATCH v4 07/13] irqchip: ti-sci-intr: Add support for Interrupt Router driver Lokesh Vutla
                     ` (6 subsequent siblings)
  11 siblings, 0 replies; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

Add the DT binding documentation for Interrupt router driver.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
 .../interrupt-controller/ti,sci-intr.txt      | 85 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 2 files changed, 86 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..4b0ca797fda1
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
@@ -0,0 +1,85 @@
+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. There is one register per output (MUXCNTL_N) that
+controls the selection.
+
+
+                                 Interrupt Router
+                             +----------------------+
+                             |  Inputs     Outputs  |
+        +-------+            | +------+             |
+        | GPIO  |----------->| | irq0 |             |       Host IRQ
+        +-------+            | +------+             |      controller
+                             |    .        +-----+  |      +-------+
+        +-------+            |    .        |  0  |  |----->|  IRQ  |
+        | INTA  |----------->|    .        +-----+  |      +-------+
+        +-------+            |    .          .      |
+                             | +------+      .      |
+                             | | irqM |    +-----+  |
+                             | +------+    |  N  |  |
+                             |             +-----+  |
+                             +----------------------+
+
+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:
+----------------------------
+- compatible:		Must be "ti,sci-intr".
+- 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 4.
+			First cell should contain the TISCI device ID of source
+			Second cell should contain the interrupt source offset
+			within the device
+			Third cell specifies the trigger type as defined
+			in interrupts.txt in this directory.
+			Fourth cell should be 1 if the irq is coming from
+			interrupt aggregator else 0.
+- 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";
+	interrupt-controller;
+	interrupt-parent = <&gic500>;
+	#interrupt-cells = <4>;
+	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 IRQ_TYPE_EDGE_RISING 0>,
+			<57 257 IRQ_TYPE_EDGE_RISING 0>,
+			<57 258 IRQ_TYPE_EDGE_RISING 0>,
+			<57 259 IRQ_TYPE_EDGE_RISING 0>,
+			<57 260 IRQ_TYPE_EDGE_RISING 0>,
+			<57 261 IRQ_TYPE_EDGE_RISING 0>;
+	...
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 82dc44b09a7e..8c7513b02d50 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15023,6 +15023,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 <peter.ujfalusi@ti.com>
-- 
2.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v4 07/13] irqchip: ti-sci-intr: Add support for Interrupt Router driver
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                     ` (4 preceding siblings ...)
  2018-12-27  6:13   ` [PATCH v4 06/13] dt-bindings: irqchip: Introduce TISCI Interrupt router bindings Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2019-01-16 17:16     ` Marc Zyngier
  2018-12-27  6:13   ` [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device Lokesh Vutla
                     ` (5 subsequent siblings)
  11 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

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 <lokeshvutla@ti.com>
---
 MAINTAINERS                       |   1 +
 drivers/irqchip/Kconfig           |  11 ++
 drivers/irqchip/Makefile          |   1 +
 drivers/irqchip/irq-ti-sci-intr.c | 310 ++++++++++++++++++++++++++++++
 4 files changed, 323 insertions(+)
 create mode 100644 drivers/irqchip/irq-ti-sci-intr.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 8c7513b02d50..4480eb2fe851 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15024,6 +15024,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 <peter.ujfalusi@ti.com>
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 3d1e60779078..a8d9bed0254b 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -406,6 +406,17 @@ config IMX_IRQSTEER
 	help
 	  Support for the i.MX IRQSTEER interrupt multiplexer/remapper.
 
+config TI_SCI_INTR_IRQCHIP
+	bool
+	depends on TI_SCI_PROTOCOL && ARCH_K3
+	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 c93713d24b86..b4ff376a08ef 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -94,3 +94,4 @@ obj-$(CONFIG_CSKY_APB_INTC)		+= irq-csky-apb-intc.o
 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_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..a5396e08412c
--- /dev/null
+++ b/drivers/irqchip/irq-ti-sci-intr.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments' K3 Interrupt Router irqchip driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *	Lokesh Vutla <lokeshvutla@ti.com>
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/irqdomain.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 TI_SCI_EVENT_IRQ	BIT(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 FWSPEC_TO_HWIRQ(fwspec)	(((fwspec->param[0] & TI_SCI_DEV_ID_MASK) << \
+				 TI_SCI_DEV_ID_SHIFT) | \
+				(fwspec->param[1] & 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 destination irq controller.
+ * @dst_id:	TISCI device ID of the destination irq controller.
+ */
+struct ti_sci_intr_irq_domain {
+	const struct ti_sci_handle *sci;
+	struct ti_sci_resource *dst_irq;
+	u16 dst_id;
+};
+
+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_retrigger		= irq_chip_retrigger_hierarchy,
+	.irq_set_type		= irq_chip_set_type_parent,
+	.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)
+{
+	if (is_of_node(fwspec->fwnode)) {
+		if (fwspec->param_count != 4)
+			return -EINVAL;
+
+		*hwirq = FWSPEC_TO_HWIRQ(fwspec);
+		*type = fwspec->param[2];
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static inline void ti_sci_intr_delete_desc(struct ti_sci_intr_irq_domain *intr,
+					   u16 src_id, u16 src_index,
+					   u16 dst_irq)
+{
+	intr->sci->ops.rm_irq_ops.free_direct_irq(intr->sci, src_id, src_index,
+						  intr->dst_id, dst_irq);
+}
+
+/**
+ * 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;
+	u64 flags;
+	int i;
+
+	intr = domain->host_data;
+
+	for (i = 0; i < nr_irqs; i++) {
+		data = irq_domain_get_irq_data(domain, virq + i);
+		flags = (u64)irq_data_get_irq_chip_data(data);
+		parent_data = irq_domain_get_irq_data(domain->parent, virq + i);
+
+		if (!(flags & TI_SCI_EVENT_IRQ))
+			ti_sci_intr_delete_desc(intr,
+						HWIRQ_TO_DEVID(data->hwirq),
+						HWIRQ_TO_IRQID(data->hwirq),
+						parent_data->hwirq);
+		ti_sci_release_resource(intr->dst_irq, parent_data->hwirq);
+		irq_domain_free_irqs_parent(domain, virq + i, 1);
+		irq_domain_reset_irq_data(data);
+	}
+}
+
+/**
+ * ti_sci_intr_allocate_gic_irq() - Allocate GIC specific IRQ
+ * @domain:	Point to the interrupt router IRQ domain
+ * @dev:	TISCI device IRQ generating the IRQ
+ * @irq:	IRQ offset within the device
+ * @flags:	Corresponding flags to the IRQ
+ * @event_irq:	Flag to tell if requested irq is from interrupt aggregator.
+ *
+ * Returns 0 if all went well else appropriate error pointer.
+ */
+static int ti_sci_intr_allocate_gic_irq(struct irq_domain *domain,
+					unsigned int virq, u16 dev, u16 irq,
+					u32 flags, u8 event_irq)
+{
+	struct ti_sci_intr_irq_domain *intr = domain->host_data;
+	struct irq_fwspec fwspec;
+	u16 dst_irq;
+	int err;
+
+	if (!irq_domain_get_of_node(domain->parent))
+		return -EINVAL;
+
+	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] = flags & IRQ_TYPE_SENSE_MASK;
+
+	err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
+	if (err)
+		goto err_irqs;
+
+	/* If event is requested then return */
+	if (event_irq == TI_SCI_EVENT_IRQ)
+		return 0;
+
+	err = intr->sci->ops.rm_irq_ops.set_direct_irq(intr->sci, dev, irq,
+						       intr->dst_id, dst_irq);
+	if (err) {
+		pr_err("%s: IRQ allocation failed from src = %d, src_index = %d to dst_id = %d, dst_irq = %d",
+		       __func__, dev, irq, intr->dst_id, dst_irq);
+		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;
+	u16 src_id, src_index;
+	unsigned long hwirq;
+	u8 event_irq;
+	int i, err;
+	u32 type;
+
+	err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &type);
+	if (err)
+		return err;
+
+	src_id = HWIRQ_TO_DEVID(hwirq);
+	src_index = HWIRQ_TO_IRQID(hwirq);
+	event_irq = fwspec->param[3];
+
+	for (i = 0; i < nr_irqs; i++) {
+		err = ti_sci_intr_allocate_gic_irq(domain, virq + i, src_id,
+						   src_index + i, type,
+						   event_irq);
+		if (err)
+			goto err_irq;
+
+		err = irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+						    &ti_sci_intr_irq_chip,
+						    (void *)(u64)event_irq);
+		if (err)
+			goto err_irq;
+	}
+
+	return 0;
+err_irq:
+	ti_sci_intr_irq_domain_free(domain, virq, i);
+	return err;
+}
+
+static const struct irq_domain_ops ti_sci_intr_irq_domain_ops = {
+	.alloc		= ti_sci_intr_irq_domain_alloc,
+	.free		= ti_sci_intr_irq_domain_free,
+	.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;
+
+	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",
+				   (u32 *)&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.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                     ` (5 preceding siblings ...)
  2018-12-27  6:13   ` [PATCH v4 07/13] irqchip: ti-sci-intr: Add support for Interrupt Router driver Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2019-01-16 18:30     ` Marc Zyngier
  2018-12-27  6:13   ` [RFC PATCH v4 09/13] genirq/msi: Add support for .msi_unprepare callback Lokesh Vutla
                     ` (4 subsequent siblings)
  11 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

Previously all msi for a device are allocated in one go
by calling msi_domain_alloc_irq() from a bus layer. This might
not be the case when a device is trying to allocate interrupts
dynamically based on a request to it.

So introduce msi_domain_alloc/free_irq() apis to allocate a single
msi. prepare and activate operations to be handled by bus layer
calling msi_domain_alloc/free_irq() apis.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
 include/linux/msi.h |  3 +++
 kernel/irq/msi.c    | 62 +++++++++++++++++++++++++++++----------------
 2 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/include/linux/msi.h b/include/linux/msi.h
index 784fb52b9900..474490826f8c 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -301,8 +301,11 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
 struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
 					 struct msi_domain_info *info,
 					 struct irq_domain *parent);
+int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
+			 struct msi_desc *desc,  msi_alloc_info_t *arg);
 int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
 			  int nvec);
+void msi_domain_free_irq(struct msi_desc *desc);
 void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
 struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
 
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index ad26fbcfbfc8..eb7459324113 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -387,6 +387,35 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
 	return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
 }
 
+int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
+			 struct msi_desc *desc,  msi_alloc_info_t *arg)
+{
+	struct msi_domain_info *info = domain->host_data;
+	struct msi_domain_ops *ops = info->ops;
+	int i, ret, virq;
+
+	ops->set_desc(arg, desc);
+
+	virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
+				       dev_to_node(dev), arg, false,
+				       desc->affinity);
+	if (virq < 0) {
+		ret = -ENOSPC;
+		if (ops->handle_error)
+			ret = ops->handle_error(domain, desc, ret);
+		if (ops->msi_finish)
+			ops->msi_finish(arg, ret);
+		return ret;
+	}
+
+	for (i = 0; i < desc->nvec_used; i++) {
+		irq_set_msi_desc_off(virq, i, desc);
+		irq_debugfs_copy_devname(virq + i, dev);
+	}
+
+	return 0;
+}
+
 /**
  * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
  * @domain:	The domain to allocate from
@@ -404,7 +433,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
 	struct irq_data *irq_data;
 	struct msi_desc *desc;
 	msi_alloc_info_t arg;
-	int i, ret, virq;
+	int ret, virq;
 	bool can_reserve;
 
 	ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
@@ -412,24 +441,9 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
 		return ret;
 
 	for_each_msi_entry(desc, dev) {
-		ops->set_desc(&arg, desc);
-
-		virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
-					       dev_to_node(dev), &arg, false,
-					       desc->affinity);
-		if (virq < 0) {
-			ret = -ENOSPC;
-			if (ops->handle_error)
-				ret = ops->handle_error(domain, desc, ret);
-			if (ops->msi_finish)
-				ops->msi_finish(&arg, ret);
+		ret = msi_domain_alloc_irq(domain, dev, desc, &arg);
+		if (ret)
 			return ret;
-		}
-
-		for (i = 0; i < desc->nvec_used; i++) {
-			irq_set_msi_desc_off(virq, i, desc);
-			irq_debugfs_copy_devname(virq + i, dev);
-		}
 	}
 
 	if (ops->msi_finish)
@@ -487,6 +501,12 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
 	return ret;
 }
 
+void msi_domain_free_irq(struct msi_desc *desc)
+{
+	irq_domain_free_irqs(desc->irq, desc->nvec_used);
+	desc->irq = 0;
+}
+
 /**
  * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
  * @domain:	The domain to managing the interrupts
@@ -503,10 +523,8 @@ void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
 		 * enough that there is no IRQ associated to this
 		 * entry. If that's the case, don't do anything.
 		 */
-		if (desc->irq) {
-			irq_domain_free_irqs(desc->irq, desc->nvec_used);
-			desc->irq = 0;
-		}
+		if (desc->irq)
+			msi_domain_free_irq(desc);
 	}
 }
 
-- 
2.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH v4 09/13] genirq/msi: Add support for .msi_unprepare callback
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                     ` (6 preceding siblings ...)
  2018-12-27  6:13   ` [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2019-01-17 10:39     ` Marc Zyngier
  2018-12-27  6:13   ` [RFC PATCH v4 10/13] soc: ti: Add MSI domain support for K3 Interrupt Aggregator Lokesh Vutla
                     ` (3 subsequent siblings)
  11 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

Add an optional callback .msi_unprepare to struct msi_domain_ops.
This is used to clear any effect that is done by .msi_prepare callback.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
 include/linux/msi.h |  3 +++
 kernel/irq/msi.c    | 10 ++++++++++
 2 files changed, 13 insertions(+)

diff --git a/include/linux/msi.h b/include/linux/msi.h
index 474490826f8c..f35dd19f6c69 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -239,6 +239,8 @@ struct msi_domain_ops {
 	int		(*msi_prepare)(struct irq_domain *domain,
 				       struct device *dev, int nvec,
 				       msi_alloc_info_t *arg);
+	void		(*msi_unprepare)(struct irq_domain *domain, int nvec,
+					 void *data);
 	void		(*msi_finish)(msi_alloc_info_t *arg, int retval);
 	void		(*set_desc)(msi_alloc_info_t *arg,
 				    struct msi_desc *desc);
@@ -319,6 +321,7 @@ void platform_msi_domain_free_irqs(struct device *dev);
 /* When an MSI domain is used as an intermediate domain */
 int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
 			    int nvec, msi_alloc_info_t *args);
+void msi_domain_unprepare_irqs(struct irq_domain *domain, int nvec, void *data);
 int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
 			     int virq, int nvec, msi_alloc_info_t *args);
 struct irq_domain *
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index eb7459324113..1a1738690519 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -312,6 +312,16 @@ int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
 	return ret;
 }
 
+void msi_domain_unprepare_irqs(struct irq_domain *domain, int nvec,
+			       void *data)
+{
+	struct msi_domain_info *info = domain->host_data;
+	struct msi_domain_ops *ops = info->ops;
+
+	if (ops->msi_unprepare)
+		ops->msi_unprepare(domain, nvec, data);
+}
+
 int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
 			     int virq, int nvec, msi_alloc_info_t *arg)
 {
-- 
2.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH v4 10/13] soc: ti: Add MSI domain support for K3 Interrupt Aggregator
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                     ` (7 preceding siblings ...)
  2018-12-27  6:13   ` [RFC PATCH v4 09/13] genirq/msi: Add support for .msi_unprepare callback Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2019-01-15 14:41     ` Nishanth Menon
  2018-12-27  6:13   ` [RFC PATCH v4 11/13] dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings Lokesh Vutla
                     ` (2 subsequent siblings)
  11 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

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 are:
- inta_msi_create_irq_domain() that creates a MSI domain
- inta_msi_domain_alloc_group_irqs() that creates MSIs for the
  specified device and source indexes. All these are expected to
  be grouped by the parent interrupt controller to MSI domain.
- inta_msi_domain_free_group_irqs() frees the grouped irqs.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---

- May be the same functionaly can be included in platform msi. But I would
  like to get a feedback on the approach.

 drivers/soc/ti/Kconfig             |   6 +
 drivers/soc/ti/Makefile            |   1 +
 drivers/soc/ti/k3_inta_msi.c       | 193 +++++++++++++++++++++++++++++
 include/linux/irqdomain.h          |   1 +
 include/linux/msi.h                |   6 +
 include/linux/soc/ti/k3_inta_msi.h |  22 ++++
 6 files changed, 229 insertions(+)
 create mode 100644 drivers/soc/ti/k3_inta_msi.c
 create mode 100644 include/linux/soc/ti/k3_inta_msi.h

diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index be4570baad96..7640490c2a6a 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 K3_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..152b195273ee 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_K3_INTA_MSI_DOMAIN)	+= k3_inta_msi.o
diff --git a/drivers/soc/ti/k3_inta_msi.c b/drivers/soc/ti/k3_inta_msi.c
new file mode 100644
index 000000000000..4658a9f9e1c4
--- /dev/null
+++ b/drivers/soc/ti/k3_inta_msi.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments' K3 Interrupt Aggregator driver MSI support
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *	Lokesh Vutla <lokeshvutla@ti.com>
+ */
+
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
+#include <linux/soc/ti/k3_inta_msi.h>
+
+#ifdef GENERIC_MSI_DOMAIN_OPS
+
+#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 TO_HWIRQ(id, index)	(((id & TI_SCI_DEV_ID_MASK) << \
+				 TI_SCI_DEV_ID_SHIFT) | \
+				(index & TI_SCI_IRQ_ID_MASK))
+static void inta_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
+{
+	arg->desc = desc;
+	arg->hwirq = TO_HWIRQ(desc->inta.dev_id, desc->inta.msi_index);
+}
+#else
+#define inta_msi_set_desc NULL
+#endif
+
+static void inta_msi_update_dom_ops(struct msi_domain_info *info)
+{
+	struct msi_domain_ops *ops = info->ops;
+
+	BUG_ON(!ops);
+
+	if (ops->set_desc == NULL)
+		ops->set_desc = inta_msi_set_desc;
+}
+
+static void inta_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
+{
+}
+
+static void inta_msi_compose_msi_msg(struct irq_data *data,
+				     struct msi_msg *msg)
+{
+}
+
+static void inta_msi_update_chip_ops(struct msi_domain_info *info)
+{
+	struct irq_chip *chip = info->chip;
+
+	BUG_ON(!chip);
+	if (!chip->irq_mask)
+		chip->irq_mask = irq_chip_mask_parent;
+	if (!chip->irq_unmask)
+		chip->irq_unmask = irq_chip_unmask_parent;
+	if (!chip->irq_eoi)
+		chip->irq_eoi = irq_chip_eoi_parent;
+	if (!chip->irq_set_affinity)
+		chip->irq_set_affinity = msi_domain_set_affinity;
+	if (!chip->irq_write_msi_msg)
+		chip->irq_write_msi_msg = inta_msi_write_msg;
+	if (!chip->irq_compose_msi_msg)
+		chip->irq_compose_msi_msg = inta_msi_compose_msi_msg;
+}
+
+struct irq_domain *inta_msi_create_irq_domain(struct fwnode_handle *fwnode,
+					      struct msi_domain_info *info,
+					      struct irq_domain *parent)
+{
+	struct irq_domain *domain;
+
+	if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
+		inta_msi_update_dom_ops(info);
+	if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
+		inta_msi_update_chip_ops(info);
+
+	domain = msi_create_irq_domain(fwnode, info, parent);
+	if (domain)
+		irq_domain_update_bus_token(domain, DOMAIN_BUS_K3_INTA_MSI);
+
+	return domain;
+}
+EXPORT_SYMBOL_GPL(inta_msi_create_irq_domain);
+
+static struct msi_desc *inta_msi_alloc_desc(struct device *dev, u32 dev_id,
+					    u32 index)
+{
+	struct msi_desc *msi_desc;
+
+	msi_desc = alloc_msi_entry(dev, 1, NULL);
+	if (!msi_desc) {
+		dev_err(dev, "Failed to allocate msi entry\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	msi_desc->inta.msi_index = index;
+	msi_desc->inta.dev_id = dev_id;
+	INIT_LIST_HEAD(&msi_desc->list);
+	list_add_tail(&msi_desc->list, dev_to_msi_list(dev));
+
+	return msi_desc;
+}
+
+void inta_msi_domain_free_group_irqs(struct device *dev, u32 dev_id,
+				     int nr_irqs, u32 *arr_index)
+{
+	struct irq_domain *msi_domain;
+	struct msi_desc *desc, *tmp;
+	unsigned int i, virq = 0;
+
+	msi_domain = dev_get_msi_domain(dev);
+
+	list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) {
+		for (i = 0; i < nr_irqs; i++) {
+			if (desc->inta.msi_index == arr_index[i] &&
+			    desc->inta.dev_id == dev_id) {
+				msi_domain_free_irq(desc);
+				/* HACK to get parent IRQ. Any elegant solution? */
+				if (!virq)
+					virq = desc->msg.data;
+				list_del(&desc->list);
+				free_msi_entry(desc);
+			}
+		}
+	}
+
+	msi_domain_unprepare_irqs(msi_domain, nr_irqs, (void *)&virq);
+}
+EXPORT_SYMBOL_GPL(inta_msi_domain_free_group_irqs);
+
+int inta_msi_domain_alloc_group_irqs(struct device *dev, u32 dev_id,
+				     int nr_irqs, u32 *arr_index, u32 type)
+{
+	struct irq_domain *msi_domain;
+	struct msi_desc *msi_desc;
+	struct irq_data *irq_data;
+	msi_alloc_info_t arg;
+	int ret, i;
+
+	msi_domain = dev_get_msi_domain(dev);
+	if (!msi_domain)
+		return -EINVAL;
+
+	if (nr_irqs < 1)
+		return -EINVAL;
+
+	ret = msi_domain_prepare_irqs(msi_domain, dev, nr_irqs, &arg);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < nr_irqs; i++) {
+		msi_desc = inta_msi_alloc_desc(dev, dev_id, arr_index[i]);
+		if (IS_ERR(msi_desc)) {
+			ret = PTR_ERR(msi_desc);
+			goto cleanup;
+		}
+
+		ret = msi_domain_alloc_irq(msi_domain, dev, msi_desc, &arg);
+		if (ret) {
+			dev_err(dev, "Failed to allocate IRQs\n");
+			goto cleanup;
+		}
+		irq_data = irq_get_irq_data(msi_desc->irq);
+		irqd_set_trigger_type(irq_data, type);
+	}
+	return 0;
+
+cleanup:
+	inta_msi_domain_free_group_irqs(dev, dev_id, i, arr_index);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(inta_msi_domain_alloc_group_irqs);
+
+unsigned int inta_msi_get_virq(struct device *dev, u32 dev_id, u32 index)
+{
+	struct msi_desc *desc;
+
+	for_each_msi_entry(desc, dev)
+		if (desc->inta.msi_index == index &&
+		    desc->inta.dev_id == dev_id)
+			return desc->irq;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(inta_msi_get_virq);
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 35965f41d7be..05afb25062cf 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_K3_INTA_MSI,
 };
 
 /**
diff --git a/include/linux/msi.h b/include/linux/msi.h
index f35dd19f6c69..f3b009221241 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -47,6 +47,11 @@ struct fsl_mc_msi_desc {
 	u16				msi_index;
 };
 
+struct inta_msi_desc {
+	u16	dev_id;
+	u16	msi_index;
+};
+
 /**
  * struct msi_desc - Descriptor structure for MSI based interrupts
  * @list:	List head for management
@@ -106,6 +111,7 @@ struct msi_desc {
 		 */
 		struct platform_msi_desc platform;
 		struct fsl_mc_msi_desc fsl_mc;
+		struct inta_msi_desc inta;
 	};
 };
 
diff --git a/include/linux/soc/ti/k3_inta_msi.h b/include/linux/soc/ti/k3_inta_msi.h
new file mode 100644
index 000000000000..9c20fad86930
--- /dev/null
+++ b/include/linux/soc/ti/k3_inta_msi.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Texas Instruments' K3 INTA MSI helper
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *	Lokesh Vutla <lokeshvutla@ti.com>
+ */
+
+#ifndef __INCLUDE_LINUX_K3_INTA_MSI_H
+#define __INCLUDE_LINUX_K3_INTA_MSI_H
+
+#include <linux/msi.h>
+
+struct irq_domain *inta_msi_create_irq_domain(struct fwnode_handle *fwnode,
+					      struct msi_domain_info *info,
+					      struct irq_domain *parent);
+int inta_msi_domain_alloc_group_irqs(struct device *dev, u32 dev_id,
+				     int nr_irqs, u32 *arr_index, u32 flags);
+void inta_msi_domain_free_group_irqs(struct device *dev, u32 dev_id,
+				     int nr_irqs, u32 *arr_index);
+unsigned int inta_msi_get_virq(struct device *dev, u32 dev_id, u32 index);
+#endif /* __INCLUDE_LINUX_IRQCHIP_TI_SCI_INTA_H */
-- 
2.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH v4 11/13] dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                     ` (8 preceding siblings ...)
  2018-12-27  6:13   ` [RFC PATCH v4 10/13] soc: ti: Add MSI domain support for K3 Interrupt Aggregator Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2018-12-27  6:13   ` [RFC PATCH v4 12/13] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver Lokesh Vutla
  2018-12-27  6:13   ` [RFC PATCH v4 13/13] soc: ti: am6: Enable interrupt controller drivers Lokesh Vutla
  11 siblings, 0 replies; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

Add the DT binding documentation for Interrupt Aggregator driver.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
 .../interrupt-controller/ti,sci-inta.txt      | 74 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 2 files changed, 75 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..17b1fbd90312
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
@@ -0,0 +1,74 @@
+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
+- #interrupt-cells:	Specifies the number of cells needed to encode an
+			interrupt source. The value should be 4.
+			First cell should contain the TISCI device ID of source
+			Second cell should contain the event source offset
+			within the device
+			Third cell specified the interrupt number(vint)
+			reaching Interrupt aggregator.
+			Fourth cell specifies the trigger type as defined
+			in interrupts.txt in this directory.
+- interrupt-parent:	phandle of irq parent for TISCI intr.
+- 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:	TISCI subtype id representing the virtual interrupts
+			(vints) range within this IA, assigned to the
+			requesting host context.
+- ti,sci-rm-range-global-event:	TISCI subtype id 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;
+	interrupt-parent = <&main_navss_intr>;
+	#interrupt-cells = <4>;
+	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 4480eb2fe851..aebce615151e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15024,6 +15024,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.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH v4 12/13] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                     ` (9 preceding siblings ...)
  2018-12-27  6:13   ` [RFC PATCH v4 11/13] dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2019-01-02 11:49     ` Peter Ujfalusi
  2018-12-27  6:13   ` [RFC PATCH v4 13/13] soc: ti: am6: Enable interrupt controller drivers Lokesh Vutla
  11 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

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.

Add support for Interrupt Aggregator driver over TISCI protocol.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
 MAINTAINERS                       |   1 +
 drivers/irqchip/Kconfig           |  12 +
 drivers/irqchip/Makefile          |   1 +
 drivers/irqchip/irq-ti-sci-inta.c | 561 ++++++++++++++++++++++++++++++
 4 files changed, 575 insertions(+)
 create mode 100644 drivers/irqchip/irq-ti-sci-inta.c

diff --git a/MAINTAINERS b/MAINTAINERS
index aebce615151e..7d12788c844a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15026,6 +15026,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 <peter.ujfalusi@ti.com>
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index a8d9bed0254b..d16fd39408ad 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -417,6 +417,18 @@ 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 && ARCH_K3
+	select IRQ_DOMAIN
+	select IRQ_DOMAIN_HIERARCHY
+	select K3_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.
+	  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 b4ff376a08ef..a679490a7059 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -95,3 +95,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_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..78bfc83a079a
--- /dev/null
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -0,0 +1,561 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments' K3 Interrupt Aggregator irqchip driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *	Lokesh Vutla <lokeshvutla@ti.com>
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/msi.h>
+#include <linux/irqchip.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/irqdomain.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include <linux/soc/ti/k3_inta_msi.h>
+#include <linux/irqchip/chained_irq.h>
+#include <asm-generic/msi.h>
+
+#define MAX_EVENTS_PER_VINT	64
+
+#define VINT_ENABLE_SET_OFFSET	0x0
+#define VINT_ENABLE_CLR_OFFSET	0x8
+#define VINT_STATUS_OFFSET	0x18
+
+#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))
+
+/**
+ * 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.
+ * @base:	Base address of the memory mapped IO registers
+ * @ia_id:	TISCI device ID of this Interrupt Aggregator.
+ * @dst_id:	TISCI device ID of the destination irq controller.
+ */
+struct ti_sci_inta_irq_domain {
+	const struct ti_sci_handle *sci;
+	struct ti_sci_resource *vint;
+	struct ti_sci_resource *global_event;
+	void __iomem *base;
+	u16 ia_id;
+	u16 dst_id;
+};
+
+/**
+ * struct ti_sci_inta_event_desc - Description of an event coming to
+ *				   Interrupt Aggregator.
+ * @global_event:	Global event number corresponding to this event
+ * @src_id:		TISCI device ID of the event source
+ * @src_index:		Event source index within the device.
+ */
+struct ti_sci_inta_event_desc {
+	u16 global_event;
+	u16 src_id;
+	u16 src_index;
+};
+
+/**
+ * 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.
+ * @event_lock:		lock to guard the event map
+ * @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 mutex event_lock;
+	unsigned long *event_map;
+	struct ti_sci_inta_event_desc events[MAX_EVENTS_PER_VINT];
+	unsigned int parent_virq;
+	u16 vint_id;
+};
+
+static int __get_event_index(struct ti_sci_inta_vint_desc *vint_desc,
+			     int global_event)
+{
+	int event_index = -ENODEV, i;
+
+	for (i = 0; i < MAX_EVENTS_PER_VINT; i++) {
+		if (vint_desc->events[i].global_event == global_event)
+			event_index = i;
+	}
+
+	return event_index;
+}
+
+static void __ti_sci_inta_manage_event(struct irq_data *data, u32 offset)
+{
+	struct ti_sci_inta_vint_desc *vint_desc;
+	struct ti_sci_inta_irq_domain *inta;
+	int global_event, event_index;
+
+	vint_desc = irq_data_get_irq_chip_data(data);
+	global_event = data->hwirq;
+	event_index = __get_event_index(vint_desc, global_event);
+	inta = vint_desc->domain->host_data;
+
+	if (event_index < 0)
+		return;
+
+	writeq_relaxed(BIT(event_index), inta->base +
+		       vint_desc->vint_id * 0x1000 + offset);
+}
+
+static void ti_sci_inta_mask_irq(struct irq_data *data)
+{
+	__ti_sci_inta_manage_event(data, VINT_ENABLE_CLR_OFFSET);
+}
+
+static void ti_sci_inta_unmask_irq(struct irq_data *data)
+{
+	__ti_sci_inta_manage_event(data, VINT_ENABLE_SET_OFFSET);
+}
+
+static int ti_sci_inta_set_affinity(struct irq_data *d,
+				    const struct cpumask *mask_val, bool force)
+{
+	struct ti_sci_inta_vint_desc *vint_desc = irq_data_get_irq_chip_data(d);
+	struct irq_chip *chip = irq_get_chip(vint_desc->parent_virq);
+	struct irq_data *data = irq_get_irq_data(vint_desc->parent_virq);
+
+	if (chip && chip->irq_set_affinity)
+		return chip->irq_set_affinity(data, mask_val, force);
+	else
+		return -EINVAL;
+}
+
+static struct irq_chip ti_sci_inta_irq_chip = {
+	.name			= "INTA",
+	.irq_mask		= ti_sci_inta_mask_irq,
+	.irq_unmask		= ti_sci_inta_unmask_irq,
+	.irq_set_affinity	= ti_sci_inta_set_affinity,
+};
+
+/**
+ * ti_sci_free_event_irq() - Free an event from vint
+ * @domain:	Pointer to Interrupt Aggregator IRQ domain
+ * @vint_desc:	Virtual interrupt descriptor containing the event.
+ * @global_event: Global event id to be freed.
+ */
+static void ti_sci_free_event_irq(struct irq_domain *domain,
+				  struct ti_sci_inta_vint_desc *vint_desc,
+				  u16 global_event)
+{
+	struct ti_sci_inta_irq_domain *inta = domain->host_data;
+	struct ti_sci_inta_event_desc *event_desc;
+	struct irq_data *gic_data;
+	int event_index = 0;
+
+	event_index = __get_event_index(vint_desc, global_event);
+	gic_data = irq_domain_get_irq_data(domain->parent->parent,
+					   vint_desc->parent_virq);
+	event_desc = &vint_desc->events[event_index];
+	inta->sci->ops.rm_irq_ops.free_event_irq(inta->sci,
+						 event_desc->src_id,
+						 event_desc->src_index,
+						 inta->dst_id,
+						 gic_data->hwirq,
+						 inta->ia_id,
+						 vint_desc->vint_id,
+						 event_desc->global_event,
+						 event_index);
+
+	clear_bit(event_index, vint_desc->event_map);
+
+	ti_sci_release_resource(inta->global_event, event_desc->global_event);
+}
+
+static void ti_sci_inta_free_vint(struct ti_sci_inta_irq_domain *inta,
+				  struct ti_sci_inta_vint_desc *vint_desc)
+{
+	/* If all events are cleared, delete parent irq */
+	if (find_first_bit(vint_desc->event_map, MAX_EVENTS_PER_VINT) ==
+	    MAX_EVENTS_PER_VINT) {
+		irq_dispose_mapping(vint_desc->parent_virq);
+		ti_sci_release_resource(inta->vint, vint_desc->vint_id);
+		kfree(vint_desc->event_map);
+		kfree(vint_desc);
+	}
+}
+
+/**
+ * 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_desc *desc = irq_to_desc(virq);
+	struct ti_sci_inta_vint_desc *vint_desc;
+	struct msi_desc *mdesc;
+	struct irq_data *data;
+
+	mdesc = desc->irq_common_data.msi_desc;
+	data = irq_domain_get_irq_data(domain, virq);
+	vint_desc = irq_data_get_irq_chip_data(data);
+
+	mdesc->msg.data = vint_desc->parent_virq;
+	ti_sci_free_event_irq(domain, vint_desc, data->hwirq);
+	irq_domain_reset_irq_data(data);
+}
+
+/**
+ * ti_sci_allocate_event_irq() - Allocate an event to a IA vint.
+ *
+ * Return 0 if all went ok else appropriate error value.
+ */
+static struct ti_sci_inta_event_desc *
+ti_sci_allocate_event_irq(struct irq_domain *domain, msi_alloc_info_t *arg)
+{
+	struct ti_sci_inta_irq_domain *inta = domain->host_data;
+	struct ti_sci_inta_event_desc *event_desc;
+	u16 free_bit, src_id, src_index, dst_irq;
+	struct ti_sci_inta_vint_desc *vint_desc;
+	struct irq_data *gic_data;
+	int err;
+
+	src_id = HWIRQ_TO_DEVID(arg->hwirq);
+	src_index = HWIRQ_TO_IRQID(arg->hwirq);
+	vint_desc = arg->scratchpad[0].ptr;
+	gic_data = irq_domain_get_irq_data(domain->parent->parent,
+					   vint_desc->parent_virq);
+	dst_irq = gic_data->hwirq;
+
+	mutex_lock(&vint_desc->event_lock);
+	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);
+	mutex_unlock(&vint_desc->event_lock);
+
+	event_desc = &vint_desc->events[free_bit];
+
+	event_desc->src_id = src_id;
+	event_desc->src_index = src_index;
+	event_desc->global_event = ti_sci_get_free_resource(inta->global_event);
+	if (event_desc->global_event == TI_SCI_RESOURCE_NULL) {
+		err = -EINVAL;
+		goto free_event;
+	}
+
+	err = inta->sci->ops.rm_irq_ops.set_event_irq(inta->sci,
+						      src_id, src_index,
+						      inta->dst_id,
+						      dst_irq,
+						      inta->ia_id,
+						      vint_desc->vint_id,
+						      event_desc->global_event,
+						      free_bit);
+	if (err) {
+		pr_err("%s: Event allocation failed from src = %d, index = %d, to dst = %d,irq = %d,via ia_id = %d, vint = %d,global event = %d, status_bit = %d\n",
+		       __func__, src_id, src_index, inta->dst_id, dst_irq,
+		       inta->ia_id, vint_desc->vint_id,
+		       event_desc->global_event, free_bit);
+		goto free_global_event;
+	}
+
+	return event_desc;
+free_global_event:
+	ti_sci_release_resource(inta->global_event, event_desc->global_event);
+free_event:
+	clear_bit(free_bit, vint_desc->event_map);
+	return ERR_PTR(err);
+}
+
+static void inta_msi_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;
+	struct irq_data *irq_data;
+	u32 hwirq, bit, virq;
+	u64 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 (bit = 0; bit < MAX_EVENTS_PER_VINT; bit++) {
+		if (BIT(bit) & val) {
+			hwirq = vint_desc->events[bit].global_event;
+			virq = irq_find_mapping(domain, hwirq);
+			irq_data = irq_get_irq_data(virq);
+			if (irqd_get_trigger_type(irq_data) ==
+			    IRQF_TRIGGER_HIGH)
+				writeq_relaxed(BIT(bit),
+					       inta->base + vint_desc->vint_id *
+					       0x1000 + VINT_STATUS_OFFSET);
+
+			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
+ * @virq:	Linux virtual IRQ number
+ *
+ * Return pointer to vint descriptor if all went well else corresponding
+ * error pointer.
+ */
+static struct ti_sci_inta_vint_desc *
+ti_sci_inta_alloc_parent_irq(struct irq_domain *domain, msi_alloc_info_t *arg)
+{
+	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 virq;
+
+	if (!irq_domain_get_of_node(domain->parent))
+		return ERR_PTR(-EINVAL);
+
+	vint_desc = kzalloc(sizeof(*vint_desc), GFP_KERNEL);
+	if (!vint_desc)
+		return ERR_PTR(-ENOMEM);
+
+	vint_desc->event_map = kcalloc(BITS_TO_LONGS(MAX_EVENTS_PER_VINT),
+				       sizeof(*vint_desc->event_map),
+				       GFP_KERNEL);
+	if (!vint_desc->event_map) {
+		kfree(vint_desc);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	vint_desc->domain = domain;
+	vint_desc->vint_id = ti_sci_get_free_resource(inta->vint);
+
+	parent_fwspec.fwnode = domain->parent->fwnode;
+	parent_fwspec.param_count = 4;
+	/* Interrupt parent is Interrupt Router */
+	parent_fwspec.param[0] = inta->ia_id;
+	parent_fwspec.param[1] = vint_desc->vint_id;
+	parent_fwspec.param[2] = IRQF_TRIGGER_HIGH;
+	parent_fwspec.param[3] = 1;
+
+	virq = irq_create_fwspec_mapping(&parent_fwspec);
+	if (virq <= 0)
+		goto err_irqs;
+
+	irq_set_chained_handler_and_data(virq, inta_msi_irq_handler, vint_desc);
+	vint_desc->parent_virq = virq;
+
+	mutex_init(&vint_desc->event_lock);
+
+	return vint_desc;
+
+err_irqs:
+	ti_sci_release_resource(inta->vint, vint_desc->vint_id);
+	kfree(vint_desc);
+	return ERR_PTR(virq);
+}
+
+/**
+ * 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
+ *
+ * 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)
+{
+	struct ti_sci_inta_event_desc *event_desc;
+	msi_alloc_info_t *arg = data;
+
+	event_desc = ti_sci_allocate_event_irq(domain, arg);
+	if (IS_ERR(event_desc)) {
+		ti_sci_inta_free_vint(domain->host_data,
+				      arg->scratchpad[0].ptr);
+		return PTR_ERR(event_desc);
+	}
+
+	irq_domain_set_info(domain, virq, event_desc->global_event,
+			    &ti_sci_inta_irq_chip, arg->scratchpad[0].ptr,
+			    handle_simple_irq, NULL, NULL);
+
+	return 0;
+}
+
+static const struct irq_domain_ops ti_sci_inta_irq_domain_ops = {
+	.alloc		= ti_sci_inta_irq_domain_alloc,
+	.free		= ti_sci_inta_irq_domain_free,
+};
+
+static int inta_msi_domain_ops_prepare(struct irq_domain *domain,
+				       struct device *dev, int nvec,
+				       msi_alloc_info_t *arg)
+{
+	struct ti_sci_inta_vint_desc *vint_desc;
+
+	memset(arg, 0, sizeof(*arg));
+
+	vint_desc = ti_sci_inta_alloc_parent_irq(domain->parent, arg);
+	if (IS_ERR(vint_desc))
+		return PTR_ERR(vint_desc);
+	arg->scratchpad[0].ptr = vint_desc;
+
+	return 0;
+}
+
+void inta_msi_domain_ops_unprepare(struct irq_domain *domain, int nvec,
+				   void *data)
+{
+	struct ti_sci_inta_irq_domain *inta = domain->parent->host_data;
+	struct ti_sci_inta_vint_desc *vint_desc;
+	struct irq_desc *desc;
+	unsigned int virq;
+
+	virq = *(unsigned int *)data;
+	desc = irq_to_desc(virq);
+	vint_desc = irq_desc_get_handler_data(desc);
+	ti_sci_inta_free_vint(inta, vint_desc);
+}
+
+static struct irq_chip inta_msi_irq_chip = {
+	.name		= "MSI-INTA",
+};
+
+static struct msi_domain_ops inta_msi_ops = {
+	.msi_prepare	= inta_msi_domain_ops_prepare,
+	.msi_unprepare	= inta_msi_domain_ops_unprepare,
+};
+
+static struct msi_domain_info inta_msi_domain_info = {
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
+	.ops	= &inta_msi_ops,
+	.chip	= &inta_msi_irq_chip,
+};
+
+static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
+{
+	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;
+	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->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",
+				   (u32 *)&inta->ia_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,
+						 inta->ia_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,
+					    inta->ia_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;
+
+	ret = of_property_read_u32(parent_node, "ti,sci-dst-id",
+				   (u32 *)&inta->dst_id);
+
+	domain = irq_domain_add_hierarchy(parent_domain, 0, 0, dev_of_node(dev),
+					  &ti_sci_inta_irq_domain_ops, inta);
+	if (!domain) {
+		dev_err(dev, "Failed to allocate IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	msi_domain = inta_msi_create_irq_domain(of_node_to_fwnode(node),
+						&inta_msi_domain_info,
+						domain);
+	if (!msi_domain) {
+		irq_domain_remove(domain);
+		dev_err(dev, "Failed to allocate msi domain\n");
+		return -ENOMEM;
+	}
+
+	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.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH v4 13/13] soc: ti: am6: Enable interrupt controller drivers
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
                     ` (10 preceding siblings ...)
  2018-12-27  6:13   ` [RFC PATCH v4 12/13] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver Lokesh Vutla
@ 2018-12-27  6:13   ` Lokesh Vutla
  2019-01-15 13:54     ` Nishanth Menon
  11 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2018-12-27  6:13 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi, Lokesh Vutla

Select all the TISCI dependent interrupt controller drivers
for AM6 SoC.

Suggested-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
 drivers/soc/ti/Kconfig | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index 7640490c2a6a..145b701a3d96 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -5,6 +5,11 @@ if ARCH_K3
 
 config ARCH_K3_AM6_SOC
 	bool "K3 AM6 SoC"
+	select MAILBOX
+	select TI_MESSAGE_MANAGER
+	select TI_SCI_PROTOCOL
+	select TI_SCI_INTR_IRQCHIP
+	select TI_SCI_INTA_IRQCHIP
 	help
 	  Enable support for TI's AM6 SoC Family support
 
-- 
2.19.2


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v4 05/13] firmware: ti_sci: Add helper apis to manage resources
  2018-12-27  6:13   ` [PATCH v4 05/13] firmware: ti_sci: Add helper apis to manage resources Lokesh Vutla
@ 2018-12-27 16:15     ` Nishanth Menon
  0 siblings, 0 replies; 31+ messages in thread
From: Nishanth Menon @ 2018-12-27 16:15 UTC (permalink / raw)
  To: Lokesh Vutla
  Cc: marc.zyngier, Santosh Shilimkar, Rob Herring, tglx, jason,
	Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

On 11:43-20181227, Lokesh Vutla wrote:
> Each resource with in the device can be uniquely identified
> by a type and subtype 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 <lokeshvutla@ti.com>
> ---
>  drivers/firmware/ti_sci.c              | 126 +++++++++++++++++++++++++
>  include/linux/soc/ti/ti_sci_protocol.h |  48 ++++++++++
>  2 files changed, 174 insertions(+)
> 
> diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
> index c2f0815edab6..b6804c214be9 100644
> --- a/drivers/firmware/ti_sci.c
> +++ b/drivers/firmware/ti_sci.c
> @@ -2480,6 +2480,132 @@ 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
> + */
> +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);
> +
> +/**
> + * 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
> + * @of_prop:	property name by which the resource are represented
> + *
> + * Note: This function expects of_prop to be in the form of tuples
> + *	<type, subtype>. Allocates and initializes ti_sci_resource structure
> + *	for each of_prop. Client driver can directly call
> + *	ti_sci_(get_free, release)_resource apis for handling the resource.
> + *
> + * 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;
> +	u16 resource_type;
> +	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);
> +
> +	ret = ti_sci_get_resource_type(handle_to_ti_sci_info(handle), dev_id,
> +				       &resource_type);
> +	if (ret) {
> +		dev_err(dev, "No valid resource type for %u\n", dev_id);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	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, "type %d subtype %d not allocated for host %d\n",
> +				resource_type, resource_subtype,
> +				handle_to_ti_sci_info(handle)->host_id);
> +			return ERR_PTR(ret);
> +		}
> +
> +		dev_dbg(dev, "res type = %d, subtype = %d, start = %d, num = %d\n",
> +			resource_type, 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);

Again - ofparse, I'd rather keep out of this unless directly used by
tisci layer. There are'nt too many of these parse needs and they can
easily be incorporated as part of corresponding drivers such as irqchip
or ra drivers, no?

the pain here is that without an approved set of binding, and valid
users, the entire series will make no sense to incorporate.

> +
> +	return res;
> +}
> +EXPORT_SYMBOL_GPL(devm_ti_sci_get_of_resource);
> +
>  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 6d17580839dc..2a1a41a17295 100644
> --- a/include/linux/soc/ti/ti_sci_protocol.h
> +++ b/include/linux/soc/ti/ti_sci_protocol.h
> @@ -317,6 +317,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);
> @@ -325,6 +352,11 @@ 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);
> +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 */
>  
> @@ -357,6 +389,22 @@ 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 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.19.2
> 

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 12/13] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
  2018-12-27  6:13   ` [RFC PATCH v4 12/13] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver Lokesh Vutla
@ 2019-01-02 11:49     ` Peter Ujfalusi
  2019-01-02 12:26       ` Lokesh Vutla
  0 siblings, 1 reply; 31+ messages in thread
From: Peter Ujfalusi @ 2019-01-02 11:49 UTC (permalink / raw)
  To: Lokesh Vutla, marc.zyngier, Nishanth Menon, Santosh Shilimkar,
	Rob Herring, tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List




On 27/12/2018 8.13, Lokesh Vutla wrote:
> 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.
> 
> Add support for Interrupt Aggregator driver over TISCI protocol.
> 
> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> ---
>  MAINTAINERS                       |   1 +
>  drivers/irqchip/Kconfig           |  12 +
>  drivers/irqchip/Makefile          |   1 +
>  drivers/irqchip/irq-ti-sci-inta.c | 561 ++++++++++++++++++++++++++++++
>  4 files changed, 575 insertions(+)
>  create mode 100644 drivers/irqchip/irq-ti-sci-inta.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aebce615151e..7d12788c844a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15026,6 +15026,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 <peter.ujfalusi@ti.com>
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index a8d9bed0254b..d16fd39408ad 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -417,6 +417,18 @@ 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 && ARCH_K3
> +	select IRQ_DOMAIN
> +	select IRQ_DOMAIN_HIERARCHY
> +	select K3_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.
> +	  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 b4ff376a08ef..a679490a7059 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -95,3 +95,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_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..78bfc83a079a
> --- /dev/null
> +++ b/drivers/irqchip/irq-ti-sci-inta.c
> @@ -0,0 +1,561 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Texas Instruments' K3 Interrupt Aggregator irqchip driver
> + *
> + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
> + *	Lokesh Vutla <lokeshvutla@ti.com>
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/msi.h>
> +#include <linux/irqchip.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/irqdomain.h>

To fix this:

drivers/irqchip/irq-ti-sci-inta.c: In function ‘inta_msi_irq_handler’:
drivers/irqchip/irq-ti-sci-inta.c:308:8: error: ‘IRQF_TRIGGER_HIGH’ undeclared (first use in this function); did you mean ‘IRQD_TRIGGER_MASK’?
        IRQF_TRIGGER_HIGH)
        ^~~~~~~~~~~~~~~~~
        IRQD_TRIGGER_MASK
drivers/irqchip/irq-ti-sci-inta.c:308:8: note: each undeclared identifier is reported only once for each function it appears in
drivers/irqchip/irq-ti-sci-inta.c: In function ‘ti_sci_inta_alloc_parent_irq’:
drivers/irqchip/irq-ti-sci-inta.c:360:27: error: ‘IRQF_TRIGGER_HIGH’ undeclared (first use in this function); did you mean ‘IRQD_TRIGGER_MASK’?
  parent_fwspec.param[2] = IRQF_TRIGGER_HIGH;
                           ^~~~~~~~~~~~~~~~~
                           IRQD_TRIGGER_MASK
make[3]: *** [scripts/Makefile.build:276: drivers/irqchip/irq-ti-sci-inta.o] Error 1

Add this:
#include <linux/interrupt.h>
> +#include <linux/soc/ti/ti_sci_protocol.h>
> +#include <linux/soc/ti/k3_inta_msi.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <asm-generic/msi.h>
> +
> +#define MAX_EVENTS_PER_VINT	64
> +
> +#define VINT_ENABLE_SET_OFFSET	0x0
> +#define VINT_ENABLE_CLR_OFFSET	0x8
> +#define VINT_STATUS_OFFSET	0x18
> +
> +#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))
> +
> +/**
> + * 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.
> + * @base:	Base address of the memory mapped IO registers
> + * @ia_id:	TISCI device ID of this Interrupt Aggregator.
> + * @dst_id:	TISCI device ID of the destination irq controller.
> + */
> +struct ti_sci_inta_irq_domain {
> +	const struct ti_sci_handle *sci;
> +	struct ti_sci_resource *vint;
> +	struct ti_sci_resource *global_event;
> +	void __iomem *base;
> +	u16 ia_id;
> +	u16 dst_id;
> +};
> +
> +/**
> + * struct ti_sci_inta_event_desc - Description of an event coming to
> + *				   Interrupt Aggregator.
> + * @global_event:	Global event number corresponding to this event
> + * @src_id:		TISCI device ID of the event source
> + * @src_index:		Event source index within the device.
> + */
> +struct ti_sci_inta_event_desc {
> +	u16 global_event;
> +	u16 src_id;
> +	u16 src_index;
> +};
> +
> +/**
> + * 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.
> + * @event_lock:		lock to guard the event map
> + * @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 mutex event_lock;
> +	unsigned long *event_map;
> +	struct ti_sci_inta_event_desc events[MAX_EVENTS_PER_VINT];
> +	unsigned int parent_virq;
> +	u16 vint_id;
> +};
> +
> +static int __get_event_index(struct ti_sci_inta_vint_desc *vint_desc,
> +			     int global_event)
> +{
> +	int event_index = -ENODEV, i;
> +
> +	for (i = 0; i < MAX_EVENTS_PER_VINT; i++) {
> +		if (vint_desc->events[i].global_event == global_event)
> +			event_index = i;
> +	}
> +
> +	return event_index;
> +}
> +
> +static void __ti_sci_inta_manage_event(struct irq_data *data, u32 offset)
> +{
> +	struct ti_sci_inta_vint_desc *vint_desc;
> +	struct ti_sci_inta_irq_domain *inta;
> +	int global_event, event_index;
> +
> +	vint_desc = irq_data_get_irq_chip_data(data);
> +	global_event = data->hwirq;
> +	event_index = __get_event_index(vint_desc, global_event);
> +	inta = vint_desc->domain->host_data;
> +
> +	if (event_index < 0)
> +		return;
> +
> +	writeq_relaxed(BIT(event_index), inta->base +
> +		       vint_desc->vint_id * 0x1000 + offset);
> +}
> +
> +static void ti_sci_inta_mask_irq(struct irq_data *data)
> +{
> +	__ti_sci_inta_manage_event(data, VINT_ENABLE_CLR_OFFSET);
> +}
> +
> +static void ti_sci_inta_unmask_irq(struct irq_data *data)
> +{
> +	__ti_sci_inta_manage_event(data, VINT_ENABLE_SET_OFFSET);
> +}
> +
> +static int ti_sci_inta_set_affinity(struct irq_data *d,
> +				    const struct cpumask *mask_val, bool force)
> +{
> +	struct ti_sci_inta_vint_desc *vint_desc = irq_data_get_irq_chip_data(d);
> +	struct irq_chip *chip = irq_get_chip(vint_desc->parent_virq);
> +	struct irq_data *data = irq_get_irq_data(vint_desc->parent_virq);
> +
> +	if (chip && chip->irq_set_affinity)
> +		return chip->irq_set_affinity(data, mask_val, force);
> +	else
> +		return -EINVAL;
> +}
> +
> +static struct irq_chip ti_sci_inta_irq_chip = {
> +	.name			= "INTA",
> +	.irq_mask		= ti_sci_inta_mask_irq,
> +	.irq_unmask		= ti_sci_inta_unmask_irq,
> +	.irq_set_affinity	= ti_sci_inta_set_affinity,
> +};
> +
> +/**
> + * ti_sci_free_event_irq() - Free an event from vint
> + * @domain:	Pointer to Interrupt Aggregator IRQ domain
> + * @vint_desc:	Virtual interrupt descriptor containing the event.
> + * @global_event: Global event id to be freed.
> + */
> +static void ti_sci_free_event_irq(struct irq_domain *domain,
> +				  struct ti_sci_inta_vint_desc *vint_desc,
> +				  u16 global_event)
> +{
> +	struct ti_sci_inta_irq_domain *inta = domain->host_data;
> +	struct ti_sci_inta_event_desc *event_desc;
> +	struct irq_data *gic_data;
> +	int event_index = 0;
> +
> +	event_index = __get_event_index(vint_desc, global_event);
> +	gic_data = irq_domain_get_irq_data(domain->parent->parent,
> +					   vint_desc->parent_virq);
> +	event_desc = &vint_desc->events[event_index];
> +	inta->sci->ops.rm_irq_ops.free_event_irq(inta->sci,
> +						 event_desc->src_id,
> +						 event_desc->src_index,
> +						 inta->dst_id,
> +						 gic_data->hwirq,
> +						 inta->ia_id,
> +						 vint_desc->vint_id,
> +						 event_desc->global_event,
> +						 event_index);
> +
> +	clear_bit(event_index, vint_desc->event_map);
> +
> +	ti_sci_release_resource(inta->global_event, event_desc->global_event);
> +}
> +
> +static void ti_sci_inta_free_vint(struct ti_sci_inta_irq_domain *inta,
> +				  struct ti_sci_inta_vint_desc *vint_desc)
> +{
> +	/* If all events are cleared, delete parent irq */
> +	if (find_first_bit(vint_desc->event_map, MAX_EVENTS_PER_VINT) ==
> +	    MAX_EVENTS_PER_VINT) {
> +		irq_dispose_mapping(vint_desc->parent_virq);
> +		ti_sci_release_resource(inta->vint, vint_desc->vint_id);
> +		kfree(vint_desc->event_map);
> +		kfree(vint_desc);
> +	}
> +}
> +
> +/**
> + * 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_desc *desc = irq_to_desc(virq);
> +	struct ti_sci_inta_vint_desc *vint_desc;
> +	struct msi_desc *mdesc;
> +	struct irq_data *data;
> +
> +	mdesc = desc->irq_common_data.msi_desc;
> +	data = irq_domain_get_irq_data(domain, virq);
> +	vint_desc = irq_data_get_irq_chip_data(data);
> +
> +	mdesc->msg.data = vint_desc->parent_virq;
> +	ti_sci_free_event_irq(domain, vint_desc, data->hwirq);
> +	irq_domain_reset_irq_data(data);
> +}
> +
> +/**
> + * ti_sci_allocate_event_irq() - Allocate an event to a IA vint.
> + *
> + * Return 0 if all went ok else appropriate error value.
> + */
> +static struct ti_sci_inta_event_desc *
> +ti_sci_allocate_event_irq(struct irq_domain *domain, msi_alloc_info_t *arg)
> +{
> +	struct ti_sci_inta_irq_domain *inta = domain->host_data;
> +	struct ti_sci_inta_event_desc *event_desc;
> +	u16 free_bit, src_id, src_index, dst_irq;
> +	struct ti_sci_inta_vint_desc *vint_desc;
> +	struct irq_data *gic_data;
> +	int err;
> +
> +	src_id = HWIRQ_TO_DEVID(arg->hwirq);
> +	src_index = HWIRQ_TO_IRQID(arg->hwirq);
> +	vint_desc = arg->scratchpad[0].ptr;
> +	gic_data = irq_domain_get_irq_data(domain->parent->parent,
> +					   vint_desc->parent_virq);
> +	dst_irq = gic_data->hwirq;
> +
> +	mutex_lock(&vint_desc->event_lock);
> +	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);
> +	mutex_unlock(&vint_desc->event_lock);
> +
> +	event_desc = &vint_desc->events[free_bit];
> +
> +	event_desc->src_id = src_id;
> +	event_desc->src_index = src_index;
> +	event_desc->global_event = ti_sci_get_free_resource(inta->global_event);
> +	if (event_desc->global_event == TI_SCI_RESOURCE_NULL) {
> +		err = -EINVAL;
> +		goto free_event;
> +	}
> +
> +	err = inta->sci->ops.rm_irq_ops.set_event_irq(inta->sci,
> +						      src_id, src_index,
> +						      inta->dst_id,
> +						      dst_irq,
> +						      inta->ia_id,
> +						      vint_desc->vint_id,
> +						      event_desc->global_event,
> +						      free_bit);
> +	if (err) {
> +		pr_err("%s: Event allocation failed from src = %d, index = %d, to dst = %d,irq = %d,via ia_id = %d, vint = %d,global event = %d, status_bit = %d\n",
> +		       __func__, src_id, src_index, inta->dst_id, dst_irq,
> +		       inta->ia_id, vint_desc->vint_id,
> +		       event_desc->global_event, free_bit);
> +		goto free_global_event;
> +	}
> +
> +	return event_desc;
> +free_global_event:
> +	ti_sci_release_resource(inta->global_event, event_desc->global_event);
> +free_event:
> +	clear_bit(free_bit, vint_desc->event_map);
> +	return ERR_PTR(err);
> +}
> +
> +static void inta_msi_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;
> +	struct irq_data *irq_data;
> +	u32 hwirq, bit, virq;
> +	u64 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 (bit = 0; bit < MAX_EVENTS_PER_VINT; bit++) {
> +		if (BIT(bit) & val) {
> +			hwirq = vint_desc->events[bit].global_event;
> +			virq = irq_find_mapping(domain, hwirq);
> +			irq_data = irq_get_irq_data(virq);
> +			if (irqd_get_trigger_type(irq_data) ==
> +			    IRQF_TRIGGER_HIGH)
> +				writeq_relaxed(BIT(bit),
> +					       inta->base + vint_desc->vint_id *
> +					       0x1000 + VINT_STATUS_OFFSET);
> +
> +			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
> + * @virq:	Linux virtual IRQ number
> + *
> + * Return pointer to vint descriptor if all went well else corresponding
> + * error pointer.
> + */
> +static struct ti_sci_inta_vint_desc *
> +ti_sci_inta_alloc_parent_irq(struct irq_domain *domain, msi_alloc_info_t *arg)
> +{
> +	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 virq;
> +
> +	if (!irq_domain_get_of_node(domain->parent))
> +		return ERR_PTR(-EINVAL);
> +
> +	vint_desc = kzalloc(sizeof(*vint_desc), GFP_KERNEL);
> +	if (!vint_desc)
> +		return ERR_PTR(-ENOMEM);
> +
> +	vint_desc->event_map = kcalloc(BITS_TO_LONGS(MAX_EVENTS_PER_VINT),
> +				       sizeof(*vint_desc->event_map),
> +				       GFP_KERNEL);
> +	if (!vint_desc->event_map) {
> +		kfree(vint_desc);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	vint_desc->domain = domain;
> +	vint_desc->vint_id = ti_sci_get_free_resource(inta->vint);
> +
> +	parent_fwspec.fwnode = domain->parent->fwnode;
> +	parent_fwspec.param_count = 4;
> +	/* Interrupt parent is Interrupt Router */
> +	parent_fwspec.param[0] = inta->ia_id;
> +	parent_fwspec.param[1] = vint_desc->vint_id;
> +	parent_fwspec.param[2] = IRQF_TRIGGER_HIGH;
> +	parent_fwspec.param[3] = 1;
> +
> +	virq = irq_create_fwspec_mapping(&parent_fwspec);
> +	if (virq <= 0)
> +		goto err_irqs;
> +
> +	irq_set_chained_handler_and_data(virq, inta_msi_irq_handler, vint_desc);
> +	vint_desc->parent_virq = virq;
> +
> +	mutex_init(&vint_desc->event_lock);
> +
> +	return vint_desc;
> +
> +err_irqs:
> +	ti_sci_release_resource(inta->vint, vint_desc->vint_id);
> +	kfree(vint_desc);
> +	return ERR_PTR(virq);
> +}
> +
> +/**
> + * 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
> + *
> + * 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)
> +{
> +	struct ti_sci_inta_event_desc *event_desc;
> +	msi_alloc_info_t *arg = data;
> +
> +	event_desc = ti_sci_allocate_event_irq(domain, arg);
> +	if (IS_ERR(event_desc)) {
> +		ti_sci_inta_free_vint(domain->host_data,
> +				      arg->scratchpad[0].ptr);
> +		return PTR_ERR(event_desc);
> +	}
> +
> +	irq_domain_set_info(domain, virq, event_desc->global_event,
> +			    &ti_sci_inta_irq_chip, arg->scratchpad[0].ptr,
> +			    handle_simple_irq, NULL, NULL);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops ti_sci_inta_irq_domain_ops = {
> +	.alloc		= ti_sci_inta_irq_domain_alloc,
> +	.free		= ti_sci_inta_irq_domain_free,
> +};
> +
> +static int inta_msi_domain_ops_prepare(struct irq_domain *domain,
> +				       struct device *dev, int nvec,
> +				       msi_alloc_info_t *arg)
> +{
> +	struct ti_sci_inta_vint_desc *vint_desc;
> +
> +	memset(arg, 0, sizeof(*arg));
> +
> +	vint_desc = ti_sci_inta_alloc_parent_irq(domain->parent, arg);
> +	if (IS_ERR(vint_desc))
> +		return PTR_ERR(vint_desc);
> +	arg->scratchpad[0].ptr = vint_desc;
> +
> +	return 0;
> +}
> +
> +void inta_msi_domain_ops_unprepare(struct irq_domain *domain, int nvec,
> +				   void *data)
> +{
> +	struct ti_sci_inta_irq_domain *inta = domain->parent->host_data;
> +	struct ti_sci_inta_vint_desc *vint_desc;
> +	struct irq_desc *desc;
> +	unsigned int virq;
> +
> +	virq = *(unsigned int *)data;
> +	desc = irq_to_desc(virq);
> +	vint_desc = irq_desc_get_handler_data(desc);
> +	ti_sci_inta_free_vint(inta, vint_desc);
> +}
> +
> +static struct irq_chip inta_msi_irq_chip = {
> +	.name		= "MSI-INTA",
> +};
> +
> +static struct msi_domain_ops inta_msi_ops = {
> +	.msi_prepare	= inta_msi_domain_ops_prepare,
> +	.msi_unprepare	= inta_msi_domain_ops_unprepare,
> +};
> +
> +static struct msi_domain_info inta_msi_domain_info = {
> +	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
> +	.ops	= &inta_msi_ops,
> +	.chip	= &inta_msi_irq_chip,
> +};
> +
> +static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
> +{
> +	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;
> +	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->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",
> +				   (u32 *)&inta->ia_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,
> +						 inta->ia_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,
> +					    inta->ia_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;
> +
> +	ret = of_property_read_u32(parent_node, "ti,sci-dst-id",
> +				   (u32 *)&inta->dst_id);
> +
> +	domain = irq_domain_add_hierarchy(parent_domain, 0, 0, dev_of_node(dev),
> +					  &ti_sci_inta_irq_domain_ops, inta);
> +	if (!domain) {
> +		dev_err(dev, "Failed to allocate IRQ domain\n");
> +		return -ENOMEM;
> +	}
> +
> +	msi_domain = inta_msi_create_irq_domain(of_node_to_fwnode(node),
> +						&inta_msi_domain_info,
> +						domain);
> +	if (!msi_domain) {
> +		irq_domain_remove(domain);
> +		dev_err(dev, "Failed to allocate msi domain\n");
> +		return -ENOMEM;
> +	}
> +
> +	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");
> 

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v4 00/13] Add support for TISCI irqchip drivers
  2018-12-27  6:08 [PATCH v4 00/13] Add support for TISCI irqchip drivers Lokesh Vutla
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
@ 2019-01-02 11:58 ` Peter Ujfalusi
  2019-01-11 10:28 ` Lokesh Vutla
  2 siblings, 0 replies; 31+ messages in thread
From: Peter Ujfalusi @ 2019-01-02 11:58 UTC (permalink / raw)
  To: Lokesh Vutla, marc.zyngier, Nishanth Menon, Santosh Shilimkar,
	Rob Herring, tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List



On 27/12/2018 8.08, 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) and Interrupt Aggregator(INTA) drivers

With the compilation fix to drivers/irqchip/irq-ti-sci-inta.c dmatest
and audio works with the series:

Tested-by: Peter Ujfalusi <peter.ujfalusi@ti.com>

> Changes since v3:
> - Fix documentation for Interrupt Router driver
> - Rebased on top of latest next.
> - Fully tested with DMA(using out of tree patches)
> - Fixed a build error with allmodconfig
> 
> Grygorii Strashko (1):
>   firmware: ti_sci: Add support to get TISCI handle using of_phandle
> 
> Lokesh Vutla (11):
>   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
>   dt-bindings: irqchip: Introduce TISCI Interrupt router bindings
>   irqchip: ti-sci-intr: Add support for Interrupt Router driver
>   genirq/msi: Add support for allocating single MSI for a device
>   genirq/msi: Add support for .msi_unprepare callback
>   soc: ti: Add MSI domain support for K3 Interrupt Aggregator
>   dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings
>   irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
>   soc: ti: am6: 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      |  74 ++
>  .../interrupt-controller/ti,sci-intr.txt      |  85 ++
>  MAINTAINERS                                   |   4 +
>  drivers/firmware/ti_sci.c                     | 848 ++++++++++++++++++
>  drivers/firmware/ti_sci.h                     | 102 +++
>  drivers/irqchip/Kconfig                       |  23 +
>  drivers/irqchip/Makefile                      |   2 +
>  drivers/irqchip/irq-ti-sci-inta.c             | 561 ++++++++++++
>  drivers/irqchip/irq-ti-sci-intr.c             | 310 +++++++
>  drivers/soc/ti/Kconfig                        |  11 +
>  drivers/soc/ti/Makefile                       |   1 +
>  drivers/soc/ti/k3_inta_msi.c                  | 193 ++++
>  include/linux/irqdomain.h                     |   1 +
>  include/linux/msi.h                           |  12 +
>  include/linux/soc/ti/k3_inta_msi.h            |  22 +
>  include/linux/soc/ti/ti_sci_protocol.h        | 169 ++++
>  kernel/irq/msi.c                              |  72 +-
>  18 files changed, 2470 insertions(+), 23 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/k3_inta_msi.c
>  create mode 100644 include/linux/soc/ti/k3_inta_msi.h
> 

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 12/13] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
  2019-01-02 11:49     ` Peter Ujfalusi
@ 2019-01-02 12:26       ` Lokesh Vutla
  2019-01-15 12:38         ` Tero Kristo
  0 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2019-01-02 12:26 UTC (permalink / raw)
  To: Peter Ujfalusi, marc.zyngier, Nishanth Menon, Santosh Shilimkar,
	Rob Herring, tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List

Hi Peter,

On 02/01/19 5:19 PM, Peter Ujfalusi wrote:
> 
> 
> 
> On 27/12/2018 8.13, Lokesh Vutla wrote:
>> 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.
>>
>> Add support for Interrupt Aggregator driver over TISCI protocol.
>>
>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
>> ---
>>   MAINTAINERS                       |   1 +
>>   drivers/irqchip/Kconfig           |  12 +
>>   drivers/irqchip/Makefile          |   1 +
>>   drivers/irqchip/irq-ti-sci-inta.c | 561 ++++++++++++++++++++++++++++++
>>   4 files changed, 575 insertions(+)
>>   create mode 100644 drivers/irqchip/irq-ti-sci-inta.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index aebce615151e..7d12788c844a 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -15026,6 +15026,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 <peter.ujfalusi@ti.com>
>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>> index a8d9bed0254b..d16fd39408ad 100644
>> --- a/drivers/irqchip/Kconfig
>> +++ b/drivers/irqchip/Kconfig
>> @@ -417,6 +417,18 @@ 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 && ARCH_K3
>> +	select IRQ_DOMAIN
>> +	select IRQ_DOMAIN_HIERARCHY
>> +	select K3_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.
>> +	  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 b4ff376a08ef..a679490a7059 100644
>> --- a/drivers/irqchip/Makefile
>> +++ b/drivers/irqchip/Makefile
>> @@ -95,3 +95,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_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..78bfc83a079a
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-ti-sci-inta.c
>> @@ -0,0 +1,561 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Texas Instruments' K3 Interrupt Aggregator irqchip driver
>> + *
>> + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
>> + *	Lokesh Vutla <lokeshvutla@ti.com>
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/msi.h>
>> +#include <linux/irqchip.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/module.h>
>> +#include <linux/moduleparam.h>
>> +#include <linux/irqdomain.h>
> 
> To fix this:
> 
> drivers/irqchip/irq-ti-sci-inta.c: In function ‘inta_msi_irq_handler’:
> drivers/irqchip/irq-ti-sci-inta.c:308:8: error: ‘IRQF_TRIGGER_HIGH’ undeclared (first use in this function); did you mean ‘IRQD_TRIGGER_MASK’?
>          IRQF_TRIGGER_HIGH)
>          ^~~~~~~~~~~~~~~~~
>          IRQD_TRIGGER_MASK
> drivers/irqchip/irq-ti-sci-inta.c:308:8: note: each undeclared identifier is reported only once for each function it appears in
> drivers/irqchip/irq-ti-sci-inta.c: In function ‘ti_sci_inta_alloc_parent_irq’:
> drivers/irqchip/irq-ti-sci-inta.c:360:27: error: ‘IRQF_TRIGGER_HIGH’ undeclared (first use in this function); did you mean ‘IRQD_TRIGGER_MASK’?
>    parent_fwspec.param[2] = IRQF_TRIGGER_HIGH;
>                             ^~~~~~~~~~~~~~~~~
>                             IRQD_TRIGGER_MASK
> make[3]: *** [scripts/Makefile.build:276: drivers/irqchip/irq-ti-sci-inta.o] Error 1
> 
> Add this:
> #include <linux/interrupt.h>

I did not see any such build error during my testing as shown below. But agree 
about the report. Will fix it in next version

➜  linux git:(nex-master) v8make defconfig
   HOSTCC  scripts/basic/fixdep
   HOSTCC  scripts/kconfig/conf.o
   HOSTCC  scripts/kconfig/confdata.o
   HOSTCC  scripts/kconfig/expr.o
   HOSTCC  scripts/kconfig/symbol.o
   HOSTCC  scripts/kconfig/preprocess.o
   LEX     scripts/kconfig/zconf.lex.c
   YACC    scripts/kconfig/zconf.tab.h
   HOSTCC  scripts/kconfig/zconf.lex.o
   YACC    scripts/kconfig/zconf.tab.c
   HOSTCC  scripts/kconfig/zconf.tab.o
v8  HOSTLD  scripts/kconfig/conf
*** Default configuration is based on 'defconfig'
make #
# configuration written to .config
#
I% 
 
                              ➜  linux git:(nex-master) v8make Image dtbs -j4 -s
arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts:25.9-29.5: Warning (graph_port): 
/edp-panel/ports: graph port node name should be 'port'
arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts:46.9-50.5: Warning 
(graph_port): /edp-panel/ports: graph port node name should be 'port'
arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts:94.9-98.5: Warning 
(graph_port): /edp-panel/ports: graph port node name should be 'port'
<stdin>:1339:2: warning: #warning syscall open_tree not implemented [-Wcpp]
<stdin>:1342:2: warning: #warning syscall move_mount not implemented [-Wcpp]
<stdin>:1345:2: warning: #warning syscall fsopen not implemented [-Wcpp]
<stdin>:1348:2: warning: #warning syscall fsconfig not implemented [-Wcpp]
<stdin>:1351:2: warning: #warning syscall fsmount not implemented [-Wcpp]
<stdin>:1354:2: warning: #warning syscall fspick not implemented [-Wcpp]
➜  linux git:(nex-master)

Thanks and regards,
Lokesh

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v4 00/13] Add support for TISCI irqchip drivers
  2018-12-27  6:08 [PATCH v4 00/13] Add support for TISCI irqchip drivers Lokesh Vutla
  2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
  2019-01-02 11:58 ` [PATCH v4 00/13] Add support for TISCI irqchip drivers Peter Ujfalusi
@ 2019-01-11 10:28 ` Lokesh Vutla
  2 siblings, 0 replies; 31+ messages in thread
From: Lokesh Vutla @ 2019-01-11 10:28 UTC (permalink / raw)
  To: marc.zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

Hi Marc,

On 27/12/18 11:38 AM, 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           |
>           |                           |
>           +---------------------------+


Can you please take a look at the MSI changes and provide your feedback? There
are few places(mentioned in the respective patches) where I felt I am hacking
around. It would be really helpful if you give any direction for such hacks.

Thanks and regards,
Lokesh

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 12/13] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
  2019-01-02 12:26       ` Lokesh Vutla
@ 2019-01-15 12:38         ` Tero Kristo
  2019-01-15 14:04           ` Nishanth Menon
  0 siblings, 1 reply; 31+ messages in thread
From: Tero Kristo @ 2019-01-15 12:38 UTC (permalink / raw)
  To: Lokesh Vutla, Peter Ujfalusi, marc.zyngier, Nishanth Menon,
	Santosh Shilimkar, Rob Herring, tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Sekhar Nori,
	Device Tree Mailing List

On 02/01/2019 14:26, Lokesh Vutla wrote:
> Hi Peter,
> 
> On 02/01/19 5:19 PM, Peter Ujfalusi wrote:
>>
>>
>>
>> On 27/12/2018 8.13, Lokesh Vutla wrote:
>>> 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.
>>>
>>> Add support for Interrupt Aggregator driver over TISCI protocol.
>>>
>>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>>> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
>>> ---
>>>   MAINTAINERS                       |   1 +
>>>   drivers/irqchip/Kconfig           |  12 +
>>>   drivers/irqchip/Makefile          |   1 +
>>>   drivers/irqchip/irq-ti-sci-inta.c | 561 ++++++++++++++++++++++++++++++
>>>   4 files changed, 575 insertions(+)
>>>   create mode 100644 drivers/irqchip/irq-ti-sci-inta.c
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index aebce615151e..7d12788c844a 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -15026,6 +15026,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 <peter.ujfalusi@ti.com>
>>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>>> index a8d9bed0254b..d16fd39408ad 100644
>>> --- a/drivers/irqchip/Kconfig
>>> +++ b/drivers/irqchip/Kconfig
>>> @@ -417,6 +417,18 @@ 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 && ARCH_K3
>>> +    select IRQ_DOMAIN
>>> +    select IRQ_DOMAIN_HIERARCHY
>>> +    select K3_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.
>>> +      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 b4ff376a08ef..a679490a7059 100644
>>> --- a/drivers/irqchip/Makefile
>>> +++ b/drivers/irqchip/Makefile
>>> @@ -95,3 +95,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_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..78bfc83a079a
>>> --- /dev/null
>>> +++ b/drivers/irqchip/irq-ti-sci-inta.c
>>> @@ -0,0 +1,561 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Texas Instruments' K3 Interrupt Aggregator irqchip driver
>>> + *
>>> + * Copyright (C) 2018 Texas Instruments Incorporated - 
>>> http://www.ti.com/
>>> + *    Lokesh Vutla <lokeshvutla@ti.com>
>>> + */
>>> +
>>> +#include <linux/err.h>
>>> +#include <linux/io.h>
>>> +#include <linux/msi.h>
>>> +#include <linux/irqchip.h>
>>> +#include <linux/of_platform.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/of_irq.h>
>>> +#include <linux/module.h>
>>> +#include <linux/moduleparam.h>
>>> +#include <linux/irqdomain.h>
>>
>> To fix this:
>>
>> drivers/irqchip/irq-ti-sci-inta.c: In function ‘inta_msi_irq_handler’:
>> drivers/irqchip/irq-ti-sci-inta.c:308:8: error: ‘IRQF_TRIGGER_HIGH’ 
>> undeclared (first use in this function); did you mean 
>> ‘IRQD_TRIGGER_MASK’?
>>          IRQF_TRIGGER_HIGH)
>>          ^~~~~~~~~~~~~~~~~
>>          IRQD_TRIGGER_MASK
>> drivers/irqchip/irq-ti-sci-inta.c:308:8: note: each undeclared 
>> identifier is reported only once for each function it appears in
>> drivers/irqchip/irq-ti-sci-inta.c: In function 
>> ‘ti_sci_inta_alloc_parent_irq’:
>> drivers/irqchip/irq-ti-sci-inta.c:360:27: error: ‘IRQF_TRIGGER_HIGH’ 
>> undeclared (first use in this function); did you mean 
>> ‘IRQD_TRIGGER_MASK’?
>>    parent_fwspec.param[2] = IRQF_TRIGGER_HIGH;
>>                             ^~~~~~~~~~~~~~~~~
>>                             IRQD_TRIGGER_MASK
>> make[3]: *** [scripts/Makefile.build:276: 
>> drivers/irqchip/irq-ti-sci-inta.o] Error 1
>>
>> Add this:
>> #include <linux/interrupt.h>
> 
> I did not see any such build error during my testing as shown below. But 
> agree about the report. Will fix it in next version
> 
> ➜  linux git:(nex-master) v8make defconfig
>    HOSTCC  scripts/basic/fixdep
>    HOSTCC  scripts/kconfig/conf.o
>    HOSTCC  scripts/kconfig/confdata.o
>    HOSTCC  scripts/kconfig/expr.o
>    HOSTCC  scripts/kconfig/symbol.o
>    HOSTCC  scripts/kconfig/preprocess.o
>    LEX     scripts/kconfig/zconf.lex.c
>    YACC    scripts/kconfig/zconf.tab.h
>    HOSTCC  scripts/kconfig/zconf.lex.o
>    YACC    scripts/kconfig/zconf.tab.c
>    HOSTCC  scripts/kconfig/zconf.tab.o
> v8  HOSTLD  scripts/kconfig/conf
> *** Default configuration is based on 'defconfig'
> make #
> # configuration written to .config
> #
> I%
>                               ➜  linux git:(nex-master) v8make Image 
> dtbs -j4 -s
> arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts:25.9-29.5: Warning 
> (graph_port): /edp-panel/ports: graph port node name should be 'port'
> arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts:46.9-50.5: Warning 
> (graph_port): /edp-panel/ports: graph port node name should be 'port'
> arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts:94.9-98.5: 
> Warning (graph_port): /edp-panel/ports: graph port node name should be 
> 'port'
> <stdin>:1339:2: warning: #warning syscall open_tree not implemented [-Wcpp]
> <stdin>:1342:2: warning: #warning syscall move_mount not implemented 
> [-Wcpp]
> <stdin>:1345:2: warning: #warning syscall fsopen not implemented [-Wcpp]
> <stdin>:1348:2: warning: #warning syscall fsconfig not implemented [-Wcpp]
> <stdin>:1351:2: warning: #warning syscall fsmount not implemented [-Wcpp]
> <stdin>:1354:2: warning: #warning syscall fspick not implemented [-Wcpp]
> ➜  linux git:(nex-master)
> 
> Thanks and regards,
> Lokesh

The mentioned failure only happens with a specific .config. Not sure 
what is the actual Kconfig that masks the failure though, but anyway it 
looks like interrupt.h gets included via some indirect path with arm64 
defconfig making it pass.

-Tero
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 13/13] soc: ti: am6: Enable interrupt controller drivers
  2018-12-27  6:13   ` [RFC PATCH v4 13/13] soc: ti: am6: Enable interrupt controller drivers Lokesh Vutla
@ 2019-01-15 13:54     ` Nishanth Menon
  0 siblings, 0 replies; 31+ messages in thread
From: Nishanth Menon @ 2019-01-15 13:54 UTC (permalink / raw)
  To: Lokesh Vutla
  Cc: marc.zyngier, Santosh Shilimkar, Rob Herring, tglx, jason,
	Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

On 11:43-20181227, Lokesh Vutla wrote:
> Select all the TISCI dependent interrupt controller drivers
> for AM6 SoC.
> 
> Suggested-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
> ---
>  drivers/soc/ti/Kconfig | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
> index 7640490c2a6a..145b701a3d96 100644
> --- a/drivers/soc/ti/Kconfig
> +++ b/drivers/soc/ti/Kconfig
> @@ -5,6 +5,11 @@ if ARCH_K3
>  
>  config ARCH_K3_AM6_SOC
>  	bool "K3 AM6 SoC"
> +	select MAILBOX
> +	select TI_MESSAGE_MANAGER
> +	select TI_SCI_PROTOCOL
> +	select TI_SCI_INTR_IRQCHIP
> +	select TI_SCI_INTA_IRQCHIP

Sorry for joining the party late.. but just 2 cents for thought..

Is'nt imply better than select here? for a very tiny kernel, it is
possible to boot kernel up and TISCI and mailbox could be modules as
well.. I know it is a theoretical concept, but it may be helpful (esp
during pre-silicon time frame, at least during start, I usually start
with almost everything other than the CPU cores and PSCI disabled).
there is not much you can do with it ofcourse, but it helps me with a
clean start.


>  	help
>  	  Enable support for TI's AM6 SoC Family support
>  
> -- 
> 2.19.2
> 

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 12/13] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver
  2019-01-15 12:38         ` Tero Kristo
@ 2019-01-15 14:04           ` Nishanth Menon
  0 siblings, 0 replies; 31+ messages in thread
From: Nishanth Menon @ 2019-01-15 14:04 UTC (permalink / raw)
  To: Tero Kristo
  Cc: Lokesh Vutla, Peter Ujfalusi, marc.zyngier, Santosh Shilimkar,
	Rob Herring, tglx, jason, Linux ARM Mailing List, linux-kernel,
	Sekhar Nori, Device Tree Mailing List

On 14:38-20190115, Tero Kristo wrote:
[...]
> 
> The mentioned failure only happens with a specific .config. Not sure what is
> the actual Kconfig that masks the failure though, but anyway it looks like
> interrupt.h gets included via some indirect path with arm64 defconfig making
> it pass.

I am able to reproduce the build fail as well:
.config: -> Notice that all v8 arch other than K3 is disabled, expert
mode is enabled and few ancillary "optimization" of config
	  https://pastebin.ubuntu.com/p/w5t9Wvp2jJ/
Here is what I did:
 git checkout next-20190115
 wget -O inta.mbox https://lore.kernel.org/patchwork/series/377815/mbox/
 git am inta.mbox
 I put the above .config as my .config
 make oldconfig
 make drivers/irqchip/irq-ti-sci-inta.o

I got the exact failure as well..
 https://pastebin.ubuntu.com/p/JzFXGz7Gh9/

I agree with peter than this should be fixed. randconfig would have
caught this anyways.. I did'nt bother looking further in the config to
figure out why the side effect, but glad it got caught early enough.

Thanks Peter.

Lokesh, I know you are out this week, will appreciate if you could post
a v5 once you are back?

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 10/13] soc: ti: Add MSI domain support for K3 Interrupt Aggregator
  2018-12-27  6:13   ` [RFC PATCH v4 10/13] soc: ti: Add MSI domain support for K3 Interrupt Aggregator Lokesh Vutla
@ 2019-01-15 14:41     ` Nishanth Menon
  0 siblings, 0 replies; 31+ messages in thread
From: Nishanth Menon @ 2019-01-15 14:41 UTC (permalink / raw)
  To: Lokesh Vutla
  Cc: marc.zyngier, Santosh Shilimkar, Rob Herring, tglx, jason,
	Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

On 11:43-20181227, Lokesh Vutla wrote:
> 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 are:
> - inta_msi_create_irq_domain() that creates a MSI domain
> - inta_msi_domain_alloc_group_irqs() that creates MSIs for the
>   specified device and source indexes. All these are expected to
>   be grouped by the parent interrupt controller to MSI domain.
> - inta_msi_domain_free_group_irqs() frees the grouped irqs.
> 
> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
> ---
> 
> - May be the same functionaly can be included in platform msi. But I would
>   like to get a feedback on the approach.
> 
>  drivers/soc/ti/Kconfig             |   6 +
>  drivers/soc/ti/Makefile            |   1 +
>  drivers/soc/ti/k3_inta_msi.c       | 193 +++++++++++++++++++++++++++++
>  include/linux/irqdomain.h          |   1 +
>  include/linux/msi.h                |   6 +
>  include/linux/soc/ti/k3_inta_msi.h |  22 ++++
>  6 files changed, 229 insertions(+)
>  create mode 100644 drivers/soc/ti/k3_inta_msi.c
>  create mode 100644 include/linux/soc/ti/k3_inta_msi.h

Did we miss maintainer file?

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v4 07/13] irqchip: ti-sci-intr: Add support for Interrupt Router driver
  2018-12-27  6:13   ` [PATCH v4 07/13] irqchip: ti-sci-intr: Add support for Interrupt Router driver Lokesh Vutla
@ 2019-01-16 17:16     ` Marc Zyngier
  2019-01-24 10:19       ` Lokesh Vutla
  0 siblings, 1 reply; 31+ messages in thread
From: Marc Zyngier @ 2019-01-16 17:16 UTC (permalink / raw)
  To: Lokesh Vutla, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

[Still in the process of sorting out my email - don't ask]

On 27/12/2018 06:13, Lokesh Vutla wrote:
> 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 <lokeshvutla@ti.com>
> ---
>  MAINTAINERS                       |   1 +
>  drivers/irqchip/Kconfig           |  11 ++
>  drivers/irqchip/Makefile          |   1 +
>  drivers/irqchip/irq-ti-sci-intr.c | 310 ++++++++++++++++++++++++++++++
>  4 files changed, 323 insertions(+)
>  create mode 100644 drivers/irqchip/irq-ti-sci-intr.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8c7513b02d50..4480eb2fe851 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15024,6 +15024,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 <peter.ujfalusi@ti.com>
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 3d1e60779078..a8d9bed0254b 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -406,6 +406,17 @@ config IMX_IRQSTEER
>  	help
>  	  Support for the i.MX IRQSTEER interrupt multiplexer/remapper.
>  
> +config TI_SCI_INTR_IRQCHIP
> +	bool
> +	depends on TI_SCI_PROTOCOL && ARCH_K3
> +	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 c93713d24b86..b4ff376a08ef 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -94,3 +94,4 @@ obj-$(CONFIG_CSKY_APB_INTC)		+= irq-csky-apb-intc.o
>  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_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..a5396e08412c
> --- /dev/null
> +++ b/drivers/irqchip/irq-ti-sci-intr.c
> @@ -0,0 +1,310 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Texas Instruments' K3 Interrupt Router irqchip driver
> + *
> + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
> + *	Lokesh Vutla <lokeshvutla@ti.com>
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/irqchip.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/irqdomain.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 TI_SCI_EVENT_IRQ	BIT(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 FWSPEC_TO_HWIRQ(fwspec)	(((fwspec->param[0] & TI_SCI_DEV_ID_MASK) << \
> +				 TI_SCI_DEV_ID_SHIFT) | \
> +				(fwspec->param[1] & 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 destination irq controller.
> + * @dst_id:	TISCI device ID of the destination irq controller.
> + */
> +struct ti_sci_intr_irq_domain {
> +	const struct ti_sci_handle *sci;
> +	struct ti_sci_resource *dst_irq;
> +	u16 dst_id;
> +};
> +
> +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_retrigger		= irq_chip_retrigger_hierarchy,
> +	.irq_set_type		= irq_chip_set_type_parent,
> +	.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)
> +{
> +	if (is_of_node(fwspec->fwnode)) {
> +		if (fwspec->param_count != 4)
> +			return -EINVAL;
> +
> +		*hwirq = FWSPEC_TO_HWIRQ(fwspec);
> +		*type = fwspec->param[2];
> +
> +		return 0;
> +	}

From what I can see in the code used by this platform, there is
absolutely no chance this will ever support any firmware interface other
than DT. So I think you can loose the is_of_node check here.

Another thing is that you do not seem to use the 4th parameter to the
intspec. So what is it used for here?

> +
> +	return -EINVAL;
> +}
> +
> +static inline void ti_sci_intr_delete_desc(struct ti_sci_intr_irq_domain *intr,

So this is called "delete desc". What is desc? It seems to free an irq
in the resource manager, so please call it something that matches what
this does.

> +					   u16 src_id, u16 src_index,
> +					   u16 dst_irq)
> +{
> +	intr->sci->ops.rm_irq_ops.free_direct_irq(intr->sci, src_id, src_index,
> +						  intr->dst_id, dst_irq);
> +}
> +
> +/**
> + * 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;
> +	u64 flags;
> +	int i;
> +
> +	intr = domain->host_data;
> +
> +	for (i = 0; i < nr_irqs; i++) {
> +		data = irq_domain_get_irq_data(domain, virq + i);
> +		flags = (u64)irq_data_get_irq_chip_data(data);

Are you guaranteed that this will only exist on a 64bit architecture?

> +		parent_data = irq_domain_get_irq_data(domain->parent, virq + i);
> +
> +		if (!(flags & TI_SCI_EVENT_IRQ))
> +			ti_sci_intr_delete_desc(intr,
> +						HWIRQ_TO_DEVID(data->hwirq),
> +						HWIRQ_TO_IRQID(data->hwirq),
> +						parent_data->hwirq);
> +		ti_sci_release_resource(intr->dst_irq, parent_data->hwirq);
> +		irq_domain_free_irqs_parent(domain, virq + i, 1);

Couldn't this be moved out of the loop so that you free nr_irqs directly
since you seem to be assuming that they are continuous? But are they?

Also, and depending on the context this is called from, it is pretty
unlikely that you'll see nr_irqs!=1, the only case I know about being
the PCI Multi-MSI train-wreck.

> +		irq_domain_reset_irq_data(data);
> +	}
> +}
> +
> +/**
> + * ti_sci_intr_allocate_gic_irq() - Allocate GIC specific IRQ
> + * @domain:	Point to the interrupt router IRQ domain
> + * @dev:	TISCI device IRQ generating the IRQ
> + * @irq:	IRQ offset within the device
> + * @flags:	Corresponding flags to the IRQ
> + * @event_irq:	Flag to tell if requested irq is from interrupt aggregator.
> + *
> + * Returns 0 if all went well else appropriate error pointer.
> + */
> +static int ti_sci_intr_allocate_gic_irq(struct irq_domain *domain,
> +					unsigned int virq, u16 dev, u16 irq,
> +					u32 flags, u8 event_irq)
> +{
> +	struct ti_sci_intr_irq_domain *intr = domain->host_data;
> +	struct irq_fwspec fwspec;
> +	u16 dst_irq;
> +	int err;
> +
> +	if (!irq_domain_get_of_node(domain->parent))
> +		return -EINVAL;
> +
> +	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] = flags & IRQ_TYPE_SENSE_MASK;
> +
> +	err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
> +	if (err)
> +		goto err_irqs;
> +
> +	/* If event is requested then return */
> +	if (event_irq == TI_SCI_EVENT_IRQ)
> +		return 0;
> +
> +	err = intr->sci->ops.rm_irq_ops.set_direct_irq(intr->sci, dev, irq,
> +						       intr->dst_id, dst_irq);
> +	if (err) {
> +		pr_err("%s: IRQ allocation failed from src = %d, src_index = %d to dst_id = %d, dst_irq = %d",
> +		       __func__, dev, irq, intr->dst_id, dst_irq);

Do we really needs this error message? It doesn't seem to provide any
useful information at this stage. I'd rather the terrible callback does
the screaming if required.

> +		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;
> +	u16 src_id, src_index;
> +	unsigned long hwirq;
> +	u8 event_irq;
> +	int i, err;
> +	u32 type;
> +
> +	err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &type);
> +	if (err)
> +		return err;
> +
> +	src_id = HWIRQ_TO_DEVID(hwirq);
> +	src_index = HWIRQ_TO_IRQID(hwirq);
> +	event_irq = fwspec->param[3];

Ah, so this is where it is used. You could perform some sanitization,
given that you're feeding this to other part of the system.

> +
> +	for (i = 0; i < nr_irqs; i++) {

Again, is there a case where such a loop is actually used?

> +		err = ti_sci_intr_allocate_gic_irq(domain, virq + i, src_id,
> +						   src_index + i, type,
> +						   event_irq);
> +		if (err)
> +			goto err_irq;
> +
> +		err = irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> +						    &ti_sci_intr_irq_chip,
> +						    (void *)(u64)event_irq);
> +		if (err)
> +			goto err_irq;
> +	}
> +
> +	return 0;
> +err_irq:
> +	ti_sci_intr_irq_domain_free(domain, virq, i);
> +	return err;
> +}
> +
> +static const struct irq_domain_ops ti_sci_intr_irq_domain_ops = {
> +	.alloc		= ti_sci_intr_irq_domain_alloc,
> +	.free		= ti_sci_intr_irq_domain_free,
> +	.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;
> +
> +	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",
> +				   (u32 *)&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");
> 

Thanks,

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

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device
  2018-12-27  6:13   ` [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device Lokesh Vutla
@ 2019-01-16 18:30     ` Marc Zyngier
  2019-01-24 10:19       ` Lokesh Vutla
  0 siblings, 1 reply; 31+ messages in thread
From: Marc Zyngier @ 2019-01-16 18:30 UTC (permalink / raw)
  To: Lokesh Vutla, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

On 27/12/2018 06:13, Lokesh Vutla wrote:
> Previously all msi for a device are allocated in one go
> by calling msi_domain_alloc_irq() from a bus layer. This might
> not be the case when a device is trying to allocate interrupts
> dynamically based on a request to it.
>
> So introduce msi_domain_alloc/free_irq() apis to allocate a single
> msi. prepare and activate operations to be handled by bus layer
> calling msi_domain_alloc/free_irq() apis.
>
> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
> ---
>  include/linux/msi.h |  3 +++
>  kernel/irq/msi.c    | 62 +++++++++++++++++++++++++++++----------------
>  2 files changed, 43 insertions(+), 22 deletions(-)
>
> diff --git a/include/linux/msi.h b/include/linux/msi.h
> index 784fb52b9900..474490826f8c 100644
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -301,8 +301,11 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
>  struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
>   struct msi_domain_info *info,
>   struct irq_domain *parent);
> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
> + struct msi_desc *desc,  msi_alloc_info_t *arg);
>  int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>    int nvec);
> +void msi_domain_free_irq(struct msi_desc *desc);
>  void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
>  struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
>
> diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
> index ad26fbcfbfc8..eb7459324113 100644
> --- a/kernel/irq/msi.c
> +++ b/kernel/irq/msi.c
> @@ -387,6 +387,35 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
>  return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
>  }
>
> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
> + struct msi_desc *desc,  msi_alloc_info_t *arg)
> +{
> +struct msi_domain_info *info = domain->host_data;
> +struct msi_domain_ops *ops = info->ops;
> +int i, ret, virq;
> +
> +ops->set_desc(arg, desc);
> +
> +virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
> +       dev_to_node(dev), arg, false,
> +       desc->affinity);
> +if (virq < 0) {
> +ret = -ENOSPC;
> +if (ops->handle_error)
> +ret = ops->handle_error(domain, desc, ret);
> +if (ops->msi_finish)
> +ops->msi_finish(arg, ret);
> +return ret;
> +}
> +
> +for (i = 0; i < desc->nvec_used; i++) {
> +irq_set_msi_desc_off(virq, i, desc);
> +irq_debugfs_copy_devname(virq + i, dev);
> +}
> +
> +return 0;
> +}
> +
>  /**
>   * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
>   * @domain:The domain to allocate from
> @@ -404,7 +433,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>  struct irq_data *irq_data;
>  struct msi_desc *desc;
>  msi_alloc_info_t arg;
> -int i, ret, virq;
> +int ret, virq;
>  bool can_reserve;
>
>  ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
> @@ -412,24 +441,9 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>  return ret;
>
>  for_each_msi_entry(desc, dev) {
> -ops->set_desc(&arg, desc);
> -
> -virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
> -       dev_to_node(dev), &arg, false,
> -       desc->affinity);
> -if (virq < 0) {
> -ret = -ENOSPC;
> -if (ops->handle_error)
> -ret = ops->handle_error(domain, desc, ret);
> -if (ops->msi_finish)
> -ops->msi_finish(&arg, ret);
> +ret = msi_domain_alloc_irq(domain, dev, desc, &arg);
> +if (ret)
>  return ret;
> -}
> -
> -for (i = 0; i < desc->nvec_used; i++) {
> -irq_set_msi_desc_off(virq, i, desc);
> -irq_debugfs_copy_devname(virq + i, dev);
> -}
>  }
>
>  if (ops->msi_finish)
> @@ -487,6 +501,12 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>  return ret;
>  }
>
> +void msi_domain_free_irq(struct msi_desc *desc)
> +{
> +irq_domain_free_irqs(desc->irq, desc->nvec_used);
> +desc->irq = 0;
> +}
> +
>  /**
>   * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
>   * @domain:The domain to managing the interrupts
> @@ -503,10 +523,8 @@ void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
>   * enough that there is no IRQ associated to this
>   * entry. If that's the case, don't do anything.
>   */
> -if (desc->irq) {
> -irq_domain_free_irqs(desc->irq, desc->nvec_used);
> -desc->irq = 0;
> -}
> +if (desc->irq)
> +msi_domain_free_irq(desc);
>  }
>  }
>
>

I can see some interesting issues with this API.

At the moment, MSIs are allocated upfront, and that's usually done
before the driver can do anything else. With what you're suggesting
here, MSIs can now be allocated at any time, which sounds great. But how
does it work when MSIs get added/freed in parallel? I can't see any
locking here...

It is also pretty nasty that the user of this API has to know about the
MSI descriptor. Really, nobody should have to deal with this outside of
the MSI layer.

The real question is why you need to need to allocate MSIs on demand for
a given device. Usually, you allocate them because this is a per-CPU
resource, or something similar. What makes it so variable that you need
to resort to fine grained MSI allocation?

Thanks,

M.
--
Jazz is not dead. It just smells funny...
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 09/13] genirq/msi: Add support for .msi_unprepare callback
  2018-12-27  6:13   ` [RFC PATCH v4 09/13] genirq/msi: Add support for .msi_unprepare callback Lokesh Vutla
@ 2019-01-17 10:39     ` Marc Zyngier
  0 siblings, 0 replies; 31+ messages in thread
From: Marc Zyngier @ 2019-01-17 10:39 UTC (permalink / raw)
  To: Lokesh Vutla, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

On 27/12/2018 06:13, Lokesh Vutla wrote:
> Add an optional callback .msi_unprepare to struct msi_domain_ops.
> This is used to clear any effect that is done by .msi_prepare callback.
> 
> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
> ---
>  include/linux/msi.h |  3 +++
>  kernel/irq/msi.c    | 10 ++++++++++
>  2 files changed, 13 insertions(+)
> 
> diff --git a/include/linux/msi.h b/include/linux/msi.h
> index 474490826f8c..f35dd19f6c69 100644
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -239,6 +239,8 @@ struct msi_domain_ops {
>  	int		(*msi_prepare)(struct irq_domain *domain,
>  				       struct device *dev, int nvec,
>  				       msi_alloc_info_t *arg);
> +	void		(*msi_unprepare)(struct irq_domain *domain, int nvec,
> +					 void *data);
>  	void		(*msi_finish)(msi_alloc_info_t *arg, int retval);
>  	void		(*set_desc)(msi_alloc_info_t *arg,
>  				    struct msi_desc *desc);
> @@ -319,6 +321,7 @@ void platform_msi_domain_free_irqs(struct device *dev);
>  /* When an MSI domain is used as an intermediate domain */
>  int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
>  			    int nvec, msi_alloc_info_t *args);
> +void msi_domain_unprepare_irqs(struct irq_domain *domain, int nvec, void *data);
>  int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
>  			     int virq, int nvec, msi_alloc_info_t *args);
>  struct irq_domain *
> diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
> index eb7459324113..1a1738690519 100644
> --- a/kernel/irq/msi.c
> +++ b/kernel/irq/msi.c
> @@ -312,6 +312,16 @@ int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
>  	return ret;
>  }
>  
> +void msi_domain_unprepare_irqs(struct irq_domain *domain, int nvec,
> +			       void *data)
> +{
> +	struct msi_domain_info *info = domain->host_data;
> +	struct msi_domain_ops *ops = info->ops;
> +
> +	if (ops->msi_unprepare)
> +		ops->msi_unprepare(domain, nvec, data);
> +}
> +
>  int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
>  			     int virq, int nvec, msi_alloc_info_t *arg)
>  {
> 

Again, this needs justification. What does this brings to the table?
What does this callback do that cannot be done when the MSI are freed?

Also, this only makes sense if it is plugged into the MSI framework. On
its own, this is pretty useless. This makes me think that there is a gap
in the way your MSI controller driver interacts with the reset of the
MSI code.

Thanks,

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

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device
  2019-01-16 18:30     ` Marc Zyngier
@ 2019-01-24 10:19       ` Lokesh Vutla
  2019-02-04 10:33         ` Marc Zyngier
  0 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2019-01-24 10:19 UTC (permalink / raw)
  To: Marc Zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

Hi Marc,
	Sorry for the delayed response. Just back from vacation.

On 17/01/19 12:00 AM, Marc Zyngier wrote:
> On 27/12/2018 06:13, Lokesh Vutla wrote:
>> Previously all msi for a device are allocated in one go
>> by calling msi_domain_alloc_irq() from a bus layer. This might
>> not be the case when a device is trying to allocate interrupts
>> dynamically based on a request to it.
>>
>> So introduce msi_domain_alloc/free_irq() apis to allocate a single
>> msi. prepare and activate operations to be handled by bus layer
>> calling msi_domain_alloc/free_irq() apis.
>>
>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>> ---
>>  include/linux/msi.h |  3 +++
>>  kernel/irq/msi.c    | 62 +++++++++++++++++++++++++++++----------------
>>  2 files changed, 43 insertions(+), 22 deletions(-)
>>
>> diff --git a/include/linux/msi.h b/include/linux/msi.h
>> index 784fb52b9900..474490826f8c 100644
>> --- a/include/linux/msi.h
>> +++ b/include/linux/msi.h
>> @@ -301,8 +301,11 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
>>  struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
>>   struct msi_domain_info *info,
>>   struct irq_domain *parent);
>> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
>> + struct msi_desc *desc,  msi_alloc_info_t *arg);
>>  int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>    int nvec);
>> +void msi_domain_free_irq(struct msi_desc *desc);
>>  void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
>>  struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
>>
>> diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
>> index ad26fbcfbfc8..eb7459324113 100644
>> --- a/kernel/irq/msi.c
>> +++ b/kernel/irq/msi.c
>> @@ -387,6 +387,35 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
>>  return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
>>  }
>>
>> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
>> + struct msi_desc *desc,  msi_alloc_info_t *arg)
>> +{
>> +struct msi_domain_info *info = domain->host_data;
>> +struct msi_domain_ops *ops = info->ops;
>> +int i, ret, virq;
>> +
>> +ops->set_desc(arg, desc);
>> +
>> +virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
>> +       dev_to_node(dev), arg, false,
>> +       desc->affinity);
>> +if (virq < 0) {
>> +ret = -ENOSPC;
>> +if (ops->handle_error)
>> +ret = ops->handle_error(domain, desc, ret);
>> +if (ops->msi_finish)
>> +ops->msi_finish(arg, ret);
>> +return ret;
>> +}
>> +
>> +for (i = 0; i < desc->nvec_used; i++) {
>> +irq_set_msi_desc_off(virq, i, desc);
>> +irq_debugfs_copy_devname(virq + i, dev);
>> +}
>> +
>> +return 0;
>> +}
>> +
>>  /**
>>   * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
>>   * @domain:The domain to allocate from
>> @@ -404,7 +433,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>  struct irq_data *irq_data;
>>  struct msi_desc *desc;
>>  msi_alloc_info_t arg;
>> -int i, ret, virq;
>> +int ret, virq;
>>  bool can_reserve;
>>
>>  ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
>> @@ -412,24 +441,9 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>  return ret;
>>
>>  for_each_msi_entry(desc, dev) {
>> -ops->set_desc(&arg, desc);
>> -
>> -virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
>> -       dev_to_node(dev), &arg, false,
>> -       desc->affinity);
>> -if (virq < 0) {
>> -ret = -ENOSPC;
>> -if (ops->handle_error)
>> -ret = ops->handle_error(domain, desc, ret);
>> -if (ops->msi_finish)
>> -ops->msi_finish(&arg, ret);
>> +ret = msi_domain_alloc_irq(domain, dev, desc, &arg);
>> +if (ret)
>>  return ret;
>> -}
>> -
>> -for (i = 0; i < desc->nvec_used; i++) {
>> -irq_set_msi_desc_off(virq, i, desc);
>> -irq_debugfs_copy_devname(virq + i, dev);
>> -}
>>  }
>>
>>  if (ops->msi_finish)
>> @@ -487,6 +501,12 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>  return ret;
>>  }
>>
>> +void msi_domain_free_irq(struct msi_desc *desc)
>> +{
>> +irq_domain_free_irqs(desc->irq, desc->nvec_used);
>> +desc->irq = 0;
>> +}
>> +
>>  /**
>>   * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
>>   * @domain:The domain to managing the interrupts
>> @@ -503,10 +523,8 @@ void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
>>   * enough that there is no IRQ associated to this
>>   * entry. If that's the case, don't do anything.
>>   */
>> -if (desc->irq) {
>> -irq_domain_free_irqs(desc->irq, desc->nvec_used);
>> -desc->irq = 0;
>> -}
>> +if (desc->irq)
>> +msi_domain_free_irq(desc);
>>  }
>>  }
>>
>>
> 
> I can see some interesting issues with this API.
> 
> At the moment, MSIs are allocated upfront, and that's usually done
> before the driver can do anything else. With what you're suggesting
> here, MSIs can now be allocated at any time, which sounds great. But how
> does it work when MSIs get added/freed in parallel? I can't see any
> locking here...
> 
> It is also pretty nasty that the user of this API has to know about the
> MSI descriptor. Really, nobody should have to deal with this outside of
> the MSI layer.
> 
> The real question is why you need to need to allocate MSIs on demand for
> a given device. Usually, you allocate them because this is a per-CPU
> resource, or something similar. What makes it so variable that you need
> to resort to fine grained MSI allocation?

I added this after the discussion we had in the previous version[1] of this
series. Let me provide the details again:

As you must be aware INTR is interrupt re-director and INTA is the interrupt
multiplexer is the SoC. Here we are trying to address the interrupt connection
route as below:
Device(Global event) --> INTA --> INTR --> GIC

For the above case you suggested to have the following sw IRQ domain hierarchy:
INTA multi MSI --> INTA  -->  INTR  --> GIC

The problem here with the INTA MSI is that all the interrupts for a device
should be pre-allocated during the device probe time. But this is not what we
wanted especially for the DMA case.

An example DMA ring connection would look like below[2]:

                      +---------------------+
                       |         IA                |
+--------+        |            +------+   |        +--------+         +------+
| ring 1 +----->evtA+->VintX+-------->+   IR   +-- --->  GIC +-->
+--------+       |             +------+   |        +--------+         +------+
Linux IRQ Y
   evtA            |                             |
                       |                             |
                      +----------------------+

So when a DMA client driver requests a dma channel during probe, the DMA driver
gets a free ring in its allocated range. Then DMA driver requests MSI layer for
an IRQ. This is why I had to introduce on demand allocation of MSIs for a device.

The reason why we avoided DMA driver to allocate interrupts during its probe as
it is not aware of the exact no of channels that are going to be used. Also max
allocation of interrupts will overrun the gic IRQs available to this INTA and
the IPs that are connected to INTR directly will not get any interrupts.

I hope this is clear.

[1] https://lkml.org/lkml/2018/11/5/894
[2] https://pastebin.ubuntu.com/p/RTrgzfCMby/

Thanks and regards,
Lokesh

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v4 07/13] irqchip: ti-sci-intr: Add support for Interrupt Router driver
  2019-01-16 17:16     ` Marc Zyngier
@ 2019-01-24 10:19       ` Lokesh Vutla
  0 siblings, 0 replies; 31+ messages in thread
From: Lokesh Vutla @ 2019-01-24 10:19 UTC (permalink / raw)
  To: Marc Zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

Hi Marc,

On 16/01/19 10:46 PM, Marc Zyngier wrote:
> [Still in the process of sorting out my email - don't ask]
> 
> On 27/12/2018 06:13, Lokesh Vutla wrote:
>> 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 <lokeshvutla@ti.com>
>> ---
>>  MAINTAINERS                       |   1 +
>>  drivers/irqchip/Kconfig           |  11 ++
>>  drivers/irqchip/Makefile          |   1 +
>>  drivers/irqchip/irq-ti-sci-intr.c | 310 ++++++++++++++++++++++++++++++
>>  4 files changed, 323 insertions(+)
>>  create mode 100644 drivers/irqchip/irq-ti-sci-intr.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 8c7513b02d50..4480eb2fe851 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -15024,6 +15024,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 <peter.ujfalusi@ti.com>
>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>> index 3d1e60779078..a8d9bed0254b 100644
>> --- a/drivers/irqchip/Kconfig
>> +++ b/drivers/irqchip/Kconfig
>> @@ -406,6 +406,17 @@ config IMX_IRQSTEER
>>  	help
>>  	  Support for the i.MX IRQSTEER interrupt multiplexer/remapper.
>>  
>> +config TI_SCI_INTR_IRQCHIP
>> +	bool
>> +	depends on TI_SCI_PROTOCOL && ARCH_K3
>> +	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 c93713d24b86..b4ff376a08ef 100644
>> --- a/drivers/irqchip/Makefile
>> +++ b/drivers/irqchip/Makefile
>> @@ -94,3 +94,4 @@ obj-$(CONFIG_CSKY_APB_INTC)		+= irq-csky-apb-intc.o
>>  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_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..a5396e08412c
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-ti-sci-intr.c
>> @@ -0,0 +1,310 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Texas Instruments' K3 Interrupt Router irqchip driver
>> + *
>> + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
>> + *	Lokesh Vutla <lokeshvutla@ti.com>
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/irqchip.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/module.h>
>> +#include <linux/moduleparam.h>
>> +#include <linux/irqdomain.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 TI_SCI_EVENT_IRQ	BIT(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 FWSPEC_TO_HWIRQ(fwspec)	(((fwspec->param[0] & TI_SCI_DEV_ID_MASK) << \
>> +				 TI_SCI_DEV_ID_SHIFT) | \
>> +				(fwspec->param[1] & 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 destination irq controller.
>> + * @dst_id:	TISCI device ID of the destination irq controller.
>> + */
>> +struct ti_sci_intr_irq_domain {
>> +	const struct ti_sci_handle *sci;
>> +	struct ti_sci_resource *dst_irq;
>> +	u16 dst_id;
>> +};
>> +
>> +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_retrigger		= irq_chip_retrigger_hierarchy,
>> +	.irq_set_type		= irq_chip_set_type_parent,
>> +	.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)
>> +{
>> +	if (is_of_node(fwspec->fwnode)) {
>> +		if (fwspec->param_count != 4)
>> +			return -EINVAL;
>> +
>> +		*hwirq = FWSPEC_TO_HWIRQ(fwspec);
>> +		*type = fwspec->param[2];
>> +
>> +		return 0;
>> +	}
> 
> From what I can see in the code used by this platform, there is
> absolutely no chance this will ever support any firmware interface other
> than DT. So I think you can loose the is_of_node check here.

Sure will drop it in next version.

> 
> Another thing is that you do not seem to use the 4th parameter to the
> intspec. So what is it used for here?
> 
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static inline void ti_sci_intr_delete_desc(struct ti_sci_intr_irq_domain *intr,
> 
> So this is called "delete desc". What is desc? It seems to free an irq
> in the resource manager, so please call it something that matches what
> this does.

will change it to delete_irq.

> 
>> +					   u16 src_id, u16 src_index,
>> +					   u16 dst_irq)
>> +{
>> +	intr->sci->ops.rm_irq_ops.free_direct_irq(intr->sci, src_id, src_index,
>> +						  intr->dst_id, dst_irq);
>> +}
>> +
>> +/**
>> + * 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;
>> +	u64 flags;
>> +	int i;
>> +
>> +	intr = domain->host_data;
>> +
>> +	for (i = 0; i < nr_irqs; i++) {
>> +		data = irq_domain_get_irq_data(domain, virq + i);
>> +		flags = (u64)irq_data_get_irq_chip_data(data);
> 
> Are you guaranteed that this will only exist on a 64bit architecture?

most likely yes. But will use phys_addr_t to be more specific

> 
>> +		parent_data = irq_domain_get_irq_data(domain->parent, virq + i);
>> +
>> +		if (!(flags & TI_SCI_EVENT_IRQ))
>> +			ti_sci_intr_delete_desc(intr,
>> +						HWIRQ_TO_DEVID(data->hwirq),
>> +						HWIRQ_TO_IRQID(data->hwirq),
>> +						parent_data->hwirq);
>> +		ti_sci_release_resource(intr->dst_irq, parent_data->hwirq);
>> +		irq_domain_free_irqs_parent(domain, virq + i, 1);
> 
> Couldn't this be moved out of the loop so that you free nr_irqs directly
> since you seem to be assuming that they are continuous? But are they?
> 
> Also, and depending on the context this is called from, it is pretty
> unlikely that you'll see nr_irqs!=1, the only case I know about being
> the PCI Multi-MSI train-wreck.

okay, ill drop the loop and consider only the case nr_irqs == 1

> 
>> +		irq_domain_reset_irq_data(data);
>> +	}
>> +}
>> +
>> +/**
>> + * ti_sci_intr_allocate_gic_irq() - Allocate GIC specific IRQ
>> + * @domain:	Point to the interrupt router IRQ domain
>> + * @dev:	TISCI device IRQ generating the IRQ
>> + * @irq:	IRQ offset within the device
>> + * @flags:	Corresponding flags to the IRQ
>> + * @event_irq:	Flag to tell if requested irq is from interrupt aggregator.
>> + *
>> + * Returns 0 if all went well else appropriate error pointer.
>> + */
>> +static int ti_sci_intr_allocate_gic_irq(struct irq_domain *domain,
>> +					unsigned int virq, u16 dev, u16 irq,
>> +					u32 flags, u8 event_irq)
>> +{
>> +	struct ti_sci_intr_irq_domain *intr = domain->host_data;
>> +	struct irq_fwspec fwspec;
>> +	u16 dst_irq;
>> +	int err;
>> +
>> +	if (!irq_domain_get_of_node(domain->parent))
>> +		return -EINVAL;
>> +
>> +	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] = flags & IRQ_TYPE_SENSE_MASK;
>> +
>> +	err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
>> +	if (err)
>> +		goto err_irqs;
>> +
>> +	/* If event is requested then return */
>> +	if (event_irq == TI_SCI_EVENT_IRQ)
>> +		return 0;
>> +
>> +	err = intr->sci->ops.rm_irq_ops.set_direct_irq(intr->sci, dev, irq,
>> +						       intr->dst_id, dst_irq);
>> +	if (err) {
>> +		pr_err("%s: IRQ allocation failed from src = %d, src_index = %d to dst_id = %d, dst_irq = %d",
>> +		       __func__, dev, irq, intr->dst_id, dst_irq);
> 
> Do we really needs this error message? It doesn't seem to provide any
> useful information at this stage. I'd rather the terrible callback does
> the screaming if required.

okay will drop this error message.

> 
>> +		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;
>> +	u16 src_id, src_index;
>> +	unsigned long hwirq;
>> +	u8 event_irq;
>> +	int i, err;
>> +	u32 type;
>> +
>> +	err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &type);
>> +	if (err)
>> +		return err;
>> +
>> +	src_id = HWIRQ_TO_DEVID(hwirq);
>> +	src_index = HWIRQ_TO_IRQID(hwirq);
>> +	event_irq = fwspec->param[3];
> 
> Ah, so this is where it is used. You could perform some sanitization,
> given that you're feeding this to other part of the system.

sure will add a check for fwspec->param[3].

Thanks and regards,
Lokesh

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device
  2019-01-24 10:19       ` Lokesh Vutla
@ 2019-02-04 10:33         ` Marc Zyngier
  2019-02-05 13:42           ` Lokesh Vutla
  0 siblings, 1 reply; 31+ messages in thread
From: Marc Zyngier @ 2019-02-04 10:33 UTC (permalink / raw)
  To: Lokesh Vutla, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

On 24/01/2019 10:19, Lokesh Vutla wrote:
> Hi Marc,
> 	Sorry for the delayed response. Just back from vacation.
> 
> On 17/01/19 12:00 AM, Marc Zyngier wrote:
>> On 27/12/2018 06:13, Lokesh Vutla wrote:
>>> Previously all msi for a device are allocated in one go
>>> by calling msi_domain_alloc_irq() from a bus layer. This might
>>> not be the case when a device is trying to allocate interrupts
>>> dynamically based on a request to it.
>>>
>>> So introduce msi_domain_alloc/free_irq() apis to allocate a single
>>> msi. prepare and activate operations to be handled by bus layer
>>> calling msi_domain_alloc/free_irq() apis.
>>>
>>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>>> ---
>>>  include/linux/msi.h |  3 +++
>>>  kernel/irq/msi.c    | 62 +++++++++++++++++++++++++++++----------------
>>>  2 files changed, 43 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/include/linux/msi.h b/include/linux/msi.h
>>> index 784fb52b9900..474490826f8c 100644
>>> --- a/include/linux/msi.h
>>> +++ b/include/linux/msi.h
>>> @@ -301,8 +301,11 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
>>>  struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
>>>   struct msi_domain_info *info,
>>>   struct irq_domain *parent);
>>> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
>>> + struct msi_desc *desc,  msi_alloc_info_t *arg);
>>>  int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>    int nvec);
>>> +void msi_domain_free_irq(struct msi_desc *desc);
>>>  void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
>>>  struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
>>>
>>> diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
>>> index ad26fbcfbfc8..eb7459324113 100644
>>> --- a/kernel/irq/msi.c
>>> +++ b/kernel/irq/msi.c
>>> @@ -387,6 +387,35 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
>>>  return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
>>>  }
>>>
>>> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
>>> + struct msi_desc *desc,  msi_alloc_info_t *arg)
>>> +{
>>> +struct msi_domain_info *info = domain->host_data;
>>> +struct msi_domain_ops *ops = info->ops;
>>> +int i, ret, virq;
>>> +
>>> +ops->set_desc(arg, desc);
>>> +
>>> +virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
>>> +       dev_to_node(dev), arg, false,
>>> +       desc->affinity);
>>> +if (virq < 0) {
>>> +ret = -ENOSPC;
>>> +if (ops->handle_error)
>>> +ret = ops->handle_error(domain, desc, ret);
>>> +if (ops->msi_finish)
>>> +ops->msi_finish(arg, ret);
>>> +return ret;
>>> +}
>>> +
>>> +for (i = 0; i < desc->nvec_used; i++) {
>>> +irq_set_msi_desc_off(virq, i, desc);
>>> +irq_debugfs_copy_devname(virq + i, dev);
>>> +}
>>> +
>>> +return 0;
>>> +}
>>> +
>>>  /**
>>>   * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
>>>   * @domain:The domain to allocate from
>>> @@ -404,7 +433,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>  struct irq_data *irq_data;
>>>  struct msi_desc *desc;
>>>  msi_alloc_info_t arg;
>>> -int i, ret, virq;
>>> +int ret, virq;
>>>  bool can_reserve;
>>>
>>>  ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
>>> @@ -412,24 +441,9 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>  return ret;
>>>
>>>  for_each_msi_entry(desc, dev) {
>>> -ops->set_desc(&arg, desc);
>>> -
>>> -virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
>>> -       dev_to_node(dev), &arg, false,
>>> -       desc->affinity);
>>> -if (virq < 0) {
>>> -ret = -ENOSPC;
>>> -if (ops->handle_error)
>>> -ret = ops->handle_error(domain, desc, ret);
>>> -if (ops->msi_finish)
>>> -ops->msi_finish(&arg, ret);
>>> +ret = msi_domain_alloc_irq(domain, dev, desc, &arg);
>>> +if (ret)
>>>  return ret;
>>> -}
>>> -
>>> -for (i = 0; i < desc->nvec_used; i++) {
>>> -irq_set_msi_desc_off(virq, i, desc);
>>> -irq_debugfs_copy_devname(virq + i, dev);
>>> -}
>>>  }
>>>
>>>  if (ops->msi_finish)
>>> @@ -487,6 +501,12 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>  return ret;
>>>  }
>>>
>>> +void msi_domain_free_irq(struct msi_desc *desc)
>>> +{
>>> +irq_domain_free_irqs(desc->irq, desc->nvec_used);
>>> +desc->irq = 0;
>>> +}
>>> +
>>>  /**
>>>   * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
>>>   * @domain:The domain to managing the interrupts
>>> @@ -503,10 +523,8 @@ void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
>>>   * enough that there is no IRQ associated to this
>>>   * entry. If that's the case, don't do anything.
>>>   */
>>> -if (desc->irq) {
>>> -irq_domain_free_irqs(desc->irq, desc->nvec_used);
>>> -desc->irq = 0;
>>> -}
>>> +if (desc->irq)
>>> +msi_domain_free_irq(desc);
>>>  }
>>>  }
>>>
>>>
>>
>> I can see some interesting issues with this API.
>>
>> At the moment, MSIs are allocated upfront, and that's usually done
>> before the driver can do anything else. With what you're suggesting
>> here, MSIs can now be allocated at any time, which sounds great. But how
>> does it work when MSIs get added/freed in parallel? I can't see any
>> locking here...
>>
>> It is also pretty nasty that the user of this API has to know about the
>> MSI descriptor. Really, nobody should have to deal with this outside of
>> the MSI layer.
>>
>> The real question is why you need to need to allocate MSIs on demand for
>> a given device. Usually, you allocate them because this is a per-CPU
>> resource, or something similar. What makes it so variable that you need
>> to resort to fine grained MSI allocation?
> 
> I added this after the discussion we had in the previous version[1] of this
> series. Let me provide the details again:
> 
> As you must be aware INTR is interrupt re-director and INTA is the interrupt
> multiplexer is the SoC. Here we are trying to address the interrupt connection
> route as below:
> Device(Global event) --> INTA --> INTR --> GIC
> 
> For the above case you suggested to have the following sw IRQ domain hierarchy:
> INTA multi MSI --> INTA  -->  INTR  --> GIC
> 
> The problem here with the INTA MSI is that all the interrupts for a device
> should be pre-allocated during the device probe time. But this is not what we
> wanted especially for the DMA case.
> 
> An example DMA ring connection would look like below[2]:
> 
>                       +---------------------+
>                        |         IA                |
> +--------+        |            +------+   |        +--------+         +------+
> | ring 1 +----->evtA+->VintX+-------->+   IR   +-- --->  GIC +-->
> +--------+       |             +------+   |        +--------+         +------+
> Linux IRQ Y
>    evtA            |                             |
>                        |                             |
>                       +----------------------+
> 
> So when a DMA client driver requests a dma channel during probe, the DMA driver
> gets a free ring in its allocated range. Then DMA driver requests MSI layer for
> an IRQ. This is why I had to introduce on demand allocation of MSIs for a device.
> 
> The reason why we avoided DMA driver to allocate interrupts during its probe as
> it is not aware of the exact no of channels that are going to be used. Also max
> allocation of interrupts will overrun the gic IRQs available to this INTA and
> the IPs that are connected to INTR directly will not get any interrupts.

But surely there is an upper bound that does exist for a given system,
right?  DMA rings are not allocated out of nowhere. Or are you saying
that when a DMA client requests DMA rings, it doesn't know how many it
wants? Or does it? I don't think this is new in any of TI's design (the
crossbar already had such limitation).

That being said, I'm open to revisiting this, but you must then
introduce the right level of mutual exclusion in core code, as the
msi_desc list now becomes much more dynamic and things would otherwise
break badly. This has implications all over the place, and probably
requires quite a bit of work (things like for_each_msi_desc_entry will
break).

Between the two solutions outlined above, the first one is much easier
to achieve than the second one.

Another avenue to explore would be to let the clients allocate as many
MSIs as they want upfront, and use the "activate" callback to actually
perform the assignment when such interrupt gets requested. In a way,
this is not that different from what x86 does with the "early
reservation, late assignment" type mechanism.

Thanks,

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

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device
  2019-02-04 10:33         ` Marc Zyngier
@ 2019-02-05 13:42           ` Lokesh Vutla
  2019-02-08 10:39             ` Marc Zyngier
  0 siblings, 1 reply; 31+ messages in thread
From: Lokesh Vutla @ 2019-02-05 13:42 UTC (permalink / raw)
  To: Marc Zyngier, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

Hi Marc,

On 04/02/19 4:03 PM, Marc Zyngier wrote:
> On 24/01/2019 10:19, Lokesh Vutla wrote:
>> Hi Marc,
>> 	Sorry for the delayed response. Just back from vacation.
>>
>> On 17/01/19 12:00 AM, Marc Zyngier wrote:
>>> On 27/12/2018 06:13, Lokesh Vutla wrote:
>>>> Previously all msi for a device are allocated in one go
>>>> by calling msi_domain_alloc_irq() from a bus layer. This might
>>>> not be the case when a device is trying to allocate interrupts
>>>> dynamically based on a request to it.
>>>>
>>>> So introduce msi_domain_alloc/free_irq() apis to allocate a single
>>>> msi. prepare and activate operations to be handled by bus layer
>>>> calling msi_domain_alloc/free_irq() apis.
>>>>
>>>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>>>> ---
>>>>  include/linux/msi.h |  3 +++
>>>>  kernel/irq/msi.c    | 62 +++++++++++++++++++++++++++++----------------
>>>>  2 files changed, 43 insertions(+), 22 deletions(-)
>>>>
>>>> diff --git a/include/linux/msi.h b/include/linux/msi.h
>>>> index 784fb52b9900..474490826f8c 100644
>>>> --- a/include/linux/msi.h
>>>> +++ b/include/linux/msi.h
>>>> @@ -301,8 +301,11 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
>>>>  struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
>>>>   struct msi_domain_info *info,
>>>>   struct irq_domain *parent);
>>>> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
>>>> + struct msi_desc *desc,  msi_alloc_info_t *arg);
>>>>  int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>>    int nvec);
>>>> +void msi_domain_free_irq(struct msi_desc *desc);
>>>>  void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
>>>>  struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
>>>>
>>>> diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
>>>> index ad26fbcfbfc8..eb7459324113 100644
>>>> --- a/kernel/irq/msi.c
>>>> +++ b/kernel/irq/msi.c
>>>> @@ -387,6 +387,35 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
>>>>  return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
>>>>  }
>>>>
>>>> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
>>>> + struct msi_desc *desc,  msi_alloc_info_t *arg)
>>>> +{
>>>> +struct msi_domain_info *info = domain->host_data;
>>>> +struct msi_domain_ops *ops = info->ops;
>>>> +int i, ret, virq;
>>>> +
>>>> +ops->set_desc(arg, desc);
>>>> +
>>>> +virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
>>>> +       dev_to_node(dev), arg, false,
>>>> +       desc->affinity);
>>>> +if (virq < 0) {
>>>> +ret = -ENOSPC;
>>>> +if (ops->handle_error)
>>>> +ret = ops->handle_error(domain, desc, ret);
>>>> +if (ops->msi_finish)
>>>> +ops->msi_finish(arg, ret);
>>>> +return ret;
>>>> +}
>>>> +
>>>> +for (i = 0; i < desc->nvec_used; i++) {
>>>> +irq_set_msi_desc_off(virq, i, desc);
>>>> +irq_debugfs_copy_devname(virq + i, dev);
>>>> +}
>>>> +
>>>> +return 0;
>>>> +}
>>>> +
>>>>  /**
>>>>   * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
>>>>   * @domain:The domain to allocate from
>>>> @@ -404,7 +433,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>>  struct irq_data *irq_data;
>>>>  struct msi_desc *desc;
>>>>  msi_alloc_info_t arg;
>>>> -int i, ret, virq;
>>>> +int ret, virq;
>>>>  bool can_reserve;
>>>>
>>>>  ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
>>>> @@ -412,24 +441,9 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>>  return ret;
>>>>
>>>>  for_each_msi_entry(desc, dev) {
>>>> -ops->set_desc(&arg, desc);
>>>> -
>>>> -virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
>>>> -       dev_to_node(dev), &arg, false,
>>>> -       desc->affinity);
>>>> -if (virq < 0) {
>>>> -ret = -ENOSPC;
>>>> -if (ops->handle_error)
>>>> -ret = ops->handle_error(domain, desc, ret);
>>>> -if (ops->msi_finish)
>>>> -ops->msi_finish(&arg, ret);
>>>> +ret = msi_domain_alloc_irq(domain, dev, desc, &arg);
>>>> +if (ret)
>>>>  return ret;
>>>> -}
>>>> -
>>>> -for (i = 0; i < desc->nvec_used; i++) {
>>>> -irq_set_msi_desc_off(virq, i, desc);
>>>> -irq_debugfs_copy_devname(virq + i, dev);
>>>> -}
>>>>  }
>>>>
>>>>  if (ops->msi_finish)
>>>> @@ -487,6 +501,12 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>>  return ret;
>>>>  }
>>>>
>>>> +void msi_domain_free_irq(struct msi_desc *desc)
>>>> +{
>>>> +irq_domain_free_irqs(desc->irq, desc->nvec_used);
>>>> +desc->irq = 0;
>>>> +}
>>>> +
>>>>  /**
>>>>   * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
>>>>   * @domain:The domain to managing the interrupts
>>>> @@ -503,10 +523,8 @@ void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
>>>>   * enough that there is no IRQ associated to this
>>>>   * entry. If that's the case, don't do anything.
>>>>   */
>>>> -if (desc->irq) {
>>>> -irq_domain_free_irqs(desc->irq, desc->nvec_used);
>>>> -desc->irq = 0;
>>>> -}
>>>> +if (desc->irq)
>>>> +msi_domain_free_irq(desc);
>>>>  }
>>>>  }
>>>>
>>>>
>>>
>>> I can see some interesting issues with this API.
>>>
>>> At the moment, MSIs are allocated upfront, and that's usually done
>>> before the driver can do anything else. With what you're suggesting
>>> here, MSIs can now be allocated at any time, which sounds great. But how
>>> does it work when MSIs get added/freed in parallel? I can't see any
>>> locking here...
>>>
>>> It is also pretty nasty that the user of this API has to know about the
>>> MSI descriptor. Really, nobody should have to deal with this outside of
>>> the MSI layer.
>>>
>>> The real question is why you need to need to allocate MSIs on demand for
>>> a given device. Usually, you allocate them because this is a per-CPU
>>> resource, or something similar. What makes it so variable that you need
>>> to resort to fine grained MSI allocation?
>>
>> I added this after the discussion we had in the previous version[1] of this
>> series. Let me provide the details again:
>>
>> As you must be aware INTR is interrupt re-director and INTA is the interrupt
>> multiplexer is the SoC. Here we are trying to address the interrupt connection
>> route as below:
>> Device(Global event) --> INTA --> INTR --> GIC
>>
>> For the above case you suggested to have the following sw IRQ domain hierarchy:
>> INTA multi MSI --> INTA  -->  INTR  --> GIC
>>
>> The problem here with the INTA MSI is that all the interrupts for a device
>> should be pre-allocated during the device probe time. But this is not what we
>> wanted especially for the DMA case.
>>
>> An example DMA ring connection would look like below[2]:
>>
>>                       +---------------------+
>>                        |         IA                |
>> +--------+        |            +------+   |        +--------+         +------+
>> | ring 1 +----->evtA+->VintX+-------->+   IR   +-- --->  GIC +-->
>> +--------+       |             +------+   |        +--------+         +------+
>> Linux IRQ Y
>>    evtA            |                             |
>>                        |                             |
>>                       +----------------------+
>>
>> So when a DMA client driver requests a dma channel during probe, the DMA driver
>> gets a free ring in its allocated range. Then DMA driver requests MSI layer for
>> an IRQ. This is why I had to introduce on demand allocation of MSIs for a device.
>>
>> The reason why we avoided DMA driver to allocate interrupts during its probe as
>> it is not aware of the exact no of channels that are going to be used. Also max
>> allocation of interrupts will overrun the gic IRQs available to this INTA and
>> the IPs that are connected to INTR directly will not get any interrupts.
> 
> But surely there is an upper bound that does exist for a given system,
> right?  DMA rings are not allocated out of nowhere. Or are you saying

Right, there is an upper limit on the DMA rings and DMA driver knows it. But
when an MSI is requested for each ring then the global events allocated for the
IA gets exhausted and MSI allocation gets failed.

Either I did not explain the the complete picture properly or I must be missing
something very badly here. Sorry for being dumb here. Let me give a pure
software perspective:

In the IRQ route we have the following variables:
1) source id
2) source index.
3) global events
4) vint
5) vint status bit(global event mapping to vint)
6) gic_irqs

- Source id and source index are managed by MSI client driver.
- Global event, vint and vint_status_bit allocation is managed by INTA driver
- Grouping of global event and mapping to vint is handled by INTA driver(chained
IRQ)
- gic_irqs allocation is managed by INTR driver.

When MSI client tries to allocate MSI for each source_index(rings for eg.)
available in a source, msi domain tries to allocate parent IRQs. Then INTA
driver will try to allocate a global event to each source index and fails when
the global events are exhausted. What am I missing here?

keeping in mind the above scenario, I started with single MSI allocations. I
agree there are issues with $patch. But before doing that I was hoping if the
above problem can be solved easily.

Also the same problem occurs for INTA parent IRQ allocation. INTA probe cannot
do a irq_create_fwspec_mapping() for all the available vints as gic_irqs will be
exhausted. Where do you think is the best place to create parent IRQs for INTA?
In the current implementation I am allocating it during msi_prepare(). So I had
to introduce msi_unprepare for freeing parent IRQs.

Thanks and regards,
Lokesh

> that when a DMA client requests DMA rings, it doesn't know how many it
> wants? Or does it? I don't think this is new in any of TI's design (the
> crossbar already had such limitation).
> 
> That being said, I'm open to revisiting this, but you must then
> introduce the right level of mutual exclusion in core code, as the
> msi_desc list now becomes much more dynamic and things would otherwise
> break badly. This has implications all over the place, and probably
> requires quite a bit of work (things like for_each_msi_desc_entry will
> break).
> 
> Between the two solutions outlined above, the first one is much easier
> to achieve than the second one.
> 
> Another avenue to explore would be to let the clients allocate as many
> MSIs as they want upfront, and use the "activate" callback to actually
> perform the assignment when such interrupt gets requested. In a way,
> this is not that different from what x86 does with the "early
> reservation, late assignment" type mechanism.
> 
> Thanks,
> 
> 	M.
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device
  2019-02-05 13:42           ` Lokesh Vutla
@ 2019-02-08 10:39             ` Marc Zyngier
  0 siblings, 0 replies; 31+ messages in thread
From: Marc Zyngier @ 2019-02-08 10:39 UTC (permalink / raw)
  To: Lokesh Vutla, Nishanth Menon, Santosh Shilimkar, Rob Herring,
	tglx, jason
  Cc: Linux ARM Mailing List, linux-kernel, Tero Kristo, Sekhar Nori,
	Device Tree Mailing List, Peter Ujfalusi

On 05/02/2019 13:42, Lokesh Vutla wrote:
> Hi Marc,
> 
> On 04/02/19 4:03 PM, Marc Zyngier wrote:
>> On 24/01/2019 10:19, Lokesh Vutla wrote:
>>> Hi Marc,
>>> 	Sorry for the delayed response. Just back from vacation.
>>>
>>> On 17/01/19 12:00 AM, Marc Zyngier wrote:
>>>> On 27/12/2018 06:13, Lokesh Vutla wrote:
>>>>> Previously all msi for a device are allocated in one go
>>>>> by calling msi_domain_alloc_irq() from a bus layer. This might
>>>>> not be the case when a device is trying to allocate interrupts
>>>>> dynamically based on a request to it.
>>>>>
>>>>> So introduce msi_domain_alloc/free_irq() apis to allocate a single
>>>>> msi. prepare and activate operations to be handled by bus layer
>>>>> calling msi_domain_alloc/free_irq() apis.
>>>>>
>>>>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>>>>> ---
>>>>>  include/linux/msi.h |  3 +++
>>>>>  kernel/irq/msi.c    | 62 +++++++++++++++++++++++++++++----------------
>>>>>  2 files changed, 43 insertions(+), 22 deletions(-)
>>>>>
>>>>> diff --git a/include/linux/msi.h b/include/linux/msi.h
>>>>> index 784fb52b9900..474490826f8c 100644
>>>>> --- a/include/linux/msi.h
>>>>> +++ b/include/linux/msi.h
>>>>> @@ -301,8 +301,11 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
>>>>>  struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
>>>>>   struct msi_domain_info *info,
>>>>>   struct irq_domain *parent);
>>>>> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
>>>>> + struct msi_desc *desc,  msi_alloc_info_t *arg);
>>>>>  int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>>>    int nvec);
>>>>> +void msi_domain_free_irq(struct msi_desc *desc);
>>>>>  void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
>>>>>  struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
>>>>>
>>>>> diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
>>>>> index ad26fbcfbfc8..eb7459324113 100644
>>>>> --- a/kernel/irq/msi.c
>>>>> +++ b/kernel/irq/msi.c
>>>>> @@ -387,6 +387,35 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
>>>>>  return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
>>>>>  }
>>>>>
>>>>> +int msi_domain_alloc_irq(struct irq_domain *domain, struct device *dev,
>>>>> + struct msi_desc *desc,  msi_alloc_info_t *arg)
>>>>> +{
>>>>> +struct msi_domain_info *info = domain->host_data;
>>>>> +struct msi_domain_ops *ops = info->ops;
>>>>> +int i, ret, virq;
>>>>> +
>>>>> +ops->set_desc(arg, desc);
>>>>> +
>>>>> +virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
>>>>> +       dev_to_node(dev), arg, false,
>>>>> +       desc->affinity);
>>>>> +if (virq < 0) {
>>>>> +ret = -ENOSPC;
>>>>> +if (ops->handle_error)
>>>>> +ret = ops->handle_error(domain, desc, ret);
>>>>> +if (ops->msi_finish)
>>>>> +ops->msi_finish(arg, ret);
>>>>> +return ret;
>>>>> +}
>>>>> +
>>>>> +for (i = 0; i < desc->nvec_used; i++) {
>>>>> +irq_set_msi_desc_off(virq, i, desc);
>>>>> +irq_debugfs_copy_devname(virq + i, dev);
>>>>> +}
>>>>> +
>>>>> +return 0;
>>>>> +}
>>>>> +
>>>>>  /**
>>>>>   * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
>>>>>   * @domain:The domain to allocate from
>>>>> @@ -404,7 +433,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>>>  struct irq_data *irq_data;
>>>>>  struct msi_desc *desc;
>>>>>  msi_alloc_info_t arg;
>>>>> -int i, ret, virq;
>>>>> +int ret, virq;
>>>>>  bool can_reserve;
>>>>>
>>>>>  ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
>>>>> @@ -412,24 +441,9 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>>>  return ret;
>>>>>
>>>>>  for_each_msi_entry(desc, dev) {
>>>>> -ops->set_desc(&arg, desc);
>>>>> -
>>>>> -virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
>>>>> -       dev_to_node(dev), &arg, false,
>>>>> -       desc->affinity);
>>>>> -if (virq < 0) {
>>>>> -ret = -ENOSPC;
>>>>> -if (ops->handle_error)
>>>>> -ret = ops->handle_error(domain, desc, ret);
>>>>> -if (ops->msi_finish)
>>>>> -ops->msi_finish(&arg, ret);
>>>>> +ret = msi_domain_alloc_irq(domain, dev, desc, &arg);
>>>>> +if (ret)
>>>>>  return ret;
>>>>> -}
>>>>> -
>>>>> -for (i = 0; i < desc->nvec_used; i++) {
>>>>> -irq_set_msi_desc_off(virq, i, desc);
>>>>> -irq_debugfs_copy_devname(virq + i, dev);
>>>>> -}
>>>>>  }
>>>>>
>>>>>  if (ops->msi_finish)
>>>>> @@ -487,6 +501,12 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
>>>>>  return ret;
>>>>>  }
>>>>>
>>>>> +void msi_domain_free_irq(struct msi_desc *desc)
>>>>> +{
>>>>> +irq_domain_free_irqs(desc->irq, desc->nvec_used);
>>>>> +desc->irq = 0;
>>>>> +}
>>>>> +
>>>>>  /**
>>>>>   * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
>>>>>   * @domain:The domain to managing the interrupts
>>>>> @@ -503,10 +523,8 @@ void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
>>>>>   * enough that there is no IRQ associated to this
>>>>>   * entry. If that's the case, don't do anything.
>>>>>   */
>>>>> -if (desc->irq) {
>>>>> -irq_domain_free_irqs(desc->irq, desc->nvec_used);
>>>>> -desc->irq = 0;
>>>>> -}
>>>>> +if (desc->irq)
>>>>> +msi_domain_free_irq(desc);
>>>>>  }
>>>>>  }
>>>>>
>>>>>
>>>>
>>>> I can see some interesting issues with this API.
>>>>
>>>> At the moment, MSIs are allocated upfront, and that's usually done
>>>> before the driver can do anything else. With what you're suggesting
>>>> here, MSIs can now be allocated at any time, which sounds great. But how
>>>> does it work when MSIs get added/freed in parallel? I can't see any
>>>> locking here...
>>>>
>>>> It is also pretty nasty that the user of this API has to know about the
>>>> MSI descriptor. Really, nobody should have to deal with this outside of
>>>> the MSI layer.
>>>>
>>>> The real question is why you need to need to allocate MSIs on demand for
>>>> a given device. Usually, you allocate them because this is a per-CPU
>>>> resource, or something similar. What makes it so variable that you need
>>>> to resort to fine grained MSI allocation?
>>>
>>> I added this after the discussion we had in the previous version[1] of this
>>> series. Let me provide the details again:
>>>
>>> As you must be aware INTR is interrupt re-director and INTA is the interrupt
>>> multiplexer is the SoC. Here we are trying to address the interrupt connection
>>> route as below:
>>> Device(Global event) --> INTA --> INTR --> GIC
>>>
>>> For the above case you suggested to have the following sw IRQ domain hierarchy:
>>> INTA multi MSI --> INTA  -->  INTR  --> GIC
>>>
>>> The problem here with the INTA MSI is that all the interrupts for a device
>>> should be pre-allocated during the device probe time. But this is not what we
>>> wanted especially for the DMA case.
>>>
>>> An example DMA ring connection would look like below[2]:
>>>
>>>                       +---------------------+
>>>                        |         IA                |
>>> +--------+        |            +------+   |        +--------+         +------+
>>> | ring 1 +----->evtA+->VintX+-------->+   IR   +-- --->  GIC +-->
>>> +--------+       |             +------+   |        +--------+         +------+
>>> Linux IRQ Y
>>>    evtA            |                             |
>>>                        |                             |
>>>                       +----------------------+
>>>
>>> So when a DMA client driver requests a dma channel during probe, the DMA driver
>>> gets a free ring in its allocated range. Then DMA driver requests MSI layer for
>>> an IRQ. This is why I had to introduce on demand allocation of MSIs for a device.
>>>
>>> The reason why we avoided DMA driver to allocate interrupts during its probe as
>>> it is not aware of the exact no of channels that are going to be used. Also max
>>> allocation of interrupts will overrun the gic IRQs available to this INTA and
>>> the IPs that are connected to INTR directly will not get any interrupts.
>>
>> But surely there is an upper bound that does exist for a given system,
>> right?  DMA rings are not allocated out of nowhere. Or are you saying
> 
> Right, there is an upper limit on the DMA rings and DMA driver knows it. But
> when an MSI is requested for each ring then the global events allocated for the
> IA gets exhausted and MSI allocation gets failed.
> 
> Either I did not explain the the complete picture properly or I must be missing
> something very badly here. Sorry for being dumb here. Let me give a pure
> software perspective:
> 
> In the IRQ route we have the following variables:
> 1) source id
> 2) source index.
> 3) global events
> 4) vint
> 5) vint status bit(global event mapping to vint)
> 6) gic_irqs
> 
> - Source id and source index are managed by MSI client driver.
> - Global event, vint and vint_status_bit allocation is managed by INTA driver
> - Grouping of global event and mapping to vint is handled by INTA driver(chained
> IRQ)
> - gic_irqs allocation is managed by INTR driver.
> 
> When MSI client tries to allocate MSI for each source_index(rings for eg.)
> available in a source, msi domain tries to allocate parent IRQs. Then INTA
> driver will try to allocate a global event to each source index and fails when
> the global events are exhausted. What am I missing here?

Surely this is something you can change by letting the underlying driver
know when to coalesce this things and when not to? Frankly, this looks a
lot like what the GICv3 ITS does when you have device aliasing. It knows
you're using the same global identifier for a different purpose because:

- the upper layer tells it what ID to use
- the lower layer tracks what IDs are already in use

This involves tracking, refcounting, but I don't think that's out of the
realm of possible things.

> keeping in mind the above scenario, I started with single MSI allocations. I
> agree there are issues with $patch. But before doing that I was hoping if the
> above problem can be solved easily.

If problems were solved easily, they wouldn't be problems... :-/

> Also the same problem occurs for INTA parent IRQ allocation. INTA probe cannot
> do a irq_create_fwspec_mapping() for all the available vints as gic_irqs will be
> exhausted. Where do you think is the best place to create parent IRQs for INTA?
> In the current implementation I am allocating it during msi_prepare(). So I had
> to introduce msi_unprepare for freeing parent IRQs.

And I'll continue saying that this isn't a practical option. You're
breaking so many existing assumption it is not even funny. I'm not going
to prevent you from doing so, but if you do, the API has to be robust
for the existing use cases. What you've proposed so far isn't.

Thanks,

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

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2019-02-08 10:39 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-27  6:08 [PATCH v4 00/13] Add support for TISCI irqchip drivers Lokesh Vutla
2018-12-27  6:13 ` [PATCH v4 01/13] firmware: ti_sci: Add support to get TISCI handle using of_phandle Lokesh Vutla
2018-12-27  6:13   ` [PATCH v4 02/13] firmware: ti_sci: Add support for RM core ops Lokesh Vutla
2018-12-27  6:13   ` [PATCH v4 03/13] firmware: ti_sci: Add support for IRQ management Lokesh Vutla
2018-12-27  6:13   ` [PATCH v4 04/13] firmware: ti_sci: Add RM mapping table for am654 Lokesh Vutla
2018-12-27  6:13   ` [PATCH v4 05/13] firmware: ti_sci: Add helper apis to manage resources Lokesh Vutla
2018-12-27 16:15     ` Nishanth Menon
2018-12-27  6:13   ` [PATCH v4 06/13] dt-bindings: irqchip: Introduce TISCI Interrupt router bindings Lokesh Vutla
2018-12-27  6:13   ` [PATCH v4 07/13] irqchip: ti-sci-intr: Add support for Interrupt Router driver Lokesh Vutla
2019-01-16 17:16     ` Marc Zyngier
2019-01-24 10:19       ` Lokesh Vutla
2018-12-27  6:13   ` [RFC PATCH v4 08/13] genirq/msi: Add support for allocating single MSI for a device Lokesh Vutla
2019-01-16 18:30     ` Marc Zyngier
2019-01-24 10:19       ` Lokesh Vutla
2019-02-04 10:33         ` Marc Zyngier
2019-02-05 13:42           ` Lokesh Vutla
2019-02-08 10:39             ` Marc Zyngier
2018-12-27  6:13   ` [RFC PATCH v4 09/13] genirq/msi: Add support for .msi_unprepare callback Lokesh Vutla
2019-01-17 10:39     ` Marc Zyngier
2018-12-27  6:13   ` [RFC PATCH v4 10/13] soc: ti: Add MSI domain support for K3 Interrupt Aggregator Lokesh Vutla
2019-01-15 14:41     ` Nishanth Menon
2018-12-27  6:13   ` [RFC PATCH v4 11/13] dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings Lokesh Vutla
2018-12-27  6:13   ` [RFC PATCH v4 12/13] irqchip: ti-sci-inta: Add support for Interrupt Aggregator driver Lokesh Vutla
2019-01-02 11:49     ` Peter Ujfalusi
2019-01-02 12:26       ` Lokesh Vutla
2019-01-15 12:38         ` Tero Kristo
2019-01-15 14:04           ` Nishanth Menon
2018-12-27  6:13   ` [RFC PATCH v4 13/13] soc: ti: am6: Enable interrupt controller drivers Lokesh Vutla
2019-01-15 13:54     ` Nishanth Menon
2019-01-02 11:58 ` [PATCH v4 00/13] Add support for TISCI irqchip drivers Peter Ujfalusi
2019-01-11 10:28 ` Lokesh Vutla

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).