Commit 49b32315 authored by Lokesh Vutla's avatar Lokesh Vutla Committed by Marc Zyngier

soc: ti: Add MSI domain bus support for Interrupt Aggregator

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

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

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

APIs that are implemented:
- ti_sci_inta_msi_create_irq_domain() that creates a MSI domain
- ti_sci_inta_msi_domain_alloc_irqs() that creates MSIs for the
  specified device and resource.
- ti_sci_inta_msi_domain_free_irqs() frees the irqs attached to the device.
- ti_sci_inta_msi_get_virq() for getting the virq attached to a specific event.
Signed-off-by: default avatarLokesh Vutla <lokeshvutla@ti.com>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 9f1463b8
...@@ -15353,6 +15353,8 @@ F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt ...@@ -15353,6 +15353,8 @@ F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.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-intr.c
F: drivers/irqchip/irq-ti-sci-inta.c F: drivers/irqchip/irq-ti-sci-inta.c
F: include/linux/soc/ti/ti_sci_inta_msi.h
F: drivers/soc/ti/ti_sci_inta_msi.c
Texas Instruments ASoC drivers Texas Instruments ASoC drivers
M: Peter Ujfalusi <peter.ujfalusi@ti.com> M: Peter Ujfalusi <peter.ujfalusi@ti.com>
......
...@@ -73,4 +73,10 @@ config TI_SCI_PM_DOMAINS ...@@ -73,4 +73,10 @@ config TI_SCI_PM_DOMAINS
called ti_sci_pm_domains. Note this is needed early in boot before called ti_sci_pm_domains. Note this is needed early in boot before
rootfs may be available. rootfs may be available.
config TI_SCI_INTA_MSI_DOMAIN
bool
select GENERIC_MSI_IRQ_DOMAIN
help
Driver to enable Interrupt Aggregator specific MSI Domain.
endif # SOC_TI endif # SOC_TI
...@@ -8,3 +8,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o ...@@ -8,3 +8,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o
obj-$(CONFIG_AMX3_PM) += pm33xx.o obj-$(CONFIG_AMX3_PM) += pm33xx.o
obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o
obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
obj-$(CONFIG_TI_SCI_INTA_MSI_DOMAIN) += ti_sci_inta_msi.o
// SPDX-License-Identifier: GPL-2.0
/*
* Texas Instruments' K3 Interrupt Aggregator MSI bus
*
* Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*/
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/soc/ti/ti_sci_inta_msi.h>
#include <linux/soc/ti/ti_sci_protocol.h>
static void ti_sci_inta_msi_write_msg(struct irq_data *data,
struct msi_msg *msg)
{
/* Nothing to do */
}
static void ti_sci_inta_msi_compose_msi_msg(struct irq_data *data,
struct msi_msg *msg)
{
/* Nothing to do */
}
static void ti_sci_inta_msi_update_chip_ops(struct msi_domain_info *info)
{
struct irq_chip *chip = info->chip;
if (WARN_ON(!chip))
return;
chip->irq_request_resources = irq_chip_request_resources_parent;
chip->irq_release_resources = irq_chip_release_resources_parent;
chip->irq_compose_msi_msg = ti_sci_inta_msi_compose_msi_msg;
chip->irq_write_msi_msg = ti_sci_inta_msi_write_msg;
chip->irq_set_type = irq_chip_set_type_parent;
chip->irq_unmask = irq_chip_unmask_parent;
chip->irq_mask = irq_chip_mask_parent;
chip->irq_ack = irq_chip_ack_parent;
}
struct irq_domain *ti_sci_inta_msi_create_irq_domain(struct fwnode_handle *fwnode,
struct msi_domain_info *info,
struct irq_domain *parent)
{
struct irq_domain *domain;
ti_sci_inta_msi_update_chip_ops(info);
domain = msi_create_irq_domain(fwnode, info, parent);
if (domain)
irq_domain_update_bus_token(domain, DOMAIN_BUS_TI_SCI_INTA_MSI);
return domain;
}
EXPORT_SYMBOL_GPL(ti_sci_inta_msi_create_irq_domain);
static void ti_sci_inta_msi_free_descs(struct device *dev)
{
struct msi_desc *desc, *tmp;
list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) {
list_del(&desc->list);
free_msi_entry(desc);
}
}
static int ti_sci_inta_msi_alloc_descs(struct device *dev,
struct ti_sci_resource *res)
{
struct msi_desc *msi_desc;
int set, i, count = 0;
for (set = 0; set < res->sets; set++) {
for (i = 0; i < res->desc[set].num; i++) {
msi_desc = alloc_msi_entry(dev, 1, NULL);
if (!msi_desc) {
ti_sci_inta_msi_free_descs(dev);
return -ENOMEM;
}
msi_desc->inta.dev_index = res->desc[set].start + i;
INIT_LIST_HEAD(&msi_desc->list);
list_add_tail(&msi_desc->list, dev_to_msi_list(dev));
count++;
}
}
return count;
}
int ti_sci_inta_msi_domain_alloc_irqs(struct device *dev,
struct ti_sci_resource *res)
{
struct platform_device *pdev = to_platform_device(dev);
struct irq_domain *msi_domain;
int ret, nvec;
msi_domain = dev_get_msi_domain(dev);
if (!msi_domain)
return -EINVAL;
if (pdev->id < 0)
return -ENODEV;
nvec = ti_sci_inta_msi_alloc_descs(dev, res);
if (nvec <= 0)
return nvec;
ret = msi_domain_alloc_irqs(msi_domain, dev, nvec);
if (ret) {
dev_err(dev, "Failed to allocate IRQs %d\n", ret);
goto cleanup;
}
return 0;
cleanup:
ti_sci_inta_msi_free_descs(&pdev->dev);
return ret;
}
EXPORT_SYMBOL_GPL(ti_sci_inta_msi_domain_alloc_irqs);
void ti_sci_inta_msi_domain_free_irqs(struct device *dev)
{
msi_domain_free_irqs(dev->msi_domain, dev);
ti_sci_inta_msi_free_descs(dev);
}
EXPORT_SYMBOL_GPL(ti_sci_inta_msi_domain_free_irqs);
unsigned int ti_sci_inta_msi_get_virq(struct device *dev, u32 dev_index)
{
struct msi_desc *desc;
for_each_msi_entry(desc, dev)
if (desc->inta.dev_index == dev_index)
return desc->irq;
return -ENODEV;
}
EXPORT_SYMBOL_GPL(ti_sci_inta_msi_get_virq);
...@@ -82,6 +82,7 @@ enum irq_domain_bus_token { ...@@ -82,6 +82,7 @@ enum irq_domain_bus_token {
DOMAIN_BUS_NEXUS, DOMAIN_BUS_NEXUS,
DOMAIN_BUS_IPI, DOMAIN_BUS_IPI,
DOMAIN_BUS_FSL_MC_MSI, DOMAIN_BUS_FSL_MC_MSI,
DOMAIN_BUS_TI_SCI_INTA_MSI,
}; };
/** /**
......
...@@ -47,6 +47,14 @@ struct fsl_mc_msi_desc { ...@@ -47,6 +47,14 @@ struct fsl_mc_msi_desc {
u16 msi_index; u16 msi_index;
}; };
/**
* ti_sci_inta_msi_desc - TISCI based INTA specific msi descriptor data
* @dev_index: TISCI device index
*/
struct ti_sci_inta_msi_desc {
u16 dev_index;
};
/** /**
* struct msi_desc - Descriptor structure for MSI based interrupts * struct msi_desc - Descriptor structure for MSI based interrupts
* @list: List head for management * @list: List head for management
...@@ -68,6 +76,7 @@ struct fsl_mc_msi_desc { ...@@ -68,6 +76,7 @@ struct fsl_mc_msi_desc {
* @mask_base: [PCI MSI-X] Mask register base address * @mask_base: [PCI MSI-X] Mask register base address
* @platform: [platform] Platform device specific msi descriptor data * @platform: [platform] Platform device specific msi descriptor data
* @fsl_mc: [fsl-mc] FSL MC device specific msi descriptor data * @fsl_mc: [fsl-mc] FSL MC device specific msi descriptor data
* @inta: [INTA] TISCI based INTA specific msi descriptor data
*/ */
struct msi_desc { struct msi_desc {
/* Shared device/bus type independent data */ /* Shared device/bus type independent data */
...@@ -106,6 +115,7 @@ struct msi_desc { ...@@ -106,6 +115,7 @@ struct msi_desc {
*/ */
struct platform_msi_desc platform; struct platform_msi_desc platform;
struct fsl_mc_msi_desc fsl_mc; struct fsl_mc_msi_desc fsl_mc;
struct ti_sci_inta_msi_desc inta;
}; };
}; };
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Texas Instruments' K3 TI SCI INTA MSI helper
*
* Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*/
#ifndef __INCLUDE_LINUX_TI_SCI_INTA_MSI_H
#define __INCLUDE_LINUX_TI_SCI_INTA_MSI_H
#include <linux/msi.h>
#include <linux/soc/ti/ti_sci_protocol.h>
struct irq_domain
*ti_sci_inta_msi_create_irq_domain(struct fwnode_handle *fwnode,
struct msi_domain_info *info,
struct irq_domain *parent);
int ti_sci_inta_msi_domain_alloc_irqs(struct device *dev,
struct ti_sci_resource *res);
unsigned int ti_sci_inta_msi_get_virq(struct device *dev, u32 index);
void ti_sci_inta_msi_domain_free_irqs(struct device *dev);
#endif /* __INCLUDE_LINUX_IRQCHIP_TI_SCI_INTA_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment