1 /* 2 * Copyright 2019 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include "mod_vmid.h" 27 28 struct core_vmid { 29 struct mod_vmid public; 30 struct dc *dc; 31 32 unsigned int num_vmid; 33 unsigned int num_vmids_available; 34 uint64_t ptb_assigned_to_vmid[MAX_VMID]; 35 struct dc_virtual_addr_space_config base_config; 36 }; 37 38 #define MOD_VMID_TO_CORE(mod_vmid)\ 39 container_of(mod_vmid, struct core_vmid, public) 40 41 static void add_ptb_to_table(struct core_vmid *core_vmid, unsigned int vmid, uint64_t ptb) 42 { 43 core_vmid->ptb_assigned_to_vmid[vmid] = ptb; 44 core_vmid->num_vmids_available--; 45 } 46 47 static void clear_entry_from_vmid_table(struct core_vmid *core_vmid, unsigned int vmid) 48 { 49 core_vmid->ptb_assigned_to_vmid[vmid] = 0; 50 core_vmid->num_vmids_available++; 51 } 52 53 static void evict_vmids(struct core_vmid *core_vmid) 54 { 55 int i; 56 uint16_t ord = dc_get_vmid_use_vector(core_vmid->dc); 57 58 // At this point any positions with value 0 are unused vmids, evict them 59 for (i = 1; i < core_vmid->num_vmid; i++) { 60 if (ord & (1u << i)) 61 clear_entry_from_vmid_table(core_vmid, i); 62 } 63 } 64 65 // Return value of -1 indicates vmid table unitialized or ptb dne in the table 66 static int get_existing_vmid_for_ptb(struct core_vmid *core_vmid, uint64_t ptb) 67 { 68 int i; 69 70 for (i = 0; i < core_vmid->num_vmid; i++) { 71 if (core_vmid->ptb_assigned_to_vmid[i] == ptb) 72 return i; 73 } 74 75 return -1; 76 } 77 78 // Expected to be called only when there's an available vmid 79 static int get_next_available_vmid(struct core_vmid *core_vmid) 80 { 81 int i; 82 83 for (i = 1; i < core_vmid->num_vmid; i++) { 84 if (core_vmid->ptb_assigned_to_vmid[i] == 0) 85 return i; 86 } 87 88 return -1; 89 } 90 91 uint8_t mod_vmid_get_for_ptb(struct mod_vmid *mod_vmid, uint64_t ptb) 92 { 93 struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid); 94 unsigned int vmid = 0; 95 96 // Physical address gets vmid 0 97 if (ptb == 0) 98 return 0; 99 100 vmid = get_existing_vmid_for_ptb(core_vmid, ptb); 101 102 if (vmid == -1) { 103 struct dc_virtual_addr_space_config va_config = core_vmid->base_config; 104 105 va_config.page_table_base_addr = ptb; 106 107 if (core_vmid->num_vmids_available == 0) 108 evict_vmids(core_vmid); 109 110 vmid = get_next_available_vmid(core_vmid); 111 add_ptb_to_table(core_vmid, vmid, ptb); 112 113 dc_setup_vm_context(core_vmid->dc, &va_config, vmid); 114 } 115 116 return vmid; 117 } 118 119 void mod_vmid_reset(struct mod_vmid *mod_vmid) 120 { 121 struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid); 122 123 core_vmid->num_vmids_available = core_vmid->num_vmid - 1; 124 memset(core_vmid->ptb_assigned_to_vmid, 0, sizeof(core_vmid->ptb_assigned_to_vmid[0]) * MAX_VMID); 125 } 126 127 struct mod_vmid *mod_vmid_create( 128 struct dc *dc, 129 unsigned int num_vmid, 130 struct dc_virtual_addr_space_config *va_config) 131 { 132 struct core_vmid *core_vmid; 133 134 if (num_vmid <= 1) 135 goto fail_no_vm_ctx; 136 137 if (dc == NULL) 138 goto fail_dc_null; 139 140 core_vmid = kzalloc(sizeof(struct core_vmid), GFP_KERNEL); 141 142 if (core_vmid == NULL) 143 goto fail_alloc_context; 144 145 core_vmid->dc = dc; 146 core_vmid->num_vmid = num_vmid; 147 core_vmid->num_vmids_available = num_vmid - 1; 148 core_vmid->base_config = *va_config; 149 150 memset(core_vmid->ptb_assigned_to_vmid, 0, sizeof(core_vmid->ptb_assigned_to_vmid[0]) * MAX_VMID); 151 152 return &core_vmid->public; 153 154 fail_no_vm_ctx: 155 fail_alloc_context: 156 fail_dc_null: 157 return NULL; 158 } 159 160 void mod_vmid_destroy(struct mod_vmid *mod_vmid) 161 { 162 if (mod_vmid != NULL) { 163 struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid); 164 165 kfree(core_vmid); 166 } 167 } 168