0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
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
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
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
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
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 }