From patchwork Thu Apr 6 19:47:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Patterson X-Patchwork-Id: 9668327 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 7B69E602B3 for ; Thu, 6 Apr 2017 19:50:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 71FA7285CA for ; Thu, 6 Apr 2017 19:50:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 665BB285CC; Thu, 6 Apr 2017 19:50:49 +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=-3.6 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 7BD4A285CA for ; Thu, 6 Apr 2017 19:50:48 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cwDOB-0007dj-Ij; Thu, 06 Apr 2017 19:48:15 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cwDO9-0007cc-Po for xen-devel@lists.xen.org; Thu, 06 Apr 2017 19:48:13 +0000 Received: from [85.158.143.35] by server-7.bemta-6.messagelabs.com id BD/19-04817-D7B96E85; Thu, 06 Apr 2017 19:48:13 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrKIsWRWlGSWpSXmKPExsVyMfTGYd2a2c8 iDHa2c1os+biYxYHR4+ju30wBjFGsmXlJ+RUJrBkbv3czFjzPqXg5dSVzA+Oa8C5GLg4hgYmM EjO3bGEHcVgEXrJI/H+0nw3EkRDoZ5VofXeVsYuRE8iJkdi8awMrhF0lcfzDE3YQW0hAXuLvg SmMEKMmMElMOPcRqJuDg01AQ+LUDReQGhEBaYlrny+DzWEWKJOYsPYSC4gtLBAh8eRJM9gcFg FViUPdk5lAbF4BB4ntE14wQeySkzh//CczyEhOAUeJ1pkcEGsdJP5t3cQ0gVFgASPDKkaN4tS istQiXSMLvaSizPSMktzEzBxdQwMzvdzU4uLE9NScxKRiveT83E2MwMBiAIIdjOfXBh5ilORg UhLlVfB5EiHEl5SfUpmRWJwRX1Sak1p8iFGGg0NJgvf4zGcRQoJFqempFWmZOcAQh0lLcPAoi fDeAEnzFhck5hZnpkOkTjEac7y4/P49E8eTlT/eMwmx5OXnpUqJ85aAlAqAlGaU5sENgsXeJU ZZKWFeRqDThHgKUotyM0tQ5V8xinMwKgnzyswCmsKTmVcCt+8V0ClMQKf43HoKckpJIkJKqoF Rz453p8p3u1V/jzyS95kiO8/qxbHVslPkK9beUGdp/XVCVb758g4nfSXG7dF1Rh6X91UlqXls knZvZ83hP16zoa73VVrNyXlWycfOcQToS12ecafvz52FFRuLX8wqv925kN9orqyEaN2WG4ZbH V9cjp7z5Y+/+47+FY9/rZXR2rgh6YL00a73SizFGYmGWsxFxYkASLROoLgCAAA= X-Env-Sender: cjp256@gmail.com X-Msg-Ref: server-13.tower-21.messagelabs.com!1491508091!56757122!1 X-Originating-IP: [209.85.216.195] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 9.4.12; banners=-,-,- X-VirusChecked: Checked Received: (qmail 23711 invoked from network); 6 Apr 2017 19:48:11 -0000 Received: from mail-qt0-f195.google.com (HELO mail-qt0-f195.google.com) (209.85.216.195) by server-13.tower-21.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 6 Apr 2017 19:48:11 -0000 Received: by mail-qt0-f195.google.com with SMTP id r45so7117712qte.0 for ; Thu, 06 Apr 2017 12:48:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=chubWYMMyoMsv4krCMI9OZyrBH8hkEjEDJ2/ENcgOsA=; b=nl8A2OYpq3I10AOo76NctxcGcYbmn4JBw7yPfwkuAJ/gvHgK7znU/+d3HoNqNV4rjg 81EQFf0RRz9BKKlkyPvfno41mNf3PX516U+GngkGas5EFIzjXSRhOK8PhKLhsUNughB2 gdAy1/YddraDgbNWInYJwOlp8/6twSGTkmWdyEfyY2Siz03cSSCvcjdYSbvOIyQIjZxf El78WQi7V0StCZQBbbLON/ZeXrVd7TSLRTV9p2akuLeK5C2+wh7f2LAgCZzEMpcN1hQZ qeFFWUVFrlb+p9H2bBXGqjwPzzXXgp4HXhlXvIMFu5Jmrd9u7pGWf3UqbTLLpZO63uje f9UA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=chubWYMMyoMsv4krCMI9OZyrBH8hkEjEDJ2/ENcgOsA=; b=cboVDShvkJSkDEcXuCFp/zioehPsFlB4rSDcp//R0Mk5lss07Nohq+S2KaGt29LG2c et1JaTTItT3HkpTq2OTCJCidgrx3uvy71aKFwIGSRWm+fSOMZU+mDQc+crHupvcczhKx XwV0y5XEmAJmaGa2FDAZupviVcg+cxFiUMxARJwLEOZL504cIGwFE687u0dJIev36sU6 8SLtmckch81t+GAe68hGA/Yn01FaK+FweWkAO5h0atwijEyE58hgeVp6E8zteD7Pds8Q uN8jgS9ThQV4OzswQf9cnu/cSpssUPHR7ZBy/LlNDeFtzgTmob6yR61bbOuo1B42HhKI bSsQ== X-Gm-Message-State: AFeK/H2bFpxaQB78UA7g2i4ws6nw3tC7kw5FRX6s7UamqWQ8TXRSBweRluemDuKRGOI5gg== X-Received: by 10.200.54.46 with SMTP id m43mr40832741qtb.127.1491508090675; Thu, 06 Apr 2017 12:48:10 -0700 (PDT) Received: from roost.members.linode.com (chrispatterson.net. [66.175.209.160]) by smtp.gmail.com with ESMTPSA id x67sm1424840qkd.67.2017.04.06.12.48.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 06 Apr 2017 12:48:09 -0700 (PDT) From: Chris Patterson To: xen-devel@lists.xen.org Date: Thu, 6 Apr 2017 15:47:52 -0400 Message-Id: <1491508074-31647-5-git-send-email-cjp256@gmail.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1491508074-31647-1-git-send-email-cjp256@gmail.com> References: <1491508074-31647-1-git-send-email-cjp256@gmail.com> Cc: Chris Patterson , julien.grall@arm.com, sstabellini@kernel.org, temkink@ainfosec.com Subject: [Xen-devel] [PATCH 4/6] xen/arm: platforms: Add Tegra platform to support basic IRQ routing X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: "Chris Patterson" Tegra devices have a legacy interrupt controller (lic, or ictlr) that must be programmed in parallel with their primary GIC. For all intents and purposes, we treat these devices attached to this controller as connected to the primary GIC, as it will be handling their interrupts. This commit adds support for exposing the ictlr to the hardware domain; but a future commit will extend this to support exposing a virtualized version of the ictlr to the hardware domain, and to ensure that interrupts are unmasked properly when routed to a Xen, or to a domain other than the hardware domain. Authored-by: Kyle Temkin Signed-off-by: Kyle Temkin Signed-off-by: Chris Patterson --- changes since rfc: - use bool instead of bool_t - formatting & code style cleanup - fix dt compat label (nvidia,tegra120 -> nvidia,tegra124) for K1 - separate mediated legacy interrupt controller into its own module - split tegra_ictlr_set_interrupt_enable() into tegra_lic_set_interrupt_type_normal() and tegra_lic_set_interrupt_enable() - added a couple helper functions to reduce duplicated logic - added wrapper tegra_lic_readl and writel functions for external use (mlic) - re-order defines in tegra.h - cleanup tegra_init() that was previously in patch 6 --- xen/arch/arm/platforms/Makefile | 2 + xen/arch/arm/platforms/tegra.c | 313 ++++++++++++++++++++++++++++++++++ xen/include/asm-arm/platforms/tegra.h | 54 ++++++ 3 files changed, 369 insertions(+) create mode 100644 xen/arch/arm/platforms/tegra.c create mode 100644 xen/include/asm-arm/platforms/tegra.h diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile index 49fa683..d7033d2 100644 --- a/xen/arch/arm/platforms/Makefile +++ b/xen/arch/arm/platforms/Makefile @@ -6,5 +6,7 @@ obj-$(CONFIG_ARM_32) += omap5.o obj-$(CONFIG_ARM_32) += rcar2.o obj-$(CONFIG_ARM_64) += seattle.o obj-$(CONFIG_ARM_32) += sunxi.o +obj-$(CONFIG_ARM_32) += tegra.o +obj-$(CONFIG_ARM_64) += tegra.o obj-$(CONFIG_ARM_64) += xgene-storm.o obj-$(CONFIG_ARM_64) += xilinx-zynqmp.o diff --git a/xen/arch/arm/platforms/tegra.c b/xen/arch/arm/platforms/tegra.c new file mode 100644 index 0000000..bdd9966 --- /dev/null +++ b/xen/arch/arm/platforms/tegra.c @@ -0,0 +1,312 @@ +/* + * NVIDIA Tegra specific settings + * + * Ian Campbell; Copyright (c) 2014 Citrix Systems + * Kyle Temkin; Copyright (c) 2016 Assured Information Security, Inc. + * Chris Patterson; Copyright (c) 2016 Assured Information Security, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Permanent mapping to the Tegra legacy interrupt controller. */ +static void __iomem *tegra_ictlr_base; + +/* + * List of legacy interrupt controllers that can be used to route + * Tegra interrupts. + */ +static const char * const tegra_interrupt_compat[] __initconst = +{ + "nvidia,tegra124-ictlr", /* Tegra K1 controllers */ + "nvidia,tegra210-ictlr" /* Tegra X1 controllers */ +}; + +/* + * Returns true iff the given IRQ belongs to a supported tegra interrupt + * controller. + */ +static bool tegra_irq_belongs_to_ictlr(const struct dt_raw_irq * rirq) { + int i; + + for ( i = 0; i < ARRAY_SIZE(tegra_interrupt_compat); i++ ) { + if ( dt_device_is_compatible(rirq->controller, tegra_interrupt_compat[i]) ) + return true; + } + + return false; +} + +/* + * Returns true iff the given IRQ is routable -- that is, if it is descended + * from the platform's primary GIC. + */ +static bool tegra_irq_is_routable(const struct dt_raw_irq * rirq) +{ + /* If the IRQ connects directly to our GIC, it's trivially routable. */ + if ( rirq->controller == dt_interrupt_controller ) + return true; + + /* + * If the IRQ belongs to a legacy interrupt controller, then it's + * effectively owned by the GIC, and is routable. + */ + if ( tegra_irq_belongs_to_ictlr(rirq) ) + return true; + + return false; +} + +/* + * Platform-specific reset code for the Tegra devices. + * Should not return. + */ +static void tegra_reset(void) +{ + void __iomem *addr; + u32 val; + + addr = ioremap_nocache(TEGRA_RESET_BASE, TEGRA_RESET_SIZE); + if ( !addr ) + { + printk(XENLOG_ERR "Tegra: Unable to map tegra reset address. Reset failed!\n"); + return; + } + + /* Write into the reset device. */ + val = readl(addr) | TEGRA_RESET_MASK; + writel(val, addr); + + /* Should not get here */ + iounmap(addr); +} + +/* + * Convert irq line to index of servicing legacy interrupt controller. + */ +static unsigned int tegra_lic_irq_to_ictlr_index(unsigned int irq) +{ + return (irq - NR_LOCAL_IRQS) / TEGRA_IRQS_PER_ICTLR; +} + +/* + * Convert irq line to index of irq within servicing interrupt controller. + */ +static unsigned int tegra_lic_irq_to_ictlr_irq_index(unsigned int irq) +{ + return (irq - NR_LOCAL_IRQS) % TEGRA_IRQS_PER_ICTLR; +} + +/* + * Mark interrupt as normal rather than a fast IRQ. + */ +static void tegra_lic_set_interrupt_type_normal(unsigned int irq) +{ + uint32_t previous_iep_class; + unsigned int ictlr_index = tegra_lic_irq_to_ictlr_index(irq); + unsigned int ictlr_irq_index = tegra_lic_irq_to_ictlr_irq_index(irq); + uint32_t mask = BIT(ictlr_irq_index); + + /* Mark the interrupt as a normal interrupt-- not a fast IRQ. */ + previous_iep_class = tegra_lic_readl(ictlr_index, TEGRA_ICTLR_CPU_IEP_CLASS); + tegra_lic_writel(ictlr_index, TEGRA_ICTLR_CPU_IEP_CLASS, previous_iep_class & ~mask); +} + +/* + * Enable/disable interrupt line for specified irq. + */ +static void tegra_lic_set_interrupt_enable(unsigned int irq, bool enabled) +{ + unsigned int ictlr_index = tegra_lic_irq_to_ictlr_index(irq); + unsigned int ictlr_irq_index = tegra_lic_irq_to_ictlr_irq_index(irq); + uint32_t mask = BIT(ictlr_irq_index); + + if ( enabled ) + tegra_lic_writel(ictlr_index, TEGRA_ICTLR_CPU_IER_SET, mask); + else + tegra_lic_writel(ictlr_index, TEGRA_ICTLR_CPU_IER_CLR, mask); +} + +/* + * Routes an IRQ to a guest, applying sane values to the ictlr masks. + * Returns 0 on success, or an error code on failure. + */ +static int tegra_route_irq_to_guest(struct domain *d, unsigned int virq, + struct irq_desc *desc, unsigned int priority) +{ + /* Program the core GIC to deliver the interrupt to the guest. */ + int rc = gic_route_irq_to_guest(d, virq, desc, priority); + + /* If we couldn't route the IRQ via the GIC, bail out. */ + if ( rc ) + { + printk(XENLOG_ERR "Tegra LIC: Couldn't program GIC to route vIRQ %d (%d).\n", + desc->irq, rc); + return rc; + } + + /* + * If this is a local IRQ, it's not masked by the ictlr, so we + * don't need to perform any ictlr manipulation. + */ + if ( desc->irq < NR_LOCAL_IRQS ) + return rc; + + /* + * If this is the hardware domain, it will have real access to the ictlr, + * and will program the ictlr itself, so it should start with the ictlr + * disabled. If we're not the hwdom, the domain won't interact with the + * ictlr, and the interrupt shouldn't be masked. Either way, first + * set the interrupt type to normal (if previously set to fast IRQ). + */ + tegra_lic_set_interrupt_type_normal(desc->irq); + tegra_lic_set_interrupt_enable(desc->irq, !is_hardware_domain(d)); + return rc; +} + + +/* + * Routes an IRQ to Xen. This method both performs the core IRQ routing, and + * sets up any ictlr routing necessary. + */ +static void tegra_route_irq_to_xen(struct irq_desc *desc, unsigned int priority) +{ + unsigned int irq = desc->irq; + + /* Program the core GIC to deliver the interrupt to Xen. */ + gic_route_irq_to_xen(desc, priority); + + /* + * If this is a local IRQ, it's not masked by the ictlr, so we + * don't need to perform any ictlr manipulation. + */ + if ( irq < NR_LOCAL_IRQS ) + return; + + /* + * Enable the interrupt in the ictlr. Xen only uses the GIC to + * perform masking, so we'll enable the interrupt to prevent ictlr + * gating of the interrupt. + */ + tegra_lic_set_interrupt_type_normal(desc->irq); + tegra_lic_set_interrupt_enable(desc->irq, true); +} + +/* + * Read register from specified legacy interrupt interrupt controller. + */ +uint32_t tegra_lic_readl(unsigned int ictlr_index, unsigned int register_offset) +{ + ASSERT(tegra_ictlr_base); + ASSERT(ictlr_index < TEGRA_ICTLR_COUNT); + ASSERT(register_offset < TEGRA_ICTLR_SIZE); + return readl(tegra_ictlr_base + ictlr_index * TEGRA_ICTLR_SIZE + + register_offset); +} + +/* + * Write register for specified legacy interrupt interrupt controller. + */ +void tegra_lic_writel(unsigned int ictlr_index, unsigned int register_offset, uint32_t value) +{ + ASSERT(tegra_ictlr_base); + ASSERT(ictlr_index < TEGRA_ICTLR_COUNT); + ASSERT(register_offset < TEGRA_ICTLR_SIZE); + writel(value, tegra_ictlr_base + ictlr_index * TEGRA_ICTLR_SIZE + + register_offset); +} + +/* + * Initialize the Tegra legacy interrupt controller, placing each interrupt + * into a default state. These defaults ensure that stray interrupts don't + * affect Xen. + */ +static int tegra_lic_init(void) +{ + int i; + + /* Map in the tegra ictlr. */ + tegra_ictlr_base = ioremap_nocache(TEGRA_ICTLR_BASE, + TEGRA_ICTLR_SIZE * TEGRA_ICTLR_COUNT); + + if ( !tegra_ictlr_base ) + panic("Failed to map in the Tegra legacy interrupt controller"); + + /* Initialize each of the legacy interrupt controllers. */ + for ( i = 0; i < TEGRA_ICTLR_COUNT; i++ ) { + + /* Clear the interrupt enables for every interrupt. */ + tegra_lic_writel(i, TEGRA_ICTLR_CPU_IER_CLR, ~0); + + /* + * Mark all of our interrupts as normal ARM interrupts (as opposed + * to Fast Interrupts.) + */ + tegra_lic_writel(i, TEGRA_ICTLR_CPU_IEP_CLASS, 0); + } + + return 0; +} + +/** + * Startup code for the Tegra. + */ +static int tegra_init(void) +{ + return tegra_lic_init(); +} + + +static const char * const tegra_dt_compat[] __initconst = +{ + "nvidia,tegra120", /* Tegra K1 */ + "nvidia,tegra210", /* Tegra X1 */ + NULL +}; + +static const struct dt_device_match tegra_blacklist_dev[] __initconst = +{ + /* + * The UARTs share a page which runs the risk of mapping the Xen console + * UART to dom0, so don't map any of them. + */ + DT_MATCH_COMPATIBLE("nvidia,tegra20-uart"), + { /* sentinel */ }, +}; + +PLATFORM_START(tegra, "Tegra") + .blacklist_dev = tegra_blacklist_dev, + .compatible = tegra_dt_compat, + .init = tegra_init, + .reset = tegra_reset, + .irq_is_routable = tegra_irq_is_routable, + .route_irq_to_xen = tegra_route_irq_to_xen, + .route_irq_to_guest = tegra_route_irq_to_guest, +PLATFORM_END + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-arm/platforms/tegra.h b/xen/include/asm-arm/platforms/tegra.h new file mode 100644 index 0000000..e9cd792 --- /dev/null +++ b/xen/include/asm-arm/platforms/tegra.h @@ -0,0 +1,54 @@ +/* + * NVIDIA Tegra platform definitions + * + * Kyle Temkin; Copyright (c) 2016 Assured Information Security, Inc. + * Chris Patterson; Copyright (c) 2016 Assured Information Security, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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. + */ + + +#ifndef __ASM_ARM_PLATFORMS_TEGRA_H +#define __ASM_ARM_PLATFORMS_TEGRA_H + +#define TEGRA_ICTLR_BASE 0x60004000 +#define TEGRA_ICTLR_SIZE 0x00000100 +#define TEGRA_ICTLR_COUNT 6 +#define TEGRA_IRQS_PER_ICTLR 32 + +#define TEGRA_ICTLR_CPU_IER 0x20 +#define TEGRA_ICTLR_CPU_IER_SET 0x24 +#define TEGRA_ICTLR_CPU_IER_CLR 0x28 +#define TEGRA_ICTLR_CPU_IEP_CLASS 0x2C + +#define TEGRA_ICTLR_COP_IER 0x30 +#define TEGRA_ICTLR_COP_IER_SET 0x34 +#define TEGRA_ICTLR_COP_IER_CLR 0x38 +#define TEGRA_ICTLR_COP_IEP_CLASS 0x3c + +#define TEGRA_RESET_BASE 0x7000e400 +#define TEGRA_RESET_SIZE 4 +#define TEGRA_RESET_MASK 0x10 + +uint32_t tegra_lic_readl(unsigned int ictlr_index, unsigned int register_offset); +void tegra_lic_writel(unsigned int ictlr_index, unsigned int register_offset, uint32_t value); + +#endif /* __ASM_ARM_PLATFORMS_TEGRA_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */