Home | History | Annotate | Line # | Download | only in amdkfd
      1 /*	$NetBSD: kfd_iommu.c,v 1.2 2021/12/18 23:44:59 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2018 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 #include <sys/cdefs.h>
     26 __KERNEL_RCSID(0, "$NetBSD: kfd_iommu.c,v 1.2 2021/12/18 23:44:59 riastradh Exp $");
     27 
     28 #include <linux/printk.h>
     29 #include <linux/device.h>
     30 #include <linux/slab.h>
     31 #include <linux/pci.h>
     32 #include <linux/amd-iommu.h>
     33 #include "kfd_priv.h"
     34 #include "kfd_dbgmgr.h"
     35 #include "kfd_topology.h"
     36 #include "kfd_iommu.h"
     37 
     38 static const u32 required_iommu_flags = AMD_IOMMU_DEVICE_FLAG_ATS_SUP |
     39 					AMD_IOMMU_DEVICE_FLAG_PRI_SUP |
     40 					AMD_IOMMU_DEVICE_FLAG_PASID_SUP;
     41 
     42 /** kfd_iommu_check_device - Check whether IOMMU is available for device
     43  */
     44 int kfd_iommu_check_device(struct kfd_dev *kfd)
     45 {
     46 	struct amd_iommu_device_info iommu_info;
     47 	int err;
     48 
     49 	if (!kfd->device_info->needs_iommu_device)
     50 		return -ENODEV;
     51 
     52 	iommu_info.flags = 0;
     53 	err = amd_iommu_device_info(kfd->pdev, &iommu_info);
     54 	if (err)
     55 		return err;
     56 
     57 	if ((iommu_info.flags & required_iommu_flags) != required_iommu_flags)
     58 		return -ENODEV;
     59 
     60 	return 0;
     61 }
     62 
     63 /** kfd_iommu_device_init - Initialize IOMMU for device
     64  */
     65 int kfd_iommu_device_init(struct kfd_dev *kfd)
     66 {
     67 	struct amd_iommu_device_info iommu_info;
     68 	unsigned int pasid_limit;
     69 	int err;
     70 
     71 	if (!kfd->device_info->needs_iommu_device)
     72 		return 0;
     73 
     74 	iommu_info.flags = 0;
     75 	err = amd_iommu_device_info(kfd->pdev, &iommu_info);
     76 	if (err < 0) {
     77 		dev_err(kfd_device,
     78 			"error getting iommu info. is the iommu enabled?\n");
     79 		return -ENODEV;
     80 	}
     81 
     82 	if ((iommu_info.flags & required_iommu_flags) != required_iommu_flags) {
     83 		dev_err(kfd_device,
     84 			"error required iommu flags ats %i, pri %i, pasid %i\n",
     85 		       (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_ATS_SUP) != 0,
     86 		       (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_PRI_SUP) != 0,
     87 		       (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_PASID_SUP)
     88 									!= 0);
     89 		return -ENODEV;
     90 	}
     91 
     92 	pasid_limit = min_t(unsigned int,
     93 			(unsigned int)(1 << kfd->device_info->max_pasid_bits),
     94 			iommu_info.max_pasids);
     95 
     96 	if (!kfd_set_pasid_limit(pasid_limit)) {
     97 		dev_err(kfd_device, "error setting pasid limit\n");
     98 		return -EBUSY;
     99 	}
    100 
    101 	return 0;
    102 }
    103 
    104 /** kfd_iommu_bind_process_to_device - Have the IOMMU bind a process
    105  *
    106  * Binds the given process to the given device using its PASID. This
    107  * enables IOMMUv2 address translation for the process on the device.
    108  *
    109  * This function assumes that the process mutex is held.
    110  */
    111 int kfd_iommu_bind_process_to_device(struct kfd_process_device *pdd)
    112 {
    113 	struct kfd_dev *dev = pdd->dev;
    114 	struct kfd_process *p = pdd->process;
    115 	int err;
    116 
    117 	if (!dev->device_info->needs_iommu_device || pdd->bound == PDD_BOUND)
    118 		return 0;
    119 
    120 	if (unlikely(pdd->bound == PDD_BOUND_SUSPENDED)) {
    121 		pr_err("Binding PDD_BOUND_SUSPENDED pdd is unexpected!\n");
    122 		return -EINVAL;
    123 	}
    124 
    125 	err = amd_iommu_bind_pasid(dev->pdev, p->pasid, p->lead_thread);
    126 	if (!err)
    127 		pdd->bound = PDD_BOUND;
    128 
    129 	return err;
    130 }
    131 
    132 /** kfd_iommu_unbind_process - Unbind process from all devices
    133  *
    134  * This removes all IOMMU device bindings of the process. To be used
    135  * before process termination.
    136  */
    137 void kfd_iommu_unbind_process(struct kfd_process *p)
    138 {
    139 	struct kfd_process_device *pdd;
    140 
    141 	list_for_each_entry(pdd, &p->per_device_data, per_device_list)
    142 		if (pdd->bound == PDD_BOUND)
    143 			amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid);
    144 }
    145 
    146 /* Callback for process shutdown invoked by the IOMMU driver */
    147 static void iommu_pasid_shutdown_callback(struct pci_dev *pdev, int pasid)
    148 {
    149 	struct kfd_dev *dev = kfd_device_by_pci_dev(pdev);
    150 	struct kfd_process *p;
    151 	struct kfd_process_device *pdd;
    152 
    153 	if (!dev)
    154 		return;
    155 
    156 	/*
    157 	 * Look for the process that matches the pasid. If there is no such
    158 	 * process, we either released it in amdkfd's own notifier, or there
    159 	 * is a bug. Unfortunately, there is no way to tell...
    160 	 */
    161 	p = kfd_lookup_process_by_pasid(pasid);
    162 	if (!p)
    163 		return;
    164 
    165 	pr_debug("Unbinding process 0x%x from IOMMU\n", pasid);
    166 
    167 	mutex_lock(kfd_get_dbgmgr_mutex());
    168 
    169 	if (dev->dbgmgr && dev->dbgmgr->pasid == p->pasid) {
    170 		if (!kfd_dbgmgr_unregister(dev->dbgmgr, p)) {
    171 			kfd_dbgmgr_destroy(dev->dbgmgr);
    172 			dev->dbgmgr = NULL;
    173 		}
    174 	}
    175 
    176 	mutex_unlock(kfd_get_dbgmgr_mutex());
    177 
    178 	mutex_lock(&p->mutex);
    179 
    180 	pdd = kfd_get_process_device_data(dev, p);
    181 	if (pdd)
    182 		/* For GPU relying on IOMMU, we need to dequeue here
    183 		 * when PASID is still bound.
    184 		 */
    185 		kfd_process_dequeue_from_device(pdd);
    186 
    187 	mutex_unlock(&p->mutex);
    188 
    189 	kfd_unref_process(p);
    190 }
    191 
    192 /* This function called by IOMMU driver on PPR failure */
    193 static int iommu_invalid_ppr_cb(struct pci_dev *pdev, int pasid,
    194 		unsigned long address, u16 flags)
    195 {
    196 	struct kfd_dev *dev;
    197 
    198 	dev_warn_ratelimited(kfd_device,
    199 			"Invalid PPR device %x:%x.%x pasid 0x%x address 0x%lX flags 0x%X",
    200 			PCI_BUS_NUM(pdev->devfn),
    201 			PCI_SLOT(pdev->devfn),
    202 			PCI_FUNC(pdev->devfn),
    203 			pasid,
    204 			address,
    205 			flags);
    206 
    207 	dev = kfd_device_by_pci_dev(pdev);
    208 	if (!WARN_ON(!dev))
    209 		kfd_signal_iommu_event(dev, pasid, address,
    210 			flags & PPR_FAULT_WRITE, flags & PPR_FAULT_EXEC);
    211 
    212 	return AMD_IOMMU_INV_PRI_RSP_INVALID;
    213 }
    214 
    215 /*
    216  * Bind processes do the device that have been temporarily unbound
    217  * (PDD_BOUND_SUSPENDED) in kfd_unbind_processes_from_device.
    218  */
    219 static int kfd_bind_processes_to_device(struct kfd_dev *kfd)
    220 {
    221 	struct kfd_process_device *pdd;
    222 	struct kfd_process *p;
    223 	unsigned int temp;
    224 	int err = 0;
    225 
    226 	int idx = srcu_read_lock(&kfd_processes_srcu);
    227 
    228 	hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
    229 		mutex_lock(&p->mutex);
    230 		pdd = kfd_get_process_device_data(kfd, p);
    231 
    232 		if (WARN_ON(!pdd) || pdd->bound != PDD_BOUND_SUSPENDED) {
    233 			mutex_unlock(&p->mutex);
    234 			continue;
    235 		}
    236 
    237 		err = amd_iommu_bind_pasid(kfd->pdev, p->pasid,
    238 				p->lead_thread);
    239 		if (err < 0) {
    240 			pr_err("Unexpected pasid 0x%x binding failure\n",
    241 					p->pasid);
    242 			mutex_unlock(&p->mutex);
    243 			break;
    244 		}
    245 
    246 		pdd->bound = PDD_BOUND;
    247 		mutex_unlock(&p->mutex);
    248 	}
    249 
    250 	srcu_read_unlock(&kfd_processes_srcu, idx);
    251 
    252 	return err;
    253 }
    254 
    255 /*
    256  * Mark currently bound processes as PDD_BOUND_SUSPENDED. These
    257  * processes will be restored to PDD_BOUND state in
    258  * kfd_bind_processes_to_device.
    259  */
    260 static void kfd_unbind_processes_from_device(struct kfd_dev *kfd)
    261 {
    262 	struct kfd_process_device *pdd;
    263 	struct kfd_process *p;
    264 	unsigned int temp;
    265 
    266 	int idx = srcu_read_lock(&kfd_processes_srcu);
    267 
    268 	hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) {
    269 		mutex_lock(&p->mutex);
    270 		pdd = kfd_get_process_device_data(kfd, p);
    271 
    272 		if (WARN_ON(!pdd)) {
    273 			mutex_unlock(&p->mutex);
    274 			continue;
    275 		}
    276 
    277 		if (pdd->bound == PDD_BOUND)
    278 			pdd->bound = PDD_BOUND_SUSPENDED;
    279 		mutex_unlock(&p->mutex);
    280 	}
    281 
    282 	srcu_read_unlock(&kfd_processes_srcu, idx);
    283 }
    284 
    285 /** kfd_iommu_suspend - Prepare IOMMU for suspend
    286  *
    287  * This unbinds processes from the device and disables the IOMMU for
    288  * the device.
    289  */
    290 void kfd_iommu_suspend(struct kfd_dev *kfd)
    291 {
    292 	if (!kfd->device_info->needs_iommu_device)
    293 		return;
    294 
    295 	kfd_unbind_processes_from_device(kfd);
    296 
    297 	amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
    298 	amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL);
    299 	amd_iommu_free_device(kfd->pdev);
    300 }
    301 
    302 /** kfd_iommu_resume - Restore IOMMU after resume
    303  *
    304  * This reinitializes the IOMMU for the device and re-binds previously
    305  * suspended processes to the device.
    306  */
    307 int kfd_iommu_resume(struct kfd_dev *kfd)
    308 {
    309 	unsigned int pasid_limit;
    310 	int err;
    311 
    312 	if (!kfd->device_info->needs_iommu_device)
    313 		return 0;
    314 
    315 	pasid_limit = kfd_get_pasid_limit();
    316 
    317 	err = amd_iommu_init_device(kfd->pdev, pasid_limit);
    318 	if (err)
    319 		return -ENXIO;
    320 
    321 	amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
    322 					iommu_pasid_shutdown_callback);
    323 	amd_iommu_set_invalid_ppr_cb(kfd->pdev,
    324 				     iommu_invalid_ppr_cb);
    325 
    326 	err = kfd_bind_processes_to_device(kfd);
    327 	if (err) {
    328 		amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
    329 		amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL);
    330 		amd_iommu_free_device(kfd->pdev);
    331 		return err;
    332 	}
    333 
    334 	return 0;
    335 }
    336 
    337 extern bool amd_iommu_pc_supported(void);
    338 extern u8 amd_iommu_pc_get_max_banks(u16 devid);
    339 extern u8 amd_iommu_pc_get_max_counters(u16 devid);
    340 
    341 /** kfd_iommu_add_perf_counters - Add IOMMU performance counters to topology
    342  */
    343 int kfd_iommu_add_perf_counters(struct kfd_topology_device *kdev)
    344 {
    345 	struct kfd_perf_properties *props;
    346 
    347 	if (!(kdev->node_props.capability & HSA_CAP_ATS_PRESENT))
    348 		return 0;
    349 
    350 	if (!amd_iommu_pc_supported())
    351 		return 0;
    352 
    353 	props = kfd_alloc_struct(props);
    354 	if (!props)
    355 		return -ENOMEM;
    356 	strcpy(props->block_name, "iommu");
    357 	props->max_concurrent = amd_iommu_pc_get_max_banks(0) *
    358 		amd_iommu_pc_get_max_counters(0); /* assume one iommu */
    359 	list_add_tail(&props->list, &kdev->perf_props);
    360 
    361 	return 0;
    362 }
    363