From patchwork Mon Jul 25 09:32:11 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Suthikulpanit, Suravee" X-Patchwork-Id: 72694 Delivered-To: patch@linaro.org Received: by 10.140.29.52 with SMTP id a49csp1048430qga; Mon, 25 Jul 2016 02:34:35 -0700 (PDT) X-Received: by 10.66.42.33 with SMTP id k1mr27786035pal.111.1469439275409; Mon, 25 Jul 2016 02:34:35 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p1si32811939paw.148.2016.07.25.02.34.35; Mon, 25 Jul 2016 02:34:35 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@amdcloud.onmicrosoft.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753154AbcGYJeb (ORCPT + 29 others); Mon, 25 Jul 2016 05:34:31 -0400 Received: from mail-sn1nam01on0076.outbound.protection.outlook.com ([104.47.32.76]:16256 "EHLO NAM01-SN1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753084AbcGYJeB (ORCPT ); Mon, 25 Jul 2016 05:34:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amdcloud.onmicrosoft.com; s=selector1-amd-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=rqzSrkT7oBL5tuFm60NxM8Di/f7exeFF38ctBWjpV5o=; b=FU40Zujs7hgT/fC4MbXW8MXf/cR2XRjjeGLIFaBysV7KutVXPwoh4AaiG7zDacRiD7EFWOY38oBd9bWCnbdMSgv+wKhId4FCHt6mVmX8IwGmfA3sdelhlUnTy4LjZirGrsAw2IFlRWq28npjCfWq0fAPpSr7R8NLcBjutQoAbdg= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Suravee.Suthikulpanit@amd.com; Received: from localhost.localdomain (114.109.128.54) by BLUPR12MB0434.namprd12.prod.outlook.com (10.162.92.14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.549.15; Mon, 25 Jul 2016 09:33:39 +0000 From: Suravee Suthikulpanit To: , , , CC: , , , Suravee Suthikulpanit Subject: [PART2 PATCH v5 12/12] svm: Implements update_pi_irte hook to setup posted interrupt Date: Mon, 25 Jul 2016 04:32:11 -0500 Message-ID: <1469439131-11308-13-git-send-email-suravee.suthikulpanit@amd.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1469439131-11308-1-git-send-email-suravee.suthikulpanit@amd.com> References: <1469439131-11308-1-git-send-email-suravee.suthikulpanit@amd.com> MIME-Version: 1.0 X-Originating-IP: [114.109.128.54] X-ClientProxiedBy: SG2PR06CA0066.apcprd06.prod.outlook.com (10.167.73.162) To BLUPR12MB0434.namprd12.prod.outlook.com (10.162.92.14) X-MS-Office365-Filtering-Correlation-Id: a9dbde68-158f-4175-98ac-08d3b46ec418 X-Microsoft-Exchange-Diagnostics: 1; BLUPR12MB0434; 2:+E0iHdMxKq2a50GeMBi7czE1Girqsb9lXIrJ9zDRgjFOFxmNG8AgVoLxSvogSvuCWYLfPnF1xbBJjdWBhyGX8K+fO3R8i/+4yN0oxaf/dpUcjMg0M1Sp/2UvaDe2MGrbHTyANk0pOV7ebBcNlLwdp9L6FqvIctNO8O91gOya3qvGxwMkjYoTm4u00/RjNK0a; 3:cUzPxclOHm2gR8nW/x3x7kER79GVHzvmqDCDJBbH+6Njj6Vv6FYWfFTEVGsz2iKxXgDn/5ebXIFkoL68PmPXbLsEzHt/8BjvB0z+Fb7uA17iNrHIHz1yJ2/I7m2mM79e; 25:Agt/kYXbUstzdEnKNn5EYfVaaBE4o4/llfcL+8C6iH2EPMFPlRG0y1YXrqjpSz0xBiJsd/YYb1L9zDXTsI3LFx+PxAaYlUghHUXThMdI+5bhsb3baV63R1E47HgP9ngTxUzzcwNYx+5ovdM1DIgd5386sQ0Tao0mrK/poB3HED37dUOYSMtwOqkdgmwOAyNuVCSjFEpT7V7YUdhZzvcQ2iQyxQtfHiccBQGAVgSfcU2u+oHyNLDR1fxy1b/HvyFQaG6Fv5sc/5lx4AKPOQfdCL3Pgx/CO+uUrX+0aaKZGXCCgE/khUblFWR6IUicMeLOqaja//g5gq8Nj+ebMAgRSUJSzPqRAixF/l0a6f1G7kPmC6NOafVTYuO/XprrDQVzlm6XdIQ6TTIYbcwJV0VN5lKFGiwOPcJG/zVgxVKU9p4=; 31:5XP84WGfpvlpI2MTDNW6lS7Q2lNE8Y3stwOYWAs+K5U19VVECLXWqYtifNA3UCHQxz9SYZ2opGF8smVLf7cV6ppV9/cWr8Cl2VM+Dn1uK7IGuspkspjTUXgsw4503fqsHLLLfYcGygzLHeLUTZiBjO7rtHA9ozrm1wrvFRNaoX3ilsOcWq6Jny6XbAScr3dzs8pkp2PVgjaZK8zuQVj3Yw== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BLUPR12MB0434; X-Microsoft-Exchange-Diagnostics: 1; BLUPR12MB0434; 20:wNN9CglQCq/VefEeS/ReKl0IFAWdzkvLBUuUUGpdj4fBsgu+CyZ8SI9Ban7HJZgdO2awl65juI+3OvLr9lZ9NxyMKgghJzNDOiSDhYdELqnuND33HBonPUVS3qlcwm4qcTGoS9zWF6Dcrema7B9l6NFCEulrXyR9NNtOVlTjcDhLzD2ke3NpglZcAwTw42nQdN/oT/oOOmOOa9jdQFkC3Lyw4EogQ22t6wQt978A5ZmJ2jZRagTNougY4dIkHkh5VnlucLJSr0L8lsg0ZIFGrZmb7VAc//Vb4lvX8jXBRApDd9NOAI9nhpXRfwkj8xi8UNVEwZ2vUoY+VWQPsG2neGK9YeRgVpGRtlUoCRHRWz3n/hNAr35Im4dj4pZGQsDRxR5EHqx4rpfVfdOCL+IEmm+VqB/KYKpfZN9Oy4pgsWQwmFw7Y06YV7bc2sTBXMtnhhMcx69RWMNk9laYVo+Z5lbAK34RwG9kwfssI7wpk5mAA77Pb4y4DuWcmKuMpqlR; 4:kBQspM4t6uqU1cEO3DzDLd4DQLPQPYsBZqHKEnDymko5coo2eeu4+4LL+aMTueXbwwiQLITPbaHtxmGYV1qvqGTGDzn6l9l0axqldK3nAJ7iby1AbmQTRFPOGE+a94Uz9Rs497zIo4kGYoosR6Rew6xm9ui1EitwVVapBnOSP7iIpoLYh/dPwmear6yjbC0OIG9JZe/jMxKZlMMbl6tbGy7gWJ/rzIBly00E8C3dGHST+/ouf1Nl8nycp5Syp65xpWXXAug4aqloo15+y1li9XCuy693Rzi1PdndwIzd6WaV0vZWPJdDvTYc+HI3JH46jkX9pgs+/g1z4Eb8IhsZa5vsalPiIS5jfwWbVmLcBg3BlJNV1ODT/34RYRjkQeOVstZwS0OWqmMEBhZK3IWDtnRgSpKoQK8zdLHNTiCXUF/7JzxZRcwshXdXNdGmQIcb X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046)(6055026); SRVR:BLUPR12MB0434; BCL:0; PCL:0; RULEID:; SRVR:BLUPR12MB0434; X-Forefront-PRVS: 0014E2CF50 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6069001)(6009001)(7916002)(189002)(199003)(77096005)(229853001)(15650500001)(50986999)(76176999)(586003)(48376002)(105586002)(19580405001)(81156014)(81166006)(8676002)(97736004)(4326007)(42186005)(5001770100001)(189998001)(2906002)(50226002)(19580395003)(50466002)(7846002)(66066001)(5003940100001)(68736007)(92566002)(86362001)(101416001)(7736002)(305945005)(3846002)(6116002)(2950100001)(106356001)(47776003)(36756003)(33646002)(2201001); DIR:OUT; SFP:1101; SCL:1; SRVR:BLUPR12MB0434; H:localhost.localdomain; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; Received-SPF: None (protection.outlook.com: amd.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BLUPR12MB0434; 23:Apigmve2VVhlyp2HqTzVWpDsVq0LV+VieNsnLS6lo?= =?us-ascii?Q?YiT3td5ig0c54XXuOMnjePVK7Vl/mjnf2T0enXWUh/iPxdlfcUd5f7VDfMjt?= =?us-ascii?Q?pPZewDMuLbsKFy+lup4ZnNb6wJALjSaFMEFyap7UNp4wrirxVgk0B12G0MDY?= =?us-ascii?Q?4LkBbSHfgyNTSDS8Nat8+axC0dI8KZ4zBFZ7fDEsr06+O9+rDp11bnSk+jlj?= =?us-ascii?Q?E15vLCtg4xI4qULPkXrRo4dXJM7sigLskK9W50aa6b1+O9vVZnz3uzVGEn0G?= =?us-ascii?Q?7R71Hkfp5/DtL3YD+NKkG40IXGItt6LRebWv8KmAPbwcl0MDSkDcvIM+wHur?= =?us-ascii?Q?wrphLKB38Xpq22oYpSw5WOlcX/Tg0bLIxSU2hQjYFxb9PBglJ0ZicGIJcMAo?= =?us-ascii?Q?Vhvi1DUTw9YDi9AZuYS5qIiHZwkA9zJtz11wkM1bJrZQ/B/Xt4t9g1J290UV?= =?us-ascii?Q?jUUigzQVul7+DdX+Aa++0S9vFKxPY9P4rVuNSrN7JMhJ3e22iG0pyCOOpWQI?= =?us-ascii?Q?IrF8IUfrgUV56+azwofDxET8WQHz1O0FIk4/Z6emSKvsDXP0p2UnhYikDAas?= =?us-ascii?Q?e92zyOVgYYIWyA4y4AepGxDVImTpzFYmQlJ8FIWvKdFP4CPK2AQG3cnci0Fs?= =?us-ascii?Q?4u+yB+e5xqtwPuUZlhXcYSRUTp8vX7txaMB8uReDFx0U008//rzbcJq12ORj?= =?us-ascii?Q?JEJThSiMix7ggz5kSr+K3Hkket7bBlo6HRcL1Z+5VAKlC98EnCBodN1dONBX?= =?us-ascii?Q?UsVRIIwbUBjhAJlHgUzZygdphO9yM6YCX+mHcG3sPMBr0Mcu4iaqKA6jTTQU?= =?us-ascii?Q?3bSw08sTYukZLR/W+QxRXZAV9rCupOCxlWKDECPVVJuRzvJKTeo55GHssWAF?= =?us-ascii?Q?gB3uLJgiVD9dNV5QygdlnEtkMZLhUXxeyK3CKMi3/OVv/X++3aMdQCp9/K0B?= =?us-ascii?Q?pFTRWzAVFsUebFtfq6WLFr+/39bUNHTiWP8IJWiZB6xc0bIyzb5np7DZfsEQ?= =?us-ascii?Q?m1OJiYPgR+sBt1k0i72iKwc4jIXzQAagSmPl++0qjsfvf5qZZzF/UzkTApPP?= =?us-ascii?Q?ryDr2lJvh1dhBJlpggCix5qxmvotqjgDrkWMSUiwmqtSeLTQcmWoFoLYH0i9?= =?us-ascii?Q?U2h0VfXh6Q=3D?= X-Microsoft-Exchange-Diagnostics: 1; BLUPR12MB0434; 6:cVvj8WnivOxWAXh52aZU6JHInDIXiFsglazheWx109WpJV/dUrjBTo0LtHMAIVoSVjqkJwSFm8/VudVdB8WqwOGllPL5U7WNWWvRdhIrGatirv7IjQl79unuYJ9igX2ORkJV0FfUzOeC8WzGPVrLfVbx1BBEE/6NKv+3I1N5hmW5VSOQx4cM8dxVBE5PapWQA7n+xOBo8TutnBsCTCHQR6qurgbfLTfSdCxOVjKO4aVveja3mHf+yXnOaI4zvP+ZSCgH1Guf0r/LXvx4PPtKR4+NXcoRzbybmkaDtV9zLqtXZxRG6UP3moBE9xSfz2JMTbJFUNOlLu8ruKOzeb878Q==; 5:vSAKXXg7xTAC0Ym2EC1IDeWEK9C22yxIoSaG/84PKXG33wPoUBFP009LSXEEVycOznhj5XFiJ2fNSUgc11vxiNnUhvjJUZ5iZ1N9pVeEf+JKChatvbT8z7pDw/iZPZZbsfmj9CY/L9ZdCUo0tM9UBw==; 24:sPM9lBOdl6t7L1NfADj5LuUyL77w22yCwmJi7X136uyyF5Y/CFW79nncqX+pv3bBT5XnqHloUNYYRzjPzPp6atqYQrqrMa/J9sRRjEcCOR0=; 7:CmT4f7XhySAcqCKhWPNN/X8OWl/vf1r87cfL6gAz4UEDU37f6OnMsTPBxq332tD1E24ceuidTgJXKr9YxkZ7FZQ4sdMI3nXprHVybd5OG61tlyULXTx18OaAaYvos4uhCKJ81a5gtbgg/DWiQO4kUwg7MxlSmn3VnzwoKNdpwTd/ZKDsW6YW2Qbo2ZSeIE2PaP+4d8EVcYkLxjbrWqLxP7nsO5qMlC3IrAytLQjs8/LsBrg3NdpWeriKQcubi/yk SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; BLUPR12MB0434; 20:Re46TxokgqEYd67hlDQOD8f0r3HO4fU5CQUJOGsjrOJzEZQDcHF1BMtXBUKCnEjx2LqmMNFlbzBQW+op2xV9Xeu4PKJO6FSLIDYm/NIWy1H+4m9/LBYKFT4p/R2sOBeNVGr4lxLys9ywdFZSCgj+/sKtAHE2UC7fiP+xGN6XmBGpHOGu0VEf5pVF5QTj0Q/IV01ICJQFDZD+5dq+3o4ZA/FXlj2mDT3TWCIZ1q4doGC+Y7qGZnkvnFJVsFWbGWK+ X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 25 Jul 2016 09:33:39.0147 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BLUPR12MB0434 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Suravee Suthikulpanit This patch implements update_pi_irte function hook to allow SVM communicate to IOMMU driver regarding how to set up IRTE for handling posted interrupt. In case AVIC is enabled, during vcpu_load/unload, SVM needs to update IOMMU IRTE with appropriate host physical APIC ID. Also, when vcpu_blocking/unblocking, SVM needs to update the is-running bit in the IOMMU IRTE. Both are achieved via calling amd_iommu_update_ga(). However, if GA mode is not enabled for the pass-through device, IOMMU driver will simply just return when calling amd_iommu_update_ga. Signed-off-by: Suravee Suthikulpanit --- arch/x86/kvm/svm.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 2 deletions(-) -- 1.9.1 diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 2be5ed7..39dc600 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include "trace.h" @@ -199,6 +200,16 @@ struct vcpu_svm { struct page *avic_backing_page; u64 *avic_physical_id_cache; bool avic_is_running; + + /* + * Per-vcpu list of struct amd_iommu_pi_data: + * This is used mainly to track interrupt remapping table entry (IRTE) + * to be updated when the vcpu affinity changes. This avoid the need + * for scanning for IRTE and try to match ga_tag in the IOMMU driver + * (or using hashtable). + */ + struct list_head pi_list; + spinlock_t pi_list_lock; }; #define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFF) @@ -1463,6 +1474,31 @@ free_avic: return err; } +static inline int +avic_update_iommu(struct kvm_vcpu *vcpu, int cpu, phys_addr_t pa, bool r) +{ + int ret; + unsigned long flags; + struct vcpu_svm *svm = to_svm(vcpu); + struct amd_iommu_pi_data *pi; + + if (!kvm_arch_has_assigned_device(vcpu->kvm)) + return 0; + + /* + * Here, we go through the per-vcpu pi_list to update all existing + * interrupt remapping table entry targeting this vcpu. + */ + spin_lock_irqsave(&svm->pi_list_lock, flags); + list_for_each_entry(pi, &svm->pi_list, node) { + ret = amd_iommu_update_ga(cpu, (pa & AVIC_HPA_MASK), r, pi); + if (ret) + break; + } + spin_unlock_irqrestore(&svm->pi_list_lock, flags); + return ret; +} + /** * This function is called during VCPU halt/unhalt. */ @@ -1485,9 +1521,16 @@ static void avic_set_running(struct kvm_vcpu *vcpu, bool is_run) WARN_ON(is_run == !!(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)); entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; - if (is_run) + if (is_run) { entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; - WRITE_ONCE(*(svm->avic_physical_id_cache), entry); + WRITE_ONCE(*(svm->avic_physical_id_cache), entry); + avic_update_iommu(vcpu, h_physical_id, + page_to_phys(svm->avic_backing_page), 1); + } else { + avic_update_iommu(vcpu, h_physical_id, + page_to_phys(svm->avic_backing_page), 0); + WRITE_ONCE(*(svm->avic_physical_id_cache), entry); + } } static void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu) @@ -1514,6 +1557,9 @@ static void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu) entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; WRITE_ONCE(*(svm->avic_physical_id_cache), entry); + avic_update_iommu(vcpu, h_physical_id, + page_to_phys(svm->avic_backing_page), + svm->avic_is_running); } static void avic_vcpu_put(struct kvm_vcpu *vcpu) @@ -1525,6 +1571,10 @@ static void avic_vcpu_put(struct kvm_vcpu *vcpu) return; entry = READ_ONCE(*(svm->avic_physical_id_cache)); + if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) + avic_update_iommu(vcpu, -1, + page_to_phys(svm->avic_backing_page), 0); + entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; WRITE_ONCE(*(svm->avic_physical_id_cache), entry); } @@ -1590,6 +1640,9 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) err = avic_init_backing_page(&svm->vcpu); if (err) goto free_page4; + + INIT_LIST_HEAD(&svm->pi_list); + spin_lock_init(&svm->pi_list_lock); } /* We initialize this flag to true to make sure that the is_running @@ -4386,6 +4439,178 @@ static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec) kvm_vcpu_wake_up(vcpu); } +static void svm_pi_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi) +{ + bool found = false; + unsigned long flags; + struct amd_iommu_pi_data *cur; + + spin_lock_irqsave(&svm->pi_list_lock, flags); + list_for_each_entry(cur, &svm->pi_list, node) { + if (cur->ir_data != pi->ir_data) + continue; + found = true; + break; + } + if (!found) + list_add(&pi->node, &svm->pi_list); + spin_unlock_irqrestore(&svm->pi_list_lock, flags); +} + +static void svm_pi_list_del(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi) +{ + unsigned long flags; + struct amd_iommu_pi_data *cur, *next; + + spin_lock_irqsave(&svm->pi_list_lock, flags); + list_for_each_entry_safe(cur, next, &svm->pi_list, node) { + if (cur->ir_data != pi->ir_data) + continue; + list_del(&cur->node); + kfree(cur); + break; + } + spin_unlock_irqrestore(&svm->pi_list_lock, flags); +} + +/* + * svm_update_pi_irte - set IRTE for Posted-Interrupts + * + * @kvm: kvm + * @host_irq: host irq of the interrupt + * @guest_irq: gsi of the interrupt + * @set: set or unset PI + * returns 0 on success, < 0 on failure + */ +static int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq, + uint32_t guest_irq, bool set) +{ + struct kvm_kernel_irq_routing_entry *e; + struct kvm_irq_routing_table *irq_rt; + int idx, ret = -EINVAL; + + if (!kvm_arch_has_assigned_device(kvm) || + !irq_remapping_cap(IRQ_POSTING_CAP)) + return 0; + + pr_debug("SVM: %s: host_irq=%#x, guest_irq=%#x, set=%#x\n", + __func__, host_irq, guest_irq, set); + + idx = srcu_read_lock(&kvm->irq_srcu); + irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); + WARN_ON(guest_irq >= irq_rt->nr_rt_entries); + + hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) { + struct kvm_lapic_irq irq; + struct vcpu_data vcpu_info; + struct kvm_vcpu *vcpu = NULL; + struct vcpu_svm *svm = NULL; + + if (e->type != KVM_IRQ_ROUTING_MSI) + continue; + + /** + * Note: + * The HW cannot support posting multicast/broadcast + * interrupts to a vCPU. So, we still use interrupt + * remapping for these kind of interrupts. + * + * For lowest-priority interrupts, we only support + * those with single CPU as the destination, e.g. user + * configures the interrupts via /proc/irq or uses + * irqbalance to make the interrupts single-CPU. + */ + kvm_set_msi_irq(e, &irq); + if (kvm_intr_is_single_vcpu(kvm, &irq, &vcpu)) { + svm = to_svm(vcpu); + vcpu_info.pi_desc_addr = page_to_phys(svm->avic_backing_page); + vcpu_info.vector = irq.vector; + + trace_kvm_pi_irte_update(vcpu->vcpu_id, host_irq, e->gsi, + vcpu_info.vector, + vcpu_info.pi_desc_addr, set); + + pr_debug("SVM: %s: use GA mode for irq %u\n", __func__, + irq.vector); + } else { + set = false; + + pr_debug("SVM: %s: use legacy intr remap mode for irq %u\n", + __func__, irq.vector); + } + + /** + * When AVIC is disabled, we fall-back to setup + * IRTE w/ legacy mode + */ + if (set && kvm_vcpu_apicv_active(&svm->vcpu)) { + struct amd_iommu_pi_data *pi_data; + + /** + * Allocating new amd_iommu_pi_data, which will get + * add to the per-vcpu pi_list. + */ + pi_data = kzalloc(sizeof(struct amd_iommu_pi_data), + GFP_KERNEL); + if (!pi_data) { + ret = -ENOMEM; + goto out; + } + + /* Try to enable guest_mode in IRTE */ + pi_data->ga_tag = AVIC_GATAG(kvm->arch.avic_vm_id, + vcpu->vcpu_id); + pi_data->vcpu_data = &vcpu_info; + pi_data->is_guest_mode = true; + ret = irq_set_vcpu_affinity(host_irq, pi_data); + + /** + * We save the pointer to pi_data in the struct + * vcpu_svm so that we can reference to them directly + * when we update vcpu scheduling information in IOMMU + * irte. + */ + if (!ret && pi_data->is_guest_mode) + svm_pi_list_add(svm, pi_data); + } else { + /* Use legacy mode in IRTE */ + struct amd_iommu_pi_data pi; + + /** + * Here, pi is used to: + * - Tell IOMMU to use legacy mode for this interrupt. + * - Retrieve ga_tag of prior interrupt remapping data. + */ + pi.is_guest_mode = false; + ret = irq_set_vcpu_affinity(host_irq, &pi); + + /** + * We need to check if the interrupt was previously + * setup with the guest_mode by checking if the ga_tag + * was cached. If so, we need to clean up the per-vcpu + * pi_list. + */ + if (!ret && pi.ga_tag) { + struct kvm_vcpu *vcpu = kvm_get_vcpu_by_id(kvm, + AVIC_GATAG_TO_VCPUID(pi.ga_tag)); + + if (vcpu) + svm_pi_list_del(to_svm(vcpu), &pi); + } + } + + if (ret < 0) { + pr_err("%s: failed to update PI IRTE\n", __func__); + goto out; + } + } + + ret = 0; +out: + srcu_read_unlock(&kvm->irq_srcu, idx); + return ret; +} + static int svm_nmi_allowed(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -5212,6 +5437,7 @@ static struct kvm_x86_ops svm_x86_ops = { .pmu_ops = &amd_pmu_ops, .deliver_posted_interrupt = svm_deliver_avic_intr, + .update_pi_irte = svm_update_pi_irte, }; static int __init svm_init(void)