From patchwork Thu Mar 16 11:20:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 9627937 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 28EE86048C for ; Thu, 16 Mar 2017 11:20:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1C420285B5 for ; Thu, 16 Mar 2017 11:20:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1100B28604; Thu, 16 Mar 2017 11:20:46 +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.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED 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 50EF0285B5 for ; Thu, 16 Mar 2017 11:20:45 +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 1coTQl-0007Wm-91; Thu, 16 Mar 2017 11:18:55 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1coTQj-0007V0-Uq for xen-devel@lists.xenproject.org; Thu, 16 Mar 2017 11:18:54 +0000 Received: from [85.158.143.35] by server-4.bemta-6.messagelabs.com id BC/E0-25093-D947AC85; Thu, 16 Mar 2017 11:18:53 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrOLMWRWlGSWpSXmKPExsVysyfVTXduyak Ig+2nGC2+b5nM5MDocfjDFZYAxijWzLyk/IoE1ozWOeuYC54mVmztO8XSwLjds4uRi0NIYDOj xJ9381khnOWMEt/OrmTvYuTkYBPQldhx8zUziC0iECox5+cjMJtZoFLi4of9bCC2sICfxMon9 xlBbBYBVYne7sVMIDavgLXEjHXPwOISAnISDefvg/VyCthIdJzcA9YrBFTz+ehn9gmM3AsYGV YxahSnFpWlFukaG+slFWWmZ5TkJmbm6BoamOnlphYXJ6an5iQmFesl5+duYgR6mAEIdjDuXB9 4iFGSg0lJlFdF8ESEEF9SfkplRmJxRnxRaU5q8SFGGQ4OJQneO5VAOcGi1PTUirTMHGCowaQl OHiURHglqoDSvMUFibnFmekQqVOMilLivO9B+gRAEhmleXBtsPC+xCgrJczLCHSIEE9BalFuZ gmq/CtGcQ5GJWHeeyBTeDLzSuCmvwJazAS0OPHnEZDFJYkIKakGxq1P3DMun+ZbtMVfYuVitj +M993tgp/Zn3uQGRTup60S+X2PbcSTxwprOBl2/no8ofCHRPVZ7ooXGfmfUs42FirUr111fbb Kz5fZh8r3hDn8zj3zdUpDWwxXz1fbhcmztvZPPZUZ/f5FoGvAtY1rbR6W3ft+ZW3/MUG3o8eT 3G6mZ3wXl8rok1ViKc5INNRiLipOBADr6QdTagIAAA== X-Env-Sender: andre.przywara@arm.com X-Msg-Ref: server-16.tower-21.messagelabs.com!1489663132!58121869!1 X-Originating-IP: [217.140.101.70] X-SpamReason: No, hits=0.0 required=7.0 tests=UPPERCASE_25_50 X-StarScan-Received: X-StarScan-Version: 9.2.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 60995 invoked from network); 16 Mar 2017 11:18:52 -0000 Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by server-16.tower-21.messagelabs.com with SMTP; 16 Mar 2017 11:18:52 -0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0CCB3150C; Thu, 16 Mar 2017 04:18:52 -0700 (PDT) Received: from e104803-lin.lan (unknown [10.1.207.46]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E92373F5C9; Thu, 16 Mar 2017 04:18:50 -0700 (PDT) From: Andre Przywara To: Stefano Stabellini , Julien Grall Date: Thu, 16 Mar 2017 11:20:06 +0000 Message-Id: <20170316112030.20419-4-andre.przywara@arm.com> X-Mailer: git-send-email 2.9.0 In-Reply-To: <20170316112030.20419-1-andre.przywara@arm.com> References: <20170316112030.20419-1-andre.przywara@arm.com> Cc: xen-devel@lists.xenproject.org, Shanker Donthineni , Vijay Kilari Subject: [Xen-devel] [PATCH v2 03/27] ARM: GICv3 ITS: allocate device and collection table 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 Each ITS maps a pair of a DeviceID (for instance derived from a PCI b/d/f triplet) and an EventID (the MSI payload or interrupt ID) to a pair of LPI number and collection ID, which points to the target CPU. This mapping is stored in the device and collection tables, which software has to provide for the ITS to use. Allocate the required memory and hand it to the ITS. The maximum number of devices is limited to a compile-time constant exposed in Kconfig. Signed-off-by: Andre Przywara --- docs/misc/xen-command-line.markdown | 8 ++ xen/arch/arm/Kconfig | 14 ++++ xen/arch/arm/gic-v3-its.c | 163 ++++++++++++++++++++++++++++++++++++ xen/arch/arm/gic-v3.c | 3 + xen/include/asm-arm/gic_v3_its.h | 63 +++++++++++++- 5 files changed, 250 insertions(+), 1 deletion(-) diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown index 619016d..068d116 100644 --- a/docs/misc/xen-command-line.markdown +++ b/docs/misc/xen-command-line.markdown @@ -1158,6 +1158,14 @@ based interrupts. Any higher IRQs will be available for use via PCI MSI. ### maxcpus > `= ` +### max\_its\_device\_bits +> `= ` + +Specifies the maximum number of devices using MSIs on the ARM GICv3 ITS +controller to allocate table entries for. Each table entry uses a hardware +specific size, typically 8 or 16 bytes. +Defaults to 10 bits (to cover at most 1024 devices). + ### max\_lpi\_bits > `= ` diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index 86f7b53..0d50156 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -64,6 +64,20 @@ config MAX_PHYS_LPI_BITS This can be overridden on the command line with the max_lpi_bits parameter. +config MAX_PHYS_ITS_DEVICE_BITS + depends on HAS_ITS + int "Number of device bits the ITS supports" + range 1 32 + default "10" + help + Specifies the maximum number of devices which want to use the ITS. + Xen needs to allocates memory for the whole range very early. + The allocation scheme may be sparse, so a much larger number must + be supported to cover devices with a high bus number or those on + separate bus segments. + This can be overridden on the command line with the + max_its_device_bits parameter. + endmenu menu "ARM errata workaround via the alternative framework" diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 4056e5b..9982fe9 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -19,8 +19,10 @@ */ #include +#include #include #include +#include LIST_HEAD(host_its_list); @@ -29,6 +31,167 @@ bool gicv3_its_host_has_its(void) return !list_empty(&host_its_list); } +#define BASER_ATTR_MASK \ + ((0x3UL << GITS_BASER_SHAREABILITY_SHIFT) | \ + (0x7UL << GITS_BASER_OUTER_CACHEABILITY_SHIFT) | \ + (0x7UL << GITS_BASER_INNER_CACHEABILITY_SHIFT)) +#define BASER_RO_MASK (GENMASK(58, 56) | GENMASK(52, 48)) + +/* Check that the physical address can be encoded in the PROPBASER register. */ +static bool check_propbaser_phys_addr(void *vaddr, unsigned int page_bits) +{ + paddr_t paddr = virt_to_maddr(vaddr); + + return (!(paddr & ~GENMASK(page_bits < 16 ? 47 : 51, page_bits))); +} + +static uint64_t encode_propbaser_phys_addr(paddr_t addr, unsigned int page_bits) +{ + uint64_t ret = addr & GENMASK(47, page_bits); + + if ( page_bits < 16 ) + return ret; + + /* For 64K pages address bits 51-48 are encoded in bits 15-12. */ + return ret | ((addr & GENMASK(51, 48)) >> (48 - 12)); +} + +/* The ITS BASE registers work with page sizes of 4K, 16K or 64K. */ +#define BASER_PAGE_BITS(sz) ((sz) * 2 + 12) + +static int its_map_baser(void __iomem *basereg, uint64_t regc, + unsigned int nr_items) +{ + uint64_t attr, reg; + unsigned int entry_size = GITS_BASER_ENTRY_SIZE(regc); + unsigned int pagesz = 2, order, table_size; + void *buffer; + + attr = GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT; + attr |= GIC_BASER_CACHE_SameAsInner << GITS_BASER_OUTER_CACHEABILITY_SHIFT; + attr |= GIC_BASER_CACHE_RaWaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT; + + /* + * Setup the BASE register with the attributes that we like. Then read + * it back and see what sticks (page size, cacheability and shareability + * attributes), retrying if necessary. + */ +retry: + table_size = ROUNDUP(nr_items * entry_size, BIT(BASER_PAGE_BITS(pagesz))); + /* The BASE registers support at most 256 pages. */ + table_size = min(table_size, 256U << BASER_PAGE_BITS(pagesz)); + /* The memory block must be aligned to the requested page size. */ + order = max(get_order_from_bytes(table_size), pagesz * 2); + + buffer = alloc_xenheap_pages(order, 0); + if ( !buffer ) + return -ENOMEM; + + if ( !check_propbaser_phys_addr(buffer, BASER_PAGE_BITS(pagesz)) ) + { + free_xenheap_pages(buffer, 0); + return -ERANGE; + } + memset(buffer, 0, table_size); + + reg = attr; + reg |= (pagesz << GITS_BASER_PAGE_SIZE_SHIFT); + reg |= (table_size >> BASER_PAGE_BITS(pagesz)) - 1; + reg |= regc & BASER_RO_MASK; + reg |= GITS_VALID_BIT; + reg |= encode_propbaser_phys_addr(virt_to_maddr(buffer), + BASER_PAGE_BITS(pagesz)); + + writeq_relaxed(reg, basereg); + regc = readq_relaxed(basereg); + + /* The host didn't like our attributes, just use what it returned. */ + if ( (regc & BASER_ATTR_MASK) != attr ) + { + /* If we can't map it shareable, drop cacheability as well. */ + if ( (regc & GITS_BASER_SHAREABILITY_MASK) == GIC_BASER_NonShareable ) + { + regc &= ~GITS_BASER_INNER_CACHEABILITY_MASK; + writeq_relaxed(regc, basereg); + } + attr = regc & BASER_ATTR_MASK; + } + if ( (regc & GITS_BASER_INNER_CACHEABILITY_MASK) <= GIC_BASER_CACHE_nC ) + clean_and_invalidate_dcache_va_range(buffer, table_size); + + /* If the host accepted our page size, we are done. */ + if ( ((regc >> GITS_BASER_PAGE_SIZE_SHIFT) & 0x3UL) == pagesz ) + return 0; + + free_xenheap_pages(buffer, order); + + if ( pagesz-- > 0 ) + goto retry; + + /* None of the page sizes was accepted, give up */ + return -EINVAL; +} + +static unsigned int max_its_device_bits = CONFIG_MAX_PHYS_ITS_DEVICE_BITS; +integer_param("max_its_device_bits", max_its_device_bits); + +static int gicv3_its_init_single_its(struct host_its *hw_its) +{ + uint64_t reg; + int i; + unsigned int devid_bits; + + hw_its->its_base = ioremap_nocache(hw_its->addr, hw_its->size); + if ( !hw_its->its_base ) + return -ENOMEM; + + reg = readq_relaxed(hw_its->its_base + GITS_TYPER); + devid_bits = GITS_TYPER_DEVICE_ID_BITS(reg); + devid_bits = min(devid_bits, max_its_device_bits); + + for ( i = 0; i < GITS_BASER_NR_REGS; i++ ) + { + void __iomem *basereg = hw_its->its_base + GITS_BASER0 + i * 8; + unsigned int type; + + reg = readq_relaxed(basereg); + type = (reg & GITS_BASER_TYPE_MASK) >> GITS_BASER_TYPE_SHIFT; + switch ( type ) + { + case GITS_BASER_TYPE_NONE: + continue; + case GITS_BASER_TYPE_DEVICE: + its_map_baser(basereg, reg, BIT(devid_bits)); + break; + case GITS_BASER_TYPE_COLLECTION: + its_map_baser(basereg, reg, NR_CPUS); + break; + /* In case this is a GICv4, provide a (dummy) vPE table as well. */ + case GITS_BASER_TYPE_VCPU: + its_map_baser(basereg, reg, 1); + break; + default: + continue; + } + } + + return 0; +} + +int gicv3_its_init(void) +{ + struct host_its *hw_its; + int ret; + + list_for_each_entry(hw_its, &host_its_list, entry) { + ret = gicv3_its_init_single_its(hw_its); + if ( ret ) + return ret; + } + + return 0; +} + /* Scan the DT for any ITS nodes and create a list of host ITSes out of it. */ void gicv3_its_dt_init(const struct dt_device_node *node) { diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index ed78363..cc1e219 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1590,6 +1590,9 @@ static int __init gicv3_init(void) spin_lock(&gicv3.lock); gicv3_dist_init(); + res = gicv3_its_init(); + if ( res ) + printk(XENLOG_WARNING "GICv3: ITS: initialization failed: %d\n", res); res = gicv3_cpu_init(); gicv3_hyp_init(); diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h index 219d109..a6c0acc 100644 --- a/xen/include/asm-arm/gic_v3_its.h +++ b/xen/include/asm-arm/gic_v3_its.h @@ -20,6 +20,60 @@ #ifndef __ASM_ARM_ITS_H__ #define __ASM_ARM_ITS_H__ +#define GITS_CTLR 0x000 +#define GITS_IIDR 0x004 +#define GITS_TYPER 0x008 +#define GITS_CBASER 0x080 +#define GITS_CWRITER 0x088 +#define GITS_CREADR 0x090 +#define GITS_BASER_NR_REGS 8 +#define GITS_BASER0 0x100 +#define GITS_BASER1 0x108 +#define GITS_BASER2 0x110 +#define GITS_BASER3 0x118 +#define GITS_BASER4 0x120 +#define GITS_BASER5 0x128 +#define GITS_BASER6 0x130 +#define GITS_BASER7 0x138 + +/* Register bits */ +#define GITS_VALID_BIT BIT_ULL(63) + +#define GITS_CTLR_QUIESCENT BIT(31) +#define GITS_CTLR_ENABLE BIT(0) + +#define GITS_TYPER_DEVIDS_SHIFT 13 +#define GITS_TYPER_DEVIDS_MASK (0x1fUL << GITS_TYPER_DEVIDS_SHIFT) +#define GITS_TYPER_DEVICE_ID_BITS(r) (((r & GITS_TYPER_DEVIDS_MASK) >> \ + GITS_TYPER_DEVIDS_SHIFT) + 1) + +#define GITS_IIDR_VALUE 0x34c + +#define GITS_BASER_INDIRECT BIT_ULL(62) +#define GITS_BASER_INNER_CACHEABILITY_SHIFT 59 +#define GITS_BASER_TYPE_SHIFT 56 +#define GITS_BASER_TYPE_MASK (7ULL << GITS_BASER_TYPE_SHIFT) +#define GITS_BASER_OUTER_CACHEABILITY_SHIFT 53 +#define GITS_BASER_TYPE_NONE 0UL +#define GITS_BASER_TYPE_DEVICE 1UL +#define GITS_BASER_TYPE_VCPU 2UL +#define GITS_BASER_TYPE_CPU 3UL +#define GITS_BASER_TYPE_COLLECTION 4UL +#define GITS_BASER_TYPE_RESERVED5 5UL +#define GITS_BASER_TYPE_RESERVED6 6UL +#define GITS_BASER_TYPE_RESERVED7 7UL +#define GITS_BASER_ENTRY_SIZE_SHIFT 48 +#define GITS_BASER_ENTRY_SIZE(reg) \ + (((reg >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1) +#define GITS_BASER_SHAREABILITY_SHIFT 10 +#define GITS_BASER_PAGE_SIZE_SHIFT 8 +#define GITS_BASER_RO_MASK (GITS_BASER_TYPE_MASK | \ + (31UL << GITS_BASER_ENTRY_SIZE_SHIFT) |\ + GITS_BASER_INDIRECT) +#define GITS_BASER_SHAREABILITY_MASK (0x3ULL << GITS_BASER_SHAREABILITY_SHIFT) +#define GITS_BASER_OUTER_CACHEABILITY_MASK (0x7ULL << GITS_BASER_OUTER_CACHEABILITY_SHIFT) +#define GITS_BASER_INNER_CACHEABILITY_MASK (0x7ULL << GITS_BASER_INNER_CACHEABILITY_SHIFT) + #include /* data structure for each hardware ITS */ @@ -28,6 +82,7 @@ struct host_its { const struct dt_device_node *dt_node; paddr_t addr; paddr_t size; + void __iomem *its_base; }; @@ -42,8 +97,9 @@ bool gicv3_its_host_has_its(void); int gicv3_lpi_init_rdist(void __iomem * rdist_base); -/* Initialize the host structures for LPIs. */ +/* Initialize the host structures for LPIs and the host ITSes. */ int gicv3_lpi_init_host_lpis(unsigned int nr_lpis); +int gicv3_its_init(void); #else @@ -67,6 +123,11 @@ static inline int gicv3_lpi_init_host_lpis(unsigned int nr_lpis) { return 0; } + +static inline int gicv3_its_init(void) +{ + return 0; +} #endif /* CONFIG_HAS_ITS */ #endif