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
0029 #include <drm/ttm/ttm_placement.h>
0030
0031 #include "vmwgfx_drv.h"
0032 #include "vmwgfx_resource_priv.h"
0033 #include "vmwgfx_binding.h"
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 struct vmw_dx_streamoutput {
0046 struct vmw_resource res;
0047 struct vmw_resource *ctx;
0048 struct vmw_resource *cotable;
0049 struct list_head cotable_head;
0050 u32 id;
0051 u32 size;
0052 bool committed;
0053 };
0054
0055 static int vmw_dx_streamoutput_create(struct vmw_resource *res);
0056 static int vmw_dx_streamoutput_bind(struct vmw_resource *res,
0057 struct ttm_validate_buffer *val_buf);
0058 static int vmw_dx_streamoutput_unbind(struct vmw_resource *res, bool readback,
0059 struct ttm_validate_buffer *val_buf);
0060 static void vmw_dx_streamoutput_commit_notify(struct vmw_resource *res,
0061 enum vmw_cmdbuf_res_state state);
0062
0063 static const struct vmw_res_func vmw_dx_streamoutput_func = {
0064 .res_type = vmw_res_streamoutput,
0065 .needs_backup = true,
0066 .may_evict = false,
0067 .type_name = "DX streamoutput",
0068 .backup_placement = &vmw_mob_placement,
0069 .create = vmw_dx_streamoutput_create,
0070 .destroy = NULL,
0071 .bind = vmw_dx_streamoutput_bind,
0072 .unbind = vmw_dx_streamoutput_unbind,
0073 .commit_notify = vmw_dx_streamoutput_commit_notify,
0074 };
0075
0076 static inline struct vmw_dx_streamoutput *
0077 vmw_res_to_dx_streamoutput(struct vmw_resource *res)
0078 {
0079 return container_of(res, struct vmw_dx_streamoutput, res);
0080 }
0081
0082
0083
0084
0085
0086
0087
0088 static int vmw_dx_streamoutput_unscrub(struct vmw_resource *res)
0089 {
0090 struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
0091 struct vmw_private *dev_priv = res->dev_priv;
0092 struct {
0093 SVGA3dCmdHeader header;
0094 SVGA3dCmdDXBindStreamOutput body;
0095 } *cmd;
0096
0097 if (!list_empty(&so->cotable_head) || !so->committed )
0098 return 0;
0099
0100 cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), so->ctx->id);
0101 if (!cmd)
0102 return -ENOMEM;
0103
0104 cmd->header.id = SVGA_3D_CMD_DX_BIND_STREAMOUTPUT;
0105 cmd->header.size = sizeof(cmd->body);
0106 cmd->body.soid = so->id;
0107 cmd->body.mobid = res->backup->base.resource->start;
0108 cmd->body.offsetInBytes = res->backup_offset;
0109 cmd->body.sizeInBytes = so->size;
0110 vmw_cmd_commit(dev_priv, sizeof(*cmd));
0111
0112 vmw_cotable_add_resource(so->cotable, &so->cotable_head);
0113
0114 return 0;
0115 }
0116
0117 static int vmw_dx_streamoutput_create(struct vmw_resource *res)
0118 {
0119 struct vmw_private *dev_priv = res->dev_priv;
0120 struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
0121 int ret = 0;
0122
0123 WARN_ON_ONCE(!so->committed);
0124
0125 if (vmw_resource_mob_attached(res)) {
0126 mutex_lock(&dev_priv->binding_mutex);
0127 ret = vmw_dx_streamoutput_unscrub(res);
0128 mutex_unlock(&dev_priv->binding_mutex);
0129 }
0130
0131 res->id = so->id;
0132
0133 return ret;
0134 }
0135
0136 static int vmw_dx_streamoutput_bind(struct vmw_resource *res,
0137 struct ttm_validate_buffer *val_buf)
0138 {
0139 struct vmw_private *dev_priv = res->dev_priv;
0140 struct ttm_buffer_object *bo = val_buf->bo;
0141 int ret;
0142
0143 if (WARN_ON(bo->resource->mem_type != VMW_PL_MOB))
0144 return -EINVAL;
0145
0146 mutex_lock(&dev_priv->binding_mutex);
0147 ret = vmw_dx_streamoutput_unscrub(res);
0148 mutex_unlock(&dev_priv->binding_mutex);
0149
0150 return ret;
0151 }
0152
0153
0154
0155
0156
0157
0158
0159 static int vmw_dx_streamoutput_scrub(struct vmw_resource *res)
0160 {
0161 struct vmw_private *dev_priv = res->dev_priv;
0162 struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
0163 struct {
0164 SVGA3dCmdHeader header;
0165 SVGA3dCmdDXBindStreamOutput body;
0166 } *cmd;
0167
0168 if (list_empty(&so->cotable_head))
0169 return 0;
0170
0171 WARN_ON_ONCE(!so->committed);
0172
0173 cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), so->ctx->id);
0174 if (!cmd)
0175 return -ENOMEM;
0176
0177 cmd->header.id = SVGA_3D_CMD_DX_BIND_STREAMOUTPUT;
0178 cmd->header.size = sizeof(cmd->body);
0179 cmd->body.soid = res->id;
0180 cmd->body.mobid = SVGA3D_INVALID_ID;
0181 cmd->body.offsetInBytes = 0;
0182 cmd->body.sizeInBytes = so->size;
0183 vmw_cmd_commit(dev_priv, sizeof(*cmd));
0184
0185 res->id = -1;
0186 list_del_init(&so->cotable_head);
0187
0188 return 0;
0189 }
0190
0191 static int vmw_dx_streamoutput_unbind(struct vmw_resource *res, bool readback,
0192 struct ttm_validate_buffer *val_buf)
0193 {
0194 struct vmw_private *dev_priv = res->dev_priv;
0195 struct vmw_fence_obj *fence;
0196 int ret;
0197
0198 if (WARN_ON(res->backup->base.resource->mem_type != VMW_PL_MOB))
0199 return -EINVAL;
0200
0201 mutex_lock(&dev_priv->binding_mutex);
0202 ret = vmw_dx_streamoutput_scrub(res);
0203 mutex_unlock(&dev_priv->binding_mutex);
0204
0205 if (ret)
0206 return ret;
0207
0208 (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
0209 vmw_bo_fence_single(val_buf->bo, fence);
0210
0211 if (fence != NULL)
0212 vmw_fence_obj_unreference(&fence);
0213
0214 return 0;
0215 }
0216
0217 static void vmw_dx_streamoutput_commit_notify(struct vmw_resource *res,
0218 enum vmw_cmdbuf_res_state state)
0219 {
0220 struct vmw_private *dev_priv = res->dev_priv;
0221 struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
0222
0223 if (state == VMW_CMDBUF_RES_ADD) {
0224 mutex_lock(&dev_priv->binding_mutex);
0225 vmw_cotable_add_resource(so->cotable, &so->cotable_head);
0226 so->committed = true;
0227 res->id = so->id;
0228 mutex_unlock(&dev_priv->binding_mutex);
0229 } else {
0230 mutex_lock(&dev_priv->binding_mutex);
0231 list_del_init(&so->cotable_head);
0232 so->committed = false;
0233 res->id = -1;
0234 mutex_unlock(&dev_priv->binding_mutex);
0235 }
0236 }
0237
0238
0239
0240
0241
0242
0243
0244
0245 struct vmw_resource *
0246 vmw_dx_streamoutput_lookup(struct vmw_cmdbuf_res_manager *man,
0247 u32 user_key)
0248 {
0249 return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_streamoutput,
0250 user_key);
0251 }
0252
0253 static void vmw_dx_streamoutput_res_free(struct vmw_resource *res)
0254 {
0255 struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
0256
0257 vmw_resource_unreference(&so->cotable);
0258 kfree(so);
0259 }
0260
0261 static void vmw_dx_streamoutput_hw_destroy(struct vmw_resource *res)
0262 {
0263
0264 res->id = -1;
0265 }
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276 int vmw_dx_streamoutput_add(struct vmw_cmdbuf_res_manager *man,
0277 struct vmw_resource *ctx, u32 user_key,
0278 struct list_head *list)
0279 {
0280 struct vmw_dx_streamoutput *so;
0281 struct vmw_resource *res;
0282 struct vmw_private *dev_priv = ctx->dev_priv;
0283 int ret;
0284
0285 so = kmalloc(sizeof(*so), GFP_KERNEL);
0286 if (!so) {
0287 return -ENOMEM;
0288 }
0289
0290 res = &so->res;
0291 so->ctx = ctx;
0292 so->cotable = vmw_resource_reference
0293 (vmw_context_cotable(ctx, SVGA_COTABLE_STREAMOUTPUT));
0294 so->id = user_key;
0295 so->committed = false;
0296 INIT_LIST_HEAD(&so->cotable_head);
0297 ret = vmw_resource_init(dev_priv, res, true,
0298 vmw_dx_streamoutput_res_free,
0299 &vmw_dx_streamoutput_func);
0300 if (ret)
0301 goto out_resource_init;
0302
0303 ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_streamoutput, user_key,
0304 res, list);
0305 if (ret)
0306 goto out_resource_init;
0307
0308 res->id = so->id;
0309 res->hw_destroy = vmw_dx_streamoutput_hw_destroy;
0310
0311 out_resource_init:
0312 vmw_resource_unreference(&res);
0313
0314 return ret;
0315 }
0316
0317
0318
0319
0320
0321
0322 void vmw_dx_streamoutput_set_size(struct vmw_resource *res, u32 size)
0323 {
0324 struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
0325
0326 so->size = size;
0327 }
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337 int vmw_dx_streamoutput_remove(struct vmw_cmdbuf_res_manager *man,
0338 u32 user_key,
0339 struct list_head *list)
0340 {
0341 struct vmw_resource *r;
0342
0343 return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_streamoutput,
0344 (u32)user_key, list, &r);
0345 }
0346
0347
0348
0349
0350
0351
0352
0353 void vmw_dx_streamoutput_cotable_list_scrub(struct vmw_private *dev_priv,
0354 struct list_head *list,
0355 bool readback)
0356 {
0357 struct vmw_dx_streamoutput *entry, *next;
0358
0359 lockdep_assert_held_once(&dev_priv->binding_mutex);
0360
0361 list_for_each_entry_safe(entry, next, list, cotable_head) {
0362 WARN_ON(vmw_dx_streamoutput_scrub(&entry->res));
0363 if (!readback)
0364 entry->committed =false;
0365 }
0366 }