From: Hanjun Guo <[email protected]>
v4 -> v5:
- Add mbigen support back with tested on with Agustin's patchset,
and it's a good example of how ACPI platform MSI works
- rebased on top of lastest Linus tree (commit 52bce91 splice: reinstate SIGPIPE/EPIPE handling)
v3 -> v4:
- Drop mbi-gen patches to just submit platform msi support because
will rebase mbi-gen patches on top of Agustin's patchset, and discusion
is going there.
- Add a patch to support device topology such as NC(named componant, paltform device)
->SMMU->ITS which suggested by Lorenzo;
- rebased on top of Lorenzo's v9 of ACPI IORT ARM SMMU support;
- rebased on top of 4.9-rc7
v2 -> v3:
- Drop RFC tag
- Rebase against v4.9-rc2 and Lorenzo's v6 of ACPI IORT ARM SMMU support [1]
- Add 3 cleanup patches (patch 1, 2, 3)
- Drop arch_init call patch from last version
- Introduce a callback for platform device to set msi domain
- Introduce a new API to get paltform device's domain instead of
reusing the PCI one in previous version
- Add a patch to rework iort_node_get_id()
[1]: http://www.mail-archive.com/[email protected]/msg1251993.html
v1 -> v2:
- Fix the bug of if multi Interrupt() resoures in single _PRS,
we need to calculate all the irq numbers (I missed it in previous
version);
- Rebased on Marc's irq/irqchip-4.9 branch and Lorenzo's v5
SMMU patches (also Robin's SMMu patches)
- Add patch irqchip: mbigen: promote mbigen init.
With platform msi support landed in the kernel, and the introduction
of IORT for GICv3 ITS (PCI MSI) and SMMU, the framework for platform msi
is ready, this patch set add few patches to enable the ACPI platform
msi support.
For platform device connecting to ITS on arm platform, we have IORT
table with the named componant node to describe the mappings of paltform
device and ITS, so we can retrieve the dev id and find its parent
irqdomain (ITS) from IORT table (simlar with the ACPI ITS support).
The fisrt 3 patches are cleanups;
Patch 4,5 are refactoring its_pmsi_prepare() for both DT and ACPI
then retrieve the dev id from iort;
Patch 6,7 to create platform msi domain to ACPI case which scanned
the MADT table;
Patch 8,9,10,11 to setup the msi domain for platform device based
on IORT table.
Patch 12,13,14 convert dt based mbigen driver to support ACPI.
Teasted on Hisilicon D03/D05.
Happy holidays!
Thanks
Hanjun
Hanjun Guo (12):
ACPI: ARM64: IORT: minor cleanup for iort_match_node_callback()
irqchip: gic-v3-its: keep the head file include in alphabetic order
ACPI: ARM64: IORT: add missing comment for iort_dev_find_its_id()
irqchip: gicv3-its: platform-msi: refactor its_pmsi_prepare()
ACPI: platform-msi: retrieve dev id from IORT
irqchip: gicv3-its: platform-msi: refactor its_pmsi_init() to prepare
for ACPI
irqchip: gicv3-its: platform-msi: scan MADT to create platform msi
domain
ACPI: ARM64: IORT: rework iort_node_get_id()
ACPI: platform: setup MSI domain for ACPI based platform device
ACPI: ARM64: IORT: rework iort_node_get_id() for NC->SMMU->ITS case
msi: platform: make platform_msi_create_device_domain() ACPI aware
irqchip: mbigen: Add ACPI support
Kefeng Wang (2):
irqchip: mbigen: drop module owner
irqchip: mbigen: introduce mbigen_of_create_domain()
drivers/acpi/acpi_platform.c | 11 ++
drivers/acpi/arm64/iort.c | 138 ++++++++++++++++++++------
drivers/base/platform-msi.c | 3 +-
drivers/base/platform.c | 3 +
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 106 +++++++++++++++-----
drivers/irqchip/irq-gic-v3-its.c | 3 +-
drivers/irqchip/irq-mbigen.c | 109 ++++++++++++++++----
include/linux/acpi_iort.h | 11 ++
include/linux/platform_device.h | 3 +
9 files changed, 309 insertions(+), 78 deletions(-)
--
1.7.12.4
From: Hanjun Guo <[email protected]>
Cleanup iort_match_node_callback() a little bit to reduce
some lines of code, aslo fix the indentation in iort_scan_node().
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Lorenzo Pieralisi <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Tomasz Nowicki <[email protected]>
---
drivers/acpi/arm64/iort.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index e0d2e6e..46e2d82 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -225,7 +225,7 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
if (iort_node->type == type &&
ACPI_SUCCESS(callback(iort_node, context)))
- return iort_node;
+ return iort_node;
iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
iort_node->length);
@@ -253,17 +253,15 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
void *context)
{
struct device *dev = context;
- acpi_status status;
+ acpi_status status = AE_NOT_FOUND;
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
struct acpi_iort_named_component *ncomp;
- if (!adev) {
- status = AE_NOT_FOUND;
+ if (!adev)
goto out;
- }
status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
if (ACPI_FAILURE(status)) {
@@ -289,8 +287,6 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
*/
status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
AE_OK : AE_NOT_FOUND;
- } else {
- status = AE_NOT_FOUND;
}
out:
return status;
--
1.7.12.4
From: Hanjun Guo <[email protected]>
Adding ACPI support for platform MSI, we need to retrieve the
dev id in ACPI way instead of device tree, we already have
a well formed function its_pmsi_prepare() to get the dev id
but it's OF dependent, so collect OF related code and put them
into a single function to make its_pmsi_prepare() more friendly
to ACPI later.
Signed-off-by: Hanjun Guo <[email protected]>
Tested-by: Sinan Kaya <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Lorenzo Pieralisi <[email protected]>
Cc: Tomasz Nowicki <[email protected]>
Cc: Thomas Gleixner <[email protected]>
---
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 470b4aa..3c94278 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -24,15 +24,11 @@
.name = "ITS-pMSI",
};
-static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
- int nvec, msi_alloc_info_t *info)
+static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
+ u32 *dev_id)
{
- struct msi_domain_info *msi_info;
- u32 dev_id;
int ret, index = 0;
- msi_info = msi_get_domain_info(domain->parent);
-
/* Suck the DeviceID out of the msi-parent property */
do {
struct of_phandle_args args;
@@ -43,11 +39,24 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
if (args.np == irq_domain_get_of_node(domain)) {
if (WARN_ON(args.args_count != 1))
return -EINVAL;
- dev_id = args.args[0];
+ *dev_id = args.args[0];
break;
}
} while (!ret);
+ return ret;
+}
+
+static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
+ int nvec, msi_alloc_info_t *info)
+{
+ struct msi_domain_info *msi_info;
+ u32 dev_id;
+ int ret;
+
+ msi_info = msi_get_domain_info(domain->parent);
+
+ ret = of_pmsi_get_dev_id(domain, dev, &dev_id);
if (ret)
return ret;
--
1.7.12.4
From: Hanjun Guo <[email protected]>
With the introduction of its_pmsi_init_one(), we can add some code
on top for ACPI support of platform MSI.
We are scanning the MADT table to get the ITS entry(ies), then use
the information to create the platform msi domain for devices connect
to it, just like the PCI MSI for ITS did.
Signed-off-by: Hanjun Guo <[email protected]>
Tested-by: Sinan Kaya <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Tomasz Nowicki <[email protected]>
Cc: Thomas Gleixner <[email protected]>
---
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 36 +++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index ff72704..0be0437 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -105,6 +105,41 @@ static int __init its_pmsi_init_one(struct fwnode_handle *fwnode,
return 0;
}
+#ifdef CONFIG_ACPI
+static int __init
+its_pmsi_parse_madt(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_translator *its_entry;
+ struct fwnode_handle *domain_handle;
+ const char *node_name;
+ int err = -ENXIO;
+
+ its_entry = (struct acpi_madt_generic_translator *)header;
+ node_name = kasprintf(GFP_KERNEL, "ITS@0x%lx",
+ (long)its_entry->base_address);
+ domain_handle = iort_find_domain_token(its_entry->translation_id);
+ if (!domain_handle) {
+ pr_err("%s: Unable to locate ITS domain handle\n", node_name);
+ goto out;
+ }
+
+ err = its_pmsi_init_one(domain_handle, node_name);
+
+out:
+ kfree(node_name);
+ return err;
+}
+
+static void __init its_acpi_pmsi_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+ its_pmsi_parse_madt, 0);
+}
+#else
+static inline void its_acpi_pmsi_init(void) { }
+#endif
+
static void __init its_pmsi_of_init(void)
{
struct device_node *np;
@@ -121,6 +156,7 @@ static void __init its_pmsi_of_init(void)
static int __init its_pmsi_init(void)
{
its_pmsi_of_init();
+ its_acpi_pmsi_init();
return 0;
}
early_initcall(its_pmsi_init);
--
1.7.12.4
From: Kefeng Wang <[email protected]>
Introduce mbigen_of_create_domain() to consolidate OF related
code and prepare for ACPI later, no funtional change.
Signed-off-by: Kefeng Wang <[email protected]>
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ma Jun <[email protected]>
---
drivers/irqchip/irq-mbigen.c | 42 +++++++++++++++++++++++++++---------------
1 file changed, 27 insertions(+), 15 deletions(-)
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index c01ab41..4e11da5 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -236,27 +236,15 @@ static int mbigen_irq_domain_alloc(struct irq_domain *domain,
.free = irq_domain_free_irqs_common,
};
-static int mbigen_device_probe(struct platform_device *pdev)
+static int mbigen_of_create_domain(struct platform_device *pdev,
+ struct mbigen_device *mgn_chip)
{
- struct mbigen_device *mgn_chip;
+ struct device *parent;
struct platform_device *child;
struct irq_domain *domain;
struct device_node *np;
- struct device *parent;
- struct resource *res;
u32 num_pins;
- mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
- if (!mgn_chip)
- return -ENOMEM;
-
- mgn_chip->pdev = pdev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(mgn_chip->base))
- return PTR_ERR(mgn_chip->base);
-
for_each_child_of_node(pdev->dev.of_node, np) {
if (!of_property_read_bool(np, "interrupt-controller"))
continue;
@@ -280,6 +268,30 @@ static int mbigen_device_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ return 0;
+}
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+ struct mbigen_device *mgn_chip;
+ struct resource *res;
+ int err;
+
+ mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+ if (!mgn_chip)
+ return -ENOMEM;
+
+ mgn_chip->pdev = pdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mgn_chip->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (IS_ERR(mgn_chip->base))
+ return PTR_ERR(mgn_chip->base);
+
+ err = mbigen_of_create_domain(pdev, mgn_chip);
+ if (err)
+ return err;
+
platform_set_drvdata(pdev, mgn_chip);
return 0;
}
--
1.7.12.4
From: Kefeng Wang <[email protected]>
Module owner will be set by driver core, so drop it.
Signed-off-by: Kefeng Wang <[email protected]>
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ma Jun <[email protected]>
---
drivers/irqchip/irq-mbigen.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 03b79b0..c01ab41 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -293,7 +293,6 @@ static int mbigen_device_probe(struct platform_device *pdev)
static struct platform_driver mbigen_platform_driver = {
.driver = {
.name = "Hisilicon MBIGEN-V2",
- .owner = THIS_MODULE,
.of_match_table = mbigen_of_match,
},
.probe = mbigen_device_probe,
--
1.7.12.4
From: Hanjun Guo <[email protected]>
iort_node_get_id() for now only support NC(named componant)->SMMU
or NC->ITS cases, we also have other device topology such NC->
SMMU->ITS, so rework iort_node_get_id() for those cases.
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Lorenzo Pieralisi <[email protected]>
---
drivers/acpi/arm64/iort.c | 59 ++++++++++++++++++++++++++---------------------
1 file changed, 33 insertions(+), 26 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 6b72fcb..9b3f268 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -292,22 +292,28 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
return status;
}
-static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
- u32 *rid_out)
+static int iort_id_single_map(struct acpi_iort_id_mapping *map, u8 type,
+ u32 *rid_out)
{
/* Single mapping does not care for input id */
if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
- *rid_out = map->output_base;
+ if (rid_out)
+ *rid_out = map->output_base;
return 0;
}
pr_warn(FW_BUG "[map %p] SINGLE MAPPING flag not allowed for node type %d, skipping ID map\n",
map, type);
- return -ENXIO;
}
+ return -ENXIO;
+}
+
+static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
+ u32 *rid_out)
+{
if (rid_in < map->input_base ||
(rid_in >= map->input_base + map->id_count))
return -ENXIO;
@@ -324,33 +330,34 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
struct acpi_iort_node *parent;
struct acpi_iort_id_mapping *map;
- if (!node->mapping_offset || !node->mapping_count ||
- index >= node->mapping_count)
- return NULL;
-
- map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
- node->mapping_offset);
+ while (node) {
+ if (!node->mapping_offset || !node->mapping_count ||
+ index >= node->mapping_count)
+ return NULL;
- /* Firmware bug! */
- if (!map->output_reference) {
- pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
- node, node->type);
- return NULL;
- }
+ map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+ node->mapping_offset);
- parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
- map->output_reference);
+ /* Firmware bug! */
+ if (!map->output_reference) {
+ pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+ node, node->type);
+ return NULL;
+ }
- if (!(IORT_TYPE_MASK(parent->type) & type_mask))
- return NULL;
+ parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+ map->output_reference);
- if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
- if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
- node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
- if (id_out)
- *id_out = map[index].output_base;
- return parent;
+ /* go upstream to find its parent */
+ if (!(IORT_TYPE_MASK(parent->type) & type_mask)) {
+ node = parent;
+ continue;
}
+
+ if (iort_id_single_map(&map[index], node->type, id_out))
+ break;
+
+ return parent;
}
return NULL;
--
1.7.12.4
From: Hanjun Guo <[email protected]>
The head file is strictly in alphabetic order now, so let's
be the rule breaker. As acpi_iort.h includes acpi.h so remove
the duplidate acpi.h inclusion as well.
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 69b040f..f471939 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -15,14 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
-#include <linux/acpi_iort.h>
#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/msi.h>
--
1.7.12.4
From: Hanjun Guo <[email protected]>
iort_node_get_id() has two output, one is the mapped ids,
the other is the referenced parent node which is returned
from the function.
For now we need a API just return its parent node for
single mapping, so just update this function slightly then
reuse it later.
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Lorenzo Pieralisi <[email protected]>
Cc: Marc Zyngier <[email protected]>
---
drivers/acpi/arm64/iort.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index ab7bae7..bc68d93 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -347,7 +347,8 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
- *id_out = map[index].output_base;
+ if (id_out)
+ *id_out = map[index].output_base;
return parent;
}
}
--
1.7.12.4
From: Hanjun Guo <[email protected]>
For devices connecting to ITS, it needs dev id to identify
itself, and this dev id is represented in the IORT table in
named componant node [1] for platform devices, so in this
patch we will scan the IORT to retrieve device's dev id.
Introduce iort_pmsi_get_dev_id() with pointer dev passed
in for that purpose.
[1]: https://static.docs.arm.com/den0049/b/DEN0049B_IO_Remapping_Table.pdf
Signed-off-by: Hanjun Guo <[email protected]>
Tested-by: Sinan Kaya <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Lorenzo Pieralisi <[email protected]>
Cc: Tomasz Nowicki <[email protected]>
Cc: Thomas Gleixner <[email protected]>
---
drivers/acpi/arm64/iort.c | 26 ++++++++++++++++++++++++++
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 4 +++-
include/linux/acpi_iort.h | 8 ++++++++
3 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 174e983..ab7bae7 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -444,6 +444,32 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
}
/**
+ * iort_pmsi_get_dev_id() - Get the device id for a device
+ * @dev: The device for which the mapping is to be done.
+ * @dev_id: The device ID found.
+ *
+ * Returns: 0 for successful find a dev id, errors otherwise
+ */
+int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
+{
+ struct acpi_iort_node *node;
+
+ if (!iort_table)
+ return -ENODEV;
+
+ node = iort_find_dev_node(dev);
+ if (!node) {
+ dev_err(dev, "can't find related IORT node\n");
+ return -ENODEV;
+ }
+
+ if(!iort_node_get_id(node, dev_id, IORT_MSI_TYPE, 0))
+ return -ENODEV;
+
+ return 0;
+}
+
+/**
* iort_dev_find_its_id() - Find the ITS identifier for a device
* @dev: The device.
* @req_id: Device's Requster ID
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 3c94278..16587a9 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi_iort.h>
#include <linux/device.h>
#include <linux/msi.h>
#include <linux/of.h>
@@ -56,7 +57,8 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
msi_info = msi_get_domain_info(domain->parent);
- ret = of_pmsi_get_dev_id(domain, dev, &dev_id);
+ ret = dev->of_node ? of_pmsi_get_dev_id(domain, dev, &dev_id) :
+ iort_pmsi_get_dev_id(dev, &dev_id);
if (ret)
return ret;
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 77e0809..ef99fd52 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -33,6 +33,7 @@
void acpi_iort_init(void);
bool iort_node_match(u8 type);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
+int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
/* IOMMU interface */
void iort_set_dma_mask(struct device *dev);
@@ -42,9 +43,16 @@ static inline void acpi_iort_init(void) { }
static inline bool iort_node_match(u8 type) { return false; }
static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
{ return req_id; }
+
static inline struct irq_domain *iort_get_device_domain(struct device *dev,
u32 req_id)
{ return NULL; }
+
+static inline int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
+{
+ return -ENODEV;
+}
+
/* IOMMU interface */
static inline void iort_set_dma_mask(struct device *dev) { }
static inline
--
1.7.12.4
From: Hanjun Guo <[email protected]>
With the platform msi domain created for ITS, irqchip such as
mbi-gen connecting ITS, which needs ctreate its own irqdomain.
Fortunately with the platform msi support upstreamed by Marc,
we just need to add minor code to make it run properly.
platform_msi_create_device_domain() is almost ready for ACPI use
except of_node_to_fwnode() is for dt only, make it ACPI aware then
things will work in both DTS and ACPI.
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Greg KH <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Greg KH <[email protected]>
---
drivers/base/platform-msi.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index be6a599..035ca3b 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -345,8 +345,7 @@ struct irq_domain *
data->host_data = host_data;
domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,
- of_node_to_fwnode(dev->of_node),
- ops, data);
+ dev->fwnode, ops, data);
if (!domain)
goto free_priv;
--
1.7.12.4
From: Hanjun Guo <[email protected]>
We are missing req_id's comment for iort_dev_find_its_id(),
add it back.
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Lorenzo Pieralisi <[email protected]>
Cc: Tomasz Nowicki <[email protected]>
---
drivers/acpi/arm64/iort.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 46e2d82..174e983 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -446,6 +446,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
/**
* iort_dev_find_its_id() - Find the ITS identifier for a device
* @dev: The device.
+ * @req_id: Device's Requster ID
* @idx: Index of the ITS identifier list.
* @its_id: ITS identifier.
*
--
1.7.12.4
From: Hanjun Guo <[email protected]>
With the platform msi domain created, we can set up the msi domain
for a platform device when it's probed.
In order to do that, we need to get the domain that the platform
device connecting to, so the iort_get_platform_device_domain() is
introduced to retrieve the domain from iort.
After the domain is retrieved, we need a proper way to set the
domain to paltform device, as some platform devices such as an
irqchip needs the msi irqdomain to be the interrupt parent domain,
we need to get irqdomain before platform device is probed but after
the platform device is allocated, so introduce a callback (pre_add_cb)
in pdevinfo to prepare firmware related information which is needed
for device probe, then set the msi domain in that callback.
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Rafael J. Wysocki <[email protected]>
Cc: Greg KH <[email protected]>
Cc: Lorenzo Pieralisi <[email protected]>
Cc: Thomas Gleixner <[email protected]>
---
drivers/acpi/acpi_platform.c | 11 +++++++++++
drivers/acpi/arm64/iort.c | 43 +++++++++++++++++++++++++++++++++++++++++
drivers/base/platform.c | 3 +++
include/linux/acpi_iort.h | 3 +++
include/linux/platform_device.h | 3 +++
5 files changed, 63 insertions(+)
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index b4c1a6a..5d8d61b4 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -12,6 +12,7 @@
*/
#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kernel.h>
@@ -48,6 +49,15 @@ static void acpi_platform_fill_resource(struct acpi_device *adev,
}
/**
+ * acpi_platform_pre_add_cb - callback before platform device is added, to
+ * prepare firmware related information which is needed for device probe
+ */
+static void acpi_platform_pre_add_cb(struct device *dev)
+{
+ acpi_configure_pmsi_domain(dev);
+}
+
+/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
* @properties: Optional collection of build-in properties.
@@ -109,6 +119,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
pdevinfo.num_res = count;
pdevinfo.fwnode = acpi_fwnode_handle(adev);
pdevinfo.properties = properties;
+ pdevinfo.pre_add_cb = acpi_platform_pre_add_cb;
if (acpi_dma_supported(adev))
pdevinfo.dma_mask = DMA_BIT_MASK(32);
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index bc68d93..6b72fcb 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -527,6 +527,49 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+/**
+ * iort_get_platform_device_domain() - Find MSI domain related to a
+ * platform device
+ * @dev: the dev pointer associated with the platform device
+ *
+ * Returns: the MSI domain for this device, NULL otherwise
+ */
+static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
+{
+ struct acpi_iort_node *node, *msi_parent;
+ struct fwnode_handle *iort_fwnode;
+ struct acpi_iort_its_group *its;
+
+ /* find its associated iort node */
+ node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+ iort_match_node_callback, dev);
+ if (!node)
+ return NULL;
+
+ /* then find its msi parent node */
+ msi_parent = iort_node_get_id(node, NULL, IORT_MSI_TYPE, 0);
+ if (!msi_parent)
+ return NULL;
+
+ /* Move to ITS specific data */
+ its = (struct acpi_iort_its_group *)msi_parent->node_data;
+
+ iort_fwnode = iort_find_domain_token(its->identifiers[0]);
+ if (!iort_fwnode)
+ return NULL;
+
+ return irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI);
+}
+
+void acpi_configure_pmsi_domain(struct device *dev)
+{
+ struct irq_domain *msi_domain;
+
+ msi_domain = iort_get_platform_device_domain(dev);
+ if (msi_domain)
+ dev_set_msi_domain(dev, msi_domain);
+}
+
static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
{
u32 *rid = data;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index c4af003..3e68f31 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -537,6 +537,9 @@ struct platform_device *platform_device_register_full(
goto err;
}
+ if (pdevinfo->pre_add_cb)
+ pdevinfo->pre_add_cb(&pdev->dev);
+
ret = platform_device_add(pdev);
if (ret) {
err:
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index ef99fd52..33f5ac3 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -38,6 +38,7 @@
/* IOMMU interface */
void iort_set_dma_mask(struct device *dev);
const struct iommu_ops *iort_iommu_configure(struct device *dev);
+void acpi_configure_pmsi_domain(struct device *dev);
#else
static inline void acpi_iort_init(void) { }
static inline bool iort_node_match(u8 type) { return false; }
@@ -58,6 +59,8 @@ static inline void iort_set_dma_mask(struct device *dev) { }
static inline
const struct iommu_ops *iort_iommu_configure(struct device *dev)
{ return NULL; }
+
+static inline void acpi_configure_pmsi_domain(struct device *dev) { }
#endif
#define IORT_ACPI_DECLARE(name, table_id, fn) \
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 98c2a7c..280d366fb 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -74,6 +74,9 @@ struct platform_device_info {
u64 dma_mask;
struct property_entry *properties;
+
+ /* preparation callback before the platform device is added */
+ void (*pre_add_cb)(struct device *);
};
extern struct platform_device *platform_device_register_full(
const struct platform_device_info *pdevinfo);
--
1.7.12.4
From: Hanjun Guo <[email protected]>
Introduce its_pmsi_init_one() to refactor the code to isolate
ACPI&DT common code to prepare for ACPI later.
Signed-off-by: Hanjun Guo <[email protected]>
Tested-by: Sinan Kaya <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Tomasz Nowicki <[email protected]>
Cc: Thomas Gleixner <[email protected]>
---
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 45 ++++++++++++++++-----------
1 file changed, 27 insertions(+), 18 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 16587a9..ff72704 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -84,34 +84,43 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
{},
};
-static int __init its_pmsi_init(void)
+static int __init its_pmsi_init_one(struct fwnode_handle *fwnode,
+ const char *name)
{
- struct device_node *np;
struct irq_domain *parent;
+ parent = irq_find_matching_fwnode(fwnode, DOMAIN_BUS_NEXUS);
+ if (!parent || !msi_get_domain_info(parent)) {
+ pr_err("%s: unable to locate ITS domain\n", name);
+ return -ENXIO;
+ }
+
+ if (!platform_msi_create_irq_domain(fwnode, &its_pmsi_domain_info,
+ parent)) {
+ pr_err("%s: unable to create platform domain\n", name);
+ return -ENXIO;
+ }
+
+ pr_info("Platform MSI: %s domain created\n", name);
+ return 0;
+}
+
+static void __init its_pmsi_of_init(void)
+{
+ struct device_node *np;
+
for (np = of_find_matching_node(NULL, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) {
if (!of_property_read_bool(np, "msi-controller"))
continue;
- parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
- if (!parent || !msi_get_domain_info(parent)) {
- pr_err("%s: unable to locate ITS domain\n",
- np->full_name);
- continue;
- }
-
- if (!platform_msi_create_irq_domain(of_node_to_fwnode(np),
- &its_pmsi_domain_info,
- parent)) {
- pr_err("%s: unable to create platform domain\n",
- np->full_name);
- continue;
- }
-
- pr_info("Platform MSI: %s domain created\n", np->full_name);
+ its_pmsi_init_one(of_node_to_fwnode(np), np->full_name);
}
+}
+static int __init its_pmsi_init(void)
+{
+ its_pmsi_of_init();
return 0;
}
early_initcall(its_pmsi_init);
--
1.7.12.4
From: Hanjun Guo <[email protected]>
With the preparation of platform msi support and interrupt producer
in DSDT, we can add mbigen ACPI support now.
We are using _PRS methd to indicate number of irq pins instead
of num_pins in DT to avoid _DSD usage in this case.
For mbi-gen,
Device(MBI0) {
Name(_HID, "HISI0152")
Name(_UID, Zero)
Name(_CRS, ResourceTemplate() {
Memory32Fixed(ReadWrite, 0xa0080000, 0x10000)
})
Name (_PRS, ResourceTemplate() {
Interrupt(ResourceProducer,...) {12,14,....}
})
}
For devices,
Device(COM0) {
Name(_HID, "ACPIIDxx")
Name(_UID, Zero)
Name(_CRS, ResourceTemplate() {
Memory32Fixed(ReadWrite, 0xb0030000, 0x10000)
Interrupt(ResourceConsumer,..., "\_SB.MBI0") {12}
})
}
With the helpe of platform msi and interrupt producer, then devices
will get the virq from mbi-gen's irqdomain.
Signed-off-by: Hanjun Guo <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ma Jun <[email protected]>
---
drivers/irqchip/irq-mbigen.c | 70 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 67 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 4e11da5..17d35fa 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/irqchip.h>
#include <linux/module.h>
@@ -180,7 +181,7 @@ static int mbigen_domain_translate(struct irq_domain *d,
unsigned long *hwirq,
unsigned int *type)
{
- if (is_of_node(fwspec->fwnode)) {
+ if (is_of_node(fwspec->fwnode) || is_acpi_device_node(fwspec->fwnode)) {
if (fwspec->param_count != 2)
return -EINVAL;
@@ -271,6 +272,54 @@ static int mbigen_of_create_domain(struct platform_device *pdev,
return 0;
}
+#ifdef CONFIG_ACPI
+static acpi_status mbigen_acpi_process_resource(struct acpi_resource *ares,
+ void *context)
+{
+ struct acpi_resource_extended_irq *ext_irq;
+ u32 *num_irqs = context;
+
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ ext_irq = &ares->data.extended_irq;
+ *num_irqs += ext_irq->interrupt_count;
+ break;
+ default:
+ break;
+ }
+
+ return AE_OK;
+}
+
+static int mbigen_acpi_create_domain(struct platform_device *pdev,
+ struct mbigen_device *mgn_chip)
+{
+ struct irq_domain *domain;
+ u32 num_msis = 0;
+ acpi_status status;
+
+ status = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), METHOD_NAME__PRS,
+ mbigen_acpi_process_resource, &num_msis);
+ if (ACPI_FAILURE(status) || num_msis == 0)
+ return -EINVAL;
+
+ domain = platform_msi_create_device_domain(&pdev->dev, num_msis,
+ mbigen_write_msg,
+ &mbigen_domain_ops,
+ mgn_chip);
+ if (!domain)
+ return -ENOMEM;
+
+ return 0;
+}
+#else
+static int mbigen_acpi_create_domain(struct platform_device *pdev,
+ struct mbigen_device *mgn_chip)
+{
+ return -ENODEV;
+}
+#endif
+
static int mbigen_device_probe(struct platform_device *pdev)
{
struct mbigen_device *mgn_chip;
@@ -288,9 +337,17 @@ static int mbigen_device_probe(struct platform_device *pdev)
if (IS_ERR(mgn_chip->base))
return PTR_ERR(mgn_chip->base);
- err = mbigen_of_create_domain(pdev, mgn_chip);
- if (err)
+ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
+ err = mbigen_of_create_domain(pdev, mgn_chip);
+ else if (ACPI_COMPANION(&pdev->dev))
+ err = mbigen_acpi_create_domain(pdev, mgn_chip);
+ else
+ err = -EINVAL;
+
+ if (err) {
+ dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain", mgn_chip->base);
return err;
+ }
platform_set_drvdata(pdev, mgn_chip);
return 0;
@@ -302,10 +359,17 @@ static int mbigen_device_probe(struct platform_device *pdev)
};
MODULE_DEVICE_TABLE(of, mbigen_of_match);
+static const struct acpi_device_id mbigen_acpi_match[] = {
+ { "HISI0152", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
+
static struct platform_driver mbigen_platform_driver = {
.driver = {
.name = "Hisilicon MBIGEN-V2",
.of_match_table = mbigen_of_match,
+ .acpi_match_table = ACPI_PTR(mbigen_acpi_match),
},
.probe = mbigen_device_probe,
};
--
1.7.12.4
On Thu, Dec 22, 2016 at 6:35 AM, Hanjun Guo <[email protected]> wrote:
> From: Hanjun Guo <[email protected]>
>
> With the platform msi domain created, we can set up the msi domain
> for a platform device when it's probed.
>
> In order to do that, we need to get the domain that the platform
> device connecting to, so the iort_get_platform_device_domain() is
> introduced to retrieve the domain from iort.
>
> After the domain is retrieved, we need a proper way to set the
> domain to paltform device, as some platform devices such as an
> irqchip needs the msi irqdomain to be the interrupt parent domain,
> we need to get irqdomain before platform device is probed but after
> the platform device is allocated, so introduce a callback (pre_add_cb)
> in pdevinfo to prepare firmware related information which is needed
> for device probe, then set the msi domain in that callback.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Rafael J. Wysocki <[email protected]>
> Cc: Greg KH <[email protected]>
> Cc: Lorenzo Pieralisi <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> ---
> drivers/acpi/acpi_platform.c | 11 +++++++++++
> drivers/acpi/arm64/iort.c | 43 +++++++++++++++++++++++++++++++++++++++++
> drivers/base/platform.c | 3 +++
> include/linux/acpi_iort.h | 3 +++
> include/linux/platform_device.h | 3 +++
> 5 files changed, 63 insertions(+)
>
> diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
> index b4c1a6a..5d8d61b4 100644
> --- a/drivers/acpi/acpi_platform.c
> +++ b/drivers/acpi/acpi_platform.c
> @@ -12,6 +12,7 @@
> */
>
> #include <linux/acpi.h>
> +#include <linux/acpi_iort.h>
> #include <linux/device.h>
> #include <linux/err.h>
> #include <linux/kernel.h>
> @@ -48,6 +49,15 @@ static void acpi_platform_fill_resource(struct acpi_device *adev,
> }
>
> /**
> + * acpi_platform_pre_add_cb - callback before platform device is added, to
> + * prepare firmware related information which is needed for device probe
> + */
> +static void acpi_platform_pre_add_cb(struct device *dev)
> +{
> + acpi_configure_pmsi_domain(dev);
> +}
> +
> +/**
> * acpi_create_platform_device - Create platform device for ACPI device node
> * @adev: ACPI device node to create a platform device for.
> * @properties: Optional collection of build-in properties.
> @@ -109,6 +119,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
> pdevinfo.num_res = count;
> pdevinfo.fwnode = acpi_fwnode_handle(adev);
> pdevinfo.properties = properties;
> + pdevinfo.pre_add_cb = acpi_platform_pre_add_cb;
Why don't you point that directly to acpi_configure_pmsi_domain()? It
doesn't look like the wrapper is necessary at all.
And I'm not sure why the new callback is necessary ->
>
> if (acpi_dma_supported(adev))
> pdevinfo.dma_mask = DMA_BIT_MASK(32);
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index bc68d93..6b72fcb 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -527,6 +527,49 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
> return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
> }
>
> +/**
> + * iort_get_platform_device_domain() - Find MSI domain related to a
> + * platform device
> + * @dev: the dev pointer associated with the platform device
> + *
> + * Returns: the MSI domain for this device, NULL otherwise
> + */
> +static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
> +{
> + struct acpi_iort_node *node, *msi_parent;
> + struct fwnode_handle *iort_fwnode;
> + struct acpi_iort_its_group *its;
> +
> + /* find its associated iort node */
> + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
> + iort_match_node_callback, dev);
> + if (!node)
> + return NULL;
> +
> + /* then find its msi parent node */
> + msi_parent = iort_node_get_id(node, NULL, IORT_MSI_TYPE, 0);
> + if (!msi_parent)
> + return NULL;
> +
> + /* Move to ITS specific data */
> + its = (struct acpi_iort_its_group *)msi_parent->node_data;
> +
> + iort_fwnode = iort_find_domain_token(its->identifiers[0]);
> + if (!iort_fwnode)
> + return NULL;
> +
> + return irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI);
> +}
> +
> +void acpi_configure_pmsi_domain(struct device *dev)
> +{
> + struct irq_domain *msi_domain;
> +
> + msi_domain = iort_get_platform_device_domain(dev);
> + if (msi_domain)
> + dev_set_msi_domain(dev, msi_domain);
> +}
> +
> static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
> {
> u32 *rid = data;
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index c4af003..3e68f31 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -537,6 +537,9 @@ struct platform_device *platform_device_register_full(
> goto err;
> }
>
> + if (pdevinfo->pre_add_cb)
> + pdevinfo->pre_add_cb(&pdev->dev);
> +
-> because it looks like this might be done in acpi_platform_notify()
for platform devices.
> ret = platform_device_add(pdev);
> if (ret) {
Thanks,
Rafael
Hi Rafael,
Thank you for your comments, when I was demoing your suggestion,
I got a little bit confusions, please see my comments below.
On 2016/12/22 20:57, Rafael J. Wysocki wrote:
> On Thu, Dec 22, 2016 at 6:35 AM, Hanjun Guo <[email protected]> wrote:
>> From: Hanjun Guo <[email protected]>
>>
>> With the platform msi domain created, we can set up the msi domain
>> for a platform device when it's probed.
>>
>> In order to do that, we need to get the domain that the platform
>> device connecting to, so the iort_get_platform_device_domain() is
>> introduced to retrieve the domain from iort.
>>
>> After the domain is retrieved, we need a proper way to set the
>> domain to paltform device, as some platform devices such as an
>> irqchip needs the msi irqdomain to be the interrupt parent domain,
>> we need to get irqdomain before platform device is probed but after
>> the platform device is allocated, so introduce a callback (pre_add_cb)
>> in pdevinfo to prepare firmware related information which is needed
>> for device probe, then set the msi domain in that callback.
>>
>> Signed-off-by: Hanjun Guo <[email protected]>
>> Cc: Marc Zyngier <[email protected]>
>> Cc: Rafael J. Wysocki <[email protected]>
>> Cc: Greg KH <[email protected]>
>> Cc: Lorenzo Pieralisi <[email protected]>
>> Cc: Thomas Gleixner <[email protected]>
>> ---
>> drivers/acpi/acpi_platform.c | 11 +++++++++++
>> drivers/acpi/arm64/iort.c | 43 +++++++++++++++++++++++++++++++++++++++++
>> drivers/base/platform.c | 3 +++
>> include/linux/acpi_iort.h | 3 +++
>> include/linux/platform_device.h | 3 +++
>> 5 files changed, 63 insertions(+)
>>
>> diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
>> index b4c1a6a..5d8d61b4 100644
>> --- a/drivers/acpi/acpi_platform.c
>> +++ b/drivers/acpi/acpi_platform.c
>> @@ -12,6 +12,7 @@
>> */
>>
>> #include <linux/acpi.h>
>> +#include <linux/acpi_iort.h>
>> #include <linux/device.h>
>> #include <linux/err.h>
>> #include <linux/kernel.h>
>> @@ -48,6 +49,15 @@ static void acpi_platform_fill_resource(struct acpi_device *adev,
>> }
>>
>> /**
>> + * acpi_platform_pre_add_cb - callback before platform device is added, to
>> + * prepare firmware related information which is needed for device probe
>> + */
>> +static void acpi_platform_pre_add_cb(struct device *dev)
>> +{
>> + acpi_configure_pmsi_domain(dev);
>> +}
>> +
>> +/**
>> * acpi_create_platform_device - Create platform device for ACPI device node
>> * @adev: ACPI device node to create a platform device for.
>> * @properties: Optional collection of build-in properties.
>> @@ -109,6 +119,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
>> pdevinfo.num_res = count;
>> pdevinfo.fwnode = acpi_fwnode_handle(adev);
>> pdevinfo.properties = properties;
>> + pdevinfo.pre_add_cb = acpi_platform_pre_add_cb;
> Why don't you point that directly to acpi_configure_pmsi_domain()? It
> doesn't look like the wrapper is necessary at all.
I was thinking that we can add something more in the future
if we need to extend the function of the callback, I can just
use acpi_configure_pmsi_domain() here.
>
> And I'm not sure why the new callback is necessary ->
I was demoing your suggestion but...
>
>> if (acpi_dma_supported(adev))
>> pdevinfo.dma_mask = DMA_BIT_MASK(32);
>> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
>> index bc68d93..6b72fcb 100644
>> --- a/drivers/acpi/arm64/iort.c
>> +++ b/drivers/acpi/arm64/iort.c
>> @@ -527,6 +527,49 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
>> return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
>> }
>>
>> +/**
>> + * iort_get_platform_device_domain() - Find MSI domain related to a
>> + * platform device
>> + * @dev: the dev pointer associated with the platform device
>> + *
>> + * Returns: the MSI domain for this device, NULL otherwise
>> + */
>> +static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
>> +{
>> + struct acpi_iort_node *node, *msi_parent;
>> + struct fwnode_handle *iort_fwnode;
>> + struct acpi_iort_its_group *its;
>> +
>> + /* find its associated iort node */
>> + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
>> + iort_match_node_callback, dev);
>> + if (!node)
>> + return NULL;
>> +
>> + /* then find its msi parent node */
>> + msi_parent = iort_node_get_id(node, NULL, IORT_MSI_TYPE, 0);
>> + if (!msi_parent)
>> + return NULL;
>> +
>> + /* Move to ITS specific data */
>> + its = (struct acpi_iort_its_group *)msi_parent->node_data;
>> +
>> + iort_fwnode = iort_find_domain_token(its->identifiers[0]);
>> + if (!iort_fwnode)
>> + return NULL;
>> +
>> + return irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI);
>> +}
>> +
>> +void acpi_configure_pmsi_domain(struct device *dev)
>> +{
>> + struct irq_domain *msi_domain;
>> +
>> + msi_domain = iort_get_platform_device_domain(dev);
>> + if (msi_domain)
>> + dev_set_msi_domain(dev, msi_domain);
>> +}
>> +
>> static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>> {
>> u32 *rid = data;
>> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
>> index c4af003..3e68f31 100644
>> --- a/drivers/base/platform.c
>> +++ b/drivers/base/platform.c
>> @@ -537,6 +537,9 @@ struct platform_device *platform_device_register_full(
>> goto err;
>> }
>>
>> + if (pdevinfo->pre_add_cb)
>> + pdevinfo->pre_add_cb(&pdev->dev);
>> +
> -> because it looks like this might be done in acpi_platform_notify()
> for platform devices.
It works and I just simply add the code below:
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index f8d6564..e0cd649 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/rwsem.h>
#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/dma-mapping.h>
#include "internal.h"
@@ -315,6 +316,8 @@ static int acpi_platform_notify(struct device *dev)
if (!adev)
goto out;
+ acpi_configure_pmsi_domain(dev);
+
if (type && type->setup)
type->setup(dev);
else if (adev->handler && adev->handler->bind)
Do you suggesting to configure the msi domain in this way?
or add the function in the type->setup() callback (which needs
to introduce a new acpi bus type)?
Thanks
Hanjun
On Sat, Dec 24, 2016 at 8:34 AM, Hanjun Guo <[email protected]> wrote:
> Hi Rafael,
>
> Thank you for your comments, when I was demoing your suggestion,
> I got a little bit confusions, please see my comments below.
>
[cut]
>>> +
>>> +/**
>>> * acpi_create_platform_device - Create platform device for ACPI device node
>>> * @adev: ACPI device node to create a platform device for.
>>> * @properties: Optional collection of build-in properties.
>>> @@ -109,6 +119,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
>>> pdevinfo.num_res = count;
>>> pdevinfo.fwnode = acpi_fwnode_handle(adev);
>>> pdevinfo.properties = properties;
>>> + pdevinfo.pre_add_cb = acpi_platform_pre_add_cb;
>> Why don't you point that directly to acpi_configure_pmsi_domain()? It
>> doesn't look like the wrapper is necessary at all.
>
> I was thinking that we can add something more in the future
> if we need to extend the function of the callback, I can just
> use acpi_configure_pmsi_domain() here.
So you can add the wrapper in the future just fine as well. At this
point it is just redundant.
>>
>> And I'm not sure why the new callback is necessary ->
>
> I was demoing your suggestion but...
>
>>
>>> if (acpi_dma_supported(adev))
>>> pdevinfo.dma_mask = DMA_BIT_MASK(32);
>>> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
>>> index bc68d93..6b72fcb 100644
>>> --- a/drivers/acpi/arm64/iort.c
>>> +++ b/drivers/acpi/arm64/iort.c
>>> @@ -527,6 +527,49 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
>>> return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
>>> }
>>>
>>> +/**
>>> + * iort_get_platform_device_domain() - Find MSI domain related to a
>>> + * platform device
>>> + * @dev: the dev pointer associated with the platform device
>>> + *
>>> + * Returns: the MSI domain for this device, NULL otherwise
>>> + */
>>> +static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
>>> +{
>>> + struct acpi_iort_node *node, *msi_parent;
>>> + struct fwnode_handle *iort_fwnode;
>>> + struct acpi_iort_its_group *its;
>>> +
>>> + /* find its associated iort node */
>>> + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
>>> + iort_match_node_callback, dev);
>>> + if (!node)
>>> + return NULL;
>>> +
>>> + /* then find its msi parent node */
>>> + msi_parent = iort_node_get_id(node, NULL, IORT_MSI_TYPE, 0);
>>> + if (!msi_parent)
>>> + return NULL;
>>> +
>>> + /* Move to ITS specific data */
>>> + its = (struct acpi_iort_its_group *)msi_parent->node_data;
>>> +
>>> + iort_fwnode = iort_find_domain_token(its->identifiers[0]);
>>> + if (!iort_fwnode)
>>> + return NULL;
>>> +
>>> + return irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI);
>>> +}
>>> +
>>> +void acpi_configure_pmsi_domain(struct device *dev)
>>> +{
>>> + struct irq_domain *msi_domain;
>>> +
>>> + msi_domain = iort_get_platform_device_domain(dev);
>>> + if (msi_domain)
>>> + dev_set_msi_domain(dev, msi_domain);
>>> +}
>>> +
>>> static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>>> {
>>> u32 *rid = data;
>>> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
>>> index c4af003..3e68f31 100644
>>> --- a/drivers/base/platform.c
>>> +++ b/drivers/base/platform.c
>>> @@ -537,6 +537,9 @@ struct platform_device *platform_device_register_full(
>>> goto err;
>>> }
>>>
>>> + if (pdevinfo->pre_add_cb)
>>> + pdevinfo->pre_add_cb(&pdev->dev);
>>> +
>> -> because it looks like this might be done in acpi_platform_notify()
>> for platform devices.
>
> It works and I just simply add the code below:
>
> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
> index f8d6564..e0cd649 100644
> --- a/drivers/acpi/glue.c
> +++ b/drivers/acpi/glue.c
> @@ -13,6 +13,7 @@
> #include <linux/slab.h>
> #include <linux/rwsem.h>
> #include <linux/acpi.h>
> +#include <linux/acpi_iort.h>
> #include <linux/dma-mapping.h>
>
> #include "internal.h"
> @@ -315,6 +316,8 @@ static int acpi_platform_notify(struct device *dev)
> if (!adev)
> goto out;
>
> + acpi_configure_pmsi_domain(dev);
> +
But that should apply to platform devices only I suppose?
> if (type && type->setup)
> type->setup(dev);
> else if (adev->handler && adev->handler->bind)
>
> Do you suggesting to configure the msi domain in this way?
> or add the function in the type->setup() callback (which needs
> to introduce a new acpi bus type)?
A type->setup() would be somewhat cleaner I think, but then it's more
code. Whichever works better I guess. :-)
Thanks,
Rafael
Hi Rafael,
Happy holidays! reply inline.
On 2016/12/26 8:31, Rafael J. Wysocki wrote:
> On Sat, Dec 24, 2016 at 8:34 AM, Hanjun Guo <[email protected]> wrote:
>> Hi Rafael,
>>
>> Thank you for your comments, when I was demoing your suggestion,
>> I got a little bit confusions, please see my comments below.
>>
> [cut]
>
>>>> +
>>>> +/**
>>>> * acpi_create_platform_device - Create platform device for ACPI device node
>>>> * @adev: ACPI device node to create a platform device for.
>>>> * @properties: Optional collection of build-in properties.
>>>> @@ -109,6 +119,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
>>>> pdevinfo.num_res = count;
>>>> pdevinfo.fwnode = acpi_fwnode_handle(adev);
>>>> pdevinfo.properties = properties;
>>>> + pdevinfo.pre_add_cb = acpi_platform_pre_add_cb;
>>> Why don't you point that directly to acpi_configure_pmsi_domain()? It
>>> doesn't look like the wrapper is necessary at all.
>> I was thinking that we can add something more in the future
>> if we need to extend the function of the callback, I can just
>> use acpi_configure_pmsi_domain() here.
> So you can add the wrapper in the future just fine as well. At this
> point it is just redundant.
>
>>> And I'm not sure why the new callback is necessary ->
>> I was demoing your suggestion but...
>>
>>>> if (acpi_dma_supported(adev))
>>>> pdevinfo.dma_mask = DMA_BIT_MASK(32);
>>>> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
>>>> index bc68d93..6b72fcb 100644
>>>> --- a/drivers/acpi/arm64/iort.c
>>>> +++ b/drivers/acpi/arm64/iort.c
>>>> @@ -527,6 +527,49 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
>>>> return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
>>>> }
>>>>
>>>> +/**
>>>> + * iort_get_platform_device_domain() - Find MSI domain related to a
>>>> + * platform device
>>>> + * @dev: the dev pointer associated with the platform device
>>>> + *
>>>> + * Returns: the MSI domain for this device, NULL otherwise
>>>> + */
>>>> +static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
>>>> +{
>>>> + struct acpi_iort_node *node, *msi_parent;
>>>> + struct fwnode_handle *iort_fwnode;
>>>> + struct acpi_iort_its_group *its;
>>>> +
>>>> + /* find its associated iort node */
>>>> + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
>>>> + iort_match_node_callback, dev);
>>>> + if (!node)
>>>> + return NULL;
>>>> +
>>>> + /* then find its msi parent node */
>>>> + msi_parent = iort_node_get_id(node, NULL, IORT_MSI_TYPE, 0);
>>>> + if (!msi_parent)
>>>> + return NULL;
>>>> +
>>>> + /* Move to ITS specific data */
>>>> + its = (struct acpi_iort_its_group *)msi_parent->node_data;
>>>> +
>>>> + iort_fwnode = iort_find_domain_token(its->identifiers[0]);
>>>> + if (!iort_fwnode)
>>>> + return NULL;
>>>> +
>>>> + return irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI);
>>>> +}
>>>> +
>>>> +void acpi_configure_pmsi_domain(struct device *dev)
>>>> +{
>>>> + struct irq_domain *msi_domain;
>>>> +
>>>> + msi_domain = iort_get_platform_device_domain(dev);
>>>> + if (msi_domain)
>>>> + dev_set_msi_domain(dev, msi_domain);
>>>> +}
>>>> +
>>>> static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>>>> {
>>>> u32 *rid = data;
>>>> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
>>>> index c4af003..3e68f31 100644
>>>> --- a/drivers/base/platform.c
>>>> +++ b/drivers/base/platform.c
>>>> @@ -537,6 +537,9 @@ struct platform_device *platform_device_register_full(
>>>> goto err;
>>>> }
>>>>
>>>> + if (pdevinfo->pre_add_cb)
>>>> + pdevinfo->pre_add_cb(&pdev->dev);
>>>> +
>>> -> because it looks like this might be done in acpi_platform_notify()
>>> for platform devices.
>> It works and I just simply add the code below:
>>
>> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
>> index f8d6564..e0cd649 100644
>> --- a/drivers/acpi/glue.c
>> +++ b/drivers/acpi/glue.c
>> @@ -13,6 +13,7 @@
>> #include <linux/slab.h>
>> #include <linux/rwsem.h>
>> #include <linux/acpi.h>
>> +#include <linux/acpi_iort.h>
>> #include <linux/dma-mapping.h>
>>
>> #include "internal.h"
>> @@ -315,6 +316,8 @@ static int acpi_platform_notify(struct device *dev)
>> if (!adev)
>> goto out;
>>
>> + acpi_configure_pmsi_domain(dev);
>> +
> But that should apply to platform devices only I suppose?
Yes, it's only for the platform device.
>
>> if (type && type->setup)
>> type->setup(dev);
>> else if (adev->handler && adev->handler->bind)
>>
>> Do you suggesting to configure the msi domain in this way?
>> or add the function in the type->setup() callback (which needs
>> to introduce a new acpi bus type)?
> A type->setup() would be somewhat cleaner I think, but then it's more
> code. Whichever works better I guess. :-)
Agree, I will demo the type->setup() way and send out the patch for review,
also I find one minor issue for the IORT code, will update that also for next
version.
Thanks
Hanjun
Hi Hanjun:
This patch set works fine on my Hisilicon D05 board.
Feel free to add
Tested-by: Majun <[email protected]>
?? 2016/12/22 13:35, Hanjun Guo д??:
> From: Hanjun Guo <[email protected]>
>
> v4 -> v5:
> - Add mbigen support back with tested on with Agustin's patchset,
> and it's a good example of how ACPI platform MSI works
> - rebased on top of lastest Linus tree (commit 52bce91 splice: reinstate SIGPIPE/EPIPE handling)
>
> v3 -> v4:
> - Drop mbi-gen patches to just submit platform msi support because
> will rebase mbi-gen patches on top of Agustin's patchset, and discusion
> is going there.
> - Add a patch to support device topology such as NC(named componant, paltform device)
> ->SMMU->ITS which suggested by Lorenzo;
> - rebased on top of Lorenzo's v9 of ACPI IORT ARM SMMU support;
> - rebased on top of 4.9-rc7
>
> v2 -> v3:
> - Drop RFC tag
> - Rebase against v4.9-rc2 and Lorenzo's v6 of ACPI IORT ARM SMMU support [1]
> - Add 3 cleanup patches (patch 1, 2, 3)
> - Drop arch_init call patch from last version
> - Introduce a callback for platform device to set msi domain
> - Introduce a new API to get paltform device's domain instead of
> reusing the PCI one in previous version
> - Add a patch to rework iort_node_get_id()
>
> [1]: http://www.mail-archive.com/[email protected]/msg1251993.html
>
> v1 -> v2:
> - Fix the bug of if multi Interrupt() resoures in single _PRS,
> we need to calculate all the irq numbers (I missed it in previous
> version);
> - Rebased on Marc's irq/irqchip-4.9 branch and Lorenzo's v5
> SMMU patches (also Robin's SMMu patches)
> - Add patch irqchip: mbigen: promote mbigen init.
>
> With platform msi support landed in the kernel, and the introduction
> of IORT for GICv3 ITS (PCI MSI) and SMMU, the framework for platform msi
> is ready, this patch set add few patches to enable the ACPI platform
> msi support.
>
> For platform device connecting to ITS on arm platform, we have IORT
> table with the named componant node to describe the mappings of paltform
> device and ITS, so we can retrieve the dev id and find its parent
> irqdomain (ITS) from IORT table (simlar with the ACPI ITS support).
>
> The fisrt 3 patches are cleanups;
>
> Patch 4,5 are refactoring its_pmsi_prepare() for both DT and ACPI
> then retrieve the dev id from iort;
>
> Patch 6,7 to create platform msi domain to ACPI case which scanned
> the MADT table;
>
> Patch 8,9,10,11 to setup the msi domain for platform device based
> on IORT table.
>
> Patch 12,13,14 convert dt based mbigen driver to support ACPI.
>
> Teasted on Hisilicon D03/D05.
>
> Happy holidays!
>
> Thanks
> Hanjun
>
> Hanjun Guo (12):
> ACPI: ARM64: IORT: minor cleanup for iort_match_node_callback()
> irqchip: gic-v3-its: keep the head file include in alphabetic order
> ACPI: ARM64: IORT: add missing comment for iort_dev_find_its_id()
> irqchip: gicv3-its: platform-msi: refactor its_pmsi_prepare()
> ACPI: platform-msi: retrieve dev id from IORT
> irqchip: gicv3-its: platform-msi: refactor its_pmsi_init() to prepare
> for ACPI
> irqchip: gicv3-its: platform-msi: scan MADT to create platform msi
> domain
> ACPI: ARM64: IORT: rework iort_node_get_id()
> ACPI: platform: setup MSI domain for ACPI based platform device
> ACPI: ARM64: IORT: rework iort_node_get_id() for NC->SMMU->ITS case
> msi: platform: make platform_msi_create_device_domain() ACPI aware
> irqchip: mbigen: Add ACPI support
>
> Kefeng Wang (2):
> irqchip: mbigen: drop module owner
> irqchip: mbigen: introduce mbigen_of_create_domain()
>
> drivers/acpi/acpi_platform.c | 11 ++
> drivers/acpi/arm64/iort.c | 138 ++++++++++++++++++++------
> drivers/base/platform-msi.c | 3 +-
> drivers/base/platform.c | 3 +
> drivers/irqchip/irq-gic-v3-its-platform-msi.c | 106 +++++++++++++++-----
> drivers/irqchip/irq-gic-v3-its.c | 3 +-
> drivers/irqchip/irq-mbigen.c | 109 ++++++++++++++++----
> include/linux/acpi_iort.h | 11 ++
> include/linux/platform_device.h | 3 +
> 9 files changed, 309 insertions(+), 78 deletions(-)
>
Hi hanjun??
?? 2016/12/22 13:35, Hanjun Guo д??:
> From: Kefeng Wang <[email protected]>
>
> Module owner will be set by driver core, so drop it.
>
> Signed-off-by: Kefeng Wang <[email protected]>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ma Jun <[email protected]>
> ---
> drivers/irqchip/irq-mbigen.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
> index 03b79b0..c01ab41 100644
> --- a/drivers/irqchip/irq-mbigen.c
> +++ b/drivers/irqchip/irq-mbigen.c
> @@ -293,7 +293,6 @@ static int mbigen_device_probe(struct platform_device *pdev)
> static struct platform_driver mbigen_platform_driver = {
> .driver = {
> .name = "Hisilicon MBIGEN-V2",
> - .owner = THIS_MODULE,
> .of_match_table = mbigen_of_match,
> },
> .probe = mbigen_device_probe,
>
Reviewed-by: MaJun <[email protected]>
Hi hanjun??
?? 2016/12/22 13:35, Hanjun Guo д??:
> From: Kefeng Wang <[email protected]>
>
> Introduce mbigen_of_create_domain() to consolidate OF related
> code and prepare for ACPI later, no funtional change.
>
> Signed-off-by: Kefeng Wang <[email protected]>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ma Jun <[email protected]>
> ---
> drivers/irqchip/irq-mbigen.c | 42 +++++++++++++++++++++++++++---------------
> 1 file changed, 27 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
> index c01ab41..4e11da5 100644
> --- a/drivers/irqchip/irq-mbigen.c
> +++ b/drivers/irqchip/irq-mbigen.c
> @@ -236,27 +236,15 @@ static int mbigen_irq_domain_alloc(struct irq_domain *domain,
> .free = irq_domain_free_irqs_common,
> };
>
> -static int mbigen_device_probe(struct platform_device *pdev)
> +static int mbigen_of_create_domain(struct platform_device *pdev,
> + struct mbigen_device *mgn_chip)
> {
> - struct mbigen_device *mgn_chip;
> + struct device *parent;
> struct platform_device *child;
> struct irq_domain *domain;
> struct device_node *np;
> - struct device *parent;
> - struct resource *res;
> u32 num_pins;
>
> - mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
> - if (!mgn_chip)
> - return -ENOMEM;
> -
> - mgn_chip->pdev = pdev;
> -
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
> - if (IS_ERR(mgn_chip->base))
> - return PTR_ERR(mgn_chip->base);
> -
> for_each_child_of_node(pdev->dev.of_node, np) {
> if (!of_property_read_bool(np, "interrupt-controller"))
> continue;
> @@ -280,6 +268,30 @@ static int mbigen_device_probe(struct platform_device *pdev)
> return -ENOMEM;
> }
>
> + return 0;
> +}
> +
> +static int mbigen_device_probe(struct platform_device *pdev)
> +{
> + struct mbigen_device *mgn_chip;
> + struct resource *res;
> + int err;
> +
> + mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
> + if (!mgn_chip)
> + return -ENOMEM;
> +
> + mgn_chip->pdev = pdev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + mgn_chip->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
> + if (IS_ERR(mgn_chip->base))
> + return PTR_ERR(mgn_chip->base);
> +
> + err = mbigen_of_create_domain(pdev, mgn_chip);
> + if (err)
> + return err;
> +
> platform_set_drvdata(pdev, mgn_chip);
> return 0;
> }
>
Reviewed-by: MaJun <[email protected]>
Hi hanjun??
?? 2016/12/22 13:35, Hanjun Guo д??:
> From: Hanjun Guo <[email protected]>
>
> With the preparation of platform msi support and interrupt producer
> in DSDT, we can add mbigen ACPI support now.
>
> We are using _PRS methd to indicate number of irq pins instead
> of num_pins in DT to avoid _DSD usage in this case.
>
> For mbi-gen,
> Device(MBI0) {
> Name(_HID, "HISI0152")
> Name(_UID, Zero)
> Name(_CRS, ResourceTemplate() {
> Memory32Fixed(ReadWrite, 0xa0080000, 0x10000)
> })
>
> Name (_PRS, ResourceTemplate() {
> Interrupt(ResourceProducer,...) {12,14,....}
> })
> }
>
> For devices,
>
> Device(COM0) {
> Name(_HID, "ACPIIDxx")
> Name(_UID, Zero)
> Name(_CRS, ResourceTemplate() {
> Memory32Fixed(ReadWrite, 0xb0030000, 0x10000)
> Interrupt(ResourceConsumer,..., "\_SB.MBI0") {12}
> })
> }
>
> With the helpe of platform msi and interrupt producer, then devices
> will get the virq from mbi-gen's irqdomain.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ma Jun <[email protected]>
> ---
> drivers/irqchip/irq-mbigen.c | 70 ++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 67 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
> index 4e11da5..17d35fa 100644
> --- a/drivers/irqchip/irq-mbigen.c
> +++ b/drivers/irqchip/irq-mbigen.c
> @@ -16,6 +16,7 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> +#include <linux/acpi.h>
> #include <linux/interrupt.h>
> #include <linux/irqchip.h>
> #include <linux/module.h>
> @@ -180,7 +181,7 @@ static int mbigen_domain_translate(struct irq_domain *d,
> unsigned long *hwirq,
> unsigned int *type)
> {
> - if (is_of_node(fwspec->fwnode)) {
> + if (is_of_node(fwspec->fwnode) || is_acpi_device_node(fwspec->fwnode)) {
> if (fwspec->param_count != 2)
> return -EINVAL;
>
> @@ -271,6 +272,54 @@ static int mbigen_of_create_domain(struct platform_device *pdev,
> return 0;
> }
>
> +#ifdef CONFIG_ACPI
> +static acpi_status mbigen_acpi_process_resource(struct acpi_resource *ares,
> + void *context)
> +{
> + struct acpi_resource_extended_irq *ext_irq;
> + u32 *num_irqs = context;
> +
> + switch (ares->type) {
> + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
> + ext_irq = &ares->data.extended_irq;
> + *num_irqs += ext_irq->interrupt_count;
> + break;
> + default:
> + break;
> + }
> +
> + return AE_OK;
> +}
> +
> +static int mbigen_acpi_create_domain(struct platform_device *pdev,
> + struct mbigen_device *mgn_chip)
> +{
> + struct irq_domain *domain;
> + u32 num_msis = 0;
> + acpi_status status;
> +
> + status = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), METHOD_NAME__PRS,
> + mbigen_acpi_process_resource, &num_msis);
> + if (ACPI_FAILURE(status) || num_msis == 0)
> + return -EINVAL;
> +
> + domain = platform_msi_create_device_domain(&pdev->dev, num_msis,
> + mbigen_write_msg,
> + &mbigen_domain_ops,
> + mgn_chip);
> + if (!domain)
> + return -ENOMEM;
> +
> + return 0;
> +}
> +#else
> +static int mbigen_acpi_create_domain(struct platform_device *pdev,
> + struct mbigen_device *mgn_chip)
> +{
> + return -ENODEV;
> +}
> +#endif
> +
> static int mbigen_device_probe(struct platform_device *pdev)
> {
> struct mbigen_device *mgn_chip;
> @@ -288,9 +337,17 @@ static int mbigen_device_probe(struct platform_device *pdev)
> if (IS_ERR(mgn_chip->base))
> return PTR_ERR(mgn_chip->base);
>
> - err = mbigen_of_create_domain(pdev, mgn_chip);
> - if (err)
> + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
> + err = mbigen_of_create_domain(pdev, mgn_chip);
> + else if (ACPI_COMPANION(&pdev->dev))
> + err = mbigen_acpi_create_domain(pdev, mgn_chip);
> + else
> + err = -EINVAL;
> +
> + if (err) {
> + dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain", mgn_chip->base);
> return err;
> + }
>
> platform_set_drvdata(pdev, mgn_chip);
> return 0;
> @@ -302,10 +359,17 @@ static int mbigen_device_probe(struct platform_device *pdev)
> };
> MODULE_DEVICE_TABLE(of, mbigen_of_match);
>
> +static const struct acpi_device_id mbigen_acpi_match[] = {
> + { "HISI0152", 0 },
> + {}
> +};
> +MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
> +
> static struct platform_driver mbigen_platform_driver = {
> .driver = {
> .name = "Hisilicon MBIGEN-V2",
> .of_match_table = mbigen_of_match,
> + .acpi_match_table = ACPI_PTR(mbigen_acpi_match),
> },
> .probe = mbigen_device_probe,
> };
>
Reviewed-by: MaJun <[email protected]>
Hi:
?? 2016/12/26 16:57, majun (Euler7) д??:
> Hi Hanjun:
> This patch set works fine on my Hisilicon D05 board.
> Feel free to add
Based on the Patch 1/3, 2/3 of [PATCH V9 0/3] irqchip: qcom: Add IRQ combiner driver
from Agustin Vega-Frias
https://lwn.net/Articles/709222/
> Tested-by: Majun <[email protected]>
>
> ?? 2016/12/22 13:35, Hanjun Guo д??:
>> From: Hanjun Guo <[email protected]>
>>
>> v4 -> v5:
>> - Add mbigen support back with tested on with Agustin's patchset,
>> and it's a good example of how ACPI platform MSI works
>> - rebased on top of lastest Linus tree (commit 52bce91 splice: reinstate SIGPIPE/EPIPE handling)
>>
>> v3 -> v4:
>> - Drop mbi-gen patches to just submit platform msi support because
>> will rebase mbi-gen patches on top of Agustin's patchset, and discusion
>> is going there.
>> - Add a patch to support device topology such as NC(named componant, paltform device)
>> ->SMMU->ITS which suggested by Lorenzo;
>> - rebased on top of Lorenzo's v9 of ACPI IORT ARM SMMU support;
>> - rebased on top of 4.9-rc7
>>
>> v2 -> v3:
>> - Drop RFC tag
>> - Rebase against v4.9-rc2 and Lorenzo's v6 of ACPI IORT ARM SMMU support [1]
>> - Add 3 cleanup patches (patch 1, 2, 3)
>> - Drop arch_init call patch from last version
>> - Introduce a callback for platform device to set msi domain
>> - Introduce a new API to get paltform device's domain instead of
>> reusing the PCI one in previous version
>> - Add a patch to rework iort_node_get_id()
>>
>> [1]: http://www.mail-archive.com/[email protected]/msg1251993.html
>>
>> v1 -> v2:
>> - Fix the bug of if multi Interrupt() resoures in single _PRS,
>> we need to calculate all the irq numbers (I missed it in previous
>> version);
>> - Rebased on Marc's irq/irqchip-4.9 branch and Lorenzo's v5
>> SMMU patches (also Robin's SMMu patches)
>> - Add patch irqchip: mbigen: promote mbigen init.
>>
>> With platform msi support landed in the kernel, and the introduction
>> of IORT for GICv3 ITS (PCI MSI) and SMMU, the framework for platform msi
>> is ready, this patch set add few patches to enable the ACPI platform
>> msi support.
>>
>> For platform device connecting to ITS on arm platform, we have IORT
>> table with the named componant node to describe the mappings of paltform
>> device and ITS, so we can retrieve the dev id and find its parent
>> irqdomain (ITS) from IORT table (simlar with the ACPI ITS support).
>>
>> The fisrt 3 patches are cleanups;
>>
>> Patch 4,5 are refactoring its_pmsi_prepare() for both DT and ACPI
>> then retrieve the dev id from iort;
>>
>> Patch 6,7 to create platform msi domain to ACPI case which scanned
>> the MADT table;
>>
>> Patch 8,9,10,11 to setup the msi domain for platform device based
>> on IORT table.
>>
>> Patch 12,13,14 convert dt based mbigen driver to support ACPI.
>>
>> Teasted on Hisilicon D03/D05.
>>
>> Happy holidays!
>>
>> Thanks
>> Hanjun
>>
>> Hanjun Guo (12):
>> ACPI: ARM64: IORT: minor cleanup for iort_match_node_callback()
>> irqchip: gic-v3-its: keep the head file include in alphabetic order
>> ACPI: ARM64: IORT: add missing comment for iort_dev_find_its_id()
>> irqchip: gicv3-its: platform-msi: refactor its_pmsi_prepare()
>> ACPI: platform-msi: retrieve dev id from IORT
>> irqchip: gicv3-its: platform-msi: refactor its_pmsi_init() to prepare
>> for ACPI
>> irqchip: gicv3-its: platform-msi: scan MADT to create platform msi
>> domain
>> ACPI: ARM64: IORT: rework iort_node_get_id()
>> ACPI: platform: setup MSI domain for ACPI based platform device
>> ACPI: ARM64: IORT: rework iort_node_get_id() for NC->SMMU->ITS case
>> msi: platform: make platform_msi_create_device_domain() ACPI aware
>> irqchip: mbigen: Add ACPI support
>>
>> Kefeng Wang (2):
>> irqchip: mbigen: drop module owner
>> irqchip: mbigen: introduce mbigen_of_create_domain()
>>
>> drivers/acpi/acpi_platform.c | 11 ++
>> drivers/acpi/arm64/iort.c | 138 ++++++++++++++++++++------
>> drivers/base/platform-msi.c | 3 +-
>> drivers/base/platform.c | 3 +
>> drivers/irqchip/irq-gic-v3-its-platform-msi.c | 106 +++++++++++++++-----
>> drivers/irqchip/irq-gic-v3-its.c | 3 +-
>> drivers/irqchip/irq-mbigen.c | 109 ++++++++++++++++----
>> include/linux/acpi_iort.h | 11 ++
>> include/linux/platform_device.h | 3 +
>> 9 files changed, 309 insertions(+), 78 deletions(-)
>>
>
>
> .
>
On 12/25/2016 8:31 PM, Hanjun Guo wrote:
>> A type->setup() would be somewhat cleaner I think, but then it's more
>> code. Whichever works better I guess. :-)
> Agree, I will demo the type->setup() way and send out the patch for review,
> also I find one minor issue for the IORT code, will update that also for next
> version.
Can you provide details on what the minor issue is with the IORT code?
--
Sinan Kaya
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> Cleanup iort_match_node_callback() a little bit to reduce
> some lines of code, aslo fix the indentation in iort_scan_node().
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Lorenzo Pieralisi <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Tomasz Nowicki <[email protected]>
> ---
> drivers/acpi/arm64/iort.c | 10 +++-------
> 1 file changed, 3 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index e0d2e6e..46e2d82 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -225,7 +225,7 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
>
> if (iort_node->type == type &&
> ACPI_SUCCESS(callback(iort_node, context)))
> - return iort_node;
> + return iort_node;
>
> iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
> iort_node->length);
> @@ -253,17 +253,15 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
> void *context)
> {
> struct device *dev = context;
> - acpi_status status;
> + acpi_status status = AE_NOT_FOUND;
>
> if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
> struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
> struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
> struct acpi_iort_named_component *ncomp;
>
> - if (!adev) {
> - status = AE_NOT_FOUND;
> + if (!adev)
> goto out;
> - }
>
> status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
> if (ACPI_FAILURE(status)) {
> @@ -289,8 +287,6 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
> */
> status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
> AE_OK : AE_NOT_FOUND;
> - } else {
> - status = AE_NOT_FOUND;
> }
> out:
> return status;
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> We are missing req_id's comment for iort_dev_find_its_id(),
> add it back.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Lorenzo Pieralisi <[email protected]>
> Cc: Tomasz Nowicki <[email protected]>
> ---
> drivers/acpi/arm64/iort.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index 46e2d82..174e983 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -446,6 +446,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
> /**
> * iort_dev_find_its_id() - Find the ITS identifier for a device
> * @dev: The device.
> + * @req_id: Device's Requster ID
> * @idx: Index of the ITS identifier list.
> * @its_id: ITS identifier.
> *
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> For devices connecting to ITS, it needs dev id to identify
> itself, and this dev id is represented in the IORT table in
> named componant node [1] for platform devices, so in this
> patch we will scan the IORT to retrieve device's dev id.
>
> Introduce iort_pmsi_get_dev_id() with pointer dev passed
> in for that purpose.
>
> [1]: https://static.docs.arm.com/den0049/b/DEN0049B_IO_Remapping_Table.pdf
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Tested-by: Sinan Kaya <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Lorenzo Pieralisi <[email protected]>
> Cc: Tomasz Nowicki <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> ---
> drivers/acpi/arm64/iort.c | 26 ++++++++++++++++++++++++++
> drivers/irqchip/irq-gic-v3-its-platform-msi.c | 4 +++-
> include/linux/acpi_iort.h | 8 ++++++++
> 3 files changed, 37 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index 174e983..ab7bae7 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -444,6 +444,32 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
> }
>
> /**
> + * iort_pmsi_get_dev_id() - Get the device id for a device
> + * @dev: The device for which the mapping is to be done.
> + * @dev_id: The device ID found.
> + *
> + * Returns: 0 for successful find a dev id, errors otherwise
> + */
> +int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
> +{
> + struct acpi_iort_node *node;
> +
> + if (!iort_table)
> + return -ENODEV;
> +
> + node = iort_find_dev_node(dev);
> + if (!node) {
> + dev_err(dev, "can't find related IORT node\n");
> + return -ENODEV;
> + }
> +
> + if(!iort_node_get_id(node, dev_id, IORT_MSI_TYPE, 0))
> + return -ENODEV;
> +
> + return 0;
> +}
> +
> +/**
> * iort_dev_find_its_id() - Find the ITS identifier for a device
> * @dev: The device.
> * @req_id: Device's Requster ID
> diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> index 3c94278..16587a9 100644
> --- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> @@ -15,6 +15,7 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> +#include <linux/acpi_iort.h>
> #include <linux/device.h>
> #include <linux/msi.h>
> #include <linux/of.h>
> @@ -56,7 +57,8 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
>
> msi_info = msi_get_domain_info(domain->parent);
>
> - ret = of_pmsi_get_dev_id(domain, dev, &dev_id);
> + ret = dev->of_node ? of_pmsi_get_dev_id(domain, dev, &dev_id) :
> + iort_pmsi_get_dev_id(dev, &dev_id);
> if (ret)
> return ret;
>
> diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
> index 77e0809..ef99fd52 100644
> --- a/include/linux/acpi_iort.h
> +++ b/include/linux/acpi_iort.h
> @@ -33,6 +33,7 @@
> void acpi_iort_init(void);
> bool iort_node_match(u8 type);
> u32 iort_msi_map_rid(struct device *dev, u32 req_id);
> +int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
> struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
> /* IOMMU interface */
> void iort_set_dma_mask(struct device *dev);
> @@ -42,9 +43,16 @@ static inline void acpi_iort_init(void) { }
> static inline bool iort_node_match(u8 type) { return false; }
> static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
> { return req_id; }
> +
> static inline struct irq_domain *iort_get_device_domain(struct device *dev,
> u32 req_id)
> { return NULL; }
> +
> +static inline int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
> +{
> + return -ENODEV;
> +}
> +
> /* IOMMU interface */
> static inline void iort_set_dma_mask(struct device *dev) { }
> static inline
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> Adding ACPI support for platform MSI, we need to retrieve the
> dev id in ACPI way instead of device tree, we already have
> a well formed function its_pmsi_prepare() to get the dev id
> but it's OF dependent, so collect OF related code and put them
> into a single function to make its_pmsi_prepare() more friendly
> to ACPI later.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Tested-by: Sinan Kaya <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Lorenzo Pieralisi <[email protected]>
> Cc: Tomasz Nowicki <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> ---
> drivers/irqchip/irq-gic-v3-its-platform-msi.c | 23 ++++++++++++++++-------
> 1 file changed, 16 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> index 470b4aa..3c94278 100644
> --- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> @@ -24,15 +24,11 @@
> .name = "ITS-pMSI",
> };
>
> -static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
> - int nvec, msi_alloc_info_t *info)
> +static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
> + u32 *dev_id)
> {
> - struct msi_domain_info *msi_info;
> - u32 dev_id;
> int ret, index = 0;
>
> - msi_info = msi_get_domain_info(domain->parent);
> -
> /* Suck the DeviceID out of the msi-parent property */
> do {
> struct of_phandle_args args;
> @@ -43,11 +39,24 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
> if (args.np == irq_domain_get_of_node(domain)) {
> if (WARN_ON(args.args_count != 1))
> return -EINVAL;
> - dev_id = args.args[0];
> + *dev_id = args.args[0];
> break;
> }
> } while (!ret);
>
> + return ret;
> +}
> +
> +static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
> + int nvec, msi_alloc_info_t *info)
> +{
> + struct msi_domain_info *msi_info;
> + u32 dev_id;
> + int ret;
> +
> + msi_info = msi_get_domain_info(domain->parent);
> +
> + ret = of_pmsi_get_dev_id(domain, dev, &dev_id);
> if (ret)
> return ret;
>
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> With the introduction of its_pmsi_init_one(), we can add some code
> on top for ACPI support of platform MSI.
>
> We are scanning the MADT table to get the ITS entry(ies), then use
> the information to create the platform msi domain for devices connect
> to it, just like the PCI MSI for ITS did.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Tested-by: Sinan Kaya <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Tomasz Nowicki <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> ---
> drivers/irqchip/irq-gic-v3-its-platform-msi.c | 36 +++++++++++++++++++++++++++
> 1 file changed, 36 insertions(+)
>
> diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> index ff72704..0be0437 100644
> --- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> @@ -105,6 +105,41 @@ static int __init its_pmsi_init_one(struct fwnode_handle *fwnode,
> return 0;
> }
>
> +#ifdef CONFIG_ACPI
> +static int __init
> +its_pmsi_parse_madt(struct acpi_subtable_header *header,
> + const unsigned long end)
> +{
> + struct acpi_madt_generic_translator *its_entry;
> + struct fwnode_handle *domain_handle;
> + const char *node_name;
> + int err = -ENXIO;
> +
> + its_entry = (struct acpi_madt_generic_translator *)header;
> + node_name = kasprintf(GFP_KERNEL, "ITS@0x%lx",
> + (long)its_entry->base_address);
> + domain_handle = iort_find_domain_token(its_entry->translation_id);
> + if (!domain_handle) {
> + pr_err("%s: Unable to locate ITS domain handle\n", node_name);
> + goto out;
> + }
> +
> + err = its_pmsi_init_one(domain_handle, node_name);
> +
> +out:
> + kfree(node_name);
> + return err;
> +}
> +
> +static void __init its_acpi_pmsi_init(void)
> +{
> + acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
> + its_pmsi_parse_madt, 0);
> +}
> +#else
> +static inline void its_acpi_pmsi_init(void) { }
> +#endif
> +
> static void __init its_pmsi_of_init(void)
> {
> struct device_node *np;
> @@ -121,6 +156,7 @@ static void __init its_pmsi_of_init(void)
> static int __init its_pmsi_init(void)
> {
> its_pmsi_of_init();
> + its_acpi_pmsi_init();
> return 0;
> }
> early_initcall(its_pmsi_init);
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Kefeng Wang <[email protected]>
>
> Module owner will be set by driver core, so drop it.
>
> Signed-off-by: Kefeng Wang <[email protected]>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ma Jun <[email protected]>
> ---
> drivers/irqchip/irq-mbigen.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
> index 03b79b0..c01ab41 100644
> --- a/drivers/irqchip/irq-mbigen.c
> +++ b/drivers/irqchip/irq-mbigen.c
> @@ -293,7 +293,6 @@ static int mbigen_device_probe(struct platform_device *pdev)
> static struct platform_driver mbigen_platform_driver = {
> .driver = {
> .name = "Hisilicon MBIGEN-V2",
> - .owner = THIS_MODULE,
> .of_match_table = mbigen_of_match,
> },
> .probe = mbigen_device_probe,
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> iort_node_get_id() for now only support NC(named componant)->SMMU
> or NC->ITS cases, we also have other device topology such NC->
> SMMU->ITS, so rework iort_node_get_id() for those cases.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Lorenzo Pieralisi <[email protected]>
> ---
> drivers/acpi/arm64/iort.c | 59 ++++++++++++++++++++++++++---------------------
> 1 file changed, 33 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index 6b72fcb..9b3f268 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -292,22 +292,28 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
> return status;
> }
>
> -static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
> - u32 *rid_out)
> +static int iort_id_single_map(struct acpi_iort_id_mapping *map, u8 type,
> + u32 *rid_out)
> {
> /* Single mapping does not care for input id */
> if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
> if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
> type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
> - *rid_out = map->output_base;
> + if (rid_out)
> + *rid_out = map->output_base;
> return 0;
> }
>
> pr_warn(FW_BUG "[map %p] SINGLE MAPPING flag not allowed for node type %d, skipping ID map\n",
> map, type);
> - return -ENXIO;
> }
>
> + return -ENXIO;
> +}
> +
> +static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
> + u32 *rid_out)
> +{
> if (rid_in < map->input_base ||
> (rid_in >= map->input_base + map->id_count))
> return -ENXIO;
> @@ -324,33 +330,34 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
> struct acpi_iort_node *parent;
> struct acpi_iort_id_mapping *map;
>
> - if (!node->mapping_offset || !node->mapping_count ||
> - index >= node->mapping_count)
> - return NULL;
> -
> - map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
> - node->mapping_offset);
> + while (node) {
> + if (!node->mapping_offset || !node->mapping_count ||
> + index >= node->mapping_count)
> + return NULL;
>
> - /* Firmware bug! */
> - if (!map->output_reference) {
> - pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
> - node, node->type);
> - return NULL;
> - }
> + map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
> + node->mapping_offset);
>
> - parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
> - map->output_reference);
> + /* Firmware bug! */
> + if (!map->output_reference) {
> + pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
> + node, node->type);
> + return NULL;
> + }
>
> - if (!(IORT_TYPE_MASK(parent->type) & type_mask))
> - return NULL;
> + parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
> + map->output_reference);
>
> - if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
> - if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
> - node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
> - if (id_out)
> - *id_out = map[index].output_base;
> - return parent;
> + /* go upstream to find its parent */
> + if (!(IORT_TYPE_MASK(parent->type) & type_mask)) {
> + node = parent;
> + continue;
> }
> +
> + if (iort_id_single_map(&map[index], node->type, id_out))
> + break;
> +
> + return parent;
> }
>
> return NULL;
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> With the preparation of platform msi support and interrupt producer
> in DSDT, we can add mbigen ACPI support now.
>
> We are using _PRS methd to indicate number of irq pins instead
> of num_pins in DT to avoid _DSD usage in this case.
>
> For mbi-gen,
> Device(MBI0) {
> Name(_HID, "HISI0152")
> Name(_UID, Zero)
> Name(_CRS, ResourceTemplate() {
> Memory32Fixed(ReadWrite, 0xa0080000, 0x10000)
> })
>
> Name (_PRS, ResourceTemplate() {
> Interrupt(ResourceProducer,...) {12,14,....}
> })
> }
>
> For devices,
>
> Device(COM0) {
> Name(_HID, "ACPIIDxx")
> Name(_UID, Zero)
> Name(_CRS, ResourceTemplate() {
> Memory32Fixed(ReadWrite, 0xb0030000, 0x10000)
> Interrupt(ResourceConsumer,..., "\_SB.MBI0") {12}
> })
> }
>
> With the helpe of platform msi and interrupt producer, then devices
> will get the virq from mbi-gen's irqdomain.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ma Jun <[email protected]>
> ---
> drivers/irqchip/irq-mbigen.c | 70 ++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 67 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
> index 4e11da5..17d35fa 100644
> --- a/drivers/irqchip/irq-mbigen.c
> +++ b/drivers/irqchip/irq-mbigen.c
> @@ -16,6 +16,7 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> +#include <linux/acpi.h>
> #include <linux/interrupt.h>
> #include <linux/irqchip.h>
> #include <linux/module.h>
> @@ -180,7 +181,7 @@ static int mbigen_domain_translate(struct irq_domain *d,
> unsigned long *hwirq,
> unsigned int *type)
> {
> - if (is_of_node(fwspec->fwnode)) {
> + if (is_of_node(fwspec->fwnode) || is_acpi_device_node(fwspec->fwnode)) {
> if (fwspec->param_count != 2)
> return -EINVAL;
>
> @@ -271,6 +272,54 @@ static int mbigen_of_create_domain(struct platform_device *pdev,
> return 0;
> }
>
> +#ifdef CONFIG_ACPI
> +static acpi_status mbigen_acpi_process_resource(struct acpi_resource *ares,
> + void *context)
> +{
> + struct acpi_resource_extended_irq *ext_irq;
> + u32 *num_irqs = context;
> +
> + switch (ares->type) {
> + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
> + ext_irq = &ares->data.extended_irq;
> + *num_irqs += ext_irq->interrupt_count;
> + break;
> + default:
> + break;
> + }
> +
> + return AE_OK;
> +}
> +
> +static int mbigen_acpi_create_domain(struct platform_device *pdev,
> + struct mbigen_device *mgn_chip)
> +{
> + struct irq_domain *domain;
> + u32 num_msis = 0;
> + acpi_status status;
> +
> + status = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), METHOD_NAME__PRS,
> + mbigen_acpi_process_resource, &num_msis);
> + if (ACPI_FAILURE(status) || num_msis == 0)
> + return -EINVAL;
> +
> + domain = platform_msi_create_device_domain(&pdev->dev, num_msis,
> + mbigen_write_msg,
> + &mbigen_domain_ops,
> + mgn_chip);
> + if (!domain)
> + return -ENOMEM;
> +
> + return 0;
> +}
> +#else
> +static int mbigen_acpi_create_domain(struct platform_device *pdev,
> + struct mbigen_device *mgn_chip)
> +{
> + return -ENODEV;
> +}
> +#endif
> +
> static int mbigen_device_probe(struct platform_device *pdev)
> {
> struct mbigen_device *mgn_chip;
> @@ -288,9 +337,17 @@ static int mbigen_device_probe(struct platform_device *pdev)
> if (IS_ERR(mgn_chip->base))
> return PTR_ERR(mgn_chip->base);
>
> - err = mbigen_of_create_domain(pdev, mgn_chip);
> - if (err)
> + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
> + err = mbigen_of_create_domain(pdev, mgn_chip);
> + else if (ACPI_COMPANION(&pdev->dev))
> + err = mbigen_acpi_create_domain(pdev, mgn_chip);
> + else
> + err = -EINVAL;
> +
> + if (err) {
> + dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain", mgn_chip->base);
> return err;
> + }
>
> platform_set_drvdata(pdev, mgn_chip);
> return 0;
> @@ -302,10 +359,17 @@ static int mbigen_device_probe(struct platform_device *pdev)
> };
> MODULE_DEVICE_TABLE(of, mbigen_of_match);
>
> +static const struct acpi_device_id mbigen_acpi_match[] = {
> + { "HISI0152", 0 },
> + {}
> +};
> +MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
> +
> static struct platform_driver mbigen_platform_driver = {
> .driver = {
> .name = "Hisilicon MBIGEN-V2",
> .of_match_table = mbigen_of_match,
> + .acpi_match_table = ACPI_PTR(mbigen_acpi_match),
> },
> .probe = mbigen_device_probe,
> };
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> The head file is strictly in alphabetic order now, so let's
> be the rule breaker. As acpi_iort.h includes acpi.h so remove
> the duplidate acpi.h inclusion as well.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Tomasz Nowicki <[email protected]>
> ---
> drivers/irqchip/irq-gic-v3-its.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index 69b040f..f471939 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -15,14 +15,13 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> -#include <linux/acpi.h>
> +#include <linux/acpi_iort.h>
> #include <linux/bitmap.h>
> #include <linux/cpu.h>
> #include <linux/delay.h>
> #include <linux/dma-iommu.h>
> #include <linux/interrupt.h>
> #include <linux/irqdomain.h>
> -#include <linux/acpi_iort.h>
> #include <linux/log2.h>
> #include <linux/mm.h>
> #include <linux/msi.h>
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> iort_node_get_id() has two output, one is the mapped ids,
> the other is the referenced parent node which is returned
> from the function.
>
> For now we need a API just return its parent node for
> single mapping, so just update this function slightly then
> reuse it later.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Lorenzo Pieralisi <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> ---
> drivers/acpi/arm64/iort.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index ab7bae7..bc68d93 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -347,7 +347,8 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
> if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
> if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
> node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
> - *id_out = map[index].output_base;
> + if (id_out)
> + *id_out = map[index].output_base;
> return parent;
> }
> }
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Kefeng Wang <[email protected]>
>
> Introduce mbigen_of_create_domain() to consolidate OF related
> code and prepare for ACPI later, no funtional change.
>
> Signed-off-by: Kefeng Wang <[email protected]>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ma Jun <[email protected]>
> ---
> drivers/irqchip/irq-mbigen.c | 42 +++++++++++++++++++++++++++---------------
> 1 file changed, 27 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
> index c01ab41..4e11da5 100644
> --- a/drivers/irqchip/irq-mbigen.c
> +++ b/drivers/irqchip/irq-mbigen.c
> @@ -236,27 +236,15 @@ static int mbigen_irq_domain_alloc(struct irq_domain *domain,
> .free = irq_domain_free_irqs_common,
> };
>
> -static int mbigen_device_probe(struct platform_device *pdev)
> +static int mbigen_of_create_domain(struct platform_device *pdev,
> + struct mbigen_device *mgn_chip)
> {
> - struct mbigen_device *mgn_chip;
> + struct device *parent;
> struct platform_device *child;
> struct irq_domain *domain;
> struct device_node *np;
> - struct device *parent;
> - struct resource *res;
> u32 num_pins;
>
> - mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
> - if (!mgn_chip)
> - return -ENOMEM;
> -
> - mgn_chip->pdev = pdev;
> -
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
> - if (IS_ERR(mgn_chip->base))
> - return PTR_ERR(mgn_chip->base);
> -
> for_each_child_of_node(pdev->dev.of_node, np) {
> if (!of_property_read_bool(np, "interrupt-controller"))
> continue;
> @@ -280,6 +268,30 @@ static int mbigen_device_probe(struct platform_device *pdev)
> return -ENOMEM;
> }
>
> + return 0;
> +}
> +
> +static int mbigen_device_probe(struct platform_device *pdev)
> +{
> + struct mbigen_device *mgn_chip;
> + struct resource *res;
> + int err;
> +
> + mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
> + if (!mgn_chip)
> + return -ENOMEM;
> +
> + mgn_chip->pdev = pdev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + mgn_chip->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
> + if (IS_ERR(mgn_chip->base))
> + return PTR_ERR(mgn_chip->base);
> +
> + err = mbigen_of_create_domain(pdev, mgn_chip);
> + if (err)
> + return err;
> +
> platform_set_drvdata(pdev, mgn_chip);
> return 0;
> }
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> With the platform msi domain created, we can set up the msi domain
> for a platform device when it's probed.
>
> In order to do that, we need to get the domain that the platform
> device connecting to, so the iort_get_platform_device_domain() is
> introduced to retrieve the domain from iort.
>
> After the domain is retrieved, we need a proper way to set the
> domain to paltform device, as some platform devices such as an
> irqchip needs the msi irqdomain to be the interrupt parent domain,
> we need to get irqdomain before platform device is probed but after
> the platform device is allocated, so introduce a callback (pre_add_cb)
> in pdevinfo to prepare firmware related information which is needed
> for device probe, then set the msi domain in that callback.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Rafael J. Wysocki <[email protected]>
> Cc: Greg KH <[email protected]>
> Cc: Lorenzo Pieralisi <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> ---
> drivers/acpi/acpi_platform.c | 11 +++++++++++
> drivers/acpi/arm64/iort.c | 43 +++++++++++++++++++++++++++++++++++++++++
> drivers/base/platform.c | 3 +++
> include/linux/acpi_iort.h | 3 +++
> include/linux/platform_device.h | 3 +++
> 5 files changed, 63 insertions(+)
>
> diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
> index b4c1a6a..5d8d61b4 100644
> --- a/drivers/acpi/acpi_platform.c
> +++ b/drivers/acpi/acpi_platform.c
> @@ -12,6 +12,7 @@
> */
>
> #include <linux/acpi.h>
> +#include <linux/acpi_iort.h>
> #include <linux/device.h>
> #include <linux/err.h>
> #include <linux/kernel.h>
> @@ -48,6 +49,15 @@ static void acpi_platform_fill_resource(struct acpi_device *adev,
> }
>
> /**
> + * acpi_platform_pre_add_cb - callback before platform device is added, to
> + * prepare firmware related information which is needed for device probe
> + */
> +static void acpi_platform_pre_add_cb(struct device *dev)
> +{
> + acpi_configure_pmsi_domain(dev);
> +}
> +
> +/**
> * acpi_create_platform_device - Create platform device for ACPI device node
> * @adev: ACPI device node to create a platform device for.
> * @properties: Optional collection of build-in properties.
> @@ -109,6 +119,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
> pdevinfo.num_res = count;
> pdevinfo.fwnode = acpi_fwnode_handle(adev);
> pdevinfo.properties = properties;
> + pdevinfo.pre_add_cb = acpi_platform_pre_add_cb;
>
> if (acpi_dma_supported(adev))
> pdevinfo.dma_mask = DMA_BIT_MASK(32);
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index bc68d93..6b72fcb 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -527,6 +527,49 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
> return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
> }
>
> +/**
> + * iort_get_platform_device_domain() - Find MSI domain related to a
> + * platform device
> + * @dev: the dev pointer associated with the platform device
> + *
> + * Returns: the MSI domain for this device, NULL otherwise
> + */
> +static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
> +{
> + struct acpi_iort_node *node, *msi_parent;
> + struct fwnode_handle *iort_fwnode;
> + struct acpi_iort_its_group *its;
> +
> + /* find its associated iort node */
> + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
> + iort_match_node_callback, dev);
> + if (!node)
> + return NULL;
> +
> + /* then find its msi parent node */
> + msi_parent = iort_node_get_id(node, NULL, IORT_MSI_TYPE, 0);
> + if (!msi_parent)
> + return NULL;
> +
> + /* Move to ITS specific data */
> + its = (struct acpi_iort_its_group *)msi_parent->node_data;
> +
> + iort_fwnode = iort_find_domain_token(its->identifiers[0]);
> + if (!iort_fwnode)
> + return NULL;
> +
> + return irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI);
> +}
> +
> +void acpi_configure_pmsi_domain(struct device *dev)
> +{
> + struct irq_domain *msi_domain;
> +
> + msi_domain = iort_get_platform_device_domain(dev);
> + if (msi_domain)
> + dev_set_msi_domain(dev, msi_domain);
> +}
> +
> static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
> {
> u32 *rid = data;
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index c4af003..3e68f31 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -537,6 +537,9 @@ struct platform_device *platform_device_register_full(
> goto err;
> }
>
> + if (pdevinfo->pre_add_cb)
> + pdevinfo->pre_add_cb(&pdev->dev);
> +
> ret = platform_device_add(pdev);
> if (ret) {
> err:
> diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
> index ef99fd52..33f5ac3 100644
> --- a/include/linux/acpi_iort.h
> +++ b/include/linux/acpi_iort.h
> @@ -38,6 +38,7 @@
> /* IOMMU interface */
> void iort_set_dma_mask(struct device *dev);
> const struct iommu_ops *iort_iommu_configure(struct device *dev);
> +void acpi_configure_pmsi_domain(struct device *dev);
> #else
> static inline void acpi_iort_init(void) { }
> static inline bool iort_node_match(u8 type) { return false; }
> @@ -58,6 +59,8 @@ static inline void iort_set_dma_mask(struct device *dev) { }
> static inline
> const struct iommu_ops *iort_iommu_configure(struct device *dev)
> { return NULL; }
> +
> +static inline void acpi_configure_pmsi_domain(struct device *dev) { }
> #endif
>
> #define IORT_ACPI_DECLARE(name, table_id, fn) \
> diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
> index 98c2a7c..280d366fb 100644
> --- a/include/linux/platform_device.h
> +++ b/include/linux/platform_device.h
> @@ -74,6 +74,9 @@ struct platform_device_info {
> u64 dma_mask;
>
> struct property_entry *properties;
> +
> + /* preparation callback before the platform device is added */
> + void (*pre_add_cb)(struct device *);
> };
> extern struct platform_device *platform_device_register_full(
> const struct platform_device_info *pdevinfo);
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> With the platform msi domain created for ITS, irqchip such as
> mbi-gen connecting ITS, which needs ctreate its own irqdomain.
>
> Fortunately with the platform msi support upstreamed by Marc,
> we just need to add minor code to make it run properly.
>
> platform_msi_create_device_domain() is almost ready for ACPI use
> except of_node_to_fwnode() is for dt only, make it ACPI aware then
> things will work in both DTS and ACPI.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Greg KH <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Greg KH <[email protected]>
> ---
> drivers/base/platform-msi.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
> index be6a599..035ca3b 100644
> --- a/drivers/base/platform-msi.c
> +++ b/drivers/base/platform-msi.c
> @@ -345,8 +345,7 @@ struct irq_domain *
>
> data->host_data = host_data;
> domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,
> - of_node_to_fwnode(dev->of_node),
> - ops, data);
> + dev->fwnode, ops, data);
> if (!domain)
> goto free_priv;
>
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/22 13:35, Hanjun Guo wrote:
> From: Hanjun Guo <[email protected]>
>
> Introduce its_pmsi_init_one() to refactor the code to isolate
> ACPI&DT common code to prepare for ACPI later.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Tested-by: Sinan Kaya <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Tomasz Nowicki <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> ---
> drivers/irqchip/irq-gic-v3-its-platform-msi.c | 45 ++++++++++++++++-----------
> 1 file changed, 27 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> index 16587a9..ff72704 100644
> --- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
> @@ -84,34 +84,43 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
> {},
> };
>
> -static int __init its_pmsi_init(void)
> +static int __init its_pmsi_init_one(struct fwnode_handle *fwnode,
> + const char *name)
> {
> - struct device_node *np;
> struct irq_domain *parent;
>
> + parent = irq_find_matching_fwnode(fwnode, DOMAIN_BUS_NEXUS);
> + if (!parent || !msi_get_domain_info(parent)) {
> + pr_err("%s: unable to locate ITS domain\n", name);
> + return -ENXIO;
> + }
> +
> + if (!platform_msi_create_irq_domain(fwnode, &its_pmsi_domain_info,
> + parent)) {
> + pr_err("%s: unable to create platform domain\n", name);
> + return -ENXIO;
> + }
> +
> + pr_info("Platform MSI: %s domain created\n", name);
> + return 0;
> +}
> +
> +static void __init its_pmsi_of_init(void)
> +{
> + struct device_node *np;
> +
> for (np = of_find_matching_node(NULL, its_device_id); np;
> np = of_find_matching_node(np, its_device_id)) {
> if (!of_property_read_bool(np, "msi-controller"))
> continue;
>
> - parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
> - if (!parent || !msi_get_domain_info(parent)) {
> - pr_err("%s: unable to locate ITS domain\n",
> - np->full_name);
> - continue;
> - }
> -
> - if (!platform_msi_create_irq_domain(of_node_to_fwnode(np),
> - &its_pmsi_domain_info,
> - parent)) {
> - pr_err("%s: unable to create platform domain\n",
> - np->full_name);
> - continue;
> - }
> -
> - pr_info("Platform MSI: %s domain created\n", np->full_name);
> + its_pmsi_init_one(of_node_to_fwnode(np), np->full_name);
> }
> +}
>
> +static int __init its_pmsi_init(void)
> +{
> + its_pmsi_of_init();
> return 0;
> }
> early_initcall(its_pmsi_init);
Tested-by: Xinwei Kong <[email protected]>
On 2016/12/29 22:44, Sinan Kaya wrote:
> On 12/25/2016 8:31 PM, Hanjun Guo wrote:
>>> A type->setup() would be somewhat cleaner I think, but then it's more
>>> code. Whichever works better I guess. :-)
>> Agree, I will demo the type->setup() way and send out the patch for review,
>> also I find one minor issue for the IORT code, will update that also for next
>> version.
> Can you provide details on what the minor issue is with the IORT code?
It's about the mapping of NC (named component) -> SMMU -> ITS, we can
describe it as two ID mappings:
- NC->SMMU
- NC->ITS
And the code for now can work perfect for such id mappings, but if we
want to support chained mapping NC -> SMMU -> ITS, we need to add
extra code which in my [PATCH v5 10/14] ACPI: ARM64: IORT: rework
iort_node_get_id() for NC->SMMU->ITS case, but I just scanned the first
id mapping for now, I think I need to scan all the id mappings (but seems
single id mappings don't need to do that, I will investigate it more).
Thanks
Hanjun
Hi Rafael,
On 2016/12/26 9:31, Hanjun Guo wrote:
[cut]
>
> + if (pdevinfo->pre_add_cb)
> + pdevinfo->pre_add_cb(&pdev->dev);
> +
>>>> -> because it looks like this might be done in acpi_platform_notify()
>>>> for platform devices.
>>> It works and I just simply add the code below:
>>>
>>> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
>>> index f8d6564..e0cd649 100644
>>> --- a/drivers/acpi/glue.c
>>> +++ b/drivers/acpi/glue.c
>>> @@ -13,6 +13,7 @@
>>> #include <linux/slab.h>
>>> #include <linux/rwsem.h>
>>> #include <linux/acpi.h>
>>> +#include <linux/acpi_iort.h>
>>> #include <linux/dma-mapping.h>
>>>
>>> #include "internal.h"
>>> @@ -315,6 +316,8 @@ static int acpi_platform_notify(struct device *dev)
>>> if (!adev)
>>> goto out;
>>>
>>> + acpi_configure_pmsi_domain(dev);
>>> +
>> But that should apply to platform devices only I suppose?
> Yes, it's only for the platform device.
>
>>> if (type && type->setup)
>>> type->setup(dev);
>>> else if (adev->handler && adev->handler->bind)
>>>
>>> Do you suggesting to configure the msi domain in this way?
>>> or add the function in the type->setup() callback (which needs
>>> to introduce a new acpi bus type)?
>> A type->setup() would be somewhat cleaner I think, but then it's more
>> code. Whichever works better I guess. :-)
> Agree, I will demo the type->setup() way and send out the patch for review,
> also I find one minor issue for the IORT code, will update that also for next
> version.
Just demo the code and find out it's seems to cut the feet to the type->setup() code,
because we need a match function (it's ok) and a find_companion() (we don't need that
and make the code worse because we will call the find_companion callback which it not needed
for platform devices:
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 96983c9..654021d9b 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -138,3 +138,31 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
return pdev;
}
EXPORT_SYMBOL_GPL(acpi_create_platform_device);
+
+static bool platform_acpi_bus_match(struct device *dev)
+{
+ return dev->bus == &platform_bus_type;
+}
+
+static struct acpi_device *platform_acpi_bus_find_companion(struct device *dev)
+{
+ /* demo code, do nothing here */
+ return NULL;
+}
+
+static void platform_acpi_setup(struct device *dev)
+{
+ acpi_configure_pmsi_domain(dev);
+}
+
+static struct acpi_bus_type acpi_platform_bus = {
+ .name = "Platform",
+ .match = platform_acpi_bus_match,
+ .find_companion = platform_acpi_bus_find_companion,
+ .setup = platform_acpi_setup,
+};
+
+int acpi_platform_bus_register(void)
+{
+ return register_acpi_bus_type(&acpi_platform_bus);
+}
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 95855cb..0a0a639 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1199,6 +1199,7 @@ static int __init acpi_init(void)
}
pci_mmcfg_late_init();
+ acpi_platform_bus_register();
acpi_iort_init();
acpi_scan_init();
acpi_ec_init();
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 809b536..1d05f92 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -597,6 +597,8 @@ extern bool acpi_driver_match_device(struct device *dev,
struct platform_device *acpi_create_platform_device(struct acpi_device *,
struct property_entry *);
+int acpi_platform_bus_register(void);
+
#define ACPI_PTR(_ptr) (_ptr)
static inline void acpi_device_set_enumerated(struct acpi_device *adev)
So how about just add the code as below?
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 11e63dd..37a8dfe 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -316,7 +316,8 @@ static int acpi_platform_notify(struct device *dev)
if (!adev)
goto out;
+ if (dev->bus == &platform_bus_type)
+ acpi_configure_pmsi_domain(dev);
if (type && type->setup)
type->setup(dev);
Thanks
Hanjun
On Fri, Dec 30, 2016 at 11:50 AM, Hanjun Guo <[email protected]> wrote:
> Hi Rafael,
>
> On 2016/12/26 9:31, Hanjun Guo wrote:
> [cut]
>>
>> + if (pdevinfo->pre_add_cb)
>> + pdevinfo->pre_add_cb(&pdev->dev);
>> +
>>>>> -> because it looks like this might be done in acpi_platform_notify()
>>>>> for platform devices.
>>>> It works and I just simply add the code below:
>>>>
>>>> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
>>>> index f8d6564..e0cd649 100644
>>>> --- a/drivers/acpi/glue.c
>>>> +++ b/drivers/acpi/glue.c
>>>> @@ -13,6 +13,7 @@
>>>> #include <linux/slab.h>
>>>> #include <linux/rwsem.h>
>>>> #include <linux/acpi.h>
>>>> +#include <linux/acpi_iort.h>
>>>> #include <linux/dma-mapping.h>
>>>>
>>>> #include "internal.h"
>>>> @@ -315,6 +316,8 @@ static int acpi_platform_notify(struct device *dev)
>>>> if (!adev)
>>>> goto out;
>>>>
>>>> + acpi_configure_pmsi_domain(dev);
>>>> +
>>> But that should apply to platform devices only I suppose?
>> Yes, it's only for the platform device.
>>
>>>> if (type && type->setup)
>>>> type->setup(dev);
>>>> else if (adev->handler && adev->handler->bind)
>>>>
>>>> Do you suggesting to configure the msi domain in this way?
>>>> or add the function in the type->setup() callback (which needs
>>>> to introduce a new acpi bus type)?
>>> A type->setup() would be somewhat cleaner I think, but then it's more
>>> code. Whichever works better I guess. :-)
>> Agree, I will demo the type->setup() way and send out the patch for review,
>> also I find one minor issue for the IORT code, will update that also for next
>> version.
>
> Just demo the code and find out it's seems to cut the feet to the type->setup() code,
> because we need a match function (it's ok) and a find_companion() (we don't need that
> and make the code worse because we will call the find_companion callback which it not needed
> for platform devices:
>
> diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
> index 96983c9..654021d9b 100644
> --- a/drivers/acpi/acpi_platform.c
> +++ b/drivers/acpi/acpi_platform.c
> @@ -138,3 +138,31 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
> return pdev;
> }
> EXPORT_SYMBOL_GPL(acpi_create_platform_device);
> +
> +static bool platform_acpi_bus_match(struct device *dev)
> +{
> + return dev->bus == &platform_bus_type;
> +}
> +
> +static struct acpi_device *platform_acpi_bus_find_companion(struct device *dev)
> +{
> + /* demo code, do nothing here */
> + return NULL;
> +}
> +
> +static void platform_acpi_setup(struct device *dev)
> +{
> + acpi_configure_pmsi_domain(dev);
> +}
> +
> +static struct acpi_bus_type acpi_platform_bus = {
> + .name = "Platform",
> + .match = platform_acpi_bus_match,
> + .find_companion = platform_acpi_bus_find_companion,
> + .setup = platform_acpi_setup,
> +};
> +
> +int acpi_platform_bus_register(void)
> +{
> + return register_acpi_bus_type(&acpi_platform_bus);
> +}
> diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
> index 95855cb..0a0a639 100644
> --- a/drivers/acpi/bus.c
> +++ b/drivers/acpi/bus.c
> @@ -1199,6 +1199,7 @@ static int __init acpi_init(void)
> }
>
> pci_mmcfg_late_init();
> + acpi_platform_bus_register();
> acpi_iort_init();
> acpi_scan_init();
> acpi_ec_init();
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 809b536..1d05f92 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -597,6 +597,8 @@ extern bool acpi_driver_match_device(struct device *dev,
>
> struct platform_device *acpi_create_platform_device(struct acpi_device *,
> struct property_entry *);
> +int acpi_platform_bus_register(void);
> +
> #define ACPI_PTR(_ptr) (_ptr)
>
> static inline void acpi_device_set_enumerated(struct acpi_device *adev)
>
>
> So how about just add the code as below?
Works for me.
> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
> index 11e63dd..37a8dfe 100644
> --- a/drivers/acpi/glue.c
> +++ b/drivers/acpi/glue.c
> @@ -316,7 +316,8 @@ static int acpi_platform_notify(struct device *dev)
> if (!adev)
> goto out;
>
> + if (dev->bus == &platform_bus_type)
> + acpi_configure_pmsi_domain(dev);
>
> if (type && type->setup)
> type->setup(dev);
Thanks,
Rafael