lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1473105940-9761-3-git-send-email-tn@semihalf.com>
Date:   Mon,  5 Sep 2016 22:05:34 +0200
From:   Tomasz Nowicki <tn@...ihalf.com>
To:     marc.zyngier@....com, tglx@...utronix.de, jason@...edaemon.net,
        rjw@...ysocki.net, helgaas@...nel.org, rafael@...nel.org,
        Lorenzo.Pieralisi@....com
Cc:     will.deacon@....com, catalin.marinas@....com,
        hanjun.guo@...aro.org, shijie.huang@....com,
        robert.richter@...iumnetworks.com, mw@...ihalf.com,
        linux-pci@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
        linaro-acpi@...ts.linaro.org, andrea.gallo@...aro.org,
        linux-acpi@...r.kernel.org, linux-kernel@...r.kernel.org,
        al.stone@...aro.org, graeme.gregory@...aro.org,
        ddaney.cavm@...il.com, okaya@...eaurora.org,
        Tomasz Nowicki <tn@...ihalf.com>
Subject: [PATCH V9 2/8] ACPI: Add new IORT functions to support MSI domain handling

For ITS, MSI functionality consists on building domain stack and
during that process we need to reference to domain stack components
e.g. before we create new DOMAIN_BUS_PCI_MSI domain we need to specify
its DOMAIN_BUS_NEXUS parent domain. In order to manage that process
properly, maintain list which elements contain domain token
(unique for MSI domain stack) and ITS ID: iort_register_domain_token()
and iort_deregister_domain_token(). Then retrieve domain token
any time later with ITS ID being key off: iort_find_domain_token().
With domain token and domain type we are able to find corresponding
IRQ domain.

Since IORT is prepared to describe MSI domain on a per-device basis,
use existing IORT helpers and implement two calls:
1. iort_msi_map_rid() to map MSI RID for a device
2. iort_get_device_domain() to find domain token for a device

Signed-off-by: Tomasz Nowicki <tn@...ihalf.com>
Reviewed-by: Hanjun Guo <hanjun.guo@...aro.org>
---
 drivers/acpi/arm64/iort.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/iort.h      |  11 ++++
 2 files changed, 168 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 82d5e7d..f38253c 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -22,12 +22,91 @@
 #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);
+static DEFINE_SPINLOCK(iort_msi_chip_lock);
+
+/**
+ * iort_register_domain_token() - register domain token and related ITS ID
+ * to the list from where we can get it back later on.
+ * @trans_id: ITS ID.
+ * @fw_node: Domain token.
+ *
+ * Returns: 0 on success, -ENOMEM if no 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;
+
+	spin_lock(&iort_msi_chip_lock);
+	list_add(&its_msi_chip->list, &iort_msi_chip_list);
+	spin_unlock(&iort_msi_chip_lock);
+
+	return 0;
+}
+
+/**
+ * iort_deregister_domain_token() - Deregister domain token based on ITS ID
+ * @trans_id: ITS ID.
+ *
+ * Returns: none.
+ */
+void iort_deregister_domain_token(int trans_id)
+{
+	struct iort_its_msi_chip *its_msi_chip, *t;
+
+	spin_lock(&iort_msi_chip_lock);
+	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;
+		}
+	}
+	spin_unlock(&iort_msi_chip_lock);
+}
+
+/**
+ * iort_find_domain_token() - Find domain token based on given ITS ID
+ * @trans_id: ITS ID.
+ *
+ * Returns: domain token when find on the list, NULL otherwise
+ */
+struct fwnode_handle *iort_find_domain_token(int trans_id)
+{
+	struct fwnode_handle *fw_node = NULL;
+	struct iort_its_msi_chip *its_msi_chip;
+
+	spin_lock(&iort_msi_chip_lock);
+	list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
+		if (its_msi_chip->translation_id == trans_id) {
+			fw_node = its_msi_chip->fw_node;
+			break;
+		}
+	}
+	spin_unlock(&iort_msi_chip_lock);
+
+	return fw_node;
+}
+
 static struct acpi_iort_node *
 iort_scan_node(enum acpi_iort_node_type type,
 	       iort_find_node_callback callback, void *context)
@@ -209,6 +288,84 @@ iort_find_dev_node(struct device *dev)
 			      iort_match_node_callback, &pbus->dev);
 }
 
+/**
+ * iort_msi_map_rid() - Map a MSI requester ID for a device
+ * @dev: The device for which the mapping is to be done.
+ * @req_id: The device requester ID.
+ *
+ * Returns: mapped MSI RID on success, input requester ID otherwise
+ */
+u32 iort_msi_map_rid(struct device *dev, u32 req_id)
+{
+	struct acpi_iort_node *node;
+	u32 dev_id;
+
+	node = iort_find_dev_node(dev);
+	if (!node)
+		return req_id;
+
+	iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP);
+	return dev_id;
+}
+
+/**
+ * iort_dev_find_its_id() - Find the ITS identifier for a device
+ * @dev: The device.
+ * @idx: Index of the ITS identifier list.
+ * @its_id: ITS identifier.
+ *
+ * Returns: 0 on success, appropriate error value otherwise
+ */
+static int
+iort_dev_find_its_id(struct device *dev, u32 req_id, unsigned int idx,
+		     int *its_id)
+{
+	struct acpi_iort_its_group *its;
+	struct acpi_iort_node *node;
+
+	node = iort_find_dev_node(dev);
+	if (!node)
+		return -ENXIO;
+
+	node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP);
+	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(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_get_device_domain() - Find MSI domain related to a device
+ * @dev: The device.
+ * @req_id: Requester ID for the device.
+ *
+ * Returns: the MSI domain for this device, NULL otherwise
+ */
+struct irq_domain *
+iort_get_device_domain(struct device *dev, u32 req_id)
+{
+	static struct fwnode_handle *handle;
+	int its_id;
+
+	if (iort_dev_find_its_id(dev, req_id, 0, &its_id))
+		return NULL;
+
+	handle = iort_find_domain_token(its_id);
+	if (!handle)
+		return NULL;
+
+	return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
+}
+
 void __init acpi_iort_init(void)
 {
 	acpi_status status;
diff --git a/include/linux/iort.h b/include/linux/iort.h
index f4d5d45..74ab47f 100644
--- a/include/linux/iort.h
+++ b/include/linux/iort.h
@@ -20,11 +20,22 @@
 #define __IORT_H__
 
 #include <linux/acpi.h>
+#include <linux/fwnode.h>
+#include <linux/irqdomain.h>
 
+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_find_domain_token(int trans_id);
 #ifdef CONFIG_ACPI_IORT
 void acpi_iort_init(void);
+u32 iort_msi_map_rid(struct device *dev, u32 req_id);
+struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
 #else
 static inline void acpi_iort_init(void) { }
+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; }
 #endif
 
 #endif /* __IORT_H__ */
-- 
1.9.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