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
0027
0028 #include "vmwgfx_drv.h"
0029 #include "vmwgfx_resource_priv.h"
0030
0031 #define VMW_CMDBUF_RES_MAN_HT_ORDER 12
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 struct vmw_cmdbuf_res {
0044 struct vmw_resource *res;
0045 struct vmwgfx_hash_item hash;
0046 struct list_head head;
0047 enum vmw_cmdbuf_res_state state;
0048 struct vmw_cmdbuf_res_manager *man;
0049 };
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 struct vmw_cmdbuf_res_manager {
0062 struct vmwgfx_open_hash resources;
0063 struct list_head list;
0064 struct vmw_private *dev_priv;
0065 };
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 struct vmw_resource *
0080 vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man,
0081 enum vmw_cmdbuf_res_type res_type,
0082 u32 user_key)
0083 {
0084 struct vmwgfx_hash_item *hash;
0085 int ret;
0086 unsigned long key = user_key | (res_type << 24);
0087
0088 ret = vmwgfx_ht_find_item(&man->resources, key, &hash);
0089 if (unlikely(ret != 0))
0090 return ERR_PTR(ret);
0091
0092 return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res;
0093 }
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man,
0105 struct vmw_cmdbuf_res *entry)
0106 {
0107 list_del(&entry->head);
0108 WARN_ON(vmwgfx_ht_remove_item(&man->resources, &entry->hash));
0109 vmw_resource_unreference(&entry->res);
0110 kfree(entry);
0111 }
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 void vmw_cmdbuf_res_commit(struct list_head *list)
0124 {
0125 struct vmw_cmdbuf_res *entry, *next;
0126
0127 list_for_each_entry_safe(entry, next, list, head) {
0128 list_del(&entry->head);
0129 if (entry->res->func->commit_notify)
0130 entry->res->func->commit_notify(entry->res,
0131 entry->state);
0132 switch (entry->state) {
0133 case VMW_CMDBUF_RES_ADD:
0134 entry->state = VMW_CMDBUF_RES_COMMITTED;
0135 list_add_tail(&entry->head, &entry->man->list);
0136 break;
0137 case VMW_CMDBUF_RES_DEL:
0138 vmw_resource_unreference(&entry->res);
0139 kfree(entry);
0140 break;
0141 default:
0142 BUG();
0143 break;
0144 }
0145 }
0146 }
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 void vmw_cmdbuf_res_revert(struct list_head *list)
0160 {
0161 struct vmw_cmdbuf_res *entry, *next;
0162 int ret;
0163
0164 list_for_each_entry_safe(entry, next, list, head) {
0165 switch (entry->state) {
0166 case VMW_CMDBUF_RES_ADD:
0167 vmw_cmdbuf_res_free(entry->man, entry);
0168 break;
0169 case VMW_CMDBUF_RES_DEL:
0170 ret = vmwgfx_ht_insert_item(&entry->man->resources, &entry->hash);
0171 BUG_ON(ret);
0172 list_move_tail(&entry->head, &entry->man->list);
0173 entry->state = VMW_CMDBUF_RES_COMMITTED;
0174 break;
0175 default:
0176 BUG();
0177 break;
0178 }
0179 }
0180 }
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195 int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
0196 enum vmw_cmdbuf_res_type res_type,
0197 u32 user_key,
0198 struct vmw_resource *res,
0199 struct list_head *list)
0200 {
0201 struct vmw_cmdbuf_res *cres;
0202 int ret;
0203
0204 cres = kzalloc(sizeof(*cres), GFP_KERNEL);
0205 if (unlikely(!cres))
0206 return -ENOMEM;
0207
0208 cres->hash.key = user_key | (res_type << 24);
0209 ret = vmwgfx_ht_insert_item(&man->resources, &cres->hash);
0210 if (unlikely(ret != 0)) {
0211 kfree(cres);
0212 goto out_invalid_key;
0213 }
0214
0215 cres->state = VMW_CMDBUF_RES_ADD;
0216 cres->res = vmw_resource_reference(res);
0217 cres->man = man;
0218 list_add_tail(&cres->head, list);
0219
0220 out_invalid_key:
0221 return ret;
0222 }
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240 int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
0241 enum vmw_cmdbuf_res_type res_type,
0242 u32 user_key,
0243 struct list_head *list,
0244 struct vmw_resource **res_p)
0245 {
0246 struct vmw_cmdbuf_res *entry;
0247 struct vmwgfx_hash_item *hash;
0248 int ret;
0249
0250 ret = vmwgfx_ht_find_item(&man->resources, user_key | (res_type << 24),
0251 &hash);
0252 if (likely(ret != 0))
0253 return -EINVAL;
0254
0255 entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash);
0256
0257 switch (entry->state) {
0258 case VMW_CMDBUF_RES_ADD:
0259 vmw_cmdbuf_res_free(man, entry);
0260 *res_p = NULL;
0261 break;
0262 case VMW_CMDBUF_RES_COMMITTED:
0263 (void) vmwgfx_ht_remove_item(&man->resources, &entry->hash);
0264 list_del(&entry->head);
0265 entry->state = VMW_CMDBUF_RES_DEL;
0266 list_add_tail(&entry->head, list);
0267 *res_p = entry->res;
0268 break;
0269 default:
0270 BUG();
0271 break;
0272 }
0273
0274 return 0;
0275 }
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286 struct vmw_cmdbuf_res_manager *
0287 vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
0288 {
0289 struct vmw_cmdbuf_res_manager *man;
0290 int ret;
0291
0292 man = kzalloc(sizeof(*man), GFP_KERNEL);
0293 if (!man)
0294 return ERR_PTR(-ENOMEM);
0295
0296 man->dev_priv = dev_priv;
0297 INIT_LIST_HEAD(&man->list);
0298 ret = vmwgfx_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
0299 if (ret == 0)
0300 return man;
0301
0302 kfree(man);
0303 return ERR_PTR(ret);
0304 }
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316 void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
0317 {
0318 struct vmw_cmdbuf_res *entry, *next;
0319
0320 list_for_each_entry_safe(entry, next, &man->list, head)
0321 vmw_cmdbuf_res_free(man, entry);
0322
0323 vmwgfx_ht_remove(&man->resources);
0324 kfree(man);
0325 }
0326