From patchwork Thu Aug 18 19:42:44 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Suthikulpanit, Suravee" X-Patchwork-Id: 74197 Delivered-To: patch@linaro.org Received: by 10.140.29.52 with SMTP id a49csp70781qga; Thu, 18 Aug 2016 18:20:00 -0700 (PDT) X-Received: by 10.98.88.131 with SMTP id m125mr9362883pfb.63.1471569600159; Thu, 18 Aug 2016 18:20:00 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c9si5231978pav.143.2016.08.18.18.19.59; Thu, 18 Aug 2016 18:20:00 -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 S1755210AbcHSBTz (ORCPT + 27 others); Thu, 18 Aug 2016 21:19:55 -0400 Received: from mail-bl2nam02on0082.outbound.protection.outlook.com ([104.47.38.82]:22589 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754532AbcHSBTv (ORCPT ); Thu, 18 Aug 2016 21:19:51 -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=Qnmotnmm9uEoHm8YueajPDjCodRMOUz64CpdfzCGH0g=; b=WCe6QGzq+vDsG3dMpmD/NV7vSyB2dTLDxnLeQPeJvwO5uqbmHOSeAb6DIfoaSaMgjZ09n/A8xkgNBgI+45RkyyCBE6WxByN+E6Z1ZZydg4c/ybH6/MaSKgWtTkpRjJExvNQDbphwG6AHS9ZxIBRkmrMezVgxY7zjOGJdCFqZrvU= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Suravee.Suthikulpanit@amd.com; Received: from localhost.localdomain (114.109.128.54) by MWHPR12MB1453.namprd12.prod.outlook.com (10.172.55.22) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384) id 15.1.587.9; Thu, 18 Aug 2016 19:44:07 +0000 From: Suravee Suthikulpanit To: , , , CC: , , , Suravee Suthikulpanit Subject: [PART2 PATCH v6 12/12] svm: Implements update_pi_irte hook to setup posted interrupt Date: Thu, 18 Aug 2016 14:42:44 -0500 Message-ID: <1471549364-6672-13-git-send-email-Suravee.Suthikulpanit@amd.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1471549364-6672-1-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1471549364-6672-1-git-send-email-Suravee.Suthikulpanit@amd.com> MIME-Version: 1.0 X-Originating-IP: [114.109.128.54] X-ClientProxiedBy: KL1PR0201CA0016.apcprd02.prod.outlook.com (10.167.53.154) To MWHPR12MB1453.namprd12.prod.outlook.com (10.172.55.22) X-MS-Office365-Filtering-Correlation-Id: 8ee5e3cf-aeff-4489-f2b7-08d3c7a00622 X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1453; 2:x14L+DgyxwzuufE7eCLBT5BMSTgxrP3nUnwwMaSDlEKfrXOBVHC4mkUMceX77T/zM8PKqzfBwyxTctulARWA/853O29ImQm6fuWzUNO5+vN4vrcVs7QpsBkNihxl+QivJhS7fXqZuvUSJn/sKMN18u3sjAeCYE38L/IxXfUcKkmOx4ybecxqUIYuO9r37Q0V; 3:OGZnLHEVH4/GUhmPyCnTzFtgEQ9TlnB+3YftCIHP9wc47emHOZGdB+CPXoQ2EXkoMZJGzf4NX4+IxkgwD2LEonhuHxBgor0tFT270f8GedP6E1zDCLAhwdjUHVBMiWnm; 25:Hlhd5TbuZiuLh9eiLHvLqW0JU/u91L4prV4hOC4dmFJ67HKxktleROvY7ezrWp/5OhceUy0l2X90Wy3fu4LB+Ecm5nVMaf7iCe5/edhCY09mvoVM3FKV42d92EC3IvUHSzKojv8anIwLCmaD2JxSkBZTPoyBCu1zR8RHA92pm6v1sZqPWqAQoSa+P+yV4yEnjPAXRDnkL9xTWDuBL7/XLIJn6nM9Uhe3fL+GCzUQLF+H+gJsVSrDGEFRmgM6Vzrn2w2rQwV8tGjVjwxJ2Dy/PaLR3IYfVpyXnI9AONoW4QHI7brtguky5XXTrnP+T/d245dba3M1oyo0K8P/wsHhdYgxOdjh1dd79Xgey1B77VV/UNbmQx0TGaZdM8uKLSWWUbTQ9sJLVCqDIDhGX1S3pw5RDo/12nY9E+fiIb497vg= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:MWHPR12MB1453; X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1453; 31:eNT1+FvaJYmroevF5JBDFz+mW1u8sESVZTNH3D40wVB52URqdQrPoCIXwmpT+M6Bec3VnQCN4a6z8fx6LBwNjjQmS9fGdswcPRtMWAd8+orvLDqsHB54QQMSYoXOn21ckZNl/BDSF0qbuAVZv8Nl4Pajkx06avjl5bIle/cUj2IPdg9P+ipbrQku9dHwEhtbrE7B+7Thpn6UoNeF4M/99wUxl3DoU+dvUjU8eZc5oCQ=; 20:xU+47kdArX0z5+GDbeGcsgAgO3EQ5STkcedhZlqF6lsfTvsKRxiSk0gaBKczV35jAMHsAbnX7mKtZTOupAzTETvhIVtSuA+Db+hUH/n7c0B3ZRlHl63Ph/U1JCKLQ8da0k5pQTEzDnXHGabhdj7+dKZrp+kRFdAfegVM7noe0x0OVeOHl0Yhw1VcJQMowaz4pf3fo4Y0UxvidOsf9JXun57pTRS+8EZaOUWP0eR330IH0WeA+VtbKiJrfqXSgW7LFxr1V1JbuxMbl0zegu36F9Ih00rSD4MeKGIs5NkifoHhukkd6b0pqOvBYLHJtmsBY/Kehc8AGTbt9NcPM2xRTRjikUHQkWwUqehuD7OX60pXxhDajBjPS5CbBDzVACcz82flKZko5qu8ToWINQYXinjHk7NvBs4U68aRRhYsvhoLB+yqdNMIOT5Tv7DXueGu9MjRfvGIhKLnQEea9UziQWs8IdiMYS+YKZ4+Ouf6A9N0xtq4ZuU73sXY1fxfO07W X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040176)(601004)(2401047)(8121501046)(5005006)(10201501046)(3002001)(6055026); SRVR:MWHPR12MB1453; BCL:0; PCL:0; RULEID:; SRVR:MWHPR12MB1453; X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1453; 4:auMGSdUUuEPPptF94PWGP340+dI8yZrItFkayyinjKGiN0ogPvaRQJxgHUgxPvJgWhiMGdnM1v6PqdF5FS8p+eDfmxAK7RctEkNs+bhGIiRpkz5//rm1oVsjplpzg1dvPk5oJ6FP92XUZudjT3Wo/b/Ls83cvXQu2O4q1fv7ZdNRUb53blHxKxZa8p54y0yp6QcoQTtOxb3cxR9HLIT7c+Gf3Xukiwf9wlcxZ7s7u0zyqyVmP6u/cGZcxbkj9AJaCZAY6qT0FzPiEk2iSM+H+79e0KKLUJ1oHQLaEjX5bL5IKtdbhzu02/BKWExboSSek5snCMYYk/8xr+R4P8h26Tspnc/Zduh+Dr5/78jycqJdPl1THE5gOyUx9nGZxQMiRgA/0QdB5zD1K9gNQz1yi0vInpg8LX+z7XgxB+RnHvxbbo29qWn50T0jJDI81H0G X-Forefront-PRVS: 0038DE95A2 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6069001)(6009001)(7916002)(189002)(199003)(86362001)(42186005)(50226002)(19580395003)(586003)(68736007)(92566002)(3846002)(6116002)(189998001)(105586002)(8676002)(81156014)(81166006)(5003940100001)(47776003)(5001770100001)(2950100001)(97736004)(15650500001)(48376002)(77096005)(50986999)(50466002)(106356001)(36756003)(2201001)(305945005)(19580405001)(76176999)(7846002)(7736002)(4326007)(2906002)(66066001)(229853001)(101416001); DIR:OUT; SFP:1101; SCL:1; SRVR:MWHPR12MB1453; 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; MWHPR12MB1453; 23:zI7NSiW1us0ZCmchJVBwx43eMo5acLduaiFjUYAMD?= =?us-ascii?Q?LRTWMu2fNvQKB+lmVyuyZu/9HkjdPv74w+wR+Q7AhwOXoLBxOeHd9vp6yF9w?= =?us-ascii?Q?9tlnXBcMD/ZSpjNGKzYi0+Upv4BX+4zib19apMtkfDR51epphrkpk3IYZvHa?= =?us-ascii?Q?RrefU88mNfmRtYLciDJ6kMQaRyL/iurlsQBcRo0WSuKIHHxRIg3YJKS3IlK8?= =?us-ascii?Q?hDpEed7hh6Z2gm1orzhRyEt7dNJ7tZp8yfNMdB33Iq9VFi2VbhiOmqLySyfY?= =?us-ascii?Q?Vf8GNYLB9fHeAlOJMMx4Yhadhs+5412Sn+2hMrkCuq8LxzxTzBm+scqfDG77?= =?us-ascii?Q?KW9z9DH1pYSvUVAktpKzf2EDD0tRNrcsyGM/L3V67oFKEopub7dkVPyZdO9o?= =?us-ascii?Q?YlqQPLH74WywIGMDv2fxJMhEJIZaiVLqdDTF7f1EvO/kXw6f1/Cw/WSGYy5U?= =?us-ascii?Q?0sf7Fg1EcGEawlBhZtnYprinZjhIHL/gtJLYBwRica3Lju8Lz7sKEmThH5gp?= =?us-ascii?Q?Yn4LU01vKJT1zG8t9JmkgM8zugx8L451LgpPEbi8vfN7aG+/0Dt4F1nPa2Hp?= =?us-ascii?Q?nOUHtNqzHTTZ30C2tuSmHJWIwAsNo18RAckOb6THZNxO1gJPL/3VkOF0cDoO?= =?us-ascii?Q?Wc39HbvHjcrqJgsJBRkXB+XG9mycewtdk2NVdRTamZ0rr8d2SzYdWi0Gq8UG?= =?us-ascii?Q?IFnqArGOCjkx52Enai8jJigvRbeaLBZBU3xyghE1uPmXKB2Y/mc/cupc7HiP?= =?us-ascii?Q?dJjKZYqo+JFDdaL+/6pgUqE16kI7hhjnM8Rd+uZvnVWOakZVX254y5qY28XU?= =?us-ascii?Q?ixE2DncFwtO1uES1e4P5/gw1amx7IMDPJE23QpxB/AY7ypPJZE66oHQRExxO?= =?us-ascii?Q?SFNZEKur01ih2BBEdpI8kRBcBhDoDBivX8dXsunin5BSxrEQTp8TAkEXCmJ8?= =?us-ascii?Q?k005ENixnVJFZhvIh1sJwvDgCT3EfjewSgw4lYcKywDWHK9meaKh34eN+pKh?= =?us-ascii?Q?HAiXV/IOQt6LoYedLBAv5Z+UT/sUyh/3zFMmoEvHRBYL4aBkl6Zw3uj/9R5P?= =?us-ascii?Q?YdeAk/NiesmSWtVLzH/lEd/pR44Y030Db4lG0x9NuGO78tNLg=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1453; 6:kf+UzWBgAT5zlIh4f9hvAG8Hgc0kBdBuF/XMEW3I7CMfQfh1lyu4wSokIVmURK8uaAixPCvS/yQH1kAGnNr6+cJaZyFNdDPDkZhV9ued6+OyjO8aBAG4r6zzDd8tMaZWMiDWGAR0QMxrRcXBD72T4omfSFGxhWamXT5dti+ptmWLyQZDoCZdN6lkHtrYX7Sz6wPTYJlpFBvSIlV82uCPjt+R1sHWljQ2POK+5dH4zg1aUgBTEgBuq0b/X8NIYg7mBSN0YSwVz5aQAvf8wMz2DNcty+iuMyukZxra4xuGjE0du7hdlcZoUx/YnZJXQtKRngAgZ7lv58aacGpjtoPXEA==; 5:rpbB7u9o2KInNupIeHn2laLnOcsPiksxQMgXU/ojb7sHM6qgNGW/zx12WdRIeAMqLqkjuVnaPadaa+NAPo11UKfz0xuoMWOICz1+uyN+sqGkVGSqKhDawRERMpBfQ8D3Ba1aD/fmzrhhMFolqDsebg==; 24:l9d1784rCbtTniId4zG/4s98sgKTeeX1YUbhFTV+rg8Ud0zbrvhehuMojY0z1RSE1XsxPDscsHVXcFiAn6MfQ9WbxVr3qiDNqrM7H5LL7XI=; 7:CF27XC5h0hoaqnY/dGzaT2ypfuRnSOxINUTfuGW80BmzFugGrFIsGanbe+hgp9uqMaKfWsx+CytzhNlTNrrq12nX5S9e6UFc/8MilOiZJzaruesGq/pS3m3HfbY6mXGeLcO4z0ph29KCEqL8z33TJYGMXUhSAuc9aPYSowZXtUnQUsOT74Jj6c4xIF6RNIDcQX7bjj6GFRMN4gi6wcJ6ipdgU8RSFvzJqv/YCnG4ZlHBBWn6grQAtBVKrvP7K8Qp SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; MWHPR12MB1453; 20:KTA4+fMXm6a6WlyAO0zsiXGE1CX5eY/qUk2gSd0/3fq5NiReDPU93fZ5EYDUwmOOhxquH/XUk1QNKBK1x8xVx4vG9NVAzP6wgmBP9WpYKpu9AZh3U0SA8NFdY/EWoWqpoIo4FdFguiFt1lSb7Nc6KeemCuTBSoTiQ46ZTUSjL0qANT/LQkHnrO/oieGaklQdn1uXOsBBr2twBxsF3G8rzecoTcmsWWiEHbRKqVjYSyh+hCaa1BPQ0ftBBGzDeFL+ X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Aug 2016 19:44:07.6289 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: MWHPR12MB1453 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 | 247 ++++++++++++++++++++++++++++++++++++++++++---- include/linux/amd-iommu.h | 1 + 2 files changed, 227 insertions(+), 21 deletions(-) -- 1.9.1 diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index c060e05..303007a 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" @@ -200,6 +201,16 @@ struct vcpu_svm { struct page *avic_backing_page; u64 *avic_physical_id_cache; bool avic_is_running; + + /* + * Per-vcpu list of struct amd_ir_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 ir_list; + spinlock_t ir_list_lock; }; #define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFF) @@ -1443,31 +1454,29 @@ free_avic: return err; } -/** - * This function is called during VCPU halt/unhalt. - */ -static void avic_set_running(struct kvm_vcpu *vcpu, bool is_run) +static inline int +avic_update_iommu(struct kvm_vcpu *vcpu, int cpu, phys_addr_t pa, bool r) { - u64 entry; - int h_physical_id = kvm_cpu_get_apicid(vcpu->cpu); + int ret; + unsigned long flags; struct vcpu_svm *svm = to_svm(vcpu); + struct amd_ir_data *ir; - if (!kvm_vcpu_apicv_active(vcpu)) - return; - - svm->avic_is_running = is_run; - - /* ID = 0xff (broadcast), ID > 0xff (reserved) */ - if (WARN_ON(h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)) - return; - - entry = READ_ONCE(*(svm->avic_physical_id_cache)); - WARN_ON(is_run == !!(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)); + if (!kvm_arch_has_assigned_device(vcpu->kvm)) + return 0; - entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; - if (is_run) - entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; - WRITE_ONCE(*(svm->avic_physical_id_cache), entry); + /* + * Here, we go through the per-vcpu ir_list to update all existing + * interrupt remapping table entry targeting this vcpu. + */ + spin_lock_irqsave(&svm->ir_list_lock, flags); + list_for_each_entry(ir, &svm->ir_list, node) { + ret = amd_iommu_update_ga(cpu, (pa & AVIC_HPA_MASK), r, ir); + if (ret) + break; + } + spin_unlock_irqrestore(&svm->ir_list_lock, flags); + return ret; } static void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu) @@ -1494,6 +1503,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) @@ -1505,10 +1517,28 @@ 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); } +/** + * This function is called during VCPU halt/unhalt. + */ +static void avic_set_running(struct kvm_vcpu *vcpu, bool is_run) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + svm->avic_is_running = is_run; + if (is_run) + avic_vcpu_load(vcpu, vcpu->cpu); + else + avic_vcpu_put(vcpu); +} + static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) { struct vcpu_svm *svm = to_svm(vcpu); @@ -1570,6 +1600,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->ir_list); + spin_lock_init(&svm->ir_list_lock); } /* We initialize this flag to true to make sure that the is_running @@ -4366,6 +4399,177 @@ static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec) kvm_vcpu_wake_up(vcpu); } +static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_ir_data *ir) +{ + bool found = false; + unsigned long flags; + struct amd_ir_data *cur; + + /** + * In some cases, the existing irte is updaed and re-set, + * so we need to check here if it's already been * added + * to the ir_list. + */ + spin_lock_irqsave(&svm->ir_list_lock, flags); + list_for_each_entry(cur, &svm->ir_list, node) { + if (cur != ir) + continue; + found = true; + break; + } + spin_unlock_irqrestore(&svm->ir_list_lock, flags); + + if (found) + return 0; + + spin_lock_irqsave(&svm->ir_list_lock, flags); + list_add(&ir->node, &svm->ir_list); + spin_unlock_irqrestore(&svm->ir_list_lock, flags); + return 0; +} + +static void svm_ir_list_del(struct vcpu_svm *svm, struct amd_ir_data *ir) +{ + unsigned long flags; + struct amd_ir_data *cur; + + spin_lock_irqsave(&svm->ir_list_lock, flags); + list_for_each_entry(cur, &svm->ir_list, node) { + if (cur != ir) + continue; + list_del(&cur->node); + break; + } + spin_unlock_irqrestore(&svm->ir_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; + + 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); + } + + trace_kvm_pi_irte_update(vcpu->vcpu_id, host_irq, e->gsi, + vcpu_info.vector, + vcpu_info.pi_desc_addr, set); + + /** + * 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; + + /* Try to enable guest_mode in IRTE */ + pi.ga_tag = AVIC_GATAG(kvm->arch.avic_vm_id, + vcpu->vcpu_id); + pi.is_guest_mode = true; + pi.vcpu_data = &vcpu_info; + ret = irq_set_vcpu_affinity(host_irq, &pi); + + /** + * We save the pointer to pi 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.is_guest_mode) + svm_ir_list_add(svm, pi.ir_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 + * ir_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_ir_list_del(to_svm(vcpu), pi.ir_data); + } + } + + 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); @@ -5192,6 +5396,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) diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h index 7b2e802..cd10393 100644 --- a/include/linux/amd-iommu.h +++ b/include/linux/amd-iommu.h @@ -34,6 +34,7 @@ struct amd_ir_data { struct msi_msg msi_entry; void *entry; /* Pointer to union irte or struct irte_ga */ void *ref; /* Pointer to the actual irte */ + struct list_head node; /* Used by SVM for per-vcpu ir_list */ }; /*