Re: [PATCH v5 06/10] irqchip: ti-sci-intr: Add support for Interrupt Router driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Marc,

On 18/02/19 9:22 PM, Marc Zyngier wrote:
> On Tue, 12 Feb 2019 13:12:33 +0530
> Lokesh Vutla <lokeshvutla@xxxxxx> 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@xxxxxx>
>> ---
>> Changes since v4:
>> - Moved the ti_sci irq resource handling to ti-sci-common.c from ti_sci.c.
>>   Firmware maintainer rejected the idea of having this in firmware
>> driver as the resource handling is specific to the client.
>> - Obtain the number of peripheral interrupts attached to INTR by
>> parsing DT. Using this information store the max irqs that can be
>> allocated to INTA. This is done for pre allocating the INTA
>> irqs(vints) during inta driver probe.
>>   This will not work for cases where there are more that 1 INTAs
>> attached to INTR, but wanted to show this approach as suggested by
>> Marc.
> 
> Or not.
> 
>>
>>  MAINTAINERS                         |   3 +
>>  drivers/irqchip/Kconfig             |  11 +
>>  drivers/irqchip/Makefile            |   1 +
>>  drivers/irqchip/irq-ti-sci-common.c | 131 ++++++++++++
>>  drivers/irqchip/irq-ti-sci-common.h |  59 ++++++
>>  drivers/irqchip/irq-ti-sci-intr.c   | 315
>> ++++++++++++++++++++++++++++ 6 files changed, 520 insertions(+)
>>  create mode 100644 drivers/irqchip/irq-ti-sci-common.c
>>  create mode 100644 drivers/irqchip/irq-ti-sci-common.h
>>  create mode 100644 drivers/irqchip/irq-ti-sci-intr.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index c918d9b2ee18..823eeb672cf0 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -15065,6 +15065,9 @@ 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 +F:
>> drivers/irqchip/irq-ti-sci-common.c +F:
>> drivers/irqchip/irq-ti-sci-common.h 
>>  Texas Instruments ASoC drivers
>>  M:	Peter Ujfalusi <peter.ujfalusi@xxxxxx>
>> 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..0499fae148a9 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 irq-ti-sci-common.o diff --git
>> a/drivers/irqchip/irq-ti-sci-common.c
>> b/drivers/irqchip/irq-ti-sci-common.c new file mode 100644 index
>> 000000000000..79d9c4e8ea14 --- /dev/null
>> +++ b/drivers/irqchip/irq-ti-sci-common.c
>> @@ -0,0 +1,131 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Common Code for TISCI IRQCHIP drivers
>> + *
>> + * Copyright (C) 2019 Texas Instruments Incorporated -
>> http://www.ti.com/
>> + *	Lokesh Vutla <lokeshvutla@xxxxxx>
>> + */
>> +
>> +#include <linux/of.h>
>> +#include <linux/bitmap.h>
>> +#include <linux/device.h>
>> +#include <linux/soc/ti/ti_sci_protocol.h>
>> +#include "irq-ti-sci-common.h"
>> +
>> +/**
>> + * 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)
>> +{
>> +	u16 set, free_bit;
>> +
>> +	mutex_lock(&res->request_mutex);
>> +	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);
>> +			mutex_unlock(&res->request_mutex);
>> +			return res->desc[set].start + free_bit;
>> +		}
>> +	}
>> +	mutex_unlock(&res->request_mutex);
>> +
>> +	return TI_SCI_RESOURCE_NULL;
>> +}
>> +
>> +/**
>> + * ti_sci_release_resource() - Release a resource from TISCI
>> resource.
>> + * @res:	Pointer to the TISCI resource
>> + * @id:		Resource id to be released.
>> + */
>> +void ti_sci_release_resource(struct ti_sci_resource *res, u16 id)
>> +{
>> +	u16 set;
>> +
>> +	mutex_lock(&res->request_mutex);
>> +	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);
>> +	}
>> +	mutex_unlock(&res->request_mutex);
>> +}
>> +
>> +u32 ti_sci_get_num_resources(struct ti_sci_resource *res)
>> +{
>> +	u32 count = 0, set;
>> +
>> +	for (set = 0; set < res->sets; set++)
>> +		count += res->desc[set].num;
>> +
>> +	return count;
>> +}
>> +
>> +/**
>> + * 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
>> + *
>> + * Return: Pointer to ti_sci_resource if all went well else
>> appropriate
>> + *	   error pointer.
>> + */
>> +struct ti_sci_resource *
>> +devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
>> +			    struct device *dev, u32 dev_id, char
>> *of_prop) +{
>> +	struct ti_sci_resource *res;
>> +	u32 resource_subtype;
>> +	int i, ret;
>> +
>> +	res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
>> +	if (!res)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	res->sets =
>> of_property_count_elems_of_size(dev_of_node(dev), of_prop,
>> +						    sizeof(u32));
>> +	if (res->sets < 0) {
>> +		dev_err(dev, "%s resource type ids not available\n",
>> of_prop);
>> +		return ERR_PTR(res->sets);
>> +	}
>> +
>> +	res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
>> +				 GFP_KERNEL);
>> +	if (!res->desc)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	for (i = 0; i < res->sets; i++) {
>> +		ret = of_property_read_u32_index(dev_of_node(dev),
>> of_prop, i,
>> +						 &resource_subtype);
>> +		if (ret)
>> +			return ERR_PTR(-EINVAL);
>> +
>> +		ret = handle->ops.rm_core_ops.get_range(handle,
>> dev_id,
>> +
>> resource_subtype,
>> +
>> &res->desc[i].start,
>> +
>> &res->desc[i].num);
>> +		if (ret) {
>> +			dev_err(dev, "dev = %d subtype %d not
>> allocated for this host\n",
>> +				dev_id, resource_subtype);
>> +			return ERR_PTR(ret);
>> +		}
>> +
>> +		dev_dbg(dev, "dev = %d, subtype = %d, start = %d,
>> num = %d\n",
>> +			dev_id, resource_subtype, res->desc[i].start,
>> +			res->desc[i].num);
>> +
>> +		res->desc[i].res_map =
>> +			devm_kzalloc(dev,
>> BITS_TO_LONGS(res->desc[i].num) *
>> +				     sizeof(*res->desc[i].res_map),
>> GFP_KERNEL);
>> +		if (!res->desc[i].res_map)
>> +			return ERR_PTR(-ENOMEM);
>> +	}
>> +	mutex_init(&res->request_mutex);
>> +
>> +	return res;
>> +}
>> diff --git a/drivers/irqchip/irq-ti-sci-common.h
>> b/drivers/irqchip/irq-ti-sci-common.h new file mode 100644
>> index 000000000000..60c4b28bebab
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-ti-sci-common.h
>> @@ -0,0 +1,59 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Common header file for TISCI IRQCHIP drivers
>> + *
>> + * Copyright (C) 2019 Texas Instruments Incorporated -
>> http://www.ti.com/
>> + *	Lokesh Vutla <lokeshvutla@xxxxxx>
>> + */
>> +
>> +#ifndef __TI_SCI_COMMON_IRQCHIP_H
>> +#define __TI_SCI_COMMON_IRQCHIP_H
>> +
>> +#include <linux/mutex.h>
>> +
>> +#define TI_SCI_RESOURCE_NULL	0xffff
>> +#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_VINT_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 TO_HWIRQ(dev, index)	((((dev) & TI_SCI_DEV_ID_MASK)
>> << \
>> +				 TI_SCI_DEV_ID_SHIFT) | \
>> +				((index) & TI_SCI_IRQ_ID_MASK))
>> +
>> +/**
>> + * 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
>> + * @request_mutex:	mutex to protect request and release of
>> resources.
>> + * @desc:		Array of resource descriptors.
>> + */
>> +struct ti_sci_resource {
>> +	u16 sets;
>> +	/* Mutex to protect request and release of resources */
>> +	struct mutex request_mutex;
>> +	struct ti_sci_resource_desc *desc;
>> +};
>> +
>> +u16 ti_sci_get_free_resource(struct ti_sci_resource *res);
>> +void ti_sci_release_resource(struct ti_sci_resource *res, u16 id);
>> +u32 ti_sci_get_num_resources(struct ti_sci_resource *res);
>> +struct ti_sci_resource *
>> +devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
>> +			    struct device *dev, u32 dev_id, char
>> *of_prop); +#endif /*__TI_SCI_COMMON_IRQCHIP_H */
> 
> Most the above "common" should be a separate patch, really. Also, why

