diff options
| author | Christian Gmeiner <christian.gmeiner@gmail.com> | 2017-09-24 09:15:26 -0400 |
|---|---|---|
| committer | Lucas Stach <l.stach@pengutronix.de> | 2017-10-10 05:45:44 -0400 |
| commit | c8e4a7fdea98ffdb6029bc591dd4b0ba31e17774 (patch) | |
| tree | 6142704fd202422a5777b97f5448f145a6792fb9 | |
| parent | 46df52cd4395b62d05b9ac99a7f320f577b5cff5 (diff) | |
drm/etnaviv: copy pmrs from userspace
Changes from v1 -> v2:
- renamed submit_perfmon_request() to submit_perfmon_validate()
- extended flags validation
- added comment about offset 0
- moved assigment of cmdbuf->nr_pmrs below the copy_from_user of the pmrs.
Changes from v2 -> v3:
- fixed flags validation
Changes v4 -> v5
- pass cmdbuf->exec_state to etnaviv_pm_req_validate(..)
Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
| -rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 69 |
1 files changed, 67 insertions, 2 deletions
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 41abdfc7cb00..78f20a3d47d9 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "etnaviv_drv.h" | 21 | #include "etnaviv_drv.h" |
| 22 | #include "etnaviv_gpu.h" | 22 | #include "etnaviv_gpu.h" |
| 23 | #include "etnaviv_gem.h" | 23 | #include "etnaviv_gem.h" |
| 24 | #include "etnaviv_perfmon.h" | ||
| 24 | 25 | ||
| 25 | /* | 26 | /* |
| 26 | * Cmdstream submission: | 27 | * Cmdstream submission: |
| @@ -283,6 +284,54 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, | |||
| 283 | return 0; | 284 | return 0; |
| 284 | } | 285 | } |
| 285 | 286 | ||
| 287 | static int submit_perfmon_validate(struct etnaviv_gem_submit *submit, | ||
| 288 | struct etnaviv_cmdbuf *cmdbuf, | ||
| 289 | const struct drm_etnaviv_gem_submit_pmr *pmrs, | ||
| 290 | u32 nr_pms) | ||
| 291 | { | ||
| 292 | u32 i; | ||
| 293 | |||
| 294 | for (i = 0; i < nr_pms; i++) { | ||
| 295 | const struct drm_etnaviv_gem_submit_pmr *r = pmrs + i; | ||
| 296 | struct etnaviv_gem_submit_bo *bo; | ||
| 297 | int ret; | ||
| 298 | |||
| 299 | ret = submit_bo(submit, r->read_idx, &bo); | ||
| 300 | if (ret) | ||
| 301 | return ret; | ||
| 302 | |||
| 303 | /* at offset 0 a sequence number gets stored used for userspace sync */ | ||
| 304 | if (r->read_offset == 0) { | ||
| 305 | DRM_ERROR("perfmon request: offset is 0"); | ||
| 306 | return -EINVAL; | ||
| 307 | } | ||
| 308 | |||
| 309 | if (r->read_offset >= bo->obj->base.size - sizeof(u32)) { | ||
| 310 | DRM_ERROR("perfmon request: offset %u outside object", i); | ||
| 311 | return -EINVAL; | ||
| 312 | } | ||
| 313 | |||
| 314 | if (r->flags & ~(ETNA_PM_PROCESS_PRE | ETNA_PM_PROCESS_POST)) { | ||
| 315 | DRM_ERROR("perfmon request: flags are not valid"); | ||
| 316 | return -EINVAL; | ||
| 317 | } | ||
| 318 | |||
| 319 | if (etnaviv_pm_req_validate(r, cmdbuf->exec_state)) { | ||
| 320 | DRM_ERROR("perfmon request: domain or signal not valid"); | ||
| 321 | return -EINVAL; | ||
| 322 | } | ||
| 323 | |||
| 324 | cmdbuf->pmrs[i].flags = r->flags; | ||
| 325 | cmdbuf->pmrs[i].domain = r->domain; | ||
| 326 | cmdbuf->pmrs[i].signal = r->signal; | ||
| 327 | cmdbuf->pmrs[i].sequence = r->sequence; | ||
| 328 | cmdbuf->pmrs[i].offset = r->read_offset; | ||
| 329 | cmdbuf->pmrs[i].bo_vma = etnaviv_gem_vmap(&bo->obj->base); | ||
| 330 | } | ||
| 331 | |||
| 332 | return 0; | ||
| 333 | } | ||
| 334 | |||
| 286 | static void submit_cleanup(struct etnaviv_gem_submit *submit) | 335 | static void submit_cleanup(struct etnaviv_gem_submit *submit) |
| 287 | { | 336 | { |
| 288 | unsigned i; | 337 | unsigned i; |
| @@ -306,6 +355,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, | |||
| 306 | struct etnaviv_drm_private *priv = dev->dev_private; | 355 | struct etnaviv_drm_private *priv = dev->dev_private; |
| 307 | struct drm_etnaviv_gem_submit *args = data; | 356 | struct drm_etnaviv_gem_submit *args = data; |
| 308 | struct drm_etnaviv_gem_submit_reloc *relocs; | 357 | struct drm_etnaviv_gem_submit_reloc *relocs; |
| 358 | struct drm_etnaviv_gem_submit_pmr *pmrs; | ||
| 309 | struct drm_etnaviv_gem_submit_bo *bos; | 359 | struct drm_etnaviv_gem_submit_bo *bos; |
| 310 | struct etnaviv_gem_submit *submit; | 360 | struct etnaviv_gem_submit *submit; |
| 311 | struct etnaviv_cmdbuf *cmdbuf; | 361 | struct etnaviv_cmdbuf *cmdbuf; |
| @@ -347,11 +397,12 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, | |||
| 347 | */ | 397 | */ |
| 348 | bos = kvmalloc_array(args->nr_bos, sizeof(*bos), GFP_KERNEL); | 398 | bos = kvmalloc_array(args->nr_bos, sizeof(*bos), GFP_KERNEL); |
| 349 | relocs = kvmalloc_array(args->nr_relocs, sizeof(*relocs), GFP_KERNEL); | 399 | relocs = kvmalloc_array(args->nr_relocs, sizeof(*relocs), GFP_KERNEL); |
| 400 | pmrs = kvmalloc_array(args->nr_pmrs, sizeof(*pmrs), GFP_KERNEL); | ||
| 350 | stream = kvmalloc_array(1, args->stream_size, GFP_KERNEL); | 401 | stream = kvmalloc_array(1, args->stream_size, GFP_KERNEL); |
| 351 | cmdbuf = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc, | 402 | cmdbuf = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc, |
| 352 | ALIGN(args->stream_size, 8) + 8, | 403 | ALIGN(args->stream_size, 8) + 8, |
| 353 | args->nr_bos, 0); | 404 | args->nr_bos, args->nr_pmrs); |
| 354 | if (!bos || !relocs || !stream || !cmdbuf) { | 405 | if (!bos || !relocs || !pmrs || !stream || !cmdbuf) { |
| 355 | ret = -ENOMEM; | 406 | ret = -ENOMEM; |
| 356 | goto err_submit_cmds; | 407 | goto err_submit_cmds; |
| 357 | } | 408 | } |
| @@ -373,6 +424,14 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, | |||
| 373 | goto err_submit_cmds; | 424 | goto err_submit_cmds; |
| 374 | } | 425 | } |
| 375 | 426 | ||
| 427 | ret = copy_from_user(pmrs, u64_to_user_ptr(args->pmrs), | ||
| 428 | args->nr_pmrs * sizeof(*pmrs)); | ||
| 429 | if (ret) { | ||
| 430 | ret = -EFAULT; | ||
| 431 | goto err_submit_cmds; | ||
| 432 | } | ||
| 433 | cmdbuf->nr_pmrs = args->nr_pmrs; | ||
| 434 | |||
| 376 | ret = copy_from_user(stream, u64_to_user_ptr(args->stream), | 435 | ret = copy_from_user(stream, u64_to_user_ptr(args->stream), |
| 377 | args->stream_size); | 436 | args->stream_size); |
| 378 | if (ret) { | 437 | if (ret) { |
| @@ -441,6 +500,10 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, | |||
| 441 | if (ret) | 500 | if (ret) |
| 442 | goto out; | 501 | goto out; |
| 443 | 502 | ||
| 503 | ret = submit_perfmon_validate(submit, cmdbuf, pmrs, args->nr_pmrs); | ||
| 504 | if (ret) | ||
| 505 | goto out; | ||
| 506 | |||
| 444 | memcpy(cmdbuf->vaddr, stream, args->stream_size); | 507 | memcpy(cmdbuf->vaddr, stream, args->stream_size); |
| 445 | cmdbuf->user_size = ALIGN(args->stream_size, 8); | 508 | cmdbuf->user_size = ALIGN(args->stream_size, 8); |
| 446 | 509 | ||
| @@ -494,6 +557,8 @@ err_submit_cmds: | |||
| 494 | kvfree(bos); | 557 | kvfree(bos); |
| 495 | if (relocs) | 558 | if (relocs) |
| 496 | kvfree(relocs); | 559 | kvfree(relocs); |
| 560 | if (pmrs) | ||
| 561 | kvfree(pmrs); | ||
| 497 | 562 | ||
| 498 | return ret; | 563 | return ret; |
| 499 | } | 564 | } |
