From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.5 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,MSGID_FROM_MTA_HEADER,SPF_HELO_NONE, SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 62ECCC4338F for ; Tue, 27 Jul 2021 07:26:53 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1E4B56113B for ; Tue, 27 Jul 2021 07:26:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 1E4B56113B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=JeETGFCukYe0zne92RGwjM5g4sh5UxQWRBucOPXvB28=; b=XW0QJg42wgyMqb kL+hbExhC0+qLdPZkuef+MR0/f1XzxydCNm9Er1SP9sFs9TutExl+Gb2GY/vBWNofXNEo/hjmSPdL zWIIxquHnfXQG/WGrORpbT3hbvSI9CLJoqot4f+rkAxYvRb/VzAAOHsaNNk40YSbzaZ+ELsQO6x+x Af7ZctXveDCHFPdalrORDsG1Uy9BoO+gcym5r4B0LZqNCk+7EL3zTBq6h2tPXpx/iGnDnAbF+KWs3 TldvseVXLeA6nGOR6WK35k/uvDXUKXB/avb83TYR4EPsM9gteSf0W41RcCWsqgD85FpPlkbht9Ln2 JHRB+ULKBxcJbnzN5NXg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m8HTx-00DpC8-Cc; Tue, 27 Jul 2021 07:26:29 +0000 Received: from esa3.hgst.iphmx.com ([216.71.153.141]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m8G4Z-00DV0D-Hu; Tue, 27 Jul 2021 05:56:14 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1627365371; x=1658901371; h=from:to:cc:subject:date:message-id:in-reply-to: references:content-transfer-encoding:mime-version; bh=AeuDd1iZoXJqwqyIsfDLoDbcTkME5EvOFsQ8cYh4hEs=; b=hMahgNt4XEWJVVAm0Ki/bVKtLDs+PREKaBxs4OwGlA6m5JQ98o+DZL45 +WYA7Twv1ZmpkT/B0iPaX6y6ciL2Fx502uxtcICPmKgrWpI2tKPinjy28 HAZ9vuwm4pPd4xz5arW04Y5kmjrZwVaFBt/9T7r5khqYtb+jEYBnUpsAl 38Tl85MgpbJNajHT/qih/1K+jSJQyFidwLe4wPFzBUo9tCK1TxhFpEYyu 44D7IMUKPxaC7iVT7uyn1XQaAIXiMrO7h64AsJTTJviG6WOg5kUOQUYbj iF8OjLhnaBlJQTQROXdtmGy1O3s69aPHLDuPxsZzCh+Mh8SqGXKGJQL93 g==; X-IronPort-AV: E=Sophos;i="5.84,272,1620662400"; d="scan'208";a="180385936" Received: from mail-mw2nam12lp2048.outbound.protection.outlook.com (HELO NAM12-MW2-obe.outbound.protection.outlook.com) ([104.47.66.48]) by ob1.hgst.iphmx.com with ESMTP; 27 Jul 2021 13:56:10 +0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=dORkhkzWh8cJIvxAJ/45azoxZZE6sKKbalMCJSs2QGX/tZE0TlqwydZkWEHwtpGwN3VGksR2vQycD/OqZiwwwLe28y//Gt2tc0XyfnadBM0QLAI//VjxMe6R+7fyLM4+i4mbQjbXBHPfCHe5mJbvazC4SrOtiXqem+wi9s/GpKjyqtaeRfuyVy03TQX9tMXFjrB17KsEPftd3TTb9n1NDgZ5EMNqNEgSgygQKnt43Gmqm78C4tPurcDtNzqa/T4ECjnCzUKOsHia3w+abUYirAGPjLCqC7C8cAWDA11UUK/uabmyGulTfCsxQkFdBGjvz8YIIw0e7+KYik9eJe9sIQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=5fDRp5cm7yGsPgBQa8g4psIHTTiBDDbuJnt3WL6jOEs=; b=oR+IDU9ZWkrMrZYv6aD+HSmE0FWmJHm9ibUu6iF5j945NNwE6dMV5o/hw0noxzWSp/Cd5dHR7bS9XHXxlvzUwCMekEKYDz49Mncyjw2gIM+2UgStryheDZee2UKFxrtEQ72swNIgTcyvzlc9+PahLOCiHc0PkOMZDFOLVoLLasy5+hArA/JBJDv1XLSOoGxWdcn4uhWi3ZNyBQBLe2xtQS9QQ5vLDS+5ubQU5iWtoQfGAuQHCnXF3QmXUEmoCR5KvMC3dfIsvqrfV4G9es2liE9ST9nHeQdPVEh3d9nhfw5MX1qMThEzSQRxdEcYucx0ftPP7BM30wszKI1x97+vHg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=wdc.com; dmarc=pass action=none header.from=wdc.com; dkim=pass header.d=wdc.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sharedspace.onmicrosoft.com; s=selector2-sharedspace-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=5fDRp5cm7yGsPgBQa8g4psIHTTiBDDbuJnt3WL6jOEs=; b=D/DII67IgpNbniGPLV0fYsSjvJ6/J2JIUsY97/EQuKjZUPtoO5LJaoGBr/qnYQkcjY7QXWjmUSsE95XraCp+jTwfSIvALfUZa6x60q7VfZy85DUz1Ain+Cs6GkoccMikVjWfFVBHAqFvTrPhfwHrnpHrX1xz+7H4OF1frrDvKnc= Authentication-Results: dabbelt.com; dkim=none (message not signed) header.d=none;dabbelt.com; dmarc=none action=none header.from=wdc.com; Received: from CO6PR04MB7812.namprd04.prod.outlook.com (2603:10b6:303:138::6) by CO6PR04MB8377.namprd04.prod.outlook.com (2603:10b6:303:140::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4352.29; Tue, 27 Jul 2021 05:56:09 +0000 Received: from CO6PR04MB7812.namprd04.prod.outlook.com ([fe80::a153:b7f8:c87f:89f8]) by CO6PR04MB7812.namprd04.prod.outlook.com ([fe80::a153:b7f8:c87f:89f8%8]) with mapi id 15.20.4352.031; Tue, 27 Jul 2021 05:56:09 +0000 From: Anup Patel To: Palmer Dabbelt , Palmer Dabbelt , Paul Walmsley , Albert Ou , Paolo Bonzini Cc: Alexander Graf , Atish Patra , Alistair Francis , Damien Le Moal , Anup Patel , kvm@vger.kernel.org, kvm-riscv@lists.infradead.org, linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, Anup Patel , Daniel Lezcano Subject: [PATCH v19 12/17] RISC-V: KVM: Add timer functionality Date: Tue, 27 Jul 2021 11:24:45 +0530 Message-Id: <20210727055450.2742868-13-anup.patel@wdc.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210727055450.2742868-1-anup.patel@wdc.com> References: <20210727055450.2742868-1-anup.patel@wdc.com> X-ClientProxiedBy: MA1PR0101CA0030.INDPRD01.PROD.OUTLOOK.COM (2603:1096:a00:22::16) To CO6PR04MB7812.namprd04.prod.outlook.com (2603:10b6:303:138::6) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from wdc.com (122.171.179.229) by MA1PR0101CA0030.INDPRD01.PROD.OUTLOOK.COM (2603:1096:a00:22::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4352.26 via Frontend Transport; Tue, 27 Jul 2021 05:56:05 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: a32fed39-1052-4421-bedb-08d950c33b63 X-MS-TrafficTypeDiagnostic: CO6PR04MB8377: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: WDCIPOUTBOUND: EOP-TRUE X-MS-Oob-TLC-OOBClassifiers: OLM:862; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: K2rC+7bP3F9aFfAejt97w+kDBFTASgHRrX6cYjswyJ8jUD6TvtbxfYNI7+sVZH6afG6THQErrvs1vUiqc1+NiutLaxRip8ixsy/y/jkys4r0Llyy+sexZ8Fd9Rjwo8x4AR/w4ifeUcaNSWnr9b2JUHq7B6dD/sb1FouCl4NY4whINstzYfW7nz1FMGQm3qnD2kKiIvX0SEcLUe7Y3sv+gaVIvzIq/iFAHPbJo0OWZiDfJAdubyhWBVLLYD1RcrhQOXhaly0OEmv8M9ltoVXhl9t3q7RrQxqeuGqfQ+LDXA9oHE81Witzf/gbTA7F9Z29O4Ph0/Zlf2q0zRHgvO6QSyjY3W8SYvJzVazYurXR0wRLgTi313PaC92JLisePPrC7VaUDH2AlCv4j0eyhnEC75wHIZlh5nZUiUYmt7pDnA5kK4unImud8gnyjZ5owmYsWRk+SU/SBBuZxP63JtD5B9/e+q3sTB8OL7cw+4aKn7rQGG+q+GLWInojh1h+no8nF4Swsl0RbWdmLVdXycybu1IATZK4o/hCaouVqmKNMBQ9bYz+JZtR6+loUtZqgP60q+Z6lyDr994ixbi6RSvwMqufLEqiHMqRvJa9tEyW6IpTok6vqCjDS+8O6NfCwQE1uVfZJdlnQNScDNhuZ0SgA2CXEG94fSM1ACMFq3kdi6ZOgtscz/wXp3Wf35DHOhaK X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:CO6PR04MB7812.namprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(4636009)(366004)(7696005)(52116002)(26005)(66946007)(54906003)(5660300002)(6666004)(956004)(2616005)(8936002)(186003)(38100700002)(316002)(36756003)(508600001)(8886007)(7416002)(66476007)(2906002)(1076003)(110136005)(86362001)(30864003)(44832011)(83380400001)(8676002)(4326008)(66556008)(55016002)(38350700002); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?tFVMN8OMrQCX7ujqLXVl+ptbAFy2OoZF9GsiYUWfC7giSkKsiEANOvETuOkq?= =?us-ascii?Q?50h19MBJTb04KO8E2ikG+Jk5U9NcVei1Cz4llS4LI3MlSfMZ2Ee5Whkvuv+k?= =?us-ascii?Q?2CcW9MtDW7NCJDLGKB6xY3xtSlAO2qnNHU+OicRm5+1IisP/h0sGEbfYYmgh?= =?us-ascii?Q?pFAc1oP7lBjVFipiACa+yvrlncQ6BrRGMUHZsjA+zsH+jV6LRch9DaXYi9g8?= =?us-ascii?Q?nU6IiNj1l63enGAuHcep/JxSv0vBGmzRI3PoBo93zz9guFRWNggFk/lyBLSj?= =?us-ascii?Q?ajbtJaVGt5XFSFRtiupauBtZHFjAK/yqawD0pCXXBQQFnWGNTh1GdaLB+y1Y?= =?us-ascii?Q?foEOciXyrqPNUaTVvDIGVswPdtyanL7WtmvUQ01oPmZFStvVijoAoJJT6dkh?= =?us-ascii?Q?YJcUqT/cIdRDbKKjQhNR/XKcWSsvG83NKbSabFglDXiPhVFn8+Iy8r4X8zzZ?= =?us-ascii?Q?ya3SFz22RxMsCynTd3s9b0iBk4RZ3LxBa+lgdloija9st7JK40fuLQ90b1f6?= =?us-ascii?Q?2LUPsssIKmdYhYPydvtc+kiO0C1ULGjS4+ti0DEXvaiPfSFA9OLWghhM092f?= =?us-ascii?Q?8ihNA9tp42k/Yw3AdVC/lSbY8FZeck6x6HGstbXgtoLZ/aC1L36RUUwOAX2a?= =?us-ascii?Q?iIMyaNcoJGgmvvzYA4j6Hmr3dlOiqQovoaz+a1aHrqjvuUu3vWTvFi4FxfSV?= =?us-ascii?Q?txIIsTT7heN3Zbe0enZE+iaaQTBgOH3EWuv2fZi3/eRR7YbXDzcACE+MIXW/?= =?us-ascii?Q?JmP6cDU4zMtBSbKuTUbWjdiiypy7lIN9v6JMyAx7kb9OumZQHsxZ9weCz55b?= =?us-ascii?Q?RqnYkeNOWyqJxrUZ4PCGRo2IdgIay3mh3jnIoHCpx+B+BIf+h63w1cZ2v9wl?= =?us-ascii?Q?MJFAABS43mV1p+vo1SRxeDSqVUKbzVTVYuhhl39iYRZwhAVg6Nf7jw59wcvE?= =?us-ascii?Q?lNJ4pshLB75xd8Og5P3tZE4LHJlPVbH+3k+WwyFw7U9Fns9ioecT0jyWISf0?= =?us-ascii?Q?IPsHL/38hQELzCFaO/Gp4jXHfnUnrVYJUZUUwcVOy/QjDOdz9Z4lw3uNDzd5?= =?us-ascii?Q?CDldTGjYTeNHx04PBpdzdBhcqfxhn1O0v9OE0c/bfXp9dALb2h4oTb/MbpnK?= =?us-ascii?Q?NdsK9shxnomm+SU2Vk9esB3eFBwFq7yniNQ6FDPMcQNqf7PLyIsfr3G4r8Sh?= =?us-ascii?Q?vF4UC+jcY9WVIXr7e3pv2z1lesehsHPDGDSB5WOuOvjGmlN9HlNmYfgTyDKF?= =?us-ascii?Q?1tQnQCV6n8MzKgK/uJxyYwrT1ZTgfL8ipS4PjSgKbFEzPb8Bggeibr1U1I7U?= =?us-ascii?Q?82kO8k6SEvuzxlhFLoiUVHPK?= X-OriginatorOrg: wdc.com X-MS-Exchange-CrossTenant-Network-Message-Id: a32fed39-1052-4421-bedb-08d950c33b63 X-MS-Exchange-CrossTenant-AuthSource: CO6PR04MB7812.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 27 Jul 2021 05:56:09.6386 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: b61c8803-16f3-4c35-9b17-6f65f441df86 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: BSvJ1spWiPvCi1ZJPVh4LQZaC4LXjMmJLpjDw95FXgl3O5+lJ//vNNqBpo4zSTmSnlq4jR2JlW1QOSpdb58l7Q== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CO6PR04MB8377 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210726_225611_690590_79439F5D X-CRM114-Status: GOOD ( 23.47 ) X-BeenThere: linux-riscv@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-riscv" Errors-To: linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org From: Atish Patra The RISC-V hypervisor specification doesn't have any virtual timer feature. Due to this, the guest VCPU timer will be programmed via SBI calls. The host will use a separate hrtimer event for each guest VCPU to provide timer functionality. We inject a virtual timer interrupt to the guest VCPU whenever the guest VCPU hrtimer event expires. This patch adds guest VCPU timer implementation along with ONE_REG interface to access VCPU timer state from user space. Signed-off-by: Atish Patra Signed-off-by: Anup Patel Acked-by: Paolo Bonzini Reviewed-by: Paolo Bonzini Acked-by: Daniel Lezcano --- arch/riscv/include/asm/kvm_host.h | 7 + arch/riscv/include/asm/kvm_vcpu_timer.h | 44 +++++ arch/riscv/include/uapi/asm/kvm.h | 17 ++ arch/riscv/kvm/Makefile | 1 + arch/riscv/kvm/vcpu.c | 14 ++ arch/riscv/kvm/vcpu_timer.c | 225 ++++++++++++++++++++++++ arch/riscv/kvm/vm.c | 2 +- drivers/clocksource/timer-riscv.c | 9 + include/clocksource/timer-riscv.h | 16 ++ 9 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/include/asm/kvm_vcpu_timer.h create mode 100644 arch/riscv/kvm/vcpu_timer.c create mode 100644 include/clocksource/timer-riscv.h diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index a54a58a4026d..18b4ec1b5105 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef CONFIG_64BIT #define KVM_MAX_VCPUS (1U << 16) @@ -60,6 +61,9 @@ struct kvm_arch { /* stage2 page table */ pgd_t *pgd; phys_addr_t pgd_phys; + + /* Guest Timer */ + struct kvm_guest_timer timer; }; struct kvm_mmio_decode { @@ -175,6 +179,9 @@ struct kvm_vcpu_arch { unsigned long irqs_pending; unsigned long irqs_pending_mask; + /* VCPU Timer */ + struct kvm_vcpu_timer timer; + /* MMIO instruction details */ struct kvm_mmio_decode mmio_decode; diff --git a/arch/riscv/include/asm/kvm_vcpu_timer.h b/arch/riscv/include/asm/kvm_vcpu_timer.h new file mode 100644 index 000000000000..375281eb49e0 --- /dev/null +++ b/arch/riscv/include/asm/kvm_vcpu_timer.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Atish Patra + */ + +#ifndef __KVM_VCPU_RISCV_TIMER_H +#define __KVM_VCPU_RISCV_TIMER_H + +#include + +struct kvm_guest_timer { + /* Mult & Shift values to get nanoseconds from cycles */ + u32 nsec_mult; + u32 nsec_shift; + /* Time delta value */ + u64 time_delta; +}; + +struct kvm_vcpu_timer { + /* Flag for whether init is done */ + bool init_done; + /* Flag for whether timer event is configured */ + bool next_set; + /* Next timer event cycles */ + u64 next_cycles; + /* Underlying hrtimer instance */ + struct hrtimer hrt; +}; + +int kvm_riscv_vcpu_timer_next_event(struct kvm_vcpu *vcpu, u64 ncycles); +int kvm_riscv_vcpu_get_reg_timer(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg); +int kvm_riscv_vcpu_set_reg_timer(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg); +int kvm_riscv_vcpu_timer_init(struct kvm_vcpu *vcpu); +int kvm_riscv_vcpu_timer_deinit(struct kvm_vcpu *vcpu); +int kvm_riscv_vcpu_timer_reset(struct kvm_vcpu *vcpu); +void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu); +int kvm_riscv_guest_timer_init(struct kvm *kvm); + +#endif diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index f7e9dc388d54..08691dd27bcf 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -74,6 +74,18 @@ struct kvm_riscv_csr { unsigned long scounteren; }; +/* TIMER registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ +struct kvm_riscv_timer { + __u64 frequency; + __u64 time; + __u64 compare; + __u64 state; +}; + +/* Possible states for kvm_riscv_timer */ +#define KVM_RISCV_TIMER_STATE_OFF 0 +#define KVM_RISCV_TIMER_STATE_ON 1 + #define KVM_REG_SIZE(id) \ (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) @@ -96,6 +108,11 @@ struct kvm_riscv_csr { #define KVM_REG_RISCV_CSR_REG(name) \ (offsetof(struct kvm_riscv_csr, name) / sizeof(unsigned long)) +/* Timer registers are mapped as type 4 */ +#define KVM_REG_RISCV_TIMER (0x04 << KVM_REG_RISCV_TYPE_SHIFT) +#define KVM_REG_RISCV_TIMER_REG(name) \ + (offsetof(struct kvm_riscv_timer, name) / sizeof(__u64)) + #endif #endif /* __LINUX_KVM_RISCV_H */ diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile index a0274763e096..4beb4e277e96 100644 --- a/arch/riscv/kvm/Makefile +++ b/arch/riscv/kvm/Makefile @@ -21,3 +21,4 @@ kvm-y += mmu.o kvm-y += vcpu.o kvm-y += vcpu_exit.o kvm-y += vcpu_switch.o +kvm-y += vcpu_timer.o diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index e565bb158172..f26b249eae8e 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -60,6 +60,8 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) memcpy(cntx, reset_cntx, sizeof(*cntx)); + kvm_riscv_vcpu_timer_reset(vcpu); + WRITE_ONCE(vcpu->arch.irqs_pending, 0); WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0); } @@ -87,6 +89,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) cntx->hstatus |= HSTATUS_SPVP; cntx->hstatus |= HSTATUS_SPV; + /* Setup VCPU timer */ + kvm_riscv_vcpu_timer_init(vcpu); + /* Reset VCPU */ kvm_riscv_reset_vcpu(vcpu); @@ -99,6 +104,9 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { + /* Cleanup VCPU timer */ + kvm_riscv_vcpu_timer_deinit(vcpu); + /* Flush the pages pre-allocated for Stage2 page table mappings */ kvm_riscv_stage2_flush_cache(vcpu); } @@ -339,6 +347,8 @@ static int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, return kvm_riscv_vcpu_set_reg_core(vcpu, reg); else if ((reg->id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_CSR) return kvm_riscv_vcpu_set_reg_csr(vcpu, reg); + else if ((reg->id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_TIMER) + return kvm_riscv_vcpu_set_reg_timer(vcpu, reg); return -EINVAL; } @@ -352,6 +362,8 @@ static int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, return kvm_riscv_vcpu_get_reg_core(vcpu, reg); else if ((reg->id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_CSR) return kvm_riscv_vcpu_get_reg_csr(vcpu, reg); + else if ((reg->id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_TIMER) + return kvm_riscv_vcpu_get_reg_timer(vcpu, reg); return -EINVAL; } @@ -584,6 +596,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) kvm_riscv_stage2_update_hgatp(vcpu); + kvm_riscv_vcpu_timer_restore(vcpu); + vcpu->cpu = cpu; } diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c new file mode 100644 index 000000000000..ddd0ce727b83 --- /dev/null +++ b/arch/riscv/kvm/vcpu_timer.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Atish Patra + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static u64 kvm_riscv_current_cycles(struct kvm_guest_timer *gt) +{ + return get_cycles64() + gt->time_delta; +} + +static u64 kvm_riscv_delta_cycles2ns(u64 cycles, + struct kvm_guest_timer *gt, + struct kvm_vcpu_timer *t) +{ + unsigned long flags; + u64 cycles_now, cycles_delta, delta_ns; + + local_irq_save(flags); + cycles_now = kvm_riscv_current_cycles(gt); + if (cycles_now < cycles) + cycles_delta = cycles - cycles_now; + else + cycles_delta = 0; + delta_ns = (cycles_delta * gt->nsec_mult) >> gt->nsec_shift; + local_irq_restore(flags); + + return delta_ns; +} + +static enum hrtimer_restart kvm_riscv_vcpu_hrtimer_expired(struct hrtimer *h) +{ + u64 delta_ns; + struct kvm_vcpu_timer *t = container_of(h, struct kvm_vcpu_timer, hrt); + struct kvm_vcpu *vcpu = container_of(t, struct kvm_vcpu, arch.timer); + struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; + + if (kvm_riscv_current_cycles(gt) < t->next_cycles) { + delta_ns = kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t); + hrtimer_forward_now(&t->hrt, ktime_set(0, delta_ns)); + return HRTIMER_RESTART; + } + + t->next_set = false; + kvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_TIMER); + + return HRTIMER_NORESTART; +} + +static int kvm_riscv_vcpu_timer_cancel(struct kvm_vcpu_timer *t) +{ + if (!t->init_done || !t->next_set) + return -EINVAL; + + hrtimer_cancel(&t->hrt); + t->next_set = false; + + return 0; +} + +int kvm_riscv_vcpu_timer_next_event(struct kvm_vcpu *vcpu, u64 ncycles) +{ + struct kvm_vcpu_timer *t = &vcpu->arch.timer; + struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; + u64 delta_ns; + + if (!t->init_done) + return -EINVAL; + + kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_TIMER); + + delta_ns = kvm_riscv_delta_cycles2ns(ncycles, gt, t); + t->next_cycles = ncycles; + hrtimer_start(&t->hrt, ktime_set(0, delta_ns), HRTIMER_MODE_REL); + t->next_set = true; + + return 0; +} + +int kvm_riscv_vcpu_get_reg_timer(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + struct kvm_vcpu_timer *t = &vcpu->arch.timer; + struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; + u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_TIMER); + u64 reg_val; + + if (KVM_REG_SIZE(reg->id) != sizeof(u64)) + return -EINVAL; + if (reg_num >= sizeof(struct kvm_riscv_timer) / sizeof(u64)) + return -EINVAL; + + switch (reg_num) { + case KVM_REG_RISCV_TIMER_REG(frequency): + reg_val = riscv_timebase; + break; + case KVM_REG_RISCV_TIMER_REG(time): + reg_val = kvm_riscv_current_cycles(gt); + break; + case KVM_REG_RISCV_TIMER_REG(compare): + reg_val = t->next_cycles; + break; + case KVM_REG_RISCV_TIMER_REG(state): + reg_val = (t->next_set) ? KVM_RISCV_TIMER_STATE_ON : + KVM_RISCV_TIMER_STATE_OFF; + break; + default: + return -EINVAL; + }; + + if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; +} + +int kvm_riscv_vcpu_set_reg_timer(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + struct kvm_vcpu_timer *t = &vcpu->arch.timer; + struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; + u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_TIMER); + u64 reg_val; + int ret = 0; + + if (KVM_REG_SIZE(reg->id) != sizeof(u64)) + return -EINVAL; + if (reg_num >= sizeof(struct kvm_riscv_timer) / sizeof(u64)) + return -EINVAL; + + if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + switch (reg_num) { + case KVM_REG_RISCV_TIMER_REG(frequency): + ret = -EOPNOTSUPP; + break; + case KVM_REG_RISCV_TIMER_REG(time): + gt->time_delta = reg_val - get_cycles64(); + break; + case KVM_REG_RISCV_TIMER_REG(compare): + t->next_cycles = reg_val; + break; + case KVM_REG_RISCV_TIMER_REG(state): + if (reg_val == KVM_RISCV_TIMER_STATE_ON) + ret = kvm_riscv_vcpu_timer_next_event(vcpu, reg_val); + else + ret = kvm_riscv_vcpu_timer_cancel(t); + break; + default: + ret = -EINVAL; + break; + }; + + return ret; +} + +int kvm_riscv_vcpu_timer_init(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_timer *t = &vcpu->arch.timer; + + if (t->init_done) + return -EINVAL; + + hrtimer_init(&t->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + t->hrt.function = kvm_riscv_vcpu_hrtimer_expired; + t->init_done = true; + t->next_set = false; + + return 0; +} + +int kvm_riscv_vcpu_timer_deinit(struct kvm_vcpu *vcpu) +{ + int ret; + + ret = kvm_riscv_vcpu_timer_cancel(&vcpu->arch.timer); + vcpu->arch.timer.init_done = false; + + return ret; +} + +int kvm_riscv_vcpu_timer_reset(struct kvm_vcpu *vcpu) +{ + return kvm_riscv_vcpu_timer_cancel(&vcpu->arch.timer); +} + +void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu) +{ + struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; + +#ifdef CONFIG_64BIT + csr_write(CSR_HTIMEDELTA, gt->time_delta); +#else + csr_write(CSR_HTIMEDELTA, (u32)(gt->time_delta)); + csr_write(CSR_HTIMEDELTAH, (u32)(gt->time_delta >> 32)); +#endif +} + +int kvm_riscv_guest_timer_init(struct kvm *kvm) +{ + struct kvm_guest_timer *gt = &kvm->arch.timer; + + riscv_cs_get_mult_shift(>->nsec_mult, >->nsec_shift); + gt->time_delta = -get_cycles64(); + + return 0; +} diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c index 0110267eb7e3..3b6cfc633d6e 100644 --- a/arch/riscv/kvm/vm.c +++ b/arch/riscv/kvm/vm.c @@ -41,7 +41,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) return r; } - return 0; + return kvm_riscv_guest_timer_init(kvm); } void kvm_arch_destroy_vm(struct kvm *kvm) diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c index c51c5ed15aa7..1767f8bf2013 100644 --- a/drivers/clocksource/timer-riscv.c +++ b/drivers/clocksource/timer-riscv.c @@ -13,10 +13,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -79,6 +81,13 @@ static int riscv_timer_dying_cpu(unsigned int cpu) return 0; } +void riscv_cs_get_mult_shift(u32 *mult, u32 *shift) +{ + *mult = riscv_clocksource.mult; + *shift = riscv_clocksource.shift; +} +EXPORT_SYMBOL_GPL(riscv_cs_get_mult_shift); + /* called directly from the low-level interrupt handler */ static irqreturn_t riscv_timer_interrupt(int irq, void *dev_id) { diff --git a/include/clocksource/timer-riscv.h b/include/clocksource/timer-riscv.h new file mode 100644 index 000000000000..d7f455754e60 --- /dev/null +++ b/include/clocksource/timer-riscv.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Atish Patra + */ + +#ifndef __TIMER_RISCV_H +#define __TIMER_RISCV_H + +#include + +extern void riscv_cs_get_mult_shift(u32 *mult, u32 *shift); + +#endif -- 2.25.1 _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv