From patchwork Thu Apr 21 08:24:00 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Chen X-Patchwork-Id: 66336 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp4707qge; Thu, 21 Apr 2016 01:26:42 -0700 (PDT) X-Received: by 10.31.192.78 with SMTP id q75mr7270644vkf.96.1461227202571; Thu, 21 Apr 2016 01:26:42 -0700 (PDT) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org. [192.237.175.120]) by mx.google.com with ESMTPS id v82si388221vke.212.2016.04.21.01.26.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 21 Apr 2016 01:26:42 -0700 (PDT) Received-SPF: neutral (google.com: 192.237.175.120 is neither permitted nor denied by best guess record for domain of xen-devel-bounces@lists.xen.org) client-ip=192.237.175.120; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=neutral (google.com: 192.237.175.120 is neither permitted nor denied by best guess record for domain of xen-devel-bounces@lists.xen.org) smtp.mailfrom=xen-devel-bounces@lists.xen.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1at9v5-0005hs-DB; Thu, 21 Apr 2016 08:25:03 +0000 Received: from mail6.bemta6.messagelabs.com ([85.158.143.247]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1at9v4-0005hm-Hf for xen-devel@lists.xen.org; Thu, 21 Apr 2016 08:25:02 +0000 Received: from [85.158.143.35] by server-2.bemta-6.messagelabs.com id E4/C6-09532-D5E88175; Thu, 21 Apr 2016 08:25:01 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrDIsWRWlGSWpSXmKPExsVyMfTAVt3YPol wg551HBZLPi5mcWD0OLr7N1MAYxRrZl5SfkUCa8bTqbOZC+7mVfxvv8DUwLjOr4uRi0NIYBKj xKM3nSwgDotAO7PE+59nGEEcCYF3LBI/b11n7mLkBHJiJH7t2cwGYVdIzLt9BcjmAGpXkuiYU AEx6QejxKali1lAatgEVCS+v+lnhag3kzh/ciYTiC0iIC1x7fNlsAXMAp2MEj2Hz4A1CAtESJ yc+hJsGYuAqsSSpd1gNq+Ak8Tn921MEIPkJE4em8w6gZF/ASPDKkb14tSistQiXUO9pKLM9Iy S3MTMHF1DAzO93NTi4sT01JzEpGK95PzcTYzAEGIAgh2MO587HWKU5GBSEuVdUC0RLsSXlJ9S mZFYnBFfVJqTWnyIUYODQ2Dz2tUXGKVY8vLzUpUkeJV6geoEi1LTUyvSMnOAQQ5TKsHBoyTCW wKS5i0uSMwtzkyHSJ1itOTY8vvaWiaOLQtuAMltU++tZRICmyclzvujB6hBAKQhozQPbhwsEi 8xykoJ8zICHSvEU5BalJtZgir/ilGcg1FJmPcbyBSezLwSuK2vgA5iAjqI/64oyEEliQgpqQZ GY4lPfbtbj73QnvHH+uXU62VF9iui32S9n2ymsmlpYuyq23LmuqvedpxqnjR7f99D1dr6S9JF wTKNYfON9mksm/Egtqz026RCE3U3hkChjD2vN+4rTdi/Z92lWuk1cUZLzhk2Rp5ObZz3Z8WvD T84FuRv09aduPZlmsJZ505+z0v3fziHTV/FqMRSnJFoqMVcVJwIAK13+Eu/AgAA X-Env-Sender: wei.chen@linaro.org X-Msg-Ref: server-16.tower-21.messagelabs.com!1461227099!6104848!1 X-Originating-IP: [209.85.192.181] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 8.28; banners=-,-,- X-VirusChecked: Checked Received: (qmail 58998 invoked from network); 21 Apr 2016 08:25:00 -0000 Received: from mail-pf0-f181.google.com (HELO mail-pf0-f181.google.com) (209.85.192.181) by server-16.tower-21.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 21 Apr 2016 08:25:00 -0000 Received: by mail-pf0-f181.google.com with SMTP id 184so28020774pff.0 for ; Thu, 21 Apr 2016 01:25:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=PXKvgH/azLsLUnkAx5wbBEf3ouXHYG+F3fsnGWJWa/4=; b=RmWs1GZlTuGAZFQzF+P/wqeXEhulKVwOluYQEsskNDvXatObgVQULo+RGwyrf0V3i5 UJzAW54D4yNmuRd/XCdHE1ktNZRe3urAOnybAyPePZeZF7yrDOkh/3sRJRIAdUkccFuO fudSb9vON8ay24zRvFX/pPJODYq9gU6+RK7rw= 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; bh=PXKvgH/azLsLUnkAx5wbBEf3ouXHYG+F3fsnGWJWa/4=; b=RjEtsKccL+/m7J8QnzfJIlvrFVHxfa/a02hbGomv/JG3oEWA1Q8vvFZf0aZzUFy20u d/mHz7zklt7slYE/hsC1eWFvz2wYo52bT5AdNCN78Igg5VKVEkIA4xOaa9afOQ4MgJaX vwdTwQrS0T2E5lrevUz9h9gFTjNcwLMvHHe5W+iZHvvhj5nvVCDdYLnR0+VgHJ7IfVGc uDcIUb17LYqZlwi0dQxtprjNzlUTjyDgwC/QRfkiadZk5M6wbTP7qMkgcLvhO5vVJZFZ d2K/sVOz4czvwldnwwCoFvRcDkjYOBFoZmBT1qbTrxjYtoonGO7edJ8gusteLmSXGYHG iVcA== X-Gm-Message-State: AOPr4FXYUqPLax/p+kpEFEjIOvsPevhz7nKki3oeALyhhtPQfQw/FhzYazfNFIaQTmggY2qV X-Received: by 10.98.32.136 with SMTP id m8mr18991110pfj.11.1461227096288; Thu, 21 Apr 2016 01:24:56 -0700 (PDT) Received: from li713-35.members.linode.com ([2400:8900::f03c:91ff:fe56:1324]) by smtp.gmail.com with ESMTPSA id i67sm2799846pfb.56.2016.04.21.01.24.54 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 21 Apr 2016 01:24:55 -0700 (PDT) From: Wei Chen X-Google-Original-From: Wei Chen To: xen-devel@lists.xen.org Date: Thu, 21 Apr 2016 16:24:00 +0800 Message-Id: <1461227040-6105-1-git-send-email-Wei.Chen@linaro.org> X-Mailer: git-send-email 1.9.1 Cc: julien.grall@arm.com, sstabellini@kernel.org, Wei Chen , suravee.suthikulpanit@amd.com, steve.capper@arm.com Subject: [Xen-devel] [PATCH] xen/arm: gicv2: Export GICv2m register frames to domain0 by device tree 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" This patch adds v2m extension support in GIC-v2 driver. The GICv2 driver detects the MSI frames from device tree and creates corresponding device tree nodes in Domain0's DTB. It also provides one hw_ops callback to map v2m MMIO regions to domain0 and route v2m SPIs to domain0. With this GICv2m extension support, the domain0 kernel can do GICv2m frame setup and initialization. This patch is based on the GICv2m patch of Suravee Suthikulpanit: [PATCH 2/2] xen/arm: gicv2: Adding support for GICv2m in Dom0 http://lists.xen.org/archives/html/xen-devel/2015-04/msg02613.html Signed-off-by: Wei Chen --- xen/arch/arm/domain_build.c | 5 + xen/arch/arm/gic-v2.c | 285 ++++++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/gic.c | 9 ++ xen/include/asm-arm/gic.h | 3 + 4 files changed, 302 insertions(+) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index aba714c..b5d82fc 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -2176,6 +2176,11 @@ int construct_dom0(struct domain *d) if ( rc < 0 ) return rc; + /* Map extra GIC MMIO, irqs and other hw stuffs to domain0. */ + rc = gic_map_hwdom_extra_mappings(d); + if ( rc < 0 ) + return rc; + rc = platform_specific_mapping(d); if ( rc < 0 ) return rc; diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c index 450755f..4a7d65a 100644 --- a/xen/arch/arm/gic-v2.c +++ b/xen/arch/arm/gic-v2.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,41 @@ #define GICH_V2_VMCR_PRIORITY_MASK 0x1f #define GICH_V2_VMCR_PRIORITY_SHIFT 27 +/* GICv2m extension register definitions. */ +/* +* MSI_TYPER: +* [31:26] Reserved +* [25:16] lowest SPI assigned to MSI +* [15:10] Reserved +* [9:0] Number of SPIs assigned to MSI +*/ +#define V2M_MSI_TYPER 0x008 +#define V2M_MSI_TYPER_BASE_SHIFT 16 +#define V2M_MSI_TYPER_BASE_MASK 0x3FF +#define V2M_MSI_TYPER_NUM_MASK 0x3FF +#define V2M_MSI_SETSPI_NS 0x040 +#define V2M_MIN_SPI 32 +#define V2M_MAX_SPI 1019 +#define V2M_MSI_IIDR 0xFCC + +#define V2M_MSI_TYPER_BASE_SPI(x) \ + (((x) >> V2M_MSI_TYPER_BASE_SHIFT) & V2M_MSI_TYPER_BASE_MASK) + +#define V2M_MSI_TYPER_NUM_SPI(x) ((x) & V2M_MSI_TYPER_NUM_MASK) + +struct v2m_data { + struct list_head entry; + /* Pointer to the DT node representing the v2m frame */ + const struct dt_device_node *dt_node; + paddr_t addr; /* Register frame base */ + paddr_t size; /* Register frame size */ + u32 spi_start; /* The SPI number that MSIs start */ + u32 nr_spis; /* The number of SPIs for MSIs */ +}; + +/* v2m extension register frame information list */ +static LIST_HEAD(gicv2m_info); + /* Global state */ static struct { void __iomem * map_dbase; /* IO mapped Address of distributor registers */ @@ -551,6 +587,173 @@ static void gicv2_irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_m spin_unlock(&gicv2.lock); } +static int gicv2_map_hwdown_extra_mappings(struct domain *d) +{ + const struct v2m_data *v2m_data; + + /* + * For the moment, we'll assign all v2m frames to a single domain + * (i.e Domain0). + */ + list_for_each_entry( v2m_data, &gicv2m_info, entry ) + { + int ret, spi; + + printk("GICv2: Mapping v2m frame to domain%d: addr=0x%lx size=0x%lx spi_base=%u num_spis=%u\n", + d->domain_id, v2m_data->addr, v2m_data->size, + v2m_data->spi_start, v2m_data->nr_spis); + + ret = map_mmio_regions(d, paddr_to_pfn(v2m_data->addr), + DIV_ROUND_UP(v2m_data->size, PAGE_SIZE), + paddr_to_pfn(v2m_data->addr)); + if ( ret ) + { + printk(XENLOG_ERR + "GICv2: Map v2m frame to domain%d failed.\n", + d->domain_id); + return ret; + } + + /* + * Map all SPIs that are allocated to MSIs in a single frame to the + * domain. + */ + for ( spi = v2m_data->spi_start; + spi < (v2m_data->spi_start + v2m_data->nr_spis); spi++ ) + { + /* + * MSIs are always edge-triggered. Configure the associated SPIs + * to be edge-rising. + */ + ret = irq_set_spi_type(spi, IRQ_TYPE_EDGE_RISING); + if ( ret ) + { + printk(XENLOG_ERR + "GICv2: Failed to set v2m MSI SPI[%d] type.\n", spi); + return ret; + } + + /* Route a SPI that is allocated to MSI to the domain. */ + ret = route_irq_to_guest(d, spi, spi, "v2m"); + if ( ret ) + { + printk(XENLOG_ERR + "GICv2: Failed to route v2m MSI SPI[%d] to Dom%d.\n", + spi, d->domain_id); + return ret; + } + + /* Reserve a SPI that is allocated to MSI for the domain. */ + if ( !vgic_reserve_virq(d, spi) ) + { + printk(XENLOG_ERR + "GICv2: Failed to reserve v2m MSI SPI[%d] for Dom%d.\n", + spi, d->domain_id); + return -EINVAL; + } + } + } + + return 0; +} + +/* + * Set up gic v2m DT sub-node. + * Please refer to the binding document: + * https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt + */ +static int gicv2m_make_dt_node(const struct domain *d, + const struct dt_device_node *gic, + void *fdt) +{ + u32 len; + int res; + const void *prop = NULL; + const struct dt_device_node *v2m = NULL; + const struct v2m_data *v2m_data; + + /* The sub-nodes require the ranges property */ + prop = dt_get_property(gic, "ranges", &len); + if ( !prop ) + { + printk(XENLOG_ERR "Can't find ranges property for the gic node\n"); + return -FDT_ERR_XEN(ENOENT); + } + + res = fdt_property(fdt, "ranges", prop, len); + if ( res ) + return res; + + list_for_each_entry( v2m_data, &gicv2m_info, entry ) + { + v2m = v2m_data->dt_node; + + printk("GICv2: Creating v2m DT node for domain%d: addr=0x%lx size=0x%lx spi_base=%u num_spis=%u\n", + d->domain_id, v2m_data->addr, v2m_data->size, + v2m_data->spi_start, v2m_data->nr_spis); + + res = fdt_begin_node(fdt, v2m->name); + if ( res ) + return res; + + res = fdt_property_string(fdt, "compatible", "arm,gic-v2m-frame"); + if ( res ) + return res; + + res = fdt_property(fdt, "msi-controller", NULL, 0); + if ( res ) + return res; + + if ( v2m->phandle ) + { + res = fdt_property_cell(fdt, "phandle", v2m->phandle); + if ( res ) + return res; + } + + /* Use the same reg regions as v2m node in DTB. */ + prop = dt_get_property(v2m, "reg", &len); + if ( !prop ) + { + printk(XENLOG_ERR "GICv2: Can't find v2m reg property.\n"); + res = -FDT_ERR_XEN(ENOENT); + return res; + } + + res = fdt_property(fdt, "reg", prop, len); + if ( res ) + return res; + + /* + * Create msi-base-spi and msi-num-spis properties in Guest DT to + * override the hardware setting. From the binding document, we can + * find that these two properties are optional. But if these two + * properties are present in the v2m DT node, the guest v2m driver + * should read the configuration from these two properties instead + * of reading from hardware register. + */ + res = fdt_property_u32(fdt, "arm,msi-base-spi", v2m_data->spi_start); + if ( res ) + { + printk(XENLOG_ERR + "GICv2: Failed to create v2m msi-base-spi in Guest DT.\n"); + return res; + } + + res = fdt_property_u32(fdt, "arm,msi-num-spis", v2m_data->nr_spis); + if ( res ) + { + printk(XENLOG_ERR + "GICv2: Failed to create v2m msi-num-spis in Guest DT.\n"); + return res; + } + + fdt_end_node(fdt); + } + + return res; +} + static int gicv2_make_hwdom_dt_node(const struct domain *d, const struct dt_device_node *gic, void *fdt) @@ -587,6 +790,10 @@ static int gicv2_make_hwdom_dt_node(const struct domain *d, len *= 2; res = fdt_property(fdt, "reg", regs, len); + if ( res ) + return res; + + res = gicv2m_make_dt_node(d, gic, fdt); return res; } @@ -632,6 +839,77 @@ static bool_t gicv2_is_aliased(paddr_t cbase, paddr_t csize) return ((val_low & 0xfff0fff) == 0x0202043B && val_low == val_high); } +static void gicv2_extension_dt_init(const struct dt_device_node *node) +{ + int res; + u32 spi_start, nr_spis; + paddr_t addr, size; + const struct dt_device_node *v2m = NULL; + + /* + * Check whether this GIC implements the v2m extension. If so, + * add v2m register frames to gicv2m_info. + */ + dt_for_each_child_node(node, v2m) + { + struct v2m_data *v2m_data; + + if ( !dt_device_is_compatible(v2m, "arm,gic-v2m-frame") ) + continue; + + v2m_data = xzalloc_bytes(sizeof(struct v2m_data)); + if ( !v2m_data ) + panic("GICv2: Cannot allocate memory for v2m frame"); + + /* + * Check whether DT uses msi-base-spi and msi-num-spis properties to + * override the hardware setting. + */ + if ( !dt_property_read_u32(v2m, "arm,msi-base-spi", &spi_start) || + !dt_property_read_u32(v2m, "arm,msi-num-spis", &nr_spis) ) + { + u32 msi_typer; + void __iomem *base; + + /* + * DT does not override the hardware setting, so we have to read + * base_spi and num_spis from hardware registers to reserve irqs. + */ + res = dt_device_get_address(v2m, 0, &addr, &size); + if ( res ) + panic("GICv2: Cannot find a valid v2m frame address"); + + base = ioremap_nocache(addr, size); + if ( !base ) + panic("GICv2: Cannot remap v2m register frame"); + + msi_typer = readl_relaxed(base + V2M_MSI_TYPER); + spi_start = V2M_MSI_TYPER_BASE_SPI(msi_typer); + nr_spis = V2M_MSI_TYPER_NUM_SPI(msi_typer); + + iounmap(base); + } + + /* Initialize a new entry to record new frame infomation. */ + INIT_LIST_HEAD(&v2m_data->entry); + v2m_data->addr = addr; + v2m_data->size = size; + v2m_data->spi_start = spi_start; + v2m_data->nr_spis = nr_spis; + v2m_data->dt_node = v2m; + + printk("GICv2m extension register frame:\n" + " gic_v2m_addr=%"PRIpaddr"\n" + " gic_v2m_size=%"PRIpaddr"\n" + " gic_v2m_spi_base=%u\n" + " gic_v2m_num_spis=%u\n", + v2m_data->addr, v2m_data->size, + v2m_data->spi_start, v2m_data->nr_spis); + + list_add_tail(&v2m_data->entry, &gicv2m_info); + } +} + static paddr_t __initdata hbase, dbase, cbase, csize, vbase; static void __init gicv2_dt_init(void) @@ -683,6 +961,12 @@ static void __init gicv2_dt_init(void) if ( csize != vsize ) panic("GICv2: Sizes of GICC (%#"PRIpaddr") and GICV (%#"PRIpaddr") don't match\n", csize, vsize); + + /* + * Check whether this GIC implements the v2m extension. If so, + * add v2m register frames to gicv2_extension_info. + */ + gicv2_extension_dt_init(node); } static int gicv2_iomem_deny_access(const struct domain *d) @@ -936,6 +1220,7 @@ const static struct gic_hw_operations gicv2_ops = { .read_apr = gicv2_read_apr, .make_hwdom_dt_node = gicv2_make_hwdom_dt_node, .make_hwdom_madt = gicv2_make_hwdom_madt, + .map_hwdom_extra_mappings = gicv2_map_hwdown_extra_mappings, .iomem_deny_access = gicv2_iomem_deny_access, }; diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 2bfe4de..12bb0ab 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -230,6 +230,15 @@ int gic_irq_xlate(const u32 *intspec, unsigned int intsize, return 0; } +/* Map extra GIC MMIO, irqs and other hw stuffs to the hardware domain. */ +int gic_map_hwdom_extra_mappings(struct domain *d) +{ + if ( gic_hw_ops->map_hwdom_extra_mappings ) + return gic_hw_ops->map_hwdom_extra_mappings(d); + + return 0; +} + static void __init gic_dt_preinit(void) { int rc; diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index cd97bb2..836f1ad 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -360,6 +360,8 @@ struct gic_hw_operations { const struct dt_device_node *gic, void *fdt); /* Create MADT table for the hardware domain */ int (*make_hwdom_madt)(const struct domain *d, u32 offset); + /* Map extra GIC MMIO, irqs and other hw stuffs to the hardware domain. */ + int (*map_hwdom_extra_mappings)(struct domain *d); /* Deny access to GIC regions */ int (*iomem_deny_access)(const struct domain *d); }; @@ -369,6 +371,7 @@ int gic_make_hwdom_dt_node(const struct domain *d, const struct dt_device_node *gic, void *fdt); int gic_make_hwdom_madt(const struct domain *d, u32 offset); +int gic_map_hwdom_extra_mappings(struct domain *d); int gic_iomem_deny_access(const struct domain *d); #endif /* __ASSEMBLY__ */