ok will move this into a separate patch.

> isn't the whole resource management part of the firmware interface? I
> see that "Firmware maintainer rejected the idea", but I don't really
> buy the rational. I don't see anything irq specific to the whole
> devm_ti_sci_get_of_resource and co, to be honest.

I guess the concern is mostly about the way ids are represented from DT. Using
this every tisci client should mandate to have separate DT property for each of
its resource.

> 
>> diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c
>> new file mode 100644
>> index 000000000000..7e224552a735
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-ti-sci-intr.c
>> @@ -0,0 +1,315 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Texas Instruments' K3 Interrupt Router irqchip driver
>> + *
>> + * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
>> + *	Lokesh Vutla <lokeshvutla@xxxxxx>
>> + */

[..snip..]

>> +	err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &type);
>> +	if (err)
>> +		return err;
>> +
>> +	vint_irq = fwspec->param[3] & TI_SCI_VINT_IRQ;
>> +
>> +	err = ti_sci_intr_alloc_gic_irq(domain, virq, hwirq, type, vint_irq);
>> +	if (err)
>> +		return err;
>> +
>> +	err = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
>> +					    &ti_sci_intr_irq_chip,
>> +					    (void *)vint_irq);
> 
> I think I see what you're trying to achieve. I suggest you look a
> uintptr_t instead of playing with unrelated data types whose semantic
> really doesn't apply here.

As you commented on the dt-bindings patch to differentiate vints using the INTA
ids, this will not be needed anymore. Will completely drop this.

> 
>> +	if (err) {
>> +		ti_sci_intr_irq_domain_free(domain, virq, 1);
>> +		return err;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +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 device_node *parent_node, *dn;
>> +	struct ti_sci_intr_irq_domain *intr;
>> +	struct device *dev = &pdev->dev;
>> +	struct of_phandle_iterator it;
>> +	int ret, count, intsize;
>> +
>> +	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;
>> +	}
>> +
>> +	if (of_property_read_u32(dev_of_node(dev), "#interrupt-cells",
>> +				 &intsize))
>> +		return -EINVAL;
>> +
>> +	count = 0;
>> +	for_each_node_with_property(dn, "interrupts") {
>> +		if (of_irq_find_parent(dn) != dev_of_node(dev))
>> +			continue;
>> +		count += of_property_count_elems_of_size(dn, "interrupts",
>> +							 sizeof(u32) * intsize);
>> +	}
>> +
>> +	for_each_node_with_property(dn, "interrupts-extended") {
>> +		of_for_each_phandle(&it, ret, dn, "interrupts-extended",
>> +				    "#interrupt-cells", 0) {
>> +			if (it.node == dev_of_node(dev))
>> +				count++;
>> +		}
>> +	}
> 
> What is this trying to do? Counting the number of interrupt descriptors
> in the whole system? What does this even mean?

I am just trying for max utilization of GIC interrupts available for this. Since
inta vints are not represented in DT, total gic available - whatever is in DT
gives the max interrupts that can be used for the child INTA.

> 
> What I suggested was to allocate the required number of interrupts
> for a given device, based on the requirements of that device. I also

okay, then Ill get the number of interrupts needed for INTA from DT.

> suggested to investigate the x86 two phase allocation mechanism for the
> INTA driver.

Sorry, Ill try to explore this path. Any pointers to the doc/code will be really
helpful :)

Thanks and regards,
Lokesh

> 
> I never suggested that you'd parse the DT to guess how many interrupts
> you'd need to allocate...
> 
> 	M.
> 
>> +
>> +	intr->vint_irqs = ti_sci_get_num_resources(intr->dst_irq) - count;
>> +
>> +	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");
> 
> 
> 



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux