The following git branch contains submitted patches along with
the useful patches from the test point of view (mainly ACPI ARM64 PCI support).
https://github.com/semihalf-nowicki-tomasz/linux.git (its-acpi-v4)
Series has been tested on Cavium ThunderX and Qualcomm QDF2xxx server.
v3 -> v4
- rebased against v4.5
- add ACPI support for IRQ domain handling on a per-device basis
- reorder domain setup step
- improve error handling
- code style improvements
v2 -> v3
- rebased on top of 4.4
- fixes and improvements for redistributor init via GICC structures
- fixes as per kbuild reports
v1 -> v2
- rebased on top of 4.4-rc4
- use pci_msi_domain_get_msi_rid for requester ID to device ID translation
Tomasz Nowicki (7):
acpi, pci: Setup MSI domain on a per-devices basis.
irqchip, GICv3, ITS: Cleanup for ITS domain initialization.
irqchip, GICv3, ITS: Refator ITS DT init code to prepare for ACPI.
ARM64, ACPI, PCI: I/O Remapping Table (IORT) initial support.
irqchip, gicv3, its: Probe ITS in the ACPI way.
its, pci, msi: Factor out code that might be reused for ACPI.
acpi, gicv3, its: Use MADT ITS subtable to do PCI/MSI domain
initialization.
drivers/acpi/Kconfig | 3 +
drivers/acpi/Makefile | 1 +
drivers/acpi/iort.c | 335 +++++++++++++++++++++++++++++++
drivers/irqchip/Kconfig | 1 +
drivers/irqchip/irq-gic-v3-its-pci-msi.c | 87 ++++++--
drivers/irqchip/irq-gic-v3-its.c | 188 ++++++++++++-----
drivers/irqchip/irq-gic-v3.c | 7 +-
drivers/pci/msi.c | 10 +-
drivers/pci/pci-acpi.c | 77 +++++++
include/linux/iort.h | 31 +++
include/linux/irqchip/arm-gic-v3.h | 2 +-
include/linux/pci.h | 11 +
12 files changed, 678 insertions(+), 75 deletions(-)
create mode 100644 drivers/acpi/iort.c
create mode 100644 include/linux/iort.h
--
1.9.1
There is no point to initialize ITS without having msi-controller
property in corresponding DT node. However, its_probe is checking
msi-controller presence at the end, so we can save our time and do that
check prior to its_probe call. Also, for the code clarity purpose,
we put domain initialization to separate function.
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its.c | 57 ++++++++++++++++++++++++----------------
1 file changed, 34 insertions(+), 23 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 3926179..065eac5 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1429,13 +1429,37 @@ static void its_enable_quirks(struct its_node *its)
gic_enable_quirks(iidr, its_quirks, its);
}
+static int its_init_domain(struct device_node *node, struct its_node *its,
+ struct irq_domain *parent)
+{
+ struct irq_domain *inner_domain;
+ struct msi_domain_info *info;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
+ if (!inner_domain) {
+ kfree(info);
+ return -ENOMEM;
+ }
+
+ inner_domain->parent = parent;
+ inner_domain->bus_token = DOMAIN_BUS_NEXUS;
+ info->ops = &its_msi_domain_ops;
+ info->data = its;
+ inner_domain->host_data = info;
+
+ return 0;
+}
+
static int __init its_probe(struct device_node *node,
struct irq_domain *parent)
{
struct resource res;
struct its_node *its;
void __iomem *its_base;
- struct irq_domain *inner_domain;
u32 val;
u64 baser, tmp;
int err;
@@ -1526,28 +1550,9 @@ static int __init its_probe(struct device_node *node,
writeq_relaxed(0, its->base + GITS_CWRITER);
writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
- if (of_property_read_bool(node, "msi-controller")) {
- struct msi_domain_info *info;
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
- err = -ENOMEM;
- goto out_free_tables;
- }
-
- inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
- if (!inner_domain) {
- err = -ENOMEM;
- kfree(info);
- goto out_free_tables;
- }
-
- inner_domain->parent = parent;
- inner_domain->bus_token = DOMAIN_BUS_NEXUS;
- info->ops = &its_msi_domain_ops;
- info->data = its;
- inner_domain->host_data = info;
- }
+ err = its_init_domain(node, its, parent);
+ if (err)
+ goto out_free_tables;
spin_lock(&its_lock);
list_add(&its->entry, &its_nodes);
@@ -1598,6 +1603,12 @@ int __init its_init(struct device_node *node, struct rdists *rdists,
for (np = of_find_matching_node(node, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) {
+ if (!of_property_read_bool(np, "msi-controller")) {
+ pr_warn("%s: no msi-controller property, ITS ignored\n",
+ np->full_name);
+ continue;
+ }
+
its_probe(np, parent_domain);
}
--
1.9.1
ITS is prepared for being initialized different than DT,
therefore we can initialize it in ACPI way. We collect register base
address from MADT table and pass mandatory info to firmware-agnostic
ITS init call.
Note that we are using here IORT lib to register ITS domain which
then can be found and used to build another PCI MSI domain
in hierarchical stack domain.
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its.c | 61 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 2dcc7b4..a277c9b 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -15,10 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/iort.h>
#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/msi.h>
@@ -1277,6 +1280,11 @@ static int its_irq_gic_domain_alloc(struct irq_domain *domain,
fwspec.param[0] = GIC_IRQ_TYPE_LPI;
fwspec.param[1] = hwirq;
fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+ } else if (is_fwnode_irqchip(domain->parent->fwnode)) {
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 2;
+ fwspec.param[0] = hwirq;
+ fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
} else {
return -EINVAL;
}
@@ -1617,6 +1625,57 @@ its_of_probe(struct device_node *node, struct irq_domain *parent)
return 0;
}
+#ifdef CONFIG_ACPI
+
+#define ACPI_GICV3_ITS_MEM_SIZE (2 * SZ_64K)
+
+static struct irq_domain *its_parent __initdata;
+
+static int __init
+gic_acpi_parse_madt_its(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_translator *its_entry;
+ struct fwnode_handle *domain_handle;
+ int err;
+
+ its_entry = (struct acpi_madt_generic_translator *)header;
+ domain_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address);
+ if (!domain_handle) {
+ pr_err("Unable to allocate GICv3 ITS domain token\n");
+ return -ENOMEM;
+ }
+
+ err = iort_register_domain_token(its_entry->translation_id, domain_handle);
+ if (err) {
+ irq_domain_free_fwnode(domain_handle);
+ goto out;
+ }
+
+ err = its_probe_one(its_entry->base_address, ACPI_GICV3_ITS_MEM_SIZE,
+ its_parent, domain_handle);
+ if (err) {
+ iort_deregister_domain_token(its_entry->translation_id);
+ irq_domain_free_fwnode(domain_handle);
+ }
+out:
+ return err;
+}
+
+void __init its_acpi_probe(struct irq_domain *parent_domain)
+{
+ int count;
+
+ its_parent = parent_domain;
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+ gic_acpi_parse_madt_its, 0);
+ if (count <= 0)
+ pr_info("No valid GIC ITS entries exist\n");
+}
+#else
+static inline void __init its_acpi_probe(struct irq_domain *parent_domain) { }
+#endif
+
int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
struct irq_domain *parent_domain)
{
@@ -1625,6 +1684,8 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
of_node = to_of_node(handle);
if (of_node)
its_of_probe(of_node, parent_domain);
+ else
+ its_acpi_probe(parent_domain);
if (list_empty(&its_nodes)) {
pr_warn("ITS: No ITS available, not enabling LPIs\n");
--
1.9.1
IORT shows representation of IO topology for ARM based systems.
It describes how various components are connected together on
parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
Initial support allows to:
- register ITS MSI chip along with ITS translation ID and domain token
- deregister ITS MSI chip based on ITS translation ID
- find registered domain token based on ITS translation ID
- map MSI RID based on PCI device and requester ID
- find domain token based on PCI device and requester ID
To: Rafael J. Wysocki <[email protected]>
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/acpi/Kconfig | 3 +
drivers/acpi/Makefile | 1 +
drivers/acpi/iort.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/irqchip/Kconfig | 1 +
include/linux/iort.h | 31 +++++
5 files changed, 371 insertions(+)
create mode 100644 drivers/acpi/iort.c
create mode 100644 include/linux/iort.h
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee..183ffa3 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
config ACPI_CCA_REQUIRED
bool
+config IORT_TABLE
+ bool
+
config ACPI_DEBUGGER
bool "AML debugger interface"
select ACPI_DEBUG
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index cb648a4..7ea903d 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT) += bgrt.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o
obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o
+obj-$(CONFIG_IORT_TABLE) += iort.o
# processor has its own "processor." module_param namespace
processor-y := processor_driver.o
diff --git a/drivers/acpi/iort.c b/drivers/acpi/iort.c
new file mode 100644
index 0000000..3119683
--- /dev/null
+++ b/drivers/acpi/iort.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2016, Semihalf
+ * Author: Tomasz Nowicki <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * This file implements early detection/parsing of I/O mapping
+ * reported to OS through firmware via I/O Remapping Table (IORT)
+ * IORT document number: ARM DEN 0049A
+ */
+
+#define pr_fmt(fmt) "ACPI: IORT: " fmt
+
+#include <linux/export.h>
+#include <linux/iort.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+struct iort_its_msi_chip {
+ struct list_head list;
+ struct fwnode_handle *fw_node;
+ u32 translation_id;
+};
+
+typedef acpi_status (*iort_find_node_callback)
+ (struct acpi_iort_node *node, void *context);
+
+/* Root pointer to the mapped IORT table */
+static struct acpi_table_header *iort_table;
+
+static LIST_HEAD(iort_msi_chip_list);
+
+/**
+ * iort_register_domain_token() - register domain token and related ITS ID
+ * to the list from where we can get it back
+ * later on.
+ * @translation_id: ITS ID
+ * @token: domain token
+ *
+ * Returns: 0 on success, -ENOMEM if not memory when allocating list element.
+ */
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
+{
+ struct iort_its_msi_chip *its_msi_chip;
+
+ its_msi_chip = kzalloc(sizeof(*its_msi_chip), GFP_KERNEL);
+ if (!its_msi_chip)
+ return -ENOMEM;
+
+ its_msi_chip->fw_node = fw_node;
+ its_msi_chip->translation_id = trans_id;
+
+ list_add(&its_msi_chip->list, &iort_msi_chip_list);
+ return 0;
+}
+
+/**
+ * iort_unregister_domain_token() - unregister domain token based on ITS ID.
+ * @translation_id: ITS ID
+ *
+ * Returns: none.
+ */
+void iort_deregister_domain_token(int trans_id)
+{
+ struct iort_its_msi_chip *its_msi_chip, *t;
+
+ list_for_each_entry_safe(its_msi_chip, t, &iort_msi_chip_list, list) {
+ if (its_msi_chip->translation_id == trans_id) {
+ list_del(&its_msi_chip->list);
+ kfree(its_msi_chip);
+ break;
+ }
+ }
+}
+
+/**
+ * iort_find_its_domain_token() - find domain token based on given ITS ID.
+ * @translation_id: ITS ID
+ *
+ * Returns: domain token when find on the list, NULL otherwise.
+ */
+struct fwnode_handle *iort_its_find_domain_token(int trans_id)
+{
+ struct iort_its_msi_chip *its_msi_chip;
+
+ list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
+ if (its_msi_chip->translation_id == trans_id)
+ return its_msi_chip->fw_node;
+ }
+
+ return NULL;
+}
+
+static struct acpi_iort_node *
+iort_scan_node(enum acpi_iort_node_type type,
+ iort_find_node_callback callback, void *context)
+{
+ struct acpi_iort_node *iort_node, *iort_end;
+ struct acpi_table_iort *iort;
+ int i;
+
+ if (!iort_table)
+ return NULL;
+
+ /*
+ * iort_table and iort both point to the start of IORT table, but
+ * have different struct types
+ */
+ iort = (struct acpi_table_iort *)iort_table;
+
+ /* Get the first IORT node */
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+ iort->node_offset);
+ iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+ iort_table->length);
+
+ for (i = 0; i < iort->node_count; i++) {
+ if (iort_node >= iort_end) {
+ pr_err("iort node pointer overflows, bad table\n");
+ return NULL;
+ }
+
+ if (iort_node->type == type) {
+ if (ACPI_SUCCESS(callback(iort_node, context)))
+ return iort_node;
+ }
+
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+ iort_node->length);
+ }
+
+ return NULL;
+}
+
+static acpi_status
+iort_find_dev_callback(struct acpi_iort_node *node, void *context)
+{
+ struct acpi_iort_root_complex *pci_rc;
+ struct device *dev = context;
+ struct pci_bus *bus;
+
+ switch (node->type) {
+ case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
+ bus = to_pci_bus(dev);
+ pci_rc = (struct acpi_iort_root_complex *)node->node_data;
+
+ /*
+ * It is assumed that PCI segment numbers maps one-to-one
+ * with root complexes. Each segment number can represent only
+ * one root complex.
+ */
+ if (pci_rc->pci_segment_number == pci_domain_nr(bus))
+ return AE_OK;
+
+ break;
+ }
+
+ return AE_NOT_FOUND;
+}
+
+static struct acpi_iort_node *
+iort_dev_map_rid(struct acpi_iort_node *node, u32 rid_in,
+ u32 *rid_out)
+{
+
+ if (!node)
+ goto out;
+
+ /* Go upstream */
+ while (node->type != ACPI_IORT_NODE_ITS_GROUP) {
+ struct acpi_iort_id_mapping *id;
+ int i, found = 0;
+
+ /* Exit when no mapping array */
+ if (!node->mapping_offset || !node->mapping_count)
+ return NULL;
+
+ id = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+ node->mapping_offset);
+
+ for (i = 0, found = 0; i < node->mapping_count; i++, id++) {
+ /*
+ * Single mapping is not translation rule,
+ * lets move on for this case
+ */
+ if (id->flags & ACPI_IORT_ID_SINGLE_MAPPING)
+ continue;
+
+ if (rid_in < id->input_base ||
+ (rid_in > id->input_base + id->id_count))
+ continue;
+
+ rid_in = id->output_base + (rid_in - id->input_base);
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ return NULL;
+
+ /* Firmware bug! */
+ if (!id->output_reference) {
+ pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+ node, node->type);
+ return NULL;
+ }
+
+ node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+ id->output_reference);
+ }
+
+out:
+ if (rid_out)
+ *rid_out = rid_in;
+ return node;
+}
+
+static struct acpi_iort_node *
+iort_its_find_node_and_map_rid(struct pci_dev *pdev, u32 req_id, u32 *dev_id)
+{
+ struct pci_bus *pbus = pdev->bus;
+ struct acpi_iort_node *node;
+
+ /* Find a PCI root bus */
+ while (!pci_is_root_bus(pbus))
+ pbus = pbus->parent;
+
+
+ node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+ iort_find_dev_callback, &pbus->dev);
+ if (!node) {
+ dev_err(&pdev->dev, "can't find related IORT node\n");
+ return NULL;
+ }
+
+ return iort_dev_map_rid(node, req_id, dev_id);
+}
+
+/**
+ * iort_pci_domain_get_msi_rid() - find MSI RID based on PCI device ID
+ * @pdev: The PCI device
+ * @req_id: The PCI device requester ID
+ *
+ * Returns: MSI RID on success, requester ID otherwise
+ */
+u32 iort_pci_get_msi_rid(struct pci_dev *pdev, u32 req_id)
+{
+ u32 dev_id;
+
+ if (!iort_its_find_node_and_map_rid(pdev, req_id, &dev_id))
+ return req_id;
+
+ return dev_id;
+}
+
+/**
+ * iort_pci_find_its_id() - find the ITS identifier based on specified device.
+ * @pdev: The PCI device
+ * @idx: Index of the ITS identifier list
+ * @its_id: ITS identifier
+ *
+ * Returns: 0 on success, appropriate error value otherwise
+ */
+static int
+iort_pci_find_its_id(struct pci_dev *pdev, u32 req_id, unsigned int idx,
+ int *its_id)
+{
+ struct acpi_iort_its_group *its;
+ struct acpi_iort_node *node;
+
+ node = iort_its_find_node_and_map_rid(pdev, req_id, NULL);
+ if (!node)
+ return -ENXIO;
+
+ /* Move to ITS specific data */
+ its = (struct acpi_iort_its_group *)node->node_data;
+ if (idx > its->its_count) {
+ dev_err(&pdev->dev, "requested ITS ID index [%d] is greater than available[%d]\n",
+ idx, its->its_count);
+ return -ENXIO;
+ }
+
+ *its_id = its->identifiers[idx];
+ return 0;
+}
+
+/**
+ * iort_pci_get_msi_domain_handle() - find registered domain token related to
+ * PCI device
+ * @pdev: The PCI device
+ * @req_id: The PCI device requester ID
+ *
+ * Returns: domain token on success, NULL otherwise
+ */
+struct fwnode_handle *
+iort_pci_get_domain(struct pci_dev *pdev, u32 req_id)
+{
+ static struct fwnode_handle *domain_handle;
+ int its_id;
+
+ if (iort_pci_find_its_id(pdev, req_id, 0, &its_id))
+ return NULL;
+
+ domain_handle = iort_its_find_domain_token(its_id);
+ if (!domain_handle)
+ return NULL;
+
+ return domain_handle;
+}
+
+static int __init iort_table_detect(void)
+{
+ acpi_status status;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
+ if (ACPI_FAILURE(status)) {
+ const char *msg = acpi_format_exception(status);
+ pr_err("Failed to get table, %s\n", msg);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+arch_initcall(iort_table_detect);
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index fb50911..8410999 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -31,6 +31,7 @@ config ARM_GIC_V3
config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
+ select IORT_TABLE if ACPI
config HISILICON_IRQ_MBIGEN
bool "Support mbigen interrupt controller"
diff --git a/include/linux/iort.h b/include/linux/iort.h
new file mode 100644
index 0000000..7441941
--- /dev/null
+++ b/include/linux/iort.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016, Semihalf
+ * Author: Tomasz Nowicki <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __IORT_H__
+#define __IORT_H__
+
+#include <linux/acpi.h>
+
+struct fwnode_handle;
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
+void iort_deregister_domain_token(int trans_id);
+struct fwnode_handle *iort_its_find_domain_token(int trans_id);
+u32 iort_pci_get_msi_rid(struct pci_dev *pdev, u32 req_id);
+struct fwnode_handle *iort_pci_get_domain(struct pci_dev *pdev, u32 req_id);
+
+#endif /* __IORT_H__ */
--
1.9.1
Let ACPI to build ITS PCI MSI domain. If it succeed, we register IORT
domain provider and RID mapper.
We have now full PCI MSI domain stack, thus we can enable ITS initialization
from GICv3 core driver for ACPI scenario.
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its-pci-msi.c | 46 +++++++++++++++++++++++++++++++-
drivers/irqchip/irq-gic-v3.c | 3 +--
2 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
index 06165cb..df269a4 100644
--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
@@ -15,6 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi.h>
+#include <linux/iort.h>
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -143,10 +145,52 @@ static int __init its_pci_of_msi_init(void)
return 0;
}
+#ifdef CONFIG_ACPI
+
+static int __init
+its_pci_msi_parse_madt(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_translator *its_entry;
+ struct fwnode_handle *domain_handle;
+
+ its_entry = (struct acpi_madt_generic_translator *)header;
+ domain_handle = iort_its_find_domain_token(its_entry->translation_id);
+ if (!domain_handle) {
+ pr_err("ITS@0x%lx: Unable to locate ITS domain handle\n",
+ (long)its_entry->base_address);
+ return 0;
+ }
+
+ if (its_pci_msi_init_one(domain_handle))
+ return 0;
+
+ pr_info("PCI/MSI: ITS@0x%lx domain created\n",
+ (long)its_entry->base_address);
+ return 0;
+}
+
+static int __init its_pci_acpi_msi_init(void)
+{
+ if (acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+ its_pci_msi_parse_madt, 0) > 0) {
+ pci_acpi_register_msi_rid_mapper(iort_pci_get_msi_rid);
+ pci_acpi_register_dev_msi_fwnode_provider(iort_pci_get_domain);
+ }
+ return 0;
+}
+#else
+inline static int __init its_pci_acpi_msi_init(void)
+{
+ return 0;
+}
+#endif
+
static int __init its_pci_msi_init(void)
{
its_pci_of_msi_init();
+ its_pci_acpi_msi_init();
+
return 0;
}
-
early_initcall(its_pci_msi_init);
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 995b7251..fee635e 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -871,8 +871,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
set_handle_irq(gic_handle_irq);
- if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
- to_of_node(handle)) /* Temp hack to prevent ITS init for ACPI */
+ if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
its_init(handle, &gic_data.rdists, gic_data.domain);
gic_smp_init();
--
1.9.1
Firmware agnostic code lands in common functions which do necessary
domain initialization based on unique domain handler. DT specific
code goes to DT specific init call.
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its-pci-msi.c | 43 +++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
index aee60ed..06165cb 100644
--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
@@ -106,34 +106,47 @@ static struct of_device_id its_device_id[] = {
{},
};
-static int __init its_pci_msi_init(void)
+static int __init its_pci_msi_init_one(struct fwnode_handle *handle)
{
- struct device_node *np;
struct irq_domain *parent;
+ parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS);
+ if (!parent || !msi_get_domain_info(parent)) {
+ pr_err("Unable to locate ITS domain\n");
+ return -ENXIO;
+ }
+
+ if (!pci_msi_create_irq_domain(handle, &its_pci_msi_domain_info,
+ parent)) {
+ pr_err("Unable to create PCI domain\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int __init its_pci_of_msi_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);
+ if (its_pci_msi_init_one(of_node_to_fwnode(np)))
continue;
- }
-
- if (!pci_msi_create_irq_domain(of_node_to_fwnode(np),
- &its_pci_msi_domain_info,
- parent)) {
- pr_err("%s: unable to create PCI domain\n",
- np->full_name);
- continue;
- }
pr_info("PCI/MSI: %s domain created\n", np->full_name);
}
return 0;
}
+
+static int __init its_pci_msi_init(void)
+{
+ its_pci_of_msi_init();
+ return 0;
+}
+
early_initcall(its_pci_msi_init);
--
1.9.1
It is now possible to provide information about which MSI controller to
use on a per-device basis for DT. This patch supply this with ACPI support.
In order to handle MSI domain on per-devices basis we need to add
PCI device requester ID (RID) mapper, MSI domain provider and corresponding
registration:
pci_acpi_msi_domain_get_msi_rid - maps PCI ID and returns MSI RID
pci_acpi_register_msi_rid_mapper - registers RID mapper
pci_acpi_msi_get_device_domain - finds PCI device MSI domain
pci_acpi_register_dev_msi_fwnode_provider - registers MSI domain finder
Then, it is plugged into MSI infrastructure.
To: Bjorn Helgaas <[email protected]>
To: Rafael J. Wysocki <[email protected]>
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/pci/msi.c | 10 +++++--
drivers/pci/pci-acpi.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 11 ++++++++
3 files changed, 95 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index a080f44..07b59a3 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -1364,8 +1364,8 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
of_node = irq_domain_get_of_node(domain);
- if (of_node)
- rid = of_msi_map_rid(&pdev->dev, of_node, rid);
+ rid = of_node ? of_msi_map_rid(&pdev->dev, of_node, rid) :
+ pci_acpi_msi_domain_get_msi_rid(pdev, rid);
return rid;
}
@@ -1381,9 +1381,13 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
*/
struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
{
+ struct irq_domain *dom;
u32 rid = 0;
pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
- return of_msi_map_get_device_domain(&pdev->dev, rid);
+ dom = of_msi_map_get_device_domain(&pdev->dev, rid);
+ if (!dom)
+ dom = pci_acpi_msi_get_device_domain(pdev, rid);
+ return dom;
}
#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 9a033e8..26f4552 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -731,6 +731,83 @@ struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI);
}
+static u32 (*pci_msi_map_dev_rid_cb)(struct pci_dev *pdev, u32 req_id);
+
+/**
+ * pci_acpi_register_msi_rid_mapper - Register callback to map the MSI
+ * requester id (RID)
+ * @fn: Callback mapping a PCI device RID.
+ *
+ * This should be called by irqchip driver, which can provide firmware-defined
+ * topologies about MSI requester id (RID) on a per-device basis.
+ */
+void pci_acpi_register_msi_rid_mapper(u32 (*fn)(struct pci_dev *, u32))
+{
+ pci_msi_map_dev_rid_cb = fn;
+}
+
+/**
+ * pci_acpi_msi_domain_get_msi_rid - Get the MSI requester id (RID) of
+ * a PCI device
+ * @pdev: The PCI device.
+ * @rid_in: The PCI device request ID.
+ *
+ * This function uses the callback function registered by
+ * pci_acpi_register_msi_rid_mapper() to get the device RID based on ACPI
+ * supplied mapping.
+ * This should return rid_in on error or when there is no valid map.
+ */
+u32 pci_acpi_msi_domain_get_msi_rid(struct pci_dev *pdev, u32 rid_in)
+{
+ if (!pci_msi_map_dev_rid_cb)
+ return rid_in;
+
+ return pci_msi_map_dev_rid_cb(pdev, rid_in);
+}
+
+static struct fwnode_handle *(*pci_msi_get_dev_fwnode_cb)(struct pci_dev *pdev,
+ u32 req_id);
+
+/**
+ * pci_acpi_register_dev_msi_fwnode_provider - Register callback to retrieve
+ * domain fwnode on the per-device basis
+ * @fn: Callback matching a device to a fwnode that identifies a PCI
+ * MSI domain.
+ *
+ * This should be called by irqchip driver, which can provide firmware-defined
+ * topologies about which MSI controller to use on a per-device basis.
+ */
+void
+pci_acpi_register_dev_msi_fwnode_provider(
+ struct fwnode_handle *(*fn)(struct pci_dev *, u32))
+{
+ pci_msi_get_dev_fwnode_cb = fn;
+}
+
+/**
+ * pci_acpi_msi_get_device_domain - Retrieve MSI domain of a PCI device
+ * @pdev: The PCI device.
+ * @rid: The PCI device requester ID.
+ *
+ * This function uses the callback function registered by
+ * pci_acpi_register_dev_msi_fwnode_provider() to retrieve the irq_domain with
+ * type DOMAIN_BUS_PCI_MSI of the specified PCI device.
+ * This returns NULL on error or when the domain is not found.
+ */
+struct irq_domain *pci_acpi_msi_get_device_domain(struct pci_dev *pdev, u32 rid)
+{
+ struct fwnode_handle *fwnode;
+
+ if (!pci_msi_get_dev_fwnode_cb)
+ return NULL;
+
+ fwnode = pci_msi_get_dev_fwnode_cb(pdev, rid);
+ if (!fwnode)
+ return NULL;
+
+ return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI);
+}
+
static int __init acpi_pci_init(void)
{
int ret;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2771625..f50ba85 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1932,9 +1932,20 @@ struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
void
pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *));
+u32 pci_acpi_msi_domain_get_msi_rid(struct pci_dev *pdev, u32 rid_in);
+void pci_acpi_register_msi_rid_mapper(u32 (*fn)(struct pci_dev *, u32));
+struct irq_domain *
+pci_acpi_msi_get_device_domain(struct pci_dev *pdev, u32 rid);
+void pci_acpi_register_dev_msi_fwnode_provider(
+ struct fwnode_handle *(*fn)(struct pci_dev *, u32));
#else
static inline struct irq_domain *
pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
+static inline u32
+pci_acpi_msi_domain_get_msi_rid(struct pci_dev *pdev, u32 rid_in)
+{ return rid_in; }
+static inline struct irq_domain *
+pci_acpi_msi_get_device_domain(struct pci_dev *pdev, u32 rid) { return NULL; }
#endif
#ifdef CONFIG_EEH
--
1.9.1
No functional changes.
In order to add ACPI support we need to isolate ACPI&DT common code and
move DT logic to corresponding functions. To achieve this we are using
firmware agnostic handle which can be unpacked to either DT or ACPI node.
Signed-off-by: Hanjun Guo <[email protected]>
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its.c | 76 ++++++++++++++++++++++----------------
drivers/irqchip/irq-gic-v3.c | 6 +--
include/linux/irqchip/arm-gic-v3.h | 2 +-
3 files changed, 48 insertions(+), 36 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 065eac5..2dcc7b4 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -815,7 +815,7 @@ static void its_free_tables(struct its_node *its)
}
}
-static int its_alloc_tables(const char *node_name, struct its_node *its)
+static int its_alloc_tables(struct its_node *its)
{
int err;
int i;
@@ -869,8 +869,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
order);
if (order >= MAX_ORDER) {
order = MAX_ORDER - 1;
- pr_warn("%s: Device Table too large, reduce its page order to %u\n",
- node_name, order);
+ pr_warn("ITS@0x%lx: Device Table too large, reduce its page order to %u\n",
+ its->phys_base, order);
}
}
@@ -879,8 +879,8 @@ retry_alloc_baser:
if (alloc_pages > GITS_BASER_PAGES_MAX) {
alloc_pages = GITS_BASER_PAGES_MAX;
order = get_order(GITS_BASER_PAGES_MAX * psz);
- pr_warn("%s: Device Table too large, reduce its page order to %u (%u pages)\n",
- node_name, order, alloc_pages);
+ pr_warn("ITS@0x%lx: Device Table too large, reduce its page order to %u (%u pages)\n",
+ its->phys_base, order, alloc_pages);
}
base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
@@ -953,8 +953,8 @@ retry_baser:
}
if (val != tmp) {
- pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n",
- node_name, i,
+ pr_err("ITS@0x%lx: GITS_BASER%d doesn't stick: %lx %lx\n",
+ its->phys_base, i,
(unsigned long) val, (unsigned long) tmp);
err = -ENXIO;
goto out_free;
@@ -1429,7 +1429,7 @@ static void its_enable_quirks(struct its_node *its)
gic_enable_quirks(iidr, its_quirks, its);
}
-static int its_init_domain(struct device_node *node, struct its_node *its,
+static int its_init_domain(struct fwnode_handle *handler, struct its_node *its,
struct irq_domain *parent)
{
struct irq_domain *inner_domain;
@@ -1439,7 +1439,7 @@ static int its_init_domain(struct device_node *node, struct its_node *its,
if (!info)
return -ENOMEM;
- inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
+ inner_domain = irq_domain_create_tree(handler, &its_domain_ops, its);
if (!inner_domain) {
kfree(info);
return -ENOMEM;
@@ -1454,43 +1454,39 @@ static int its_init_domain(struct device_node *node, struct its_node *its,
return 0;
}
-static int __init its_probe(struct device_node *node,
- struct irq_domain *parent)
+static int __init its_probe_one(phys_addr_t phys_base, unsigned long size,
+ struct irq_domain *parent,
+ struct fwnode_handle *handler)
{
- struct resource res;
struct its_node *its;
void __iomem *its_base;
u32 val;
u64 baser, tmp;
int err;
- err = of_address_to_resource(node, 0, &res);
- if (err) {
- pr_warn("%s: no regs?\n", node->full_name);
- return -ENXIO;
- }
-
- its_base = ioremap(res.start, resource_size(&res));
+ its_base = ioremap(phys_base, size);
if (!its_base) {
- pr_warn("%s: unable to map registers\n", node->full_name);
+ pr_warn("ITS@0x%lx: Unable to map ITS registers\n",
+ (long)phys_base);
return -ENOMEM;
}
val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
if (val != 0x30 && val != 0x40) {
- pr_warn("%s: no ITS detected, giving up\n", node->full_name);
+ pr_warn("ITS@0x%lx: No ITS detected, giving up\n",
+ (long)phys_base);
err = -ENODEV;
goto out_unmap;
}
err = its_force_quiescent(its_base);
if (err) {
- pr_warn("%s: failed to quiesce, giving up\n",
- node->full_name);
+ pr_warn("ITS@0x%lx: Failed to quiesce, giving up\n",
+ (long)phys_base);
goto out_unmap;
}
- pr_info("ITS: %s\n", node->full_name);
+ pr_info("ITS@0x%lx\n", (long)phys_base);
its = kzalloc(sizeof(*its), GFP_KERNEL);
if (!its) {
@@ -1502,7 +1498,7 @@ static int __init its_probe(struct device_node *node,
INIT_LIST_HEAD(&its->entry);
INIT_LIST_HEAD(&its->its_device_list);
its->base = its_base;
- its->phys_base = res.start;
+ its->phys_base = phys_base;
its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
@@ -1514,7 +1510,7 @@ static int __init its_probe(struct device_node *node,
its_enable_quirks(its);
- err = its_alloc_tables(node->full_name, its);
+ err = its_alloc_tables(its);
if (err)
goto out_free_cmd;
@@ -1550,7 +1546,7 @@ static int __init its_probe(struct device_node *node,
writeq_relaxed(0, its->base + GITS_CWRITER);
writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
- err = its_init_domain(node, its, parent);
+ err = its_init_domain(handler, its, parent);
if (err)
goto out_free_tables;
@@ -1568,7 +1564,7 @@ out_free_its:
kfree(its);
out_unmap:
iounmap(its_base);
- pr_err("ITS: failed probing %s (%d)\n", node->full_name, err);
+ pr_err("ITS@0x%lx: failed probing (%d)\n", (long)phys_base, err);
return err;
}
@@ -1596,10 +1592,11 @@ static struct of_device_id its_device_id[] = {
{},
};
-int __init its_init(struct device_node *node, struct rdists *rdists,
- struct irq_domain *parent_domain)
+static int __init
+its_of_probe(struct device_node *node, struct irq_domain *parent)
{
struct device_node *np;
+ struct resource res;
for (np = of_find_matching_node(node, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) {
@@ -1609,8 +1606,25 @@ int __init its_init(struct device_node *node, struct rdists *rdists,
continue;
}
- its_probe(np, parent_domain);
+ if (of_address_to_resource(np, 0, &res)) {
+ pr_warn("%s: no regs?\n", np->full_name);
+ continue;
+ }
+
+ its_probe_one(res.start, resource_size(&res), parent,
+ &np->fwnode);
}
+ return 0;
+}
+
+int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
+ struct irq_domain *parent_domain)
+{
+ struct device_node *of_node;
+
+ of_node = to_of_node(handle);
+ if (of_node)
+ its_of_probe(of_node, parent_domain);
if (list_empty(&its_nodes)) {
pr_warn("ITS: No ITS available, not enabling LPIs\n");
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index dd16a60..995b7251 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -832,7 +832,6 @@ static int __init gic_init_bases(void __iomem *dist_base,
u64 redist_stride,
struct fwnode_handle *handle)
{
- struct device_node *node;
u32 typer;
int gic_irqs;
int err;
@@ -872,10 +871,9 @@ static int __init gic_init_bases(void __iomem *dist_base,
set_handle_irq(gic_handle_irq);
- node = to_of_node(handle);
if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
- node) /* Temp hack to prevent ITS init for ACPI */
- its_init(node, &gic_data.rdists, gic_data.domain);
+ to_of_node(handle)) /* Temp hack to prevent ITS init for ACPI */
+ its_init(handle, &gic_data.rdists, gic_data.domain);
gic_smp_init();
gic_dist_init();
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index d5d798b..a40ed7d 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -332,7 +332,7 @@ struct rdists {
struct irq_domain;
struct device_node;
int its_cpu_init(void);
-int its_init(struct device_node *node, struct rdists *rdists,
+int its_init(struct fwnode_handle *handle, struct rdists *rdists,
struct irq_domain *domain);
static inline bool gic_enable_sre(void)
--
1.9.1
Hi Marc, Bjorn, Rafael,
Can you please have a look at this series? Thanks in advance.
Tomasz
On 04.04.2016 10:52, Tomasz Nowicki wrote:
> The following git branch contains submitted patches along with
> the useful patches from the test point of view (mainly ACPI ARM64 PCI support).
> https://github.com/semihalf-nowicki-tomasz/linux.git (its-acpi-v4)
>
> Series has been tested on Cavium ThunderX and Qualcomm QDF2xxx server.
>
> v3 -> v4
> - rebased against v4.5
> - add ACPI support for IRQ domain handling on a per-device basis
> - reorder domain setup step
> - improve error handling
> - code style improvements
>
> v2 -> v3
> - rebased on top of 4.4
> - fixes and improvements for redistributor init via GICC structures
> - fixes as per kbuild reports
>
> v1 -> v2
> - rebased on top of 4.4-rc4
> - use pci_msi_domain_get_msi_rid for requester ID to device ID translation
>
> Tomasz Nowicki (7):
> acpi, pci: Setup MSI domain on a per-devices basis.
> irqchip, GICv3, ITS: Cleanup for ITS domain initialization.
> irqchip, GICv3, ITS: Refator ITS DT init code to prepare for ACPI.
> ARM64, ACPI, PCI: I/O Remapping Table (IORT) initial support.
> irqchip, gicv3, its: Probe ITS in the ACPI way.
> its, pci, msi: Factor out code that might be reused for ACPI.
> acpi, gicv3, its: Use MADT ITS subtable to do PCI/MSI domain
> initialization.
>
> drivers/acpi/Kconfig | 3 +
> drivers/acpi/Makefile | 1 +
> drivers/acpi/iort.c | 335 +++++++++++++++++++++++++++++++
> drivers/irqchip/Kconfig | 1 +
> drivers/irqchip/irq-gic-v3-its-pci-msi.c | 87 ++++++--
> drivers/irqchip/irq-gic-v3-its.c | 188 ++++++++++++-----
> drivers/irqchip/irq-gic-v3.c | 7 +-
> drivers/pci/msi.c | 10 +-
> drivers/pci/pci-acpi.c | 77 +++++++
> include/linux/iort.h | 31 +++
> include/linux/irqchip/arm-gic-v3.h | 2 +-
> include/linux/pci.h | 11 +
> 12 files changed, 678 insertions(+), 75 deletions(-)
> create mode 100644 drivers/acpi/iort.c
> create mode 100644 include/linux/iort.h
>
On 04.04.2016 10:52, Tomasz Nowicki wrote:
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index d5d798b..a40ed7d 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -332,7 +332,7 @@ struct rdists {
> struct irq_domain;
> struct device_node;
I forgot to add this to avoid compilation warning:
-struct device_node;
+struct fwnode_handle;
> int its_cpu_init(void);
> -int its_init(struct device_node *node, struct rdists *rdists,
> +int its_init(struct fwnode_handle *handle, struct rdists *rdists,
> struct irq_domain *domain);
>
> static inline bool gic_enable_sre(void)
Thanks,
Tomasz
On 04/04/16 09:52, Tomasz Nowicki wrote:
> It is now possible to provide information about which MSI controller to
> use on a per-device basis for DT. This patch supply this with ACPI support.
>
> In order to handle MSI domain on per-devices basis we need to add
> PCI device requester ID (RID) mapper, MSI domain provider and corresponding
> registration:
> pci_acpi_msi_domain_get_msi_rid - maps PCI ID and returns MSI RID
> pci_acpi_register_msi_rid_mapper - registers RID mapper
>
> pci_acpi_msi_get_device_domain - finds PCI device MSI domain
> pci_acpi_register_dev_msi_fwnode_provider - registers MSI domain finder
>
> Then, it is plugged into MSI infrastructure.
>
> To: Bjorn Helgaas <[email protected]>
> To: Rafael J. Wysocki <[email protected]>
> Signed-off-by: Tomasz Nowicki <[email protected]>
> ---
> drivers/pci/msi.c | 10 +++++--
> drivers/pci/pci-acpi.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/pci.h | 11 ++++++++
> 3 files changed, 95 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index a080f44..07b59a3 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -1364,8 +1364,8 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
> pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
>
> of_node = irq_domain_get_of_node(domain);
> - if (of_node)
> - rid = of_msi_map_rid(&pdev->dev, of_node, rid);
> + rid = of_node ? of_msi_map_rid(&pdev->dev, of_node, rid) :
> + pci_acpi_msi_domain_get_msi_rid(pdev, rid);
>
> return rid;
> }
> @@ -1381,9 +1381,13 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
> */
> struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
> {
> + struct irq_domain *dom;
> u32 rid = 0;
>
> pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
> - return of_msi_map_get_device_domain(&pdev->dev, rid);
> + dom = of_msi_map_get_device_domain(&pdev->dev, rid);
> + if (!dom)
> + dom = pci_acpi_msi_get_device_domain(pdev, rid);
> + return dom;
> }
> #endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> index 9a033e8..26f4552 100644
> --- a/drivers/pci/pci-acpi.c
> +++ b/drivers/pci/pci-acpi.c
> @@ -731,6 +731,83 @@ struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
> return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI);
> }
>
> +static u32 (*pci_msi_map_dev_rid_cb)(struct pci_dev *pdev, u32 req_id);
> +
> +/**
> + * pci_acpi_register_msi_rid_mapper - Register callback to map the MSI
> + * requester id (RID)
> + * @fn: Callback mapping a PCI device RID.
> + *
> + * This should be called by irqchip driver, which can provide firmware-defined
> + * topologies about MSI requester id (RID) on a per-device basis.
> + */
> +void pci_acpi_register_msi_rid_mapper(u32 (*fn)(struct pci_dev *, u32))
> +{
> + pci_msi_map_dev_rid_cb = fn;
> +}
> +
> +/**
> + * pci_acpi_msi_domain_get_msi_rid - Get the MSI requester id (RID) of
> + * a PCI device
> + * @pdev: The PCI device.
> + * @rid_in: The PCI device request ID.
> + *
> + * This function uses the callback function registered by
> + * pci_acpi_register_msi_rid_mapper() to get the device RID based on ACPI
> + * supplied mapping.
> + * This should return rid_in on error or when there is no valid map.
> + */
> +u32 pci_acpi_msi_domain_get_msi_rid(struct pci_dev *pdev, u32 rid_in)
> +{
> + if (!pci_msi_map_dev_rid_cb)
> + return rid_in;
> +
> + return pci_msi_map_dev_rid_cb(pdev, rid_in);
> +}
> +
> +static struct fwnode_handle *(*pci_msi_get_dev_fwnode_cb)(struct pci_dev *pdev,
> + u32 req_id);
> +
> +/**
> + * pci_acpi_register_dev_msi_fwnode_provider - Register callback to retrieve
> + * domain fwnode on the per-device basis
> + * @fn: Callback matching a device to a fwnode that identifies a PCI
> + * MSI domain.
> + *
> + * This should be called by irqchip driver, which can provide firmware-defined
> + * topologies about which MSI controller to use on a per-device basis.
> + */
> +void
> +pci_acpi_register_dev_msi_fwnode_provider(
> + struct fwnode_handle *(*fn)(struct pci_dev *, u32))
> +{
> + pci_msi_get_dev_fwnode_cb = fn;
> +}
I'm quite sceptical about this indirection. Either IORT is the only
mapping infrastructure that we can use for ACPI and we can then directly
call into it, or we can have several of them (which ones?) and we need
more than just this single slot.
So in any case, I don't think this is the right solution. As my
understanding is that IORT is the only source of RID remapping, we
should be able to directly call into the IORT code without this complexity.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
On 13.04.2016 12:18, Marc Zyngier wrote:
> On 04/04/16 09:52, Tomasz Nowicki wrote:
>> It is now possible to provide information about which MSI controller to
>> use on a per-device basis for DT. This patch supply this with ACPI support.
>>
>> In order to handle MSI domain on per-devices basis we need to add
>> PCI device requester ID (RID) mapper, MSI domain provider and corresponding
>> registration:
>> pci_acpi_msi_domain_get_msi_rid - maps PCI ID and returns MSI RID
>> pci_acpi_register_msi_rid_mapper - registers RID mapper
>>
>> pci_acpi_msi_get_device_domain - finds PCI device MSI domain
>> pci_acpi_register_dev_msi_fwnode_provider - registers MSI domain finder
>>
>> Then, it is plugged into MSI infrastructure.
>>
>> To: Bjorn Helgaas <[email protected]>
>> To: Rafael J. Wysocki <[email protected]>
>> Signed-off-by: Tomasz Nowicki <[email protected]>
>> ---
>> drivers/pci/msi.c | 10 +++++--
>> drivers/pci/pci-acpi.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++
>> include/linux/pci.h | 11 ++++++++
>> 3 files changed, 95 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
>> index a080f44..07b59a3 100644
>> --- a/drivers/pci/msi.c
>> +++ b/drivers/pci/msi.c
>> @@ -1364,8 +1364,8 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
>> pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
>>
>> of_node = irq_domain_get_of_node(domain);
>> - if (of_node)
>> - rid = of_msi_map_rid(&pdev->dev, of_node, rid);
>> + rid = of_node ? of_msi_map_rid(&pdev->dev, of_node, rid) :
>> + pci_acpi_msi_domain_get_msi_rid(pdev, rid);
>>
>> return rid;
>> }
>> @@ -1381,9 +1381,13 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
>> */
>> struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
>> {
>> + struct irq_domain *dom;
>> u32 rid = 0;
>>
>> pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
>> - return of_msi_map_get_device_domain(&pdev->dev, rid);
>> + dom = of_msi_map_get_device_domain(&pdev->dev, rid);
>> + if (!dom)
>> + dom = pci_acpi_msi_get_device_domain(pdev, rid);
>> + return dom;
>> }
>> #endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 9a033e8..26f4552 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -731,6 +731,83 @@ struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI);
>> }
>>
>> +static u32 (*pci_msi_map_dev_rid_cb)(struct pci_dev *pdev, u32 req_id);
>> +
>> +/**
>> + * pci_acpi_register_msi_rid_mapper - Register callback to map the MSI
>> + * requester id (RID)
>> + * @fn: Callback mapping a PCI device RID.
>> + *
>> + * This should be called by irqchip driver, which can provide firmware-defined
>> + * topologies about MSI requester id (RID) on a per-device basis.
>> + */
>> +void pci_acpi_register_msi_rid_mapper(u32 (*fn)(struct pci_dev *, u32))
>> +{
>> + pci_msi_map_dev_rid_cb = fn;
>> +}
>> +
>> +/**
>> + * pci_acpi_msi_domain_get_msi_rid - Get the MSI requester id (RID) of
>> + * a PCI device
>> + * @pdev: The PCI device.
>> + * @rid_in: The PCI device request ID.
>> + *
>> + * This function uses the callback function registered by
>> + * pci_acpi_register_msi_rid_mapper() to get the device RID based on ACPI
>> + * supplied mapping.
>> + * This should return rid_in on error or when there is no valid map.
>> + */
>> +u32 pci_acpi_msi_domain_get_msi_rid(struct pci_dev *pdev, u32 rid_in)
>> +{
>> + if (!pci_msi_map_dev_rid_cb)
>> + return rid_in;
>> +
>> + return pci_msi_map_dev_rid_cb(pdev, rid_in);
>> +}
>> +
>> +static struct fwnode_handle *(*pci_msi_get_dev_fwnode_cb)(struct pci_dev *pdev,
>> + u32 req_id);
>> +
>> +/**
>> + * pci_acpi_register_dev_msi_fwnode_provider - Register callback to retrieve
>> + * domain fwnode on the per-device basis
>> + * @fn: Callback matching a device to a fwnode that identifies a PCI
>> + * MSI domain.
>> + *
>> + * This should be called by irqchip driver, which can provide firmware-defined
>> + * topologies about which MSI controller to use on a per-device basis.
>> + */
>> +void
>> +pci_acpi_register_dev_msi_fwnode_provider(
>> + struct fwnode_handle *(*fn)(struct pci_dev *, u32))
>> +{
>> + pci_msi_get_dev_fwnode_cb = fn;
>> +}
>
> I'm quite sceptical about this indirection. Either IORT is the only
> mapping infrastructure that we can use for ACPI and we can then directly
> call into it, or we can have several of them (which ones?) and we need
> more than just this single slot.
>
> So in any case, I don't think this is the right solution. As my
> understanding is that IORT is the only source of RID remapping, we
> should be able to directly call into the IORT code without this complexity.
>
Thanks Marc. I am not aware of any other RID remapper too. I will drop
this layer and call IORT directly.
Tomasz
On 04/04/16 09:52, Tomasz Nowicki wrote:
> There is no point to initialize ITS without having msi-controller
> property in corresponding DT node. However, its_probe is checking
> msi-controller presence at the end, so we can save our time and do that
> check prior to its_probe call. Also, for the code clarity purpose,
> we put domain initialization to separate function.
>
> Signed-off-by: Tomasz Nowicki <[email protected]>
Acked-by: Marc Zyngier <[email protected]>
M.
--
Jazz is not dead. It just smells funny...
On 04/04/16 09:52, Tomasz Nowicki wrote:
> No functional changes.
>
> In order to add ACPI support we need to isolate ACPI&DT common code and
> move DT logic to corresponding functions. To achieve this we are using
> firmware agnostic handle which can be unpacked to either DT or ACPI node.
>
> Signed-off-by: Hanjun Guo <[email protected]>
> Signed-off-by: Tomasz Nowicki <[email protected]>
> ---
> drivers/irqchip/irq-gic-v3-its.c | 76 ++++++++++++++++++++++----------------
> drivers/irqchip/irq-gic-v3.c | 6 +--
> include/linux/irqchip/arm-gic-v3.h | 2 +-
> 3 files changed, 48 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index 065eac5..2dcc7b4 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -815,7 +815,7 @@ static void its_free_tables(struct its_node *its)
> }
> }
>
> -static int its_alloc_tables(const char *node_name, struct its_node *its)
> +static int its_alloc_tables(struct its_node *its)
> {
> int err;
> int i;
> @@ -869,8 +869,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
> order);
> if (order >= MAX_ORDER) {
> order = MAX_ORDER - 1;
> - pr_warn("%s: Device Table too large, reduce its page order to %u\n",
> - node_name, order);
> + pr_warn("ITS@0x%lx: Device Table too large, reduce its page order to %u\n",
> + its->phys_base, order);
Start by making the phys_base field in struct its_node a phys_addr_t (as
it should have been from day-1), and use %pa in the format strings.
> }
> }
>
> @@ -879,8 +879,8 @@ retry_alloc_baser:
> if (alloc_pages > GITS_BASER_PAGES_MAX) {
> alloc_pages = GITS_BASER_PAGES_MAX;
> order = get_order(GITS_BASER_PAGES_MAX * psz);
> - pr_warn("%s: Device Table too large, reduce its page order to %u (%u pages)\n",
> - node_name, order, alloc_pages);
> + pr_warn("ITS@0x%lx: Device Table too large, reduce its page order to %u (%u pages)\n",
> + its->phys_base, order, alloc_pages);
> }
>
> base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
> @@ -953,8 +953,8 @@ retry_baser:
> }
>
> if (val != tmp) {
> - pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n",
> - node_name, i,
> + pr_err("ITS@0x%lx: GITS_BASER%d doesn't stick: %lx %lx\n",
> + its->phys_base, i,
> (unsigned long) val, (unsigned long) tmp);
> err = -ENXIO;
> goto out_free;
> @@ -1429,7 +1429,7 @@ static void its_enable_quirks(struct its_node *its)
> gic_enable_quirks(iidr, its_quirks, its);
> }
>
> -static int its_init_domain(struct device_node *node, struct its_node *its,
> +static int its_init_domain(struct fwnode_handle *handler, struct its_node *its,
> struct irq_domain *parent)
nit: s/handler/handle/g
> {
> struct irq_domain *inner_domain;
> @@ -1439,7 +1439,7 @@ static int its_init_domain(struct device_node *node, struct its_node *its,
> if (!info)
> return -ENOMEM;
>
> - inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
> + inner_domain = irq_domain_create_tree(handler, &its_domain_ops, its);
> if (!inner_domain) {
> kfree(info);
> return -ENOMEM;
> @@ -1454,43 +1454,39 @@ static int its_init_domain(struct device_node *node, struct its_node *its,
> return 0;
> }
>
> -static int __init its_probe(struct device_node *node,
> - struct irq_domain *parent)
> +static int __init its_probe_one(phys_addr_t phys_base, unsigned long size,
Why don't you pass a resource here? That's the right abstraction to
describe an IO range. Surely you can allocate a resource on the stack in
your ACPI code and pass that around, just like we do here.
> + struct irq_domain *parent,
> + struct fwnode_handle *handler)
> {
> - struct resource res;
> struct its_node *its;
> void __iomem *its_base;
> u32 val;
> u64 baser, tmp;
> int err;
>
> - err = of_address_to_resource(node, 0, &res);
> - if (err) {
> - pr_warn("%s: no regs?\n", node->full_name);
> - return -ENXIO;
> - }
> -
> - its_base = ioremap(res.start, resource_size(&res));
> + its_base = ioremap(phys_base, size);
> if (!its_base) {
> - pr_warn("%s: unable to map registers\n", node->full_name);
> + pr_warn("ITS@0x%lx: Unable to map ITS registers\n",
> + (long)phys_base);
Same here. Use the right format, and lose the case everywhere.
> return -ENOMEM;
> }
>
> val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
> if (val != 0x30 && val != 0x40) {
> - pr_warn("%s: no ITS detected, giving up\n", node->full_name);
> + pr_warn("ITS@0x%lx: No ITS detected, giving up\n",
> + (long)phys_base);
> err = -ENODEV;
> goto out_unmap;
> }
>
> err = its_force_quiescent(its_base);
> if (err) {
> - pr_warn("%s: failed to quiesce, giving up\n",
> - node->full_name);
> + pr_warn("ITS@0x%lx: Failed to quiesce, giving up\n",
> + (long)phys_base);
> goto out_unmap;
> }
>
> - pr_info("ITS: %s\n", node->full_name);
> + pr_info("ITS@0x%lx\n", (long)phys_base);
>
> its = kzalloc(sizeof(*its), GFP_KERNEL);
> if (!its) {
> @@ -1502,7 +1498,7 @@ static int __init its_probe(struct device_node *node,
> INIT_LIST_HEAD(&its->entry);
> INIT_LIST_HEAD(&its->its_device_list);
> its->base = its_base;
> - its->phys_base = res.start;
> + its->phys_base = phys_base;
> its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
>
> its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
> @@ -1514,7 +1510,7 @@ static int __init its_probe(struct device_node *node,
>
> its_enable_quirks(its);
>
> - err = its_alloc_tables(node->full_name, its);
> + err = its_alloc_tables(its);
> if (err)
> goto out_free_cmd;
>
> @@ -1550,7 +1546,7 @@ static int __init its_probe(struct device_node *node,
> writeq_relaxed(0, its->base + GITS_CWRITER);
> writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
>
> - err = its_init_domain(node, its, parent);
> + err = its_init_domain(handler, its, parent);
> if (err)
> goto out_free_tables;
>
> @@ -1568,7 +1564,7 @@ out_free_its:
> kfree(its);
> out_unmap:
> iounmap(its_base);
> - pr_err("ITS: failed probing %s (%d)\n", node->full_name, err);
> + pr_err("ITS@0x%lx: failed probing (%d)\n", (long)phys_base, err);
> return err;
> }
>
> @@ -1596,10 +1592,11 @@ static struct of_device_id its_device_id[] = {
> {},
> };
>
> -int __init its_init(struct device_node *node, struct rdists *rdists,
> - struct irq_domain *parent_domain)
> +static int __init
> +its_of_probe(struct device_node *node, struct irq_domain *parent)
> {
> struct device_node *np;
> + struct resource res;
>
> for (np = of_find_matching_node(node, its_device_id); np;
> np = of_find_matching_node(np, its_device_id)) {
> @@ -1609,8 +1606,25 @@ int __init its_init(struct device_node *node, struct rdists *rdists,
> continue;
> }
>
> - its_probe(np, parent_domain);
> + if (of_address_to_resource(np, 0, &res)) {
> + pr_warn("%s: no regs?\n", np->full_name);
> + continue;
> + }
> +
> + its_probe_one(res.start, resource_size(&res), parent,
> + &np->fwnode);
> }
> + return 0;
> +}
> +
> +int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
> + struct irq_domain *parent_domain)
> +{
> + struct device_node *of_node;
> +
> + of_node = to_of_node(handle);
> + if (of_node)
> + its_of_probe(of_node, parent_domain);
>
> if (list_empty(&its_nodes)) {
> pr_warn("ITS: No ITS available, not enabling LPIs\n");
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index dd16a60..995b7251 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -832,7 +832,6 @@ static int __init gic_init_bases(void __iomem *dist_base,
> u64 redist_stride,
> struct fwnode_handle *handle)
> {
> - struct device_node *node;
> u32 typer;
> int gic_irqs;
> int err;
> @@ -872,10 +871,9 @@ static int __init gic_init_bases(void __iomem *dist_base,
>
> set_handle_irq(gic_handle_irq);
>
> - node = to_of_node(handle);
> if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
> - node) /* Temp hack to prevent ITS init for ACPI */
> - its_init(node, &gic_data.rdists, gic_data.domain);
> + to_of_node(handle)) /* Temp hack to prevent ITS init for ACPI */
> + its_init(handle, &gic_data.rdists, gic_data.domain);
>
> gic_smp_init();
> gic_dist_init();
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index d5d798b..a40ed7d 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -332,7 +332,7 @@ struct rdists {
> struct irq_domain;
> struct device_node;
> int its_cpu_init(void);
> -int its_init(struct device_node *node, struct rdists *rdists,
> +int its_init(struct fwnode_handle *handle, struct rdists *rdists,
> struct irq_domain *domain);
>
> static inline bool gic_enable_sre(void)
>
Thanks,
M.
--
Jazz is not dead. It just smells funny...
On 04/04/16 09:52, Tomasz Nowicki wrote:
> IORT shows representation of IO topology for ARM based systems.
> It describes how various components are connected together on
> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>
> Initial support allows to:
> - register ITS MSI chip along with ITS translation ID and domain token
> - deregister ITS MSI chip based on ITS translation ID
> - find registered domain token based on ITS translation ID
> - map MSI RID based on PCI device and requester ID
> - find domain token based on PCI device and requester ID
>
> To: Rafael J. Wysocki <[email protected]>
> Signed-off-by: Tomasz Nowicki <[email protected]>
> ---
> drivers/acpi/Kconfig | 3 +
> drivers/acpi/Makefile | 1 +
> drivers/acpi/iort.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
> drivers/irqchip/Kconfig | 1 +
> include/linux/iort.h | 31 +++++
> 5 files changed, 371 insertions(+)
> create mode 100644 drivers/acpi/iort.c
> create mode 100644 include/linux/iort.h
>
[...]
> +static acpi_status
> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
> +{
> + struct acpi_iort_root_complex *pci_rc;
> + struct device *dev = context;
> + struct pci_bus *bus;
> +
> + switch (node->type) {
> + case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
> + bus = to_pci_bus(dev);
> + pci_rc = (struct acpi_iort_root_complex *)node->node_data;
> +
> + /*
> + * It is assumed that PCI segment numbers maps one-to-one
> + * with root complexes. Each segment number can represent only
> + * one root complex.
> + */
> + if (pci_rc->pci_segment_number == pci_domain_nr(bus))
> + return AE_OK;
What guarantees that this is ever valid? As far as I know, pci_domain_nr
is completely arbitrary, and depends both on the probe order and the
phase of the moon. If you want this to be reliable, you need to allocate
the domain number from pci_segment_number.
I must be missing something. Care to shed some light on this?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
On 13.04.2016 17:23, Marc Zyngier wrote:
> On 04/04/16 09:52, Tomasz Nowicki wrote:
>> IORT shows representation of IO topology for ARM based systems.
>> It describes how various components are connected together on
>> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>>
>> Initial support allows to:
>> - register ITS MSI chip along with ITS translation ID and domain token
>> - deregister ITS MSI chip based on ITS translation ID
>> - find registered domain token based on ITS translation ID
>> - map MSI RID based on PCI device and requester ID
>> - find domain token based on PCI device and requester ID
>>
>> To: Rafael J. Wysocki <[email protected]>
>> Signed-off-by: Tomasz Nowicki <[email protected]>
>> ---
>> drivers/acpi/Kconfig | 3 +
>> drivers/acpi/Makefile | 1 +
>> drivers/acpi/iort.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
>> drivers/irqchip/Kconfig | 1 +
>> include/linux/iort.h | 31 +++++
>> 5 files changed, 371 insertions(+)
>> create mode 100644 drivers/acpi/iort.c
>> create mode 100644 include/linux/iort.h
>>
>
> [...]
>
>> +static acpi_status
>> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
>> +{
>> + struct acpi_iort_root_complex *pci_rc;
>> + struct device *dev = context;
>> + struct pci_bus *bus;
>> +
>> + switch (node->type) {
>> + case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
>> + bus = to_pci_bus(dev);
>> + pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>> +
>> + /*
>> + * It is assumed that PCI segment numbers maps one-to-one
>> + * with root complexes. Each segment number can represent only
>> + * one root complex.
>> + */
>> + if (pci_rc->pci_segment_number == pci_domain_nr(bus))
>> + return AE_OK;
>
> What guarantees that this is ever valid? As far as I know, pci_domain_nr
> is completely arbitrary, and depends both on the probe order and the
> phase of the moon. If you want this to be reliable, you need to allocate
> the domain number from pci_segment_number.
>
> I must be missing something. Care to shed some light on this?
>
Sure. Please see:
http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
3.1.1.5 PCI root complex node
PCI Segment number -> The PCI segment number, as in MCFG and as
returned by _SEG in the namespace.
So IORT spec states that pci_segment_number corresponds to the segment
number from MCFG table and _SEG method. Here is my patch which makes
sure pci_domain_nr(bus) is set properly:
https://lkml.org/lkml/2016/2/16/418
Tomasz
On 13/04/16 16:36, Tomasz Nowicki wrote:
> On 13.04.2016 17:23, Marc Zyngier wrote:
>> On 04/04/16 09:52, Tomasz Nowicki wrote:
>>> IORT shows representation of IO topology for ARM based systems.
>>> It describes how various components are connected together on
>>> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>>>
>>> Initial support allows to:
>>> - register ITS MSI chip along with ITS translation ID and domain token
>>> - deregister ITS MSI chip based on ITS translation ID
>>> - find registered domain token based on ITS translation ID
>>> - map MSI RID based on PCI device and requester ID
>>> - find domain token based on PCI device and requester ID
>>>
>>> To: Rafael J. Wysocki <[email protected]>
>>> Signed-off-by: Tomasz Nowicki <[email protected]>
>>> ---
>>> drivers/acpi/Kconfig | 3 +
>>> drivers/acpi/Makefile | 1 +
>>> drivers/acpi/iort.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
>>> drivers/irqchip/Kconfig | 1 +
>>> include/linux/iort.h | 31 +++++
>>> 5 files changed, 371 insertions(+)
>>> create mode 100644 drivers/acpi/iort.c
>>> create mode 100644 include/linux/iort.h
>>>
>>
>> [...]
>>
>>> +static acpi_status
>>> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
>>> +{
>>> + struct acpi_iort_root_complex *pci_rc;
>>> + struct device *dev = context;
>>> + struct pci_bus *bus;
>>> +
>>> + switch (node->type) {
>>> + case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
>>> + bus = to_pci_bus(dev);
>>> + pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>> +
>>> + /*
>>> + * It is assumed that PCI segment numbers maps one-to-one
>>> + * with root complexes. Each segment number can represent only
>>> + * one root complex.
>>> + */
>>> + if (pci_rc->pci_segment_number == pci_domain_nr(bus))
>>> + return AE_OK;
>>
>> What guarantees that this is ever valid? As far as I know, pci_domain_nr
>> is completely arbitrary, and depends both on the probe order and the
>> phase of the moon. If you want this to be reliable, you need to allocate
>> the domain number from pci_segment_number.
>>
>> I must be missing something. Care to shed some light on this?
>>
> Sure. Please see:
> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
> 3.1.1.5 PCI root complex node
> PCI Segment number -> The PCI segment number, as in MCFG and as
> returned by _SEG in the namespace.
>
> So IORT spec states that pci_segment_number corresponds to the segment
> number from MCFG table and _SEG method. Here is my patch which makes
> sure pci_domain_nr(bus) is set properly:
> https://lkml.org/lkml/2016/2/16/418
Lovely. So this series is actually dependent on the PCI one. I guess we
need to solve that one first, because IORT seems pretty pointless if we
don't have PCI support. What's the plan?
M.
--
Jazz is not dead. It just smells funny...
On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>> > Sure. Please see:
>> > http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>> > 3.1.1.5 PCI root complex node
>> > PCI Segment number -> The PCI segment number, as in MCFG and as
>> > returned by _SEG in the namespace.
>> >
>> > So IORT spec states that pci_segment_number corresponds to the segment
>> > number from MCFG table and _SEG method. Here is my patch which makes
>> > sure pci_domain_nr(bus) is set properly:
>> > https://lkml.org/lkml/2016/2/16/418
> Lovely. So this series is actually dependent on the PCI one. I guess we
> need to solve that one first, because IORT seems pretty pointless if we
> don't have PCI support. What's the plan?
Would it be OK to split the PCI specific section of the patch and continue
review? PCI is a user of the IORT table. Not the other way around.
We shouldn't need a two way dependency.
--
Sinan Kaya
Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
On 13.04.2016 23:18, Sinan Kaya wrote:
> On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>>>> Sure. Please see:
>>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>>> 3.1.1.5 PCI root complex node
>>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>>> returned by _SEG in the namespace.
>>>>
>>>> So IORT spec states that pci_segment_number corresponds to the segment
>>>> number from MCFG table and _SEG method. Here is my patch which makes
>>>> sure pci_domain_nr(bus) is set properly:
>>>> https://lkml.org/lkml/2016/2/16/418
>> Lovely. So this series is actually dependent on the PCI one. I guess we
>> need to solve that one first, because IORT seems pretty pointless if we
>> don't have PCI support. What's the plan?
>
> Would it be OK to split the PCI specific section of the patch and continue
> review? PCI is a user of the IORT table. Not the other way around.
I need to disagree. What would be the use case for patches w/o "PCI part" ?
Tomasz
On 14/04/16 08:20, Tomasz Nowicki wrote:
> On 13.04.2016 23:18, Sinan Kaya wrote:
>> On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>>>>> Sure. Please see:
>>>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>>>> 3.1.1.5 PCI root complex node
>>>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>>>> returned by _SEG in the namespace.
>>>>>
>>>>> So IORT spec states that pci_segment_number corresponds to the segment
>>>>> number from MCFG table and _SEG method. Here is my patch which makes
>>>>> sure pci_domain_nr(bus) is set properly:
>>>>> https://lkml.org/lkml/2016/2/16/418
>>> Lovely. So this series is actually dependent on the PCI one. I guess we
>>> need to solve that one first, because IORT seems pretty pointless if we
>>> don't have PCI support. What's the plan?
>>
>> Would it be OK to split the PCI specific section of the patch and continue
>> review? PCI is a user of the IORT table. Not the other way around.
>
> I need to disagree. What would be the use case for patches w/o "PCI part" ?
Quite. PCI (as a subsystem) doesn't need IORT at all, thank you very
much. GIC (implementing MSI) and SMMU (implementing DMA) do, by virtue
of RID/SID/DID being translated all over the place.
So by the look of it, the dependency chain is GIC+SMMU->IORT->PCI.
The GIC changes here are pretty mechanical, and not that interesting.
The stuff that needs sorting quickly is PCI, because all this work is
pointless if we don't have it.
At the risk of sounding like a stuck record: What's the plan?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
On 13.04.2016 17:52, Marc Zyngier wrote:
> On 13/04/16 16:36, Tomasz Nowicki wrote:
>> On 13.04.2016 17:23, Marc Zyngier wrote:
>>> On 04/04/16 09:52, Tomasz Nowicki wrote:
>>>> IORT shows representation of IO topology for ARM based systems.
>>>> It describes how various components are connected together on
>>>> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>>>>
>>>> Initial support allows to:
>>>> - register ITS MSI chip along with ITS translation ID and domain token
>>>> - deregister ITS MSI chip based on ITS translation ID
>>>> - find registered domain token based on ITS translation ID
>>>> - map MSI RID based on PCI device and requester ID
>>>> - find domain token based on PCI device and requester ID
>>>>
>>>> To: Rafael J. Wysocki <[email protected]>
>>>> Signed-off-by: Tomasz Nowicki <[email protected]>
>>>> ---
>>>> drivers/acpi/Kconfig | 3 +
>>>> drivers/acpi/Makefile | 1 +
>>>> drivers/acpi/iort.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>> drivers/irqchip/Kconfig | 1 +
>>>> include/linux/iort.h | 31 +++++
>>>> 5 files changed, 371 insertions(+)
>>>> create mode 100644 drivers/acpi/iort.c
>>>> create mode 100644 include/linux/iort.h
>>>>
>>>
>>> [...]
>>>
>>>> +static acpi_status
>>>> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
>>>> +{
>>>> + struct acpi_iort_root_complex *pci_rc;
>>>> + struct device *dev = context;
>>>> + struct pci_bus *bus;
>>>> +
>>>> + switch (node->type) {
>>>> + case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
>>>> + bus = to_pci_bus(dev);
>>>> + pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>>> +
>>>> + /*
>>>> + * It is assumed that PCI segment numbers maps one-to-one
>>>> + * with root complexes. Each segment number can represent only
>>>> + * one root complex.
>>>> + */
>>>> + if (pci_rc->pci_segment_number == pci_domain_nr(bus))
>>>> + return AE_OK;
>>>
>>> What guarantees that this is ever valid? As far as I know, pci_domain_nr
>>> is completely arbitrary, and depends both on the probe order and the
>>> phase of the moon. If you want this to be reliable, you need to allocate
>>> the domain number from pci_segment_number.
>>>
>>> I must be missing something. Care to shed some light on this?
>>>
>> Sure. Please see:
>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>> 3.1.1.5 PCI root complex node
>> PCI Segment number -> The PCI segment number, as in MCFG and as
>> returned by _SEG in the namespace.
>>
>> So IORT spec states that pci_segment_number corresponds to the segment
>> number from MCFG table and _SEG method. Here is my patch which makes
>> sure pci_domain_nr(bus) is set properly:
>> https://lkml.org/lkml/2016/2/16/418
>
> Lovely. So this series is actually dependent on the PCI one. I guess we
> need to solve that one first, because IORT seems pretty pointless if we
> don't have PCI support. What's the plan?
>
The plan is to make this series ready for being merged. Once we get PCI
series upstream, we can just retest ITS final series and pull it in, if
you agree. PCI domain assignment is settled so it will not be the reason
for fundamental changes here. What do you think?
Tomasz
On 14/04/16 08:39, Tomasz Nowicki wrote:
> On 13.04.2016 17:52, Marc Zyngier wrote:
>> On 13/04/16 16:36, Tomasz Nowicki wrote:
>>> On 13.04.2016 17:23, Marc Zyngier wrote:
>>>> On 04/04/16 09:52, Tomasz Nowicki wrote:
>>>>> IORT shows representation of IO topology for ARM based systems.
>>>>> It describes how various components are connected together on
>>>>> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>>>>>
>>>>> Initial support allows to:
>>>>> - register ITS MSI chip along with ITS translation ID and domain token
>>>>> - deregister ITS MSI chip based on ITS translation ID
>>>>> - find registered domain token based on ITS translation ID
>>>>> - map MSI RID based on PCI device and requester ID
>>>>> - find domain token based on PCI device and requester ID
>>>>>
>>>>> To: Rafael J. Wysocki <[email protected]>
>>>>> Signed-off-by: Tomasz Nowicki <[email protected]>
>>>>> ---
>>>>> drivers/acpi/Kconfig | 3 +
>>>>> drivers/acpi/Makefile | 1 +
>>>>> drivers/acpi/iort.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>> drivers/irqchip/Kconfig | 1 +
>>>>> include/linux/iort.h | 31 +++++
>>>>> 5 files changed, 371 insertions(+)
>>>>> create mode 100644 drivers/acpi/iort.c
>>>>> create mode 100644 include/linux/iort.h
>>>>>
>>>>
>>>> [...]
>>>>
>>>>> +static acpi_status
>>>>> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
>>>>> +{
>>>>> + struct acpi_iort_root_complex *pci_rc;
>>>>> + struct device *dev = context;
>>>>> + struct pci_bus *bus;
>>>>> +
>>>>> + switch (node->type) {
>>>>> + case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
>>>>> + bus = to_pci_bus(dev);
>>>>> + pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>>>> +
>>>>> + /*
>>>>> + * It is assumed that PCI segment numbers maps one-to-one
>>>>> + * with root complexes. Each segment number can represent only
>>>>> + * one root complex.
>>>>> + */
>>>>> + if (pci_rc->pci_segment_number == pci_domain_nr(bus))
>>>>> + return AE_OK;
>>>>
>>>> What guarantees that this is ever valid? As far as I know, pci_domain_nr
>>>> is completely arbitrary, and depends both on the probe order and the
>>>> phase of the moon. If you want this to be reliable, you need to allocate
>>>> the domain number from pci_segment_number.
>>>>
>>>> I must be missing something. Care to shed some light on this?
>>>>
>>> Sure. Please see:
>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>> 3.1.1.5 PCI root complex node
>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>> returned by _SEG in the namespace.
>>>
>>> So IORT spec states that pci_segment_number corresponds to the segment
>>> number from MCFG table and _SEG method. Here is my patch which makes
>>> sure pci_domain_nr(bus) is set properly:
>>> https://lkml.org/lkml/2016/2/16/418
>>
>> Lovely. So this series is actually dependent on the PCI one. I guess we
>> need to solve that one first, because IORT seems pretty pointless if we
>> don't have PCI support. What's the plan?
>>
>
> The plan is to make this series ready for being merged. Once we get PCI
> series upstream, we can just retest ITS final series and pull it in, if
> you agree. PCI domain assignment is settled so it will not be the reason
> for fundamental changes here. What do you think?
As long as you are making progress on the PCI front, and that we
establish that PCI must go in first, I'm OK with that.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
On 04/04/16 09:52, Tomasz Nowicki wrote:
> ITS is prepared for being initialized different than DT,
> therefore we can initialize it in ACPI way. We collect register base
> address from MADT table and pass mandatory info to firmware-agnostic
> ITS init call.
>
> Note that we are using here IORT lib to register ITS domain which
> then can be found and used to build another PCI MSI domain
> in hierarchical stack domain.
>
> Signed-off-by: Tomasz Nowicki <[email protected]>
> ---
> drivers/irqchip/irq-gic-v3-its.c | 61 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 61 insertions(+)
>
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index 2dcc7b4..a277c9b 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -15,10 +15,13 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> +#include <linux/acpi.h>
> #include <linux/bitmap.h>
> #include <linux/cpu.h>
> #include <linux/delay.h>
> #include <linux/interrupt.h>
> +#include <linux/irqdomain.h>
> +#include <linux/iort.h>
> #include <linux/log2.h>
> #include <linux/mm.h>
> #include <linux/msi.h>
> @@ -1277,6 +1280,11 @@ static int its_irq_gic_domain_alloc(struct irq_domain *domain,
> fwspec.param[0] = GIC_IRQ_TYPE_LPI;
> fwspec.param[1] = hwirq;
> fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
> + } else if (is_fwnode_irqchip(domain->parent->fwnode)) {
> + fwspec.fwnode = domain->parent->fwnode;
> + fwspec.param_count = 2;
> + fwspec.param[0] = hwirq;
> + fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
> } else {
> return -EINVAL;
> }
> @@ -1617,6 +1625,57 @@ its_of_probe(struct device_node *node, struct irq_domain *parent)
> return 0;
> }
>
> +#ifdef CONFIG_ACPI
> +
> +#define ACPI_GICV3_ITS_MEM_SIZE (2 * SZ_64K)
> +
> +static struct irq_domain *its_parent __initdata;
Given that there is only one of those, maybe it is worth making it
common to DT and ACPI, and drop the parameter from its_probe_one.
> +
> +static int __init
> +gic_acpi_parse_madt_its(struct acpi_subtable_header *header,
> + const unsigned long end)
> +{
> + struct acpi_madt_generic_translator *its_entry;
> + struct fwnode_handle *domain_handle;
> + int err;
> +
> + its_entry = (struct acpi_madt_generic_translator *)header;
> + domain_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address);
> + if (!domain_handle) {
> + pr_err("Unable to allocate GICv3 ITS domain token\n");
> + return -ENOMEM;
> + }
> +
> + err = iort_register_domain_token(its_entry->translation_id, domain_handle);
> + if (err) {
> + irq_domain_free_fwnode(domain_handle);
> + goto out;
> + }
> +
> + err = its_probe_one(its_entry->base_address, ACPI_GICV3_ITS_MEM_SIZE,
> + its_parent, domain_handle);
struct resource.
> + if (err) {
> + iort_deregister_domain_token(its_entry->translation_id);
> + irq_domain_free_fwnode(domain_handle);
> + }
> +out:
> + return err;
> +}
> +
> +void __init its_acpi_probe(struct irq_domain *parent_domain)
> +{
> + int count;
> +
> + its_parent = parent_domain;
> + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
> + gic_acpi_parse_madt_its, 0);
> + if (count <= 0)
> + pr_info("No valid GIC ITS entries exist\n");
> +}
> +#else
> +static inline void __init its_acpi_probe(struct irq_domain *parent_domain) { }
> +#endif
> +
> int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
> struct irq_domain *parent_domain)
> {
> @@ -1625,6 +1684,8 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
> of_node = to_of_node(handle);
> if (of_node)
> its_of_probe(of_node, parent_domain);
> + else
> + its_acpi_probe(parent_domain);
>
> if (list_empty(&its_nodes)) {
> pr_warn("ITS: No ITS available, not enabling LPIs\n");
>
Thanks,
M.
--
Jazz is not dead. It just smells funny...
On 2016-04-14 03:36, Marc Zyngier wrote:
> On 14/04/16 08:20, Tomasz Nowicki wrote:
>> On 13.04.2016 23:18, Sinan Kaya wrote:
>>> On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>>>>>> Sure. Please see:
>>>>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>>>>> 3.1.1.5 PCI root complex node
>>>>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>>>>> returned by _SEG in the namespace.
>>>>>>
>>>>>> So IORT spec states that pci_segment_number corresponds to the
>>>>>> segment
>>>>>> number from MCFG table and _SEG method. Here is my patch which
>>>>>> makes
>>>>>> sure pci_domain_nr(bus) is set properly:
>>>>>> https://lkml.org/lkml/2016/2/16/418
>>>> Lovely. So this series is actually dependent on the PCI one. I guess
>>>> we
>>>> need to solve that one first, because IORT seems pretty pointless if
>>>> we
>>>> don't have PCI support. What's the plan?
>>>
>>> Would it be OK to split the PCI specific section of the patch and
>>> continue
>>> review? PCI is a user of the IORT table. Not the other way around.
>>
>> I need to disagree. What would be the use case for patches w/o "PCI
>> part" ?
>
> Quite. PCI (as a subsystem) doesn't need IORT at all, thank you very
> much. GIC (implementing MSI) and SMMU (implementing DMA) do, by virtue
> of RID/SID/DID being translated all over the place.
>
> So by the look of it, the dependency chain is GIC+SMMU->IORT->PCI.
>
> The GIC changes here are pretty mechanical, and not that interesting.
> The stuff that needs sorting quickly is PCI, because all this work is
> pointless if we don't have it.
>
> At the risk of sounding like a stuck record: What's the plan?
>
> Thanks,
>
> M.
My answer is based on the spec definition. The spec defines named
components for other peripherals that are behind iommu and can
potentially implement msi.
You could have used a basic device like platform sata to take care of
basic iort and smmu support.
You can then come back and implement PCIe support.
On 14/04/16 12:37, [email protected] wrote:
> On 2016-04-14 03:36, Marc Zyngier wrote:
>> On 14/04/16 08:20, Tomasz Nowicki wrote:
>>> On 13.04.2016 23:18, Sinan Kaya wrote:
>>>> On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>>>>>>> Sure. Please see:
>>>>>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>>>>>> 3.1.1.5 PCI root complex node
>>>>>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>>>>>> returned by _SEG in the namespace.
>>>>>>>
>>>>>>> So IORT spec states that pci_segment_number corresponds to the
>>>>>>> segment
>>>>>>> number from MCFG table and _SEG method. Here is my patch which
>>>>>>> makes
>>>>>>> sure pci_domain_nr(bus) is set properly:
>>>>>>> https://lkml.org/lkml/2016/2/16/418
>>>>> Lovely. So this series is actually dependent on the PCI one. I guess
>>>>> we
>>>>> need to solve that one first, because IORT seems pretty pointless if
>>>>> we
>>>>> don't have PCI support. What's the plan?
>>>>
>>>> Would it be OK to split the PCI specific section of the patch and
>>>> continue
>>>> review? PCI is a user of the IORT table. Not the other way around.
>>>
>>> I need to disagree. What would be the use case for patches w/o "PCI
>>> part" ?
>>
>> Quite. PCI (as a subsystem) doesn't need IORT at all, thank you very
>> much. GIC (implementing MSI) and SMMU (implementing DMA) do, by virtue
>> of RID/SID/DID being translated all over the place.
>>
>> So by the look of it, the dependency chain is GIC+SMMU->IORT->PCI.
>>
>> The GIC changes here are pretty mechanical, and not that interesting.
>> The stuff that needs sorting quickly is PCI, because all this work is
>> pointless if we don't have it.
>>
>> At the risk of sounding like a stuck record: What's the plan?
>>
>> Thanks,
>>
>> M.
>
> My answer is based on the spec definition. The spec defines named
> components for other peripherals that are behind iommu and can
> potentially implement msi.
>
> You could have used a basic device like platform sata to take care of
> basic iort and smmu support.
>
> You can then come back and implement PCIe support.
I could. You could do it too. Thankfully, the dependency is dictated by
whoever is writing the code.
Thanks,
M.
--
Jazz is not dead. It just smells funny...