1 1.1 riastrad /* $NetBSD: radeon_mn.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2014 Advanced Micro Devices, Inc. 5 1.1 riastrad * All Rights Reserved. 6 1.1 riastrad * 7 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 8 1.1 riastrad * copy of this software and associated documentation files (the 9 1.1 riastrad * "Software"), to deal in the Software without restriction, including 10 1.1 riastrad * without limitation the rights to use, copy, modify, merge, publish, 11 1.1 riastrad * distribute, sub license, and/or sell copies of the Software, and to 12 1.1 riastrad * permit persons to whom the Software is furnished to do so, subject to 13 1.1 riastrad * the following conditions: 14 1.1 riastrad * 15 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 1.1 riastrad * 23 1.1 riastrad * The above copyright notice and this permission notice (including the 24 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 25 1.1 riastrad * of the Software. 26 1.1 riastrad * 27 1.1 riastrad */ 28 1.1 riastrad /* 29 1.1 riastrad * Authors: 30 1.1 riastrad * Christian Knig <christian.koenig (at) amd.com> 31 1.1 riastrad */ 32 1.1 riastrad 33 1.1 riastrad #include <sys/cdefs.h> 34 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: radeon_mn.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $"); 35 1.1 riastrad 36 1.1 riastrad #include <linux/firmware.h> 37 1.1 riastrad #include <linux/module.h> 38 1.1 riastrad #include <linux/mmu_notifier.h> 39 1.3 riastrad 40 1.1 riastrad #include <drm/drm.h> 41 1.1 riastrad 42 1.1 riastrad #include "radeon.h" 43 1.1 riastrad 44 1.1 riastrad /** 45 1.3 riastrad * radeon_mn_invalidate - callback to notify about mm change 46 1.1 riastrad * 47 1.1 riastrad * @mn: our notifier 48 1.3 riastrad * @range: the VMA under invalidation 49 1.1 riastrad * 50 1.1 riastrad * We block for all BOs between start and end to be idle and 51 1.1 riastrad * unmap them by move them into system domain again. 52 1.1 riastrad */ 53 1.3 riastrad static bool radeon_mn_invalidate(struct mmu_interval_notifier *mn, 54 1.3 riastrad const struct mmu_notifier_range *range, 55 1.3 riastrad unsigned long cur_seq) 56 1.1 riastrad { 57 1.3 riastrad struct radeon_bo *bo = container_of(mn, struct radeon_bo, notifier); 58 1.3 riastrad struct ttm_operation_ctx ctx = { false, false }; 59 1.3 riastrad long r; 60 1.1 riastrad 61 1.3 riastrad if (!bo->tbo.ttm || bo->tbo.ttm->state != tt_bound) 62 1.3 riastrad return true; 63 1.1 riastrad 64 1.3 riastrad if (!mmu_notifier_range_blockable(range)) 65 1.3 riastrad return false; 66 1.1 riastrad 67 1.3 riastrad r = radeon_bo_reserve(bo, true); 68 1.3 riastrad if (r) { 69 1.3 riastrad DRM_ERROR("(%ld) failed to reserve user bo\n", r); 70 1.3 riastrad return true; 71 1.1 riastrad } 72 1.1 riastrad 73 1.3 riastrad r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, true, false, 74 1.3 riastrad MAX_SCHEDULE_TIMEOUT); 75 1.3 riastrad if (r <= 0) 76 1.3 riastrad DRM_ERROR("(%ld) failed to wait for user bo\n", r); 77 1.1 riastrad 78 1.3 riastrad radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU); 79 1.3 riastrad r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 80 1.1 riastrad if (r) 81 1.3 riastrad DRM_ERROR("(%ld) failed to validate user bo\n", r); 82 1.1 riastrad 83 1.3 riastrad radeon_bo_unreserve(bo); 84 1.3 riastrad return true; 85 1.3 riastrad } 86 1.1 riastrad 87 1.3 riastrad static const struct mmu_interval_notifier_ops radeon_mn_ops = { 88 1.3 riastrad .invalidate = radeon_mn_invalidate, 89 1.3 riastrad }; 90 1.1 riastrad 91 1.1 riastrad /** 92 1.1 riastrad * radeon_mn_register - register a BO for notifier updates 93 1.1 riastrad * 94 1.1 riastrad * @bo: radeon buffer object 95 1.1 riastrad * @addr: userptr addr we should monitor 96 1.1 riastrad * 97 1.1 riastrad * Registers an MMU notifier for the given BO at the specified address. 98 1.1 riastrad * Returns 0 on success, -ERRNO if anything goes wrong. 99 1.1 riastrad */ 100 1.1 riastrad int radeon_mn_register(struct radeon_bo *bo, unsigned long addr) 101 1.1 riastrad { 102 1.3 riastrad int ret; 103 1.1 riastrad 104 1.3 riastrad ret = mmu_interval_notifier_insert(&bo->notifier, current->mm, addr, 105 1.3 riastrad radeon_bo_size(bo), &radeon_mn_ops); 106 1.3 riastrad if (ret) 107 1.3 riastrad return ret; 108 1.3 riastrad 109 1.3 riastrad /* 110 1.3 riastrad * FIXME: radeon appears to allow get_user_pages to run during 111 1.3 riastrad * invalidate_range_start/end, which is not a safe way to read the 112 1.3 riastrad * PTEs. It should use the mmu_interval_read_begin() scheme around the 113 1.3 riastrad * get_user_pages to ensure that the PTEs are read properly 114 1.3 riastrad */ 115 1.3 riastrad mmu_interval_read_begin(&bo->notifier); 116 1.1 riastrad return 0; 117 1.1 riastrad } 118 1.1 riastrad 119 1.1 riastrad /** 120 1.1 riastrad * radeon_mn_unregister - unregister a BO for notifier updates 121 1.1 riastrad * 122 1.1 riastrad * @bo: radeon buffer object 123 1.1 riastrad * 124 1.1 riastrad * Remove any registration of MMU notifier updates from the buffer object. 125 1.1 riastrad */ 126 1.1 riastrad void radeon_mn_unregister(struct radeon_bo *bo) 127 1.1 riastrad { 128 1.3 riastrad if (!bo->notifier.mm) 129 1.1 riastrad return; 130 1.3 riastrad mmu_interval_notifier_remove(&bo->notifier); 131 1.3 riastrad bo->notifier.mm = NULL; 132 1.1 riastrad } 133