From patchwork Mon Feb 1 09:26:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: vijayak@caviumnetworks.com X-Patchwork-Id: 8177431 Return-Path: X-Original-To: patchwork-xen-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 067379FBE9 for ; Mon, 1 Feb 2016 09:33:38 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 398F62041D for ; Mon, 1 Feb 2016 09:33:36 +0000 (UTC) Received: from lists.xen.org (lists.xenproject.org [50.57.142.19]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1FD5E20414 for ; Mon, 1 Feb 2016 09:33:34 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xen.org) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1aQAoZ-0006ue-QU; Mon, 01 Feb 2016 09:30:31 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1aQAne-0006lG-KG for xen-devel@lists.xen.org; Mon, 01 Feb 2016 09:29:34 +0000 Received: from [85.158.137.68] by server-6.bemta-3.messagelabs.com id 5F/E4-08479-D752FA65; Mon, 01 Feb 2016 09:29:33 +0000 X-Env-Sender: Vijaya.Kumar@caviumnetworks.com X-Msg-Ref: server-16.tower-31.messagelabs.com!1454318970!11919388!1 X-Originating-IP: [207.46.100.92] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 7.35.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 33837 invoked from network); 1 Feb 2016 09:29:32 -0000 Received: from mail-by2on0092.outbound.protection.outlook.com (HELO na01-by2-obe.outbound.protection.outlook.com) (207.46.100.92) by server-16.tower-31.messagelabs.com with AES256-SHA256 encrypted SMTP; 1 Feb 2016 09:29:32 -0000 Received: from cavium-Vostro-2520.caveonetworks.com (111.93.218.67) by BN3PR0701MB1688.namprd07.prod.outlook.com (10.163.39.154) with Microsoft SMTP Server (TLS) id 15.1.396.15; Mon, 1 Feb 2016 09:29:24 +0000 From: To: , , , , , Date: Mon, 1 Feb 2016 14:56:31 +0530 Message-ID: <1454318798-31913-22-git-send-email-vijayak@caviumnetworks.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1454318798-31913-1-git-send-email-vijayak@caviumnetworks.com> References: <1454318798-31913-1-git-send-email-vijayak@caviumnetworks.com> MIME-Version: 1.0 X-Originating-IP: [111.93.218.67] X-ClientProxiedBy: BM1PR01CA0026.INDPRD01.PROD.OUTLOOK.COM (25.163.198.161) To BN3PR0701MB1688.namprd07.prod.outlook.com (25.163.39.154) X-Microsoft-Exchange-Diagnostics: 1; BN3PR0701MB1688; 2:J35CXSkZVMEfmw7+AD2XXHQqZWDOIzstMHwXOmkRjQWfPPDwgxUkCkGdUjto/A2m5YcXF7IYgkt2MGKgsz5YwLqW/tp0r5mBgtYgSKS6woDDi2En5m0xx7xFLWGrxSN2OhArteob5kKzgHZcPtQAnA==; 3:CVUoobYU+1wzwFQdrwRd/fyeJnEM4gdcah3iYmjlQ6076fpsNcD/6KMOlnM3TSNSjczGH8ZcqVsTUSixyfx0I6K7Cvf2HcbLjgFrXOIq1lBToUvZrh1mx4GO+rupyYAh; 25:X/3kcho8UELgmDaIpH2BlSP5xrcwBVNXcACunH+OCQoXTJlYJsRegpdMs1NtxnzuCn7ouwVbhdCPrDUWLEEmU75SMNbP1A7oIlzB2kXNUsvBX6DUxxGj58c1LsdHKuy3RP3+Z7czX4kCraeo6ZIxUiJJM//1Z0cEaAwJT0Z+za18YOWnBAuceJST8YQprnPOJVw03ev/XexLmpbtV9tq994o9oUTgcE22N5e2OZ9YqCTd1yEJpdJqCqT+/6L5t8j X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BN3PR0701MB1688; X-MS-Office365-Filtering-Correlation-Id: cbeff644-8b0b-4dbc-d342-08d32aea2ed8 X-Microsoft-Exchange-Diagnostics: 1; BN3PR0701MB1688; 20:+QCYSFKwvjFh3q7Mji+s1GCkLj1PG+jgm9+JrOT80XRSZd7Hwr2uDdNBMxSM0axq4thbVyWEiYoBU+N+bgcyya9G8PhAi+cYzdR/bfdYfBfxHRxL6CGiRutaXgfk4K8WU1ZlK90gYaWBR7h0Qm+G4EBp8dJV0Ecg3eDNJiW05RVOkYykrOJ5ZBmFZCHJwXgSFZE7jYtheaJYQdmQbbZxuIZwnSkIvJMsMEJHw6gBl8le+yq47neindRwMsegQP0G8Qxpvj/HzYzTsPZteVXq6ujugULvAyTRY+XlpTBtCdu/8s5JuI7FGkOEmTY0ZWRA3jfcFqZaGIS0rHybfgfah72cVnECqLn2AKNuupOVTesrcL9DlliyX8q4xXx/90IBFeJQPK6wpuM5D06wOoPBN5R7shu38u971YDlnxyk7fFFHbYBNB9b8ACY97oEuTegn3znAmW1PmESp6Bkz9yNGXfL9FXnyHEiPju1CRiZA1fTqUBBAvLT3LKrAtfiqkK5qbKZpvkB0C/Typ07HRNW+mJmtDTfOUtcu1Gs0p1PI3i5X6nq9R7tLcxQx3LIbFGa9SbufEJDcmAyAeO7zUq6q5IiYtH1WeVrWSR3TSWsCZQ= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046); SRVR:BN3PR0701MB1688; BCL:0; PCL:0; RULEID:; SRVR:BN3PR0701MB1688; X-Microsoft-Exchange-Diagnostics: 1; BN3PR0701MB1688; 4:3shOYB/FbxNm+EF5+/cAS5ac+0fAV4MnH1SFv3OIL2eR6LlD5b/XaVJm0BK+Kgiu6ZYBgBjJZnqj01wb5QUDrevg4TdR9pQ6WT0x55GVbCFjVcOA4+e0ohHUW72gl1CRWYLQVWftzoR/22Ik9TrPpOPWu67OV3kQEQ1UyIgOkr/tZfW7Rfg51Jm+81bDDTg4PVYvOUi048zcnyX/Aj1UStNF/WKrEItqjRj6dxQNMXPwBt5zJcSSWChLlKrRwycCHB9FLG0+KkAnLRwqhkgC9QCRk7Rq/ryNqsIftRf1dO00fFz1otqs3YAZLFBOBrcTF2N+2AYWAcbzzEibK0KDBx6ePvE9Zn84CkVsbZHg1GgxWNb7fSsmAFsuWDH0DRi3 X-Forefront-PRVS: 0839D067E7 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(979002)(6009001)(6116002)(3846002)(5009440100003)(4001430100002)(586003)(1096002)(76176999)(50986999)(36756003)(189998001)(92566002)(5004730100002)(2950100001)(229853001)(50226001)(87976001)(86152002)(107886002)(2201001)(5001960100002)(77096005)(53416004)(48376002)(19580395003)(19580405001)(5003940100001)(5001770100001)(42186005)(33646002)(66066001)(47776003)(2906002)(2876002)(4326007)(122386002)(3470700001)(5008740100001)(50466002)(40100003)(7099028)(7059030)(2101003)(14943795004)(969003)(989001)(999001)(1009001)(1019001); DIR:OUT; SFP:1101; SCL:1; SRVR:BN3PR0701MB1688; H:cavium-Vostro-2520.caveonetworks.com; FPR:; SPF:None; MLV:ovrnspm; PTR:InfoNoRecords; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BN3PR0701MB1688; 23:6rRkNMZWHGyA7SHl9F7vVlK4uKZLoUmsGloy8lY?= =?us-ascii?Q?ZyuLa5mbHS2Lnzjd0sXH0mcixrWb2fG2LfJRx2b7uTccHgb6aLnlCxmcoob3?= =?us-ascii?Q?FN35Yln5MEzC2ICvZJue4MeAGjnbHq4ZqGOkP6Mi4Ke5mafgN7abaNObaVPl?= =?us-ascii?Q?WPfI8KuU21xrbJWdo/pBC1LIx3NWCgdqjEgPeVg4AzFkojWuap2rH4hK7iNi?= =?us-ascii?Q?o/z4wxdkmGdXmyhmRoQ3zmNznM10mQef71tW5w/YMw+OqPiCDdS3Bd3Z4zxq?= =?us-ascii?Q?EDN38BYpx7KrMp0OGYvQPmQOTnptFCyCixBxIXipqXA6eGwhCvCFCZTA0/xX?= =?us-ascii?Q?asqWgv0c+oUc0YPUGfErFo9IDAcEOPd6W6GtYXz4J1uhATtBQTs+V5fbWGZ9?= =?us-ascii?Q?Izrsn3/yNlJBMWAZfq5bH/5iUksFQpsA9XuVpSeM3HAZ1vfuksxx9lIfvugJ?= =?us-ascii?Q?Ka2LR4mMw+22Zq19RfVnxPU5hVLl1z9cHz9aaGFG2n523p00ZO8DBsuH2l2O?= =?us-ascii?Q?aDMArQ0YhcD7T2LRrhVVIZfTnyubBNR1cJ4OFZVYUcJKf/G0RN2Sz/cLPHm5?= =?us-ascii?Q?cdl87Y8UXSz96/KzMhbzMtIdPhw8CowKaeg29OIZe500D1djZwVZzGDxL38x?= =?us-ascii?Q?th215rh8a3/MhLbP38INlLd40HIkuRp3xTCl1XRwqv3qQoOk93S8NY0QsbYM?= =?us-ascii?Q?cwqeyw31KFHRCKLYLLUKKBmnQm7sumFuT669ag34NV9aw2Eg1PZReMPz5cwv?= =?us-ascii?Q?AO9ryL+uOD5IdsPfYPT0UuTENBMaL7Yog8LJHrwKSTU/UWdTWcJQqlYKOsHs?= =?us-ascii?Q?TXFSeGvuhTrcDTNn8cYkdAVtwu8x310Xf4U5wFfpv7PdCiTIoACYMP1G442U?= =?us-ascii?Q?4oEJiV0yC2Y30gC9pttH41pDoPGoBJc/A5iRq+nTI8XxLYyM1m3x2AA3451d?= =?us-ascii?Q?SAfWKdWzWjH0KdzDhsWl4pXeOM8OEoy78zhg2ECpvkgLrtGK4a7seMLnT8LS?= =?us-ascii?Q?e6jnyIxbvj3VjyQetGbrjCpAGP9kYxi1oZInPkAnfbm4/jyB0MRvvZ5LSmqk?= =?us-ascii?Q?nMjkHyiieATs/baozsYhwzoAOPBcMu64HobdBGl5BilMEuzSA1htoGQSkUQP?= =?us-ascii?Q?8lMmE/gtseU2RSCj8x1+lCAvKPg3c+DxaN1AwwMkC79FJJhu18kJLg9vk7mN?= =?us-ascii?Q?nxkcY/dwKAFCmxvRnZs48wBHyRmi32MKk0xbbcHLKMYjAocMsnj89R8O6Ofp?= =?us-ascii?Q?sAmoKQCy8nX8HUw/lT38A9+3KtS1hHO+yoY5evvAe?= X-Microsoft-Exchange-Diagnostics: 1; BN3PR0701MB1688; 5:KJPkBcKY4ABMJVtHC0HJ5SsO3pGyDuNK7pFhyQKSqpqmUR7En3EQBomEfeOG+SsqutsIMSQ2jU13PgGYj2d+7raWphoG904aVdGBIJ9XW3Tq97B4kgU2swfYQ6xuoPUwChzLxynU4RP4MWkpzNp+OQ==; 24:kQHOs+ukUb0K+RkohtS6NlHt4xBZrdfd3fvk98PyWbw2RcQZKCaAr97Xj8ccHq3CgCnJRo0wBIz8NGPo4TJPntZWlOYHhInz6R7Tm5lvlcY= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: caviumnetworks.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Feb 2016 09:29:24.1157 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN3PR0701MB1688 X-Mailman-Approved-At: Mon, 01 Feb 2016 09:30:20 +0000 Cc: Prasun.Kapoor@caviumnetworks.com, manish.jaggi@caviumnetworks.com, Vijaya Kumar K , vijay.kilari@gmail.com Subject: [Xen-devel] [PATCH v8 21/28] xen/arm: ITS: Add GICR register emulation X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAD_ENC_HEADER,BAYES_00, RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Vijaya Kumar K Emulate LPI related changes to GICR registers Signed-off-by: Vijaya Kumar K --- v8: - Updated GICR_PROPBASER and GICR_PENDBASER only on enabling LPIs and added 32/64 bit reg access - Allocated LPI property table of size supported by Xen. - Moved LPI property table related variables to vgic from vits structure. - Used Tasklet to parse LPI property table and update pending irq structures - Check is made in INV command processing to wait for LPI property table update before returning. v7: - Merged patch#23 to this patch. patch#23 is just one line. - Add 32-bit access to GICR_TYPER register - Changed dprintk to printk - LPI property table is handling is changed. Call {enable,disable}_lpi only for nr_lpis. - Changes to GICD_TYPER emulation. v6: - Moved LPI handling code to vgic-v3.c - parse LPI property table on GICR_PROPBASER update - use vgic_is_lpi_supported() v5: - Handled all sizes access to LPI configuration table - Rename vits_unmap_lpi_prop as vits_map_lpi_prop v4: - Added LPI configuration table emulation - Rename function inline with vits - Copied guest lpi configuration table to xen --- xen/arch/arm/vgic-v3-its.c | 18 ++ xen/arch/arm/vgic-v3.c | 419 +++++++++++++++++++++++++++++++++++-- xen/arch/arm/vgic.c | 24 ++- xen/include/asm-arm/domain.h | 31 +++ xen/include/asm-arm/gic-its.h | 1 + xen/include/asm-arm/gic_v3_defs.h | 3 + xen/include/asm-arm/vgic.h | 3 + 7 files changed, 479 insertions(+), 20 deletions(-) diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c index 913b49d..1bb7674 100644 --- a/xen/arch/arm/vgic-v3-its.c +++ b/xen/arch/arm/vgic-v3-its.c @@ -23,12 +23,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -299,6 +301,22 @@ static int vits_process_discard(struct vcpu *v, struct vgic_its *vits, static int vits_process_inv(struct vcpu *v, struct vgic_its *vits, its_cmd_block *virt_cmd) { + unsigned long flags; + int state; + + /* Do no complete INV command until lpi property table + * is under update by tasklet + */ + do { + spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags); + state = v->domain->arch.vgic.lpi_prop_table_state; + spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags); + if ( state != LPI_TAB_IN_PROGRESS ) + break; + cpu_relax(); + udelay(1); + } while ( 1 ); + /* Ignored */ DPRINTK("%pv vITS: INV: dev_id 0x%"PRIx32" id %"PRIu32"\n", v, virt_cmd->inv.devid, virt_cmd->inv.event); diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index 2deed24..aa3c5ed 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -26,10 +26,14 @@ #include #include #include +#include #include #include #include +#include +#include #include +#include #include /* @@ -159,6 +163,252 @@ static void vgic_store_irouter(struct domain *d, struct vgic_irq_rank *rank, rank->vcpu[offset] = new_vcpu->vcpu_id; } +static void vgic_v3_disable_lpi(struct vcpu *v, uint32_t vlpi) +{ + struct pending_irq *p; + struct vcpu *v_target = v->domain->vcpu[0]; + + p = irq_to_pending(v_target, vlpi); + if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) ) + { + clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status); + gic_remove_from_queues(v_target, vlpi); + } +} + +static void vgic_v3_enable_lpi(struct vcpu *v, uint32_t vlpi) +{ + struct pending_irq *p; + unsigned long flags; + struct vcpu *v_target = vgic_get_target_vcpu(v, vlpi); + + p = irq_to_pending(v_target, vlpi); + + set_bit(GIC_IRQ_GUEST_ENABLED, &p->status); + + spin_lock_irqsave(&v_target->arch.vgic.lock, flags); + + if ( !list_empty(&p->inflight) && + !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) ) + gic_raise_guest_irq(v_target, vlpi, p->priority); + + spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags); +} + +static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info, + register_t *r, void *priv) +{ + uint32_t offset; + void *addr; + unsigned long flags; + struct hsr_dabt dabt = info->dabt; + + spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags); + + offset = info->gpa - + (v->domain->arch.vgic.propbase & GICR_PROPBASER_PA_MASK); + addr = (void *)((u8 *)v->domain->arch.vgic.prop_page + offset); + + switch (dabt.size) + { + case DABT_DOUBLE_WORD: + *r = *((u64 *)addr); + break; + case DABT_WORD: + *r = *((u32 *)addr); + break; + case DABT_HALF_WORD: + *r = *((u16 *)addr); + break; + default: + *r = *((u8 *)addr); + } + spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags); + + return 1; +} + +static void vgic_v3_gits_update_lpis_state(struct vcpu *v, uint32_t vid, + uint32_t size) +{ + uint32_t i; + uint8_t cfg, *p; + bool_t enable; + + ASSERT(spin_is_locked(&v->domain->arch.vgic.prop_lock)); + + p = ((u8 *)v->domain->arch.vgic.prop_page + vid); + + for ( i = 0 ; i < size; i++ ) + { + cfg = *p; + enable = cfg & LPI_PROP_ENABLED; + + /* LPIs start from 8192, So add 8192 to point to correct LPI number */ + if ( !enable ) + vgic_v3_enable_lpi(v, vid + FIRST_GIC_LPI); + else + vgic_v3_disable_lpi(v, vid + FIRST_GIC_LPI); + + p++; + vid++; + } +} + +static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info, + register_t r, void *priv) +{ + uint32_t offset; + uint8_t *p, *val, i, iter; + bool_t enable; + unsigned long flags; + struct hsr_dabt dabt = info->dabt; + + spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags); + + offset = info->gpa - + (v->domain->arch.vgic.propbase & GICR_PROPBASER_PA_MASK); + + p = ((u8 *)v->domain->arch.vgic.prop_page + offset); + val = (u8 *)&r; + iter = 1 << dabt.size; + + for ( i = 0 ; i < iter; i++ ) + { + enable = (*p & *val) & LPI_PROP_ENABLED; + + if ( !enable ) + vgic_v3_enable_lpi(v, offset + FIRST_GIC_LPI); + else + vgic_v3_disable_lpi(v, offset + FIRST_GIC_LPI); + + /* Update virtual prop page */ + val++; + p++; + offset++; + } + + spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags); + + return 1; +} + +static const struct mmio_handler_ops vgic_gits_lpi_mmio_handler = { + .read = vgic_v3_gits_lpi_mmio_read, + .write = vgic_v3_gits_lpi_mmio_write, +}; + +static void lpi_prop_table_tasklet_func(unsigned long data) +{ + unsigned long flags; + uint32_t i, id_bits, lpi_size; + struct domain *d = (struct domain *)data; + struct vcpu *v = d->vcpu[0]; + + spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags); + + id_bits = ((v->domain->arch.vgic.propbase & GICR_PROPBASER_IDBITS_MASK) + + 1); + lpi_size = min_t(unsigned int, v->domain->arch.vgic.prop_size, 1 << id_bits); + + for ( i = 0; i < lpi_size / PAGE_SIZE; i++ ) + { + if ( ((i * PAGE_SIZE) + PAGE_SIZE) < v->domain->arch.vgic.nr_lpis ) + vgic_v3_gits_update_lpis_state(v, (i * PAGE_SIZE), PAGE_SIZE); + } + + v->domain->arch.vgic.lpi_prop_table_state = LPI_TAB_UPDATED; + spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags); +} + +static int vgic_v3_map_lpi_prop(struct vcpu *v) +{ + paddr_t gaddr, addr; + unsigned long mfn, flags; + uint32_t id_bits, vgic_id_bits, lpi_size; + int i; + + gaddr = v->domain->arch.vgic.propbase & GICR_PROPBASER_PA_MASK; + id_bits = ((v->domain->arch.vgic.propbase & GICR_PROPBASER_IDBITS_MASK) + + 1); + + vgic_id_bits = get_count_order(v->domain->arch.vgic.nr_lpis + + FIRST_GIC_LPI); + + spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags); + + /* + * Here we limit the size of LPI property table to the number of LPIs + * that domain supports. + */ + lpi_size = 1 << vgic_id_bits; + + /* + * Allocate Virtual LPI Property table. + * TODO: To re-use guest property table + * TODO: Free prog_page table that is already allocated. + */ + v->domain->arch.vgic.prop_page = + alloc_xenheap_pages(get_order_from_bytes(lpi_size), 0); + if ( !v->domain->arch.vgic.prop_page ) + { + spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags); + printk(XENLOG_G_ERR + "d%d: vITS: Fail to allocate LPI Prop page\n", + v->domain->domain_id); + return 0; + } + + v->domain->arch.vgic.prop_size = lpi_size; + + /* + * lpi_size is always aligned to PAGE_SIZE because it is generated from + * vgic_id_bits which is computed using get_count_order. + * + * Consider minimum size of Xen supported size(vgic.nr_lpis) or + * guest allocated size LPI property table. + */ + lpi_size = min_t(unsigned int, v->domain->arch.vgic.prop_size, 1 << id_bits); + + addr = gaddr; + for ( i = 0; i < lpi_size / PAGE_SIZE; i++ ) + { + vgic_access_guest_memory(v->domain, addr, + (void *)(v->domain->arch.vgic.prop_page + + (i * PAGE_SIZE)), PAGE_SIZE, 0); + + /* Unmap LPI property table. */ + mfn = gmfn_to_mfn(v->domain, paddr_to_pfn(addr)); + if ( unlikely(!mfn_valid(mfn)) ) + { + spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags); + printk(XENLOG_G_ERR + "vITS: Invalid propbaser address %"PRIx64" for domain %d\n", + addr, v->domain->domain_id); + return 0; + } + guest_physmap_remove_page(v->domain, paddr_to_pfn(addr), mfn, 0); + addr += PAGE_SIZE; + } + + /* + * Each re-distributor shares a common LPI configuration table + * So one set of mmio handlers to manage configuration table is enough + * + * Register mmio handlers for this region. + */ + register_mmio_handler(v->domain, &vgic_gits_lpi_mmio_handler, + gaddr, v->domain->arch.vgic.prop_size, NULL); + + v->domain->arch.vgic.lpi_prop_table_state = LPI_TAB_IN_PROGRESS; + spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags); + + /* Schedule tasklet */ + tasklet_schedule(&v->domain->arch.vgic.lpi_prop_table_tasklet); + + return 1; +} + static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info, uint32_t gicr_reg, register_t *r) @@ -168,9 +418,11 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info, switch ( gicr_reg ) { case VREG32(GICR_CTLR): - /* We have not implemented LPI's, read zero */ - goto read_as_zero_32; - + if ( dabt.size != DABT_WORD ) goto bad_width; + vgic_lock(v); + *r = vgic_reg32_extract(v->arch.vgic.gicr_ctlr, info); + vgic_unlock(v); + return 1; case VREG32(GICR_IIDR): if ( dabt.size != DABT_WORD ) goto bad_width; *r = vgic_reg32_extract(GICV3_GICR_IIDR_VAL, info); @@ -191,6 +443,12 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info, if ( v->arch.vgic.flags & VGIC_V3_RDIST_LAST ) typer |= GICR_TYPER_LAST; + /* Set Physical LPIs support */ + if ( vgic_is_lpi_supported(v->domain) ) + typer |= GICR_TYPER_PLPIS; + /* Provide vcpu number as target address */ + typer |= (v->vcpu_id << GICR_TYPER_PROCESSOR_SHIFT); + *r = vgic_reg64_extract(typer, info); return 1; @@ -222,12 +480,40 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info, goto read_reserved; case VREG64(GICR_PROPBASER): - /* LPI's not implemented */ - goto read_as_zero_64; + { + uint32_t val; + + if ( !vgic_reg64_check_access(dabt) ) goto bad_width; + if ( !vgic_is_lpi_supported(v->domain) ) + goto read_as_zero_64; + + vgic_lock(v); + val = v->arch.vgic.gicr_ctlr; + vgic_unlock(v); + + vgic_lpi_prop_lock(v); + if ( val & GICR_CTLR_ENABLE_LPIS ) + *r = vgic_reg64_extract(v->domain->arch.vgic.propbase, info); + else + *r = vgic_reg64_extract(v->domain->arch.vgic.propbase_save, info); + vgic_lpi_prop_unlock(v); + return 1; + } case VREG64(GICR_PENDBASER): - /* LPI's not implemented */ - goto read_as_zero_64; + if ( !vgic_reg64_check_access(dabt) ) goto bad_width; + if ( !vgic_is_lpi_supported(v->domain) ) + goto read_as_zero_64; + vgic_lock(v); + /* PTZ field is RAZ */ + if ( v->arch.vgic.gicr_ctlr & GICR_CTLR_ENABLE_LPIS ) + *r = vgic_reg64_extract(v->arch.vgic.pendbase & + ~GICR_PENDBASER_PTZ_MASK, info); + else + *r = vgic_reg64_extract(v->arch.vgic.pendbase_save & + ~GICR_PENDBASER_PTZ_MASK, info); + vgic_unlock(v); + return 1; case 0x0080: goto read_reserved; @@ -329,13 +615,54 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info, register_t r) { struct hsr_dabt dabt = info->dabt; + uint32_t val; switch ( gicr_reg ) { case VREG32(GICR_CTLR): - /* LPI's not implemented */ + if ( dabt.size != DABT_WORD ) goto bad_width; + if ( !vgic_is_lpi_supported(v->domain) ) goto write_ignore_32; + /* + * Enable LPI's for ITS. Direct injection of LPI + * by writing to GICR_{SET,CLR}LPIR is not supported. + */ + vgic_lock(v); + val = v->arch.vgic.gicr_ctlr & GICR_CTLR_ENABLE_LPIS; + vgic_reg32_update(&v->arch.vgic.gicr_ctlr, + (r & GICR_CTLR_ENABLE_LPIS), info); + + /* If no change in GICR_CTRL.EnableLPIs. Just return */ + if ( !((val ^ v->arch.vgic.gicr_ctlr) && + (v->arch.vgic.gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) ) + { + vgic_unlock(v); + return 1; + } + vgic_unlock(v); + vgic_lpi_prop_lock(v); + /* + * On GICR_CTLR.EnableLPIs = 1, update pendbaser and propbase + * with pendbase_save and propbase_save if they are changed. + */ + if ( v->arch.vgic.pendbase_save ^ v->arch.vgic.pendbase ) + v->arch.vgic.pendbase = v->arch.vgic.pendbase_save; + if ( v->domain->arch.vgic.propbase_save ^ v->domain->arch.vgic.propbase ) + { + if ( v->vcpu_id == 0 ) + { + v->domain->arch.vgic.propbase = + v->domain->arch.vgic.propbase_save; + vgic_lpi_prop_unlock(v); + return vgic_v3_map_lpi_prop(v); + } + else + v->domain->arch.vgic.propbase = + v->domain->arch.vgic.propbase_save; + } + vgic_lpi_prop_unlock(v); + return 1; case VREG32(GICR_IIDR): /* RO */ goto write_ignore_32; @@ -370,12 +697,51 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info, goto write_reserved; case VREG64(GICR_PROPBASER): - /* LPI is not implemented */ - goto write_ignore_64; + if ( !vgic_reg64_check_access(dabt) ) goto bad_width; + if ( !vgic_is_lpi_supported(v->domain) ) + goto write_ignore_64; + /* + * As per spec, updating GICR_PROPBASER when GICR_CTLR.EnableLPIs = 1 + * is unpredictable. Here we ignore the update. + */ + vgic_lock(v); + val = v->arch.vgic.gicr_ctlr; + vgic_unlock(v); + + if ( val & GICR_CTLR_ENABLE_LPIS ) + goto write_ignore_64; + vgic_lpi_prop_lock(v); + /* + * LPI configuration tables are shared across cpus. Should be same. + * + * Allow updating on propbase only for vcpu0 once with below check. + * TODO: Manage change in property table. + */ + if ( v->vcpu_id == 0 && v->domain->arch.vgic.propbase_save != 0 ) + { + printk(XENLOG_G_WARNING + "%pv: vGICR: Updating LPI propbase is not allowed\n", v); + vgic_lpi_prop_unlock(v); + return 1; + } + vgic_reg64_update(&v->domain->arch.vgic.propbase_save, r, info); + vgic_lpi_prop_unlock(v); + return 1; case VREG64(GICR_PENDBASER): - /* LPI is not implemented */ - goto write_ignore_64; + if ( !vgic_reg64_check_access(dabt) ) goto bad_width; + if ( !vgic_is_lpi_supported(v->domain) ) + goto write_ignore_64; + /* Just hold pendbaser value for guest read */ + vgic_lock(v); + if ( v->arch.vgic.gicr_ctlr & GICR_CTLR_ENABLE_LPIS ) + { + vgic_unlock(v); + goto write_ignore_64; + } + vgic_reg64_update(&v->arch.vgic.pendbase_save, r, info); + vgic_unlock(v); + return 1; case 0x0080: goto write_reserved; @@ -441,7 +807,7 @@ bad_width: return 0; write_ignore_64: - if ( vgic_reg64_check_access(dabt) ) goto bad_width; + if ( !vgic_reg64_check_access(dabt) ) goto bad_width; return 1; write_ignore_32: @@ -899,11 +1265,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info, case VREG32(GICD_TYPER): { - /* - * Number of interrupt identifier bits supported by the GIC - * Stream Protocol Interface - */ - unsigned int irq_bits = get_count_order(vgic_num_irq_lines(v->domain)); + unsigned int irqs; /* * Number of processors that may be used as interrupt targets when ARE * bit is zero. The maximum is 8. @@ -916,7 +1278,15 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info, typer = ((ncpus - 1) << GICD_TYPER_CPUS_SHIFT | DIV_ROUND_UP(v->domain->arch.vgic.nr_spis, 32)); - typer |= (irq_bits - 1) << GICD_TYPER_ID_BITS_SHIFT; + if ( vgic_is_lpi_supported(v->domain) ) + { + irqs = v->domain->arch.vgic.nr_lpis + FIRST_GIC_LPI; + typer |= GICD_TYPER_LPIS_SUPPORTED; + } + else + irqs = vgic_num_irq_lines(v->domain); + + typer |= (get_count_order(irqs) - 1) << GICD_TYPER_ID_BITS_SHIFT; *r = vgic_reg32_extract(typer, info); @@ -1459,6 +1829,17 @@ static int vgic_v3_domain_init(struct domain *d) d->arch.vgic.ctlr = VGICD_CTLR_DEFAULT; + spin_lock_init(&d->arch.vgic.prop_lock); + + if ( is_hardware_domain(d) && vgic_v3_hw.its_support ) + { + if ( vits_domain_init(d) ) + return -ENODEV; + + tasklet_init(&d->arch.vgic.lpi_prop_table_tasklet, + lpi_prop_table_tasklet_func, (unsigned long)d); + } + return 0; } diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 2d89b7c..8d75d90 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -67,6 +67,12 @@ bool_t vgic_is_lpi_supported(struct domain *d) return (d->arch.vgic.nr_lpis != 0); } +static bool_t vgic_is_domain_lpi(struct domain *d, unsigned int lpi) +{ + return ((lpi >= FIRST_GIC_LPI) && + (lpi < (d->arch.vgic.nr_lpis + FIRST_GIC_LPI))); +} + static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq) { INIT_LIST_HEAD(&p->inflight); @@ -186,6 +192,10 @@ void domain_vgic_free(struct domain *d) xfree(d->arch.vgic.shared_irqs); xfree(d->arch.vgic.pending_irqs); xfree(d->arch.vgic.allocated_irqs); + + if ( vgic_is_lpi_supported(d) && d->arch.vgic.prop_page != NULL ) + free_xenheap_pages(d->arch.vgic.prop_page, + get_order_from_bytes(d->arch.vgic.prop_size)); } int vcpu_vgic_init(struct vcpu *v) @@ -232,9 +242,21 @@ static struct vcpu *__vgic_get_target_vcpu(struct vcpu *v, unsigned int virq) struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int virq) { struct vcpu *v_target; - struct vgic_irq_rank *rank = vgic_rank_irq(v, virq); + struct vgic_irq_rank *rank; unsigned long flags; + /* + * We don't have vlpi to plpi mapping and hence we cannot + * have target on which corresponding vlpi is enabled. + * So for now we are always injecting vlpi on vcpu0. + * (See vgic_vcpu_inject_lpi() function) and so we get pending_irq + * structure on vcpu0. + * TODO: Get correct target vcpu + */ + if ( vgic_is_domain_lpi(v->domain, virq) ) + return v->domain->vcpu[0]; + + rank = vgic_rank_irq(v, virq); vgic_lock_rank(v, rank, flags); v_target = __vgic_get_target_vcpu(v, virq); vgic_unlock_rank(v, rank, flags); diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 0904204..48dcd9a 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -12,6 +12,7 @@ #include #include #include +#include struct hvm_domain { @@ -116,6 +117,26 @@ struct arch_domain /* Virtual ITS */ struct vgic_its *vits; #endif + /* LPI propbase */ + uint64_t propbase; + /* + * Holds temparary GICR_PROPBASER register value. This value + * is used to update propbase after GICR_CTLR.EnableLPIs is set to 1. + * This helps to support 32-bit updates on GICR_PROPBASER + */ + uint64_t propbase_save; + /* Virtual LPI property table */ + void *prop_page; + /* Virtual LPI property size */ + uint32_t prop_size; + /* spinlock to protect lpi property table */ + spinlock_t prop_lock; +#define LPI_TAB_IN_PROGRESS 1 +#define LPI_TAB_UPDATED 2 + /* lpi property table state */ + int lpi_prop_table_state; + /* Tasklet for parsing lpi property table */ + struct tasklet lpi_prop_table_tasklet; } vgic; struct vuart { @@ -248,6 +269,16 @@ struct arch_vcpu /* GICv3: redistributor base and flags for this vCPU */ paddr_t rdist_base; + /* GICv3-ITS: LPI pending table for this vCPU */ + uint64_t pendbase; + /* + * Holds temparary GICR_PENDBASER register value. This value + * is used to update propbase after GICR_CTLR.EnableLPIs is set to 1. + * This helps to support 32-bit updates on GICR_PENDBASER. + */ + uint64_t pendbase_save; + /* GICv3: Redistributor control register */ + uint32_t gicr_ctlr; #define VGIC_V3_RDIST_LAST (1 << 0) /* last vCPU of the rdist */ uint8_t flags; } vgic; diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h index 26b2b9e..aad51fa 100644 --- a/xen/include/asm-arm/gic-its.h +++ b/xen/include/asm-arm/gic-its.h @@ -114,6 +114,7 @@ #define LPI_PROP_ENABLED (1 << 0) #define LPI_PROP_GROUP1 (1 << 1) +#define LPI_PRIORITY_MASK (0xfc) /* * Collection structure - just an ID, and a redistributor address to diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h index 843da8a..bf3c53d 100644 --- a/xen/include/asm-arm/gic_v3_defs.h +++ b/xen/include/asm-arm/gic_v3_defs.h @@ -129,14 +129,17 @@ #define GICR_PROPBASER_WaWb (5U << 7) #define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7) #define GICR_PROPBASER_IDBITS_MASK (0x1f) +#define GICR_PROPBASER_PA_MASK (0xfffffffff000UL) #define GICR_TYPER_PLPIS (1U << 0) #define GICR_TYPER_VLPIS (1U << 1) #define GICR_TYPER_LAST (1U << 4) +#define GICR_TYPER_PROCESSOR_SHIFT (8) #define GICR_PENDBASER_InnerShareable (1U << 10) #define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10) #define GICR_PENDBASER_nC (1U << 7) #define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7) +#define GICR_PENDBASER_PTZ_MASK (1UL << 62) #define DEFAULT_PMR_VALUE 0xff diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index 35d06b8..473fd8e 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -143,6 +143,9 @@ struct vgic_ops { #define vgic_lock_rank(v, r, flags) spin_lock_irqsave(&(r)->lock, flags) #define vgic_unlock_rank(v, r, flags) spin_unlock_irqrestore(&(r)->lock, flags) +#define vgic_lpi_prop_lock(v) spin_lock_irq(&(v)->domain->arch.vgic.prop_lock) +#define vgic_lpi_prop_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.prop_lock) + /* * Rank containing GICD_ for GICD_ with * -bits-per-interrupt