Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2019 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "mod_vmid.h"
0027 
0028 struct core_vmid {
0029     struct mod_vmid public;
0030     struct dc *dc;
0031 
0032     unsigned int num_vmid;
0033     unsigned int num_vmids_available;
0034     uint64_t ptb_assigned_to_vmid[MAX_VMID];
0035     struct dc_virtual_addr_space_config base_config;
0036 };
0037 
0038 #define MOD_VMID_TO_CORE(mod_vmid)\
0039         container_of(mod_vmid, struct core_vmid, public)
0040 
0041 static void add_ptb_to_table(struct core_vmid *core_vmid, unsigned int vmid, uint64_t ptb)
0042 {
0043     if (vmid < MAX_VMID) {
0044         core_vmid->ptb_assigned_to_vmid[vmid] = ptb;
0045         core_vmid->num_vmids_available--;
0046     }
0047 }
0048 
0049 static void clear_entry_from_vmid_table(struct core_vmid *core_vmid, unsigned int vmid)
0050 {
0051     if (vmid < MAX_VMID) {
0052         core_vmid->ptb_assigned_to_vmid[vmid] = 0;
0053         core_vmid->num_vmids_available++;
0054     }
0055 }
0056 
0057 static void evict_vmids(struct core_vmid *core_vmid)
0058 {
0059     int i;
0060     uint16_t ord = dc_get_vmid_use_vector(core_vmid->dc);
0061 
0062     // At this point any positions with value 0 are unused vmids, evict them
0063     for (i = 1; i < core_vmid->num_vmid; i++) {
0064         if (!(ord & (1u << i)))
0065             clear_entry_from_vmid_table(core_vmid, i);
0066     }
0067 }
0068 
0069 // Return value of -1 indicates vmid table uninitialized or ptb dne in the table
0070 static int get_existing_vmid_for_ptb(struct core_vmid *core_vmid, uint64_t ptb)
0071 {
0072     int i;
0073 
0074     for (i = 0; i < core_vmid->num_vmid; i++) {
0075         if (core_vmid->ptb_assigned_to_vmid[i] == ptb)
0076             return i;
0077     }
0078 
0079     return -1;
0080 }
0081 
0082 // Expected to be called only when there's an available vmid
0083 static int get_next_available_vmid(struct core_vmid *core_vmid)
0084 {
0085     int i;
0086 
0087     for (i = 1; i < core_vmid->num_vmid; i++) {
0088         if (core_vmid->ptb_assigned_to_vmid[i] == 0)
0089             return i;
0090     }
0091 
0092     return -1;
0093 }
0094 
0095 uint8_t mod_vmid_get_for_ptb(struct mod_vmid *mod_vmid, uint64_t ptb)
0096 {
0097     struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid);
0098     int vmid = 0;
0099 
0100     // Physical address gets vmid 0
0101     if (ptb == 0)
0102         return 0;
0103 
0104     vmid = get_existing_vmid_for_ptb(core_vmid, ptb);
0105 
0106     if (vmid == -1) {
0107         struct dc_virtual_addr_space_config va_config = core_vmid->base_config;
0108 
0109         va_config.page_table_base_addr = ptb;
0110 
0111         if (core_vmid->num_vmids_available == 0)
0112             evict_vmids(core_vmid);
0113 
0114         vmid = get_next_available_vmid(core_vmid);
0115         if (vmid != -1) {
0116             add_ptb_to_table(core_vmid, vmid, ptb);
0117 
0118             dc_setup_vm_context(core_vmid->dc, &va_config, vmid);
0119         } else
0120             ASSERT(0);
0121     }
0122 
0123     return vmid;
0124 }
0125 
0126 void mod_vmid_reset(struct mod_vmid *mod_vmid)
0127 {
0128     struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid);
0129 
0130     core_vmid->num_vmids_available = core_vmid->num_vmid - 1;
0131     memset(core_vmid->ptb_assigned_to_vmid, 0, sizeof(core_vmid->ptb_assigned_to_vmid[0]) * MAX_VMID);
0132 }
0133 
0134 struct mod_vmid *mod_vmid_create(
0135         struct dc *dc,
0136         unsigned int num_vmid,
0137         struct dc_virtual_addr_space_config *va_config)
0138 {
0139     struct core_vmid *core_vmid;
0140 
0141     if (num_vmid <= 1)
0142         goto fail_no_vm_ctx;
0143 
0144     if (dc == NULL)
0145         goto fail_dc_null;
0146 
0147     core_vmid = kzalloc(sizeof(struct core_vmid), GFP_KERNEL);
0148 
0149     if (core_vmid == NULL)
0150         goto fail_alloc_context;
0151 
0152     core_vmid->dc = dc;
0153     core_vmid->num_vmid = num_vmid;
0154     core_vmid->num_vmids_available = num_vmid - 1;
0155     core_vmid->base_config = *va_config;
0156 
0157     memset(core_vmid->ptb_assigned_to_vmid, 0, sizeof(core_vmid->ptb_assigned_to_vmid[0]) * MAX_VMID);
0158 
0159     return &core_vmid->public;
0160 
0161 fail_no_vm_ctx:
0162 fail_alloc_context:
0163 fail_dc_null:
0164     return NULL;
0165 }
0166 
0167 void mod_vmid_destroy(struct mod_vmid *mod_vmid)
0168 {
0169     if (mod_vmid != NULL) {
0170         struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid);
0171 
0172         kfree(core_vmid);
0173     }
0174 }