Message ID | 20160905101401.7003-5-temkink@ainfosec.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Mon, Sep 05, 2016 at 06:13:59AM -0400, Kyle Temkin wrote: > From: "Kyle J. Temkin" <temkink@ainfosec.com> > > 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 this devices attached to this controller as > connected to the primary GIC, as it will be handling their interrupts. Is there a link to the specification? Could that be included in the file or in the commit description? > > 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. > > Signed-off-by: Kyle Temkin <temkink@ainfosec.com> > --- > xen/arch/arm/platforms/Makefile | 2 + > xen/arch/arm/platforms/tegra.c | 339 ++++++++++++++++++++++++++++++++++ > xen/include/asm-arm/platforms/tegra.h | 50 +++++ > 3 files changed, 391 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..0c3a7f4 100644 > --- a/xen/arch/arm/platforms/Makefile > +++ b/xen/arch/arm/platforms/Makefile > @@ -4,7 +4,9 @@ obj-$(CONFIG_ARM_32) += exynos5.o > obj-$(CONFIG_ARM_32) += midway.o > obj-$(CONFIG_ARM_32) += omap5.o > obj-$(CONFIG_ARM_32) += rcar2.o > +obj-$(CONFIG_ARM_32) += tegra.o > obj-$(CONFIG_ARM_64) += seattle.o > obj-$(CONFIG_ARM_32) += sunxi.o > obj-$(CONFIG_ARM_64) += xgene-storm.o > obj-$(CONFIG_ARM_64) += xilinx-zynqmp.o > +obj-$(CONFIG_ARM_64) += tegra.o > diff --git a/xen/arch/arm/platforms/tegra.c b/xen/arch/arm/platforms/tegra.c > new file mode 100644 > index 0000000..e75242c > --- /dev/null > +++ b/xen/arch/arm/platforms/tegra.c > @@ -0,0 +1,339 @@ > +/* > + * 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 <xen/config.h> No config.h pls. > +#include <xen/lib.h> > +#include <xen/stdbool.h> > +#include <xen/sched.h> > +#include <xen/vmap.h> > + > +#include <asm/io.h> > +#include <asm/gic.h> > +#include <asm/platform.h> > +#include <asm/platforms/tegra.h> > + > + > +/* Permanent mapping to the Tegra legacy interrupt controller. */ > +static void __iomem *tegra_ictlr_base = NULL; No need for NULL. > + > +/* > + * List of legacy interrupt controllers that can be used to route > + * Tegra interrupts. > + */ > +static const char * const tegra_interrupt_compat[] __initconst = > +{ > + "nvidia,tegra120-ictlr", /* Tegra K1 controllers */ > + "nvidia,tegra210-ictlr" /* Tegra X1 controllers */ > +}; > + > + > +/** > + * Returns true if the given IRQ belongs to a supported tegra interrupt > + * controller. > + * > + * @param rirq The raw IRQ to be identified. > + * @return True iff the given IRQ belongs to a Tegra ictlr. > + */ > +static bool_t tegra_irq_belongs_to_ictlr(struct dt_raw_irq * rirq) { > + int i; > + > + for (i = 0; i < ARRAY_SIZE(tegra_interrupt_compat); i++) Something is off with your style ({, and the lack of spaces around ()). > + { > + 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. > + * > + * @param rirq The raw IRQ in question. > + * @return True iff the given IRQ routes to a platform GIC. > + */ > +static bool_t tegra_irq_is_routable(struct dt_raw_irq * rirq) And as I found out just recently, use 'bool' instead of bool_t. > +{ > + /* 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; > +} > + > +/** > + * Returns the IRQ number for a given device. Tegra IRQs transalate using the > + * same algorithm as normal GIC IRQs, but aren't parented by the system GIC. > + * > + * As a result, translation fails an assertion in the normal translation path. > + * The normal version is essentially dt_irq_xlate wrapped with an assert, so > + * we'll just call dt_irq_xlate directly. > + * > + * @param device The DT node describing the device. > + * @param index The index of the interrupt within the device node. > + * @return The translated number of the IRQ, or a negative error code. > + */ > +static int tegra_irq_for_device(const struct dt_device_node *device, int index) > +{ > + struct dt_raw_irq raw; > + struct dt_irq dt_irq; > + int res; > + > + res = dt_device_get_raw_irq(device, index, &raw); > + if ( res ) > + return -ENODEV; > + > + /* > + * The translation function for the Tegra ictlr happens to match the > + * translation function for the normal GIC, so we'll use that in either > + * case. > + */ > + res = dt_irq_xlate(raw.specifier, raw.size, &dt_irq.irq, &dt_irq.type); > + if ( res ) > + return -ENODEV; > + > + if ( irq_set_type(dt_irq.irq, dt_irq.type) ) > + return -ENODEV; > + > + return dt_irq.irq; > +} > + > +/** > + * 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); No need to re-read the register? > + > + iounmap(addr); > +} > + > +/** > + * Applies an interrupt enable to a given interrupt via the legacy > + * interrupt controller, and marks that interrupt as a normal interrupt, > + * rather than a fast IRQ. > + * > + * @param irq The hardware IRQ number for the given interrupt. > + */ > +static void tegra_ictlr_set_interrupt_enable(unsigned int irq, bool enabled) > +{ > + uint32_t previous_iep_class; > + > + /* If we're enabling a given bit, use the SET register; otherwise CLR. */ > + unsigned int register_number = > + enabled ? TEGRA_ICTLR_CPU_IER_SET : TEGRA_ICTLR_CPU_IER_CLR; > + > + /* > + * Determine the IRQ number in the ictlr domain, and figure out the indexA > + * of the individual controller we're working with. */ Put the */ on its own line please. > + unsigned int ictlr_irq = irq - NR_LOCAL_IRQS; > + unsigned int ictlr_number = ictlr_irq / TEGRA_IRQS_PER_ICTLR; > + > + /* Get a pointer to the target ictlr. */ > + void __iomem * target_ictlr = tegra_ictlr_base + TEGRA_ICTLR_SIZE * ictlr_number; > + > + /* Determine the mask we'll be working with. */ > + uint32_t mask = BIT(ictlr_irq % TEGRA_IRQS_PER_ICTLR); > + > + /* Sanity check our memory access. */ > + ASSERT(tegra_ictlr_base); > + ASSERT(ictlr_number < TEGRA_ICTLR_COUNT); > + ASSERT(irq >= NR_LOCAL_IRQS); > + > + /* Enable the given IRQ. */ > + writel(mask, target_ictlr + register_number); > + > + /* Mark the interrupt as a normal interrupt-- not a fast IRQ. */ > + previous_iep_class = readl(target_ictlr + TEGRA_ICTLR_CPU_IEP_CLASS); > + writel(previous_iep_class & ~mask, target_ictlr + TEGRA_ICTLR_CPU_IEP_CLASS); > +} > + > + > +/** > + * Routes an IRQ to a guest, applying sane values to the ictlr masks. > + * > + * @param domain The domain to which the IRQ will be routed. > + * @param virq The virtual IRQ number. > + * @param desc The IRQ to be routed. > + * @param priority The IRQ priority. > + * @return 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) Uh oh. > + { > + 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. > + */ > + tegra_ictlr_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. > + * > + * @param desc The IRQ to be routed. > + * @param priority The IRQ priority. > + */ > +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_ictlr_set_interrupt_enable(irq, true); > + > +} > + > +/** > + * 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_initialize_legacy_interrupt_controller(void) > +{ > + int i; > + > + /* Map in the tegra ictlr. */ > + tegra_ictlr_base = ioremap_nocache(TEGRA_ICTLR_BASE, > + TEGRA_ICTLR_SIZE * TEGRA_ICTLR_COUNT); Odd, style? > + > + if ( !tegra_ictlr_base ) > + panic("Failed to map in the Tegra legacy interrupt controller!\n"); > + > + /* Initialize each of the legacy interrupt controllers. */ > + for (i = 0; i < TEGRA_ICTLR_COUNT; i++) Style. > + { > + void __iomem *ictlr_n = tegra_ictlr_base + TEGRA_ICTLR_SIZE * i; > + > + /* Clear the interrupt enables for every interrupt. */ > + writel(~0, ictlr_n + TEGRA_ICTLR_CPU_IER_CLR); > + > + /* > + * Mark all of our interrupts as normal ARM interrupts (as opposed > + * to Fast Interrupts.) > + */ > + writel(0, ictlr_n + TEGRA_ICTLR_CPU_IEP_CLASS); > + } > + > + return 0; > +} > + > +/** > + * Startup code for the Tegra. > + */ > +static int tegra_init(void) __init ? > +{ > + int rc; > + > + rc = tegra_initialize_legacy_interrupt_controller(); How about you jsut make this: return tegra_initializa...() > + > + /* > + * TODO: Virtualize the MMIO regions for the ictlr, ensuring the hwdom > + * (and possibly passhtrough domains) can only access ictlr registers for > + * interrupts they actually own. > + */ > + > + return rc; > +} > + > + > +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, > + .irq_for_device = tegra_irq_for_device, > + .route_irq_to_xen = tegra_route_irq_to_xen, > + .route_irq_to_guest = tegra_route_irq_to_guest, > +PLATFORM_END You are missing this: > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 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..821add5 > --- /dev/null > +++ b/xen/include/asm-arm/platforms/tegra.h > @@ -0,0 +1,50 @@ > +/* > + * 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 Add please two underscores at the far end. > +#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_RESET_BASE 0x7000e400 > +#define TEGRA_RESET_SIZE 4 > +#define TEGRA_RESET_MASK 0x10 > + > +#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 > + > + > +#endif /* __ASM_ARM_PLATFORMS_TEGRA_H */ > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > -- > 2.9.2 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > https://lists.xen.org/xen-devel
Thanks for the patch! I would like to see it in Xen 4.9. On Fri, 16 Sep 2016, Konrad Rzeszutek Wilk wrote: > On Mon, Sep 05, 2016 at 06:13:59AM -0400, Kyle Temkin wrote: > > From: "Kyle J. Temkin" <temkink@ainfosec.com> > > > > 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 this devices attached to this controller as ^ these > > connected to the primary GIC, as it will be handling their interrupts. > > Is there a link to the specification? Could that be included in the file > or in the commit description? > > > > > 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. > > > > Signed-off-by: Kyle Temkin <temkink@ainfosec.com> > > --- > > xen/arch/arm/platforms/Makefile | 2 + > > xen/arch/arm/platforms/tegra.c | 339 ++++++++++++++++++++++++++++++++++ > > xen/include/asm-arm/platforms/tegra.h | 50 +++++ > > 3 files changed, 391 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..0c3a7f4 100644 > > --- a/xen/arch/arm/platforms/Makefile > > +++ b/xen/arch/arm/platforms/Makefile > > @@ -4,7 +4,9 @@ obj-$(CONFIG_ARM_32) += exynos5.o > > obj-$(CONFIG_ARM_32) += midway.o > > obj-$(CONFIG_ARM_32) += omap5.o > > obj-$(CONFIG_ARM_32) += rcar2.o > > +obj-$(CONFIG_ARM_32) += tegra.o > > obj-$(CONFIG_ARM_64) += seattle.o > > obj-$(CONFIG_ARM_32) += sunxi.o > > obj-$(CONFIG_ARM_64) += xgene-storm.o > > obj-$(CONFIG_ARM_64) += xilinx-zynqmp.o > > +obj-$(CONFIG_ARM_64) += tegra.o Are there both 32bit and 64bit versions of tegra? > > diff --git a/xen/arch/arm/platforms/tegra.c b/xen/arch/arm/platforms/tegra.c > > new file mode 100644 > > index 0000000..e75242c > > --- /dev/null > > +++ b/xen/arch/arm/platforms/tegra.c > > @@ -0,0 +1,339 @@ > > +/* > > + * 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 <xen/config.h> > > No config.h pls. > > +#include <xen/lib.h> > > +#include <xen/stdbool.h> > > +#include <xen/sched.h> > > +#include <xen/vmap.h> > > + > > +#include <asm/io.h> > > +#include <asm/gic.h> > > +#include <asm/platform.h> > > +#include <asm/platforms/tegra.h> > > + > > + > > +/* Permanent mapping to the Tegra legacy interrupt controller. */ > > +static void __iomem *tegra_ictlr_base = NULL; > > No need for NULL. > > + > > +/* > > + * List of legacy interrupt controllers that can be used to route > > + * Tegra interrupts. > > + */ > > +static const char * const tegra_interrupt_compat[] __initconst = > > +{ > > + "nvidia,tegra120-ictlr", /* Tegra K1 controllers */ > > + "nvidia,tegra210-ictlr" /* Tegra X1 controllers */ > > +}; > > + > > + > > +/** > > + * Returns true if the given IRQ belongs to a supported tegra interrupt > > + * controller. > > + * > > + * @param rirq The raw IRQ to be identified. > > + * @return True iff the given IRQ belongs to a Tegra ictlr. > > + */ > > +static bool_t tegra_irq_belongs_to_ictlr(struct dt_raw_irq * rirq) { > > + int i; > > + > > + for (i = 0; i < ARRAY_SIZE(tegra_interrupt_compat); i++) > > Something is off with your style ({, and the lack of spaces around ()). > > > + { > > + 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. > > + * > > + * @param rirq The raw IRQ in question. > > + * @return True iff the given IRQ routes to a platform GIC. > > + */ > > +static bool_t tegra_irq_is_routable(struct dt_raw_irq * rirq) > > And as I found out just recently, use 'bool' instead of bool_t. > > > +{ > > + /* 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; > > +} > > + > > +/** > > + * Returns the IRQ number for a given device. Tegra IRQs transalate using the > > + * same algorithm as normal GIC IRQs, but aren't parented by the system GIC. > > + * > > + * As a result, translation fails an assertion in the normal translation path. > > + * The normal version is essentially dt_irq_xlate wrapped with an assert, so > > + * we'll just call dt_irq_xlate directly. > > + * > > + * @param device The DT node describing the device. > > + * @param index The index of the interrupt within the device node. > > + * @return The translated number of the IRQ, or a negative error code. > > + */ > > +static int tegra_irq_for_device(const struct dt_device_node *device, int index) > > +{ > > + struct dt_raw_irq raw; > > + struct dt_irq dt_irq; > > + int res; > > + > > + res = dt_device_get_raw_irq(device, index, &raw); > > + if ( res ) > > + return -ENODEV; > > + > > + /* > > + * The translation function for the Tegra ictlr happens to match the > > + * translation function for the normal GIC, so we'll use that in either > > + * case. > > + */ > > + res = dt_irq_xlate(raw.specifier, raw.size, &dt_irq.irq, &dt_irq.type); > > + if ( res ) > > + return -ENODEV; > > + > > + if ( irq_set_type(dt_irq.irq, dt_irq.type) ) > > + return -ENODEV; > > + > > + return dt_irq.irq; > > +} Instead of duplicating this code, I am tempted to suggest to modify dt_irq_translate to make it work for tegra too. You just need to change the raw->controller != dt_interrupt_controller check to also check for tegra right? > > +/** > > + * 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); > > No need to re-read the register? > > > + > > + iounmap(addr); > > +} > > + > > +/** > > + * Applies an interrupt enable to a given interrupt via the legacy > > + * interrupt controller, and marks that interrupt as a normal interrupt, > > + * rather than a fast IRQ. > > + * > > + * @param irq The hardware IRQ number for the given interrupt. > > + */ > > +static void tegra_ictlr_set_interrupt_enable(unsigned int irq, bool enabled) > > +{ > > + uint32_t previous_iep_class; > > + > > + /* If we're enabling a given bit, use the SET register; otherwise CLR. */ > > + unsigned int register_number = > > + enabled ? TEGRA_ICTLR_CPU_IER_SET : TEGRA_ICTLR_CPU_IER_CLR; > > + > > + /* > > + * Determine the IRQ number in the ictlr domain, and figure out the indexA > > + * of the individual controller we're working with. */ > > Put the */ on its own line please. > > > + unsigned int ictlr_irq = irq - NR_LOCAL_IRQS; > > + unsigned int ictlr_number = ictlr_irq / TEGRA_IRQS_PER_ICTLR; > > + > > + /* Get a pointer to the target ictlr. */ > > + void __iomem * target_ictlr = tegra_ictlr_base + TEGRA_ICTLR_SIZE * ictlr_number; > > + > > + /* Determine the mask we'll be working with. */ > > + uint32_t mask = BIT(ictlr_irq % TEGRA_IRQS_PER_ICTLR); > > + > > + /* Sanity check our memory access. */ > > + ASSERT(tegra_ictlr_base); > > + ASSERT(ictlr_number < TEGRA_ICTLR_COUNT); > > + ASSERT(irq >= NR_LOCAL_IRQS); > > + > > + /* Enable the given IRQ. */ > > + writel(mask, target_ictlr + register_number); > > + > > + /* Mark the interrupt as a normal interrupt-- not a fast IRQ. */ > > + previous_iep_class = readl(target_ictlr + TEGRA_ICTLR_CPU_IEP_CLASS); > > + writel(previous_iep_class & ~mask, target_ictlr + TEGRA_ICTLR_CPU_IEP_CLASS); > > +} I think it makes sense to split this function into two: one that set the interrupt as normal, and the other to enable/disable it. > > + > > +/** > > + * Routes an IRQ to a guest, applying sane values to the ictlr masks. > > + * > > + * @param domain The domain to which the IRQ will be routed. > > + * @param virq The virtual IRQ number. > > + * @param desc The IRQ to be routed. > > + * @param priority The IRQ priority. > > + * @return 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) > > Uh oh. Style. No need to add another warning message here, given that this error doesn't seem to be tegra specific. > > + { > > + 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. > > + */ > > + tegra_ictlr_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. > > + * > > + * @param desc The IRQ to be routed. > > + * @param priority The IRQ priority. > > + */ > > +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_ictlr_set_interrupt_enable(irq, true); > > + > > +} > > + > > +/** > > + * 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_initialize_legacy_interrupt_controller(void) > > +{ > > + int i; > > + > > + /* Map in the tegra ictlr. */ > > + tegra_ictlr_base = ioremap_nocache(TEGRA_ICTLR_BASE, > > + TEGRA_ICTLR_SIZE * TEGRA_ICTLR_COUNT); > > Odd, style? > > > + > > + if ( !tegra_ictlr_base ) > > + panic("Failed to map in the Tegra legacy interrupt controller!\n"); > > + > > + /* Initialize each of the legacy interrupt controllers. */ > > + for (i = 0; i < TEGRA_ICTLR_COUNT; i++) > > Style. > > + { > > + void __iomem *ictlr_n = tegra_ictlr_base + TEGRA_ICTLR_SIZE * i; > > + > > + /* Clear the interrupt enables for every interrupt. */ > > + writel(~0, ictlr_n + TEGRA_ICTLR_CPU_IER_CLR); > > + > > + /* > > + * Mark all of our interrupts as normal ARM interrupts (as opposed > > + * to Fast Interrupts.) > > + */ > > + writel(0, ictlr_n + TEGRA_ICTLR_CPU_IEP_CLASS); > > + } > > + > > + return 0; > > +} > > + > > +/** style > > + * Startup code for the Tegra. > > + */ > > +static int tegra_init(void) > > __init ? > > +{ > > + int rc; > > + > > + rc = tegra_initialize_legacy_interrupt_controller(); > > How about you jsut make this: > > return tegra_initializa...() > > + > > + /* > > + * TODO: Virtualize the MMIO regions for the ictlr, ensuring the hwdom > > + * (and possibly passhtrough domains) can only access ictlr registers for > > + * interrupts they actually own. > > + */ > > + > > + return rc; > > +} > > + > > + > > +static const char * const tegra_dt_compat[] __initconst = > > +{ > > + "nvidia,tegra120", /* Tegra K1 */ > > + "nvidia,tegra210", /* Tegra X1 */ I can find "nvidia,tegra210" under arch/arm64/boot/dts/nvidia, but I cannot find "nvidia,tegra120" anywhere. Do you have a pointer? If it hasn't been upstreamed in Linux, we need to provide a pointer to the Linux tree and the device tree for K1. > > + 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, > > + .irq_for_device = tegra_irq_for_device, > > + .route_irq_to_xen = tegra_route_irq_to_xen, > > + .route_irq_to_guest = tegra_route_irq_to_guest, > > +PLATFORM_END > > You are missing this: > > > + * Local variables: > > + * mode: C > > + * c-file-style: "BSD" > > + * c-basic-offset: 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..821add5 > > --- /dev/null > > +++ b/xen/include/asm-arm/platforms/tegra.h > > @@ -0,0 +1,50 @@ > > +/* > > + * 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 > > Add please two underscores at the far end. > > > +#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_RESET_BASE 0x7000e400 > > +#define TEGRA_RESET_SIZE 4 > > +#define TEGRA_RESET_MASK 0x10 Please keep all the TEGRA_ICTLR* defines together: move TEGRA_RESET* below. > > +#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 > > + > > + > > +#endif /* __ASM_ARM_PLATFORMS_TEGRA_H */ > > +/* > > + * Local variables: > > + * mode: C > > + * c-file-style: "BSD" > > + * c-basic-offset: 4 > > + * indent-tabs-mode: nil > > + * End: > > + */
diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile index 49fa683..0c3a7f4 100644 --- a/xen/arch/arm/platforms/Makefile +++ b/xen/arch/arm/platforms/Makefile @@ -4,7 +4,9 @@ obj-$(CONFIG_ARM_32) += exynos5.o obj-$(CONFIG_ARM_32) += midway.o obj-$(CONFIG_ARM_32) += omap5.o obj-$(CONFIG_ARM_32) += rcar2.o +obj-$(CONFIG_ARM_32) += tegra.o obj-$(CONFIG_ARM_64) += seattle.o obj-$(CONFIG_ARM_32) += sunxi.o obj-$(CONFIG_ARM_64) += xgene-storm.o obj-$(CONFIG_ARM_64) += xilinx-zynqmp.o +obj-$(CONFIG_ARM_64) += tegra.o diff --git a/xen/arch/arm/platforms/tegra.c b/xen/arch/arm/platforms/tegra.c new file mode 100644 index 0000000..e75242c --- /dev/null +++ b/xen/arch/arm/platforms/tegra.c @@ -0,0 +1,339 @@ +/* + * 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 <xen/config.h> +#include <xen/lib.h> +#include <xen/stdbool.h> +#include <xen/sched.h> +#include <xen/vmap.h> + +#include <asm/io.h> +#include <asm/gic.h> +#include <asm/platform.h> +#include <asm/platforms/tegra.h> + + +/* Permanent mapping to the Tegra legacy interrupt controller. */ +static void __iomem *tegra_ictlr_base = NULL; + +/* + * List of legacy interrupt controllers that can be used to route + * Tegra interrupts. + */ +static const char * const tegra_interrupt_compat[] __initconst = +{ + "nvidia,tegra120-ictlr", /* Tegra K1 controllers */ + "nvidia,tegra210-ictlr" /* Tegra X1 controllers */ +}; + + +/** + * Returns true if the given IRQ belongs to a supported tegra interrupt + * controller. + * + * @param rirq The raw IRQ to be identified. + * @return True iff the given IRQ belongs to a Tegra ictlr. + */ +static bool_t tegra_irq_belongs_to_ictlr(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. + * + * @param rirq The raw IRQ in question. + * @return True iff the given IRQ routes to a platform GIC. + */ +static bool_t tegra_irq_is_routable(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; +} + +/** + * Returns the IRQ number for a given device. Tegra IRQs transalate using the + * same algorithm as normal GIC IRQs, but aren't parented by the system GIC. + * + * As a result, translation fails an assertion in the normal translation path. + * The normal version is essentially dt_irq_xlate wrapped with an assert, so + * we'll just call dt_irq_xlate directly. + * + * @param device The DT node describing the device. + * @param index The index of the interrupt within the device node. + * @return The translated number of the IRQ, or a negative error code. + */ +static int tegra_irq_for_device(const struct dt_device_node *device, int index) +{ + struct dt_raw_irq raw; + struct dt_irq dt_irq; + int res; + + res = dt_device_get_raw_irq(device, index, &raw); + if ( res ) + return -ENODEV; + + /* + * The translation function for the Tegra ictlr happens to match the + * translation function for the normal GIC, so we'll use that in either + * case. + */ + res = dt_irq_xlate(raw.specifier, raw.size, &dt_irq.irq, &dt_irq.type); + if ( res ) + return -ENODEV; + + if ( irq_set_type(dt_irq.irq, dt_irq.type) ) + return -ENODEV; + + return dt_irq.irq; +} + +/** + * 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); + + iounmap(addr); +} + +/** + * Applies an interrupt enable to a given interrupt via the legacy + * interrupt controller, and marks that interrupt as a normal interrupt, + * rather than a fast IRQ. + * + * @param irq The hardware IRQ number for the given interrupt. + */ +static void tegra_ictlr_set_interrupt_enable(unsigned int irq, bool enabled) +{ + uint32_t previous_iep_class; + + /* If we're enabling a given bit, use the SET register; otherwise CLR. */ + unsigned int register_number = + enabled ? TEGRA_ICTLR_CPU_IER_SET : TEGRA_ICTLR_CPU_IER_CLR; + + /* + * Determine the IRQ number in the ictlr domain, and figure out the indexA + * of the individual controller we're working with. */ + unsigned int ictlr_irq = irq - NR_LOCAL_IRQS; + unsigned int ictlr_number = ictlr_irq / TEGRA_IRQS_PER_ICTLR; + + /* Get a pointer to the target ictlr. */ + void __iomem * target_ictlr = tegra_ictlr_base + TEGRA_ICTLR_SIZE * ictlr_number; + + /* Determine the mask we'll be working with. */ + uint32_t mask = BIT(ictlr_irq % TEGRA_IRQS_PER_ICTLR); + + /* Sanity check our memory access. */ + ASSERT(tegra_ictlr_base); + ASSERT(ictlr_number < TEGRA_ICTLR_COUNT); + ASSERT(irq >= NR_LOCAL_IRQS); + + /* Enable the given IRQ. */ + writel(mask, target_ictlr + register_number); + + /* Mark the interrupt as a normal interrupt-- not a fast IRQ. */ + previous_iep_class = readl(target_ictlr + TEGRA_ICTLR_CPU_IEP_CLASS); + writel(previous_iep_class & ~mask, target_ictlr + TEGRA_ICTLR_CPU_IEP_CLASS); +} + + +/** + * Routes an IRQ to a guest, applying sane values to the ictlr masks. + * + * @param domain The domain to which the IRQ will be routed. + * @param virq The virtual IRQ number. + * @param desc The IRQ to be routed. + * @param priority The IRQ priority. + * @return 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. + */ + tegra_ictlr_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. + * + * @param desc The IRQ to be routed. + * @param priority The IRQ priority. + */ +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_ictlr_set_interrupt_enable(irq, true); + +} + +/** + * 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_initialize_legacy_interrupt_controller(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!\n"); + + /* Initialize each of the legacy interrupt controllers. */ + for (i = 0; i < TEGRA_ICTLR_COUNT; i++) + { + void __iomem *ictlr_n = tegra_ictlr_base + TEGRA_ICTLR_SIZE * i; + + /* Clear the interrupt enables for every interrupt. */ + writel(~0, ictlr_n + TEGRA_ICTLR_CPU_IER_CLR); + + /* + * Mark all of our interrupts as normal ARM interrupts (as opposed + * to Fast Interrupts.) + */ + writel(0, ictlr_n + TEGRA_ICTLR_CPU_IEP_CLASS); + } + + return 0; +} + +/** + * Startup code for the Tegra. + */ +static int tegra_init(void) +{ + int rc; + + rc = tegra_initialize_legacy_interrupt_controller(); + + /* + * TODO: Virtualize the MMIO regions for the ictlr, ensuring the hwdom + * (and possibly passhtrough domains) can only access ictlr registers for + * interrupts they actually own. + */ + + return rc; +} + + +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, + .irq_for_device = tegra_irq_for_device, + .route_irq_to_xen = tegra_route_irq_to_xen, + .route_irq_to_guest = tegra_route_irq_to_guest, +PLATFORM_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..821add5 --- /dev/null +++ b/xen/include/asm-arm/platforms/tegra.h @@ -0,0 +1,50 @@ +/* + * 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_RESET_BASE 0x7000e400 +#define TEGRA_RESET_SIZE 4 +#define TEGRA_RESET_MASK 0x10 + +#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 + + +#endif /* __ASM_ARM_PLATFORMS_TEGRA_H */ +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */