From patchwork Thu Aug 11 10:06:32 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Nowicki X-Patchwork-Id: 9274951 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 9CC2060231 for ; Thu, 11 Aug 2016 10:09:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8B4F1285E4 for ; Thu, 11 Aug 2016 10:09:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7FCD8285E9; Thu, 11 Aug 2016 10:09:08 +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.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C358D285E4 for ; Thu, 11 Aug 2016 10:09:07 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bXmtk-00040e-Gp; Thu, 11 Aug 2016 10:07:36 +0000 Received: from mail-wm0-x22a.google.com ([2a00:1450:400c:c09::22a]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bXmtJ-0003lZ-8P for linux-arm-kernel@lists.infradead.org; Thu, 11 Aug 2016 10:07:12 +0000 Received: by mail-wm0-x22a.google.com with SMTP id q128so20114969wma.1 for ; Thu, 11 Aug 2016 03:06:48 -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=pN/N9iuKYo7ylX6nhInzqBMepzMyeANFJZnYVqsxXd0=; b=x5vpQyS6Q3hSfrSGxd8NwaY3fTCk7jExCjBLH28dSRRDrMdWUmcOmQNPyx5Y73/abl 5ZsLmhbCHnZyqpgiMJCKK20vgUd2x0H0XL5uiyhZNnCNTJu74r1iql/4wjf/+dTTyHNk oQEXba/t9CRwNS437DcWA4Clv7f0bBZAs6QbPG/IwM1eNLGQmoxXLuYuOM1JLIibMz4N z5x3tfiHWuF/oDEk16pA2+L7jxtsM2n9g6EWGWGtui151sBEvscU6OI9sogiADik7yaK ASlj8wSJQazHDwqUQpZKHZmfYDa4w3RcsNs1i0meYfZVE9UUbsrL68TtKtLyzfQ5hh6+ t/9Q== 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=pN/N9iuKYo7ylX6nhInzqBMepzMyeANFJZnYVqsxXd0=; b=CqH0EHSZ005Dpw16q+qXYb4De7lnmcr3udps5J9v1cg99+Mtg6sdw/FJcQ1HBPnCYn 8q9kw2R7zqMEdD0W41kMvDAD4gPttDX2mY7alwI+OMnz7gqP5m1mFQrqCQrbuJQfmm5G 4kOwWBnyloKRqbftNDBAiS5oevtGPAsGwueW3qMdeSPxRE3Jceo45DCaWsRnEj0df4ob jf1+TZjbkTWPDDiv8FtN4/QwuEaOAsIKsIEkFub1oZ1dDNJL5QFq35/1Ry/hK6H8YLBI vhwL8TyUSZathxctvNY0ZzOS+aP87eiNPD14k9b0SwLuwcfuve492xAXiKHOxsNj9xJI y/Ww== X-Gm-Message-State: AEkoous5QalLeclI8FSihsK4/bBjHsT6HPwXWiUhAabh+w/0j4+IADOAgd/LtL744KONUw== X-Received: by 10.25.76.137 with SMTP id z131mr1397484lfa.49.1470910006964; Thu, 11 Aug 2016 03:06:46 -0700 (PDT) Received: from tn-HP-4.semihalf.local (31-172-191-173.noc.fibertech.net.pl. [31.172.191.173]) by smtp.gmail.com with ESMTPSA id p21sm448233lfp.4.2016.08.11.03.06.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 11 Aug 2016 03:06:45 -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 Subject: [PATCH V8 2/8] ACPI: Add new IORT functions to support MSI domain handling Date: Thu, 11 Aug 2016 12:06:32 +0200 Message-Id: <1470909998-16710-3-git-send-email-tn@semihalf.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1470909998-16710-1-git-send-email-tn@semihalf.com> References: <1470909998-16710-1-git-send-email-tn@semihalf.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160811_030709_675746_44471025 X-CRM114-Status: GOOD ( 16.74 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: graeme.gregory@linaro.org, al.stone@linaro.org, linaro-acpi@lists.linaro.org, catalin.marinas@arm.com, will.deacon@arm.com, linux-kernel@vger.kernel.org, okaya@codeaurora.org, linux-acpi@vger.kernel.org, robert.richter@caviumnetworks.com, hanjun.guo@linaro.org, ddaney.cavm@gmail.com, linux-pci@vger.kernel.org, shijie.huang@arm.com, Tomasz Nowicki , mw@semihalf.com, andrea.gallo@linaro.org, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.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 | 169 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/iort.h | 11 +++ 2 files changed, 180 insertions(+) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index f89056e..a03386d 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) @@ -206,6 +285,96 @@ 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; + + if (!iort_table) + return req_id; + + node = iort_find_dev_node(dev); + if (!node) { + dev_err(dev, "can't find related IORT node\n"); + 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) { + dev_err(dev, "can't find related IORT node\n"); + return -ENXIO; + } + + node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP); + if (!node) { + dev_err(dev, "can't find related ITS node\n"); + 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_table) + return NULL; + + 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 iort_table_detect(void) { acpi_status status; diff --git a/include/linux/iort.h b/include/linux/iort.h index cde6809..d7daba1 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_IORT_TABLE void iort_table_detect(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 iort_table_detect(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__ */