From patchwork Mon Sep 5 20:05:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Nowicki X-Patchwork-Id: 9315173 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 936F660869 for ; Mon, 5 Sep 2016 20:12:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 83CD8288F8 for ; Mon, 5 Sep 2016 20:12:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 75657288F3; Mon, 5 Sep 2016 20:12:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.4 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E6741288E4 for ; Mon, 5 Sep 2016 20:12:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S936202AbcIEUIN (ORCPT ); Mon, 5 Sep 2016 16:08:13 -0400 Received: from mail-lf0-f41.google.com ([209.85.215.41]:32899 "EHLO mail-lf0-f41.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935909AbcIEUG4 (ORCPT ); Mon, 5 Sep 2016 16:06:56 -0400 Received: by mail-lf0-f41.google.com with SMTP id h127so29400291lfh.0 for ; Mon, 05 Sep 2016 13:06:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=semihalf-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=+/BYq3TpsvzhyiVOOhX9ROHSYdLBwfvyi2IOfRVFQqM=; b=d4ReAfY0RROrbXExqNkUHe3BnYPuMKxn12hh1yhdcYvOLhKp1DeHvNZ5oZF8mo0V4r /kTX4ZG2PnwP+mTORTU//66n83eDpieNnP1z7AHocS71CrbxaGcUuIvT0a0/V4xwhEDA Bx6O7aVVdd3xng9PsiKQbcMYBe8XX1CtsmFv2NuKC8rEDwljfTyQiHdanTGgpZsy0q6d omN5EcgTsevYr7ApH0pLpdcUQZYT8Qh7WqhX30xn9E6UMHBUUx2RRfqJZMoYVsmNZOom jDWXQuko7yneQ1gy/QsWmSqFBqFLjID/5tLj626+O1Yz5qdYCh4rgpEvFZxpA/ctdndX LT/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=+/BYq3TpsvzhyiVOOhX9ROHSYdLBwfvyi2IOfRVFQqM=; b=cFLXqk4OLHT3dxqpHVxhPnBSjI0K3myX2AfOsD+Ylv/ZS9bR+xgxKQKi8F088tF4RI MLaW4MXcbtABWzhn3VXMnuHsYVah0B8lsSYQEp8V7SWBLdtvQlji7eK46V2tAJTyjump zao+7TSUOgtXKpS1DQbKNd6CzM+qPZh3pmyR/cYgng2SL+WxZEh89OSp2GnLN+Ujhczm 7JAfYLDk6vkxuGFkh8w8GWmTFADODgfLp4Lt+xFIuYWIPIVKVWYbdepNh1OcPmdMmqu5 Xo34Kn0l6+fEL8c2yqX1sO5UZTixNHXmn+dzWkRdA8PsZ8rB1B27/i4wm27CHOvvG2OR 1EEQ== X-Gm-Message-State: AE9vXwPsIkdcjTNlWU3zzmST3+TU1T3POUD0ODNzUJoPokuQC+N4kMR1xQkdByf4Xhgzpg== X-Received: by 10.25.90.198 with SMTP id o189mr9249823lfb.193.1473106014881; Mon, 05 Sep 2016 13:06:54 -0700 (PDT) Received: from localhost.localdomain (50-233-148-156-static.hfc.comcastbusiness.net. [50.233.148.156]) by smtp.gmail.com with ESMTPSA id p82sm5068405lfd.15.2016.09.05.13.06.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 05 Sep 2016 13:06:54 -0700 (PDT) From: Tomasz Nowicki To: marc.zyngier@arm.com, tglx@linutronix.de, jason@lakedaemon.net, rjw@rjwysocki.net, helgaas@kernel.org, rafael@kernel.org, Lorenzo.Pieralisi@arm.com Cc: will.deacon@arm.com, catalin.marinas@arm.com, hanjun.guo@linaro.org, shijie.huang@arm.com, robert.richter@caviumnetworks.com, mw@semihalf.com, linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linaro-acpi@lists.linaro.org, andrea.gallo@linaro.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, al.stone@linaro.org, graeme.gregory@linaro.org, ddaney.cavm@gmail.com, okaya@codeaurora.org, Tomasz Nowicki Subject: [PATCH V9 2/8] ACPI: Add new IORT functions to support MSI domain handling Date: Mon, 5 Sep 2016 22:05:34 +0200 Message-Id: <1473105940-9761-3-git-send-email-tn@semihalf.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1473105940-9761-1-git-send-email-tn@semihalf.com> References: <1473105940-9761-1-git-send-email-tn@semihalf.com> Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 Reviewed-by: Hanjun Guo --- 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 #include +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 +#include +#include +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__ */