diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_shader.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 467 |
1 files changed, 418 insertions, 49 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index 1457ec4b7125..217d941b8176 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include "vmwgfx_resource_priv.h" | 29 | #include "vmwgfx_resource_priv.h" |
30 | #include "ttm/ttm_placement.h" | 30 | #include "ttm/ttm_placement.h" |
31 | 31 | ||
32 | #define VMW_COMPAT_SHADER_HT_ORDER 12 | ||
33 | |||
32 | struct vmw_shader { | 34 | struct vmw_shader { |
33 | struct vmw_resource res; | 35 | struct vmw_resource res; |
34 | SVGA3dShaderType type; | 36 | SVGA3dShaderType type; |
@@ -40,6 +42,50 @@ struct vmw_user_shader { | |||
40 | struct vmw_shader shader; | 42 | struct vmw_shader shader; |
41 | }; | 43 | }; |
42 | 44 | ||
45 | /** | ||
46 | * enum vmw_compat_shader_state - Staging state for compat shaders | ||
47 | */ | ||
48 | enum vmw_compat_shader_state { | ||
49 | VMW_COMPAT_COMMITED, | ||
50 | VMW_COMPAT_ADD, | ||
51 | VMW_COMPAT_DEL | ||
52 | }; | ||
53 | |||
54 | /** | ||
55 | * struct vmw_compat_shader - Metadata for compat shaders. | ||
56 | * | ||
57 | * @handle: The TTM handle of the guest backed shader. | ||
58 | * @tfile: The struct ttm_object_file the guest backed shader is registered | ||
59 | * with. | ||
60 | * @hash: Hash item for lookup. | ||
61 | * @head: List head for staging lists or the compat shader manager list. | ||
62 | * @state: Staging state. | ||
63 | * | ||
64 | * The structure is protected by the cmdbuf lock. | ||
65 | */ | ||
66 | struct vmw_compat_shader { | ||
67 | u32 handle; | ||
68 | struct ttm_object_file *tfile; | ||
69 | struct drm_hash_item hash; | ||
70 | struct list_head head; | ||
71 | enum vmw_compat_shader_state state; | ||
72 | }; | ||
73 | |||
74 | /** | ||
75 | * struct vmw_compat_shader_manager - Compat shader manager. | ||
76 | * | ||
77 | * @shaders: Hash table containing staged and commited compat shaders | ||
78 | * @list: List of commited shaders. | ||
79 | * @dev_priv: Pointer to a device private structure. | ||
80 | * | ||
81 | * @shaders and @list are protected by the cmdbuf mutex for now. | ||
82 | */ | ||
83 | struct vmw_compat_shader_manager { | ||
84 | struct drm_open_hash shaders; | ||
85 | struct list_head list; | ||
86 | struct vmw_private *dev_priv; | ||
87 | }; | ||
88 | |||
43 | static void vmw_user_shader_free(struct vmw_resource *res); | 89 | static void vmw_user_shader_free(struct vmw_resource *res); |
44 | static struct vmw_resource * | 90 | static struct vmw_resource * |
45 | vmw_user_shader_base_to_res(struct ttm_base_object *base); | 91 | vmw_user_shader_base_to_res(struct ttm_base_object *base); |
@@ -258,7 +304,7 @@ static int vmw_gb_shader_destroy(struct vmw_resource *res) | |||
258 | return 0; | 304 | return 0; |
259 | 305 | ||
260 | mutex_lock(&dev_priv->binding_mutex); | 306 | mutex_lock(&dev_priv->binding_mutex); |
261 | vmw_context_binding_res_list_kill(&res->binding_head); | 307 | vmw_context_binding_res_list_scrub(&res->binding_head); |
262 | 308 | ||
263 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); | 309 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
264 | if (unlikely(cmd == NULL)) { | 310 | if (unlikely(cmd == NULL)) { |
@@ -325,13 +371,81 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, | |||
325 | TTM_REF_USAGE); | 371 | TTM_REF_USAGE); |
326 | } | 372 | } |
327 | 373 | ||
374 | int vmw_shader_alloc(struct vmw_private *dev_priv, | ||
375 | struct vmw_dma_buffer *buffer, | ||
376 | size_t shader_size, | ||
377 | size_t offset, | ||
378 | SVGA3dShaderType shader_type, | ||
379 | struct ttm_object_file *tfile, | ||
380 | u32 *handle) | ||
381 | { | ||
382 | struct vmw_user_shader *ushader; | ||
383 | struct vmw_resource *res, *tmp; | ||
384 | int ret; | ||
385 | |||
386 | /* | ||
387 | * Approximate idr memory usage with 128 bytes. It will be limited | ||
388 | * by maximum number_of shaders anyway. | ||
389 | */ | ||
390 | if (unlikely(vmw_user_shader_size == 0)) | ||
391 | vmw_user_shader_size = | ||
392 | ttm_round_pot(sizeof(struct vmw_user_shader)) + 128; | ||
393 | |||
394 | ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), | ||
395 | vmw_user_shader_size, | ||
396 | false, true); | ||
397 | if (unlikely(ret != 0)) { | ||
398 | if (ret != -ERESTARTSYS) | ||
399 | DRM_ERROR("Out of graphics memory for shader " | ||
400 | "creation.\n"); | ||
401 | goto out; | ||
402 | } | ||
403 | |||
404 | ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); | ||
405 | if (unlikely(ushader == NULL)) { | ||
406 | ttm_mem_global_free(vmw_mem_glob(dev_priv), | ||
407 | vmw_user_shader_size); | ||
408 | ret = -ENOMEM; | ||
409 | goto out; | ||
410 | } | ||
411 | |||
412 | res = &ushader->shader.res; | ||
413 | ushader->base.shareable = false; | ||
414 | ushader->base.tfile = NULL; | ||
415 | |||
416 | /* | ||
417 | * From here on, the destructor takes over resource freeing. | ||
418 | */ | ||
419 | |||
420 | ret = vmw_gb_shader_init(dev_priv, res, shader_size, | ||
421 | offset, shader_type, buffer, | ||
422 | vmw_user_shader_free); | ||
423 | if (unlikely(ret != 0)) | ||
424 | goto out; | ||
425 | |||
426 | tmp = vmw_resource_reference(res); | ||
427 | ret = ttm_base_object_init(tfile, &ushader->base, false, | ||
428 | VMW_RES_SHADER, | ||
429 | &vmw_user_shader_base_release, NULL); | ||
430 | |||
431 | if (unlikely(ret != 0)) { | ||
432 | vmw_resource_unreference(&tmp); | ||
433 | goto out_err; | ||
434 | } | ||
435 | |||
436 | if (handle) | ||
437 | *handle = ushader->base.hash.key; | ||
438 | out_err: | ||
439 | vmw_resource_unreference(&res); | ||
440 | out: | ||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | |||
328 | int vmw_shader_define_ioctl(struct drm_device *dev, void *data, | 445 | int vmw_shader_define_ioctl(struct drm_device *dev, void *data, |
329 | struct drm_file *file_priv) | 446 | struct drm_file *file_priv) |
330 | { | 447 | { |
331 | struct vmw_private *dev_priv = vmw_priv(dev); | 448 | struct vmw_private *dev_priv = vmw_priv(dev); |
332 | struct vmw_user_shader *ushader; | ||
333 | struct vmw_resource *res; | ||
334 | struct vmw_resource *tmp; | ||
335 | struct drm_vmw_shader_create_arg *arg = | 449 | struct drm_vmw_shader_create_arg *arg = |
336 | (struct drm_vmw_shader_create_arg *)data; | 450 | (struct drm_vmw_shader_create_arg *)data; |
337 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | 451 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
@@ -373,69 +487,324 @@ int vmw_shader_define_ioctl(struct drm_device *dev, void *data, | |||
373 | goto out_bad_arg; | 487 | goto out_bad_arg; |
374 | } | 488 | } |
375 | 489 | ||
376 | /* | 490 | ret = ttm_read_lock(&vmaster->lock, true); |
377 | * Approximate idr memory usage with 128 bytes. It will be limited | 491 | if (unlikely(ret != 0)) |
378 | * by maximum number_of shaders anyway. | 492 | goto out_bad_arg; |
379 | */ | ||
380 | 493 | ||
381 | if (unlikely(vmw_user_shader_size == 0)) | 494 | ret = vmw_shader_alloc(dev_priv, buffer, arg->size, arg->offset, |
382 | vmw_user_shader_size = ttm_round_pot(sizeof(*ushader)) | 495 | shader_type, tfile, &arg->shader_handle); |
383 | + 128; | ||
384 | 496 | ||
385 | ret = ttm_read_lock(&vmaster->lock, true); | 497 | ttm_read_unlock(&vmaster->lock); |
498 | out_bad_arg: | ||
499 | vmw_dmabuf_unreference(&buffer); | ||
500 | return ret; | ||
501 | } | ||
502 | |||
503 | /** | ||
504 | * vmw_compat_shader_lookup - Look up a compat shader | ||
505 | * | ||
506 | * @man: Pointer to the compat shader manager. | ||
507 | * @shader_type: The shader type, that combined with the user_key identifies | ||
508 | * the shader. | ||
509 | * @user_key: On entry, this should be a pointer to the user_key. | ||
510 | * On successful exit, it will contain the guest-backed shader's TTM handle. | ||
511 | * | ||
512 | * Returns 0 on success. Non-zero on failure, in which case the value pointed | ||
513 | * to by @user_key is unmodified. | ||
514 | */ | ||
515 | int vmw_compat_shader_lookup(struct vmw_compat_shader_manager *man, | ||
516 | SVGA3dShaderType shader_type, | ||
517 | u32 *user_key) | ||
518 | { | ||
519 | struct drm_hash_item *hash; | ||
520 | int ret; | ||
521 | unsigned long key = *user_key | (shader_type << 24); | ||
522 | |||
523 | ret = drm_ht_find_item(&man->shaders, key, &hash); | ||
386 | if (unlikely(ret != 0)) | 524 | if (unlikely(ret != 0)) |
387 | return ret; | 525 | return ret; |
388 | 526 | ||
389 | ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), | 527 | *user_key = drm_hash_entry(hash, struct vmw_compat_shader, |
390 | vmw_user_shader_size, | 528 | hash)->handle; |
391 | false, true); | 529 | |
392 | if (unlikely(ret != 0)) { | 530 | return 0; |
393 | if (ret != -ERESTARTSYS) | 531 | } |
394 | DRM_ERROR("Out of graphics memory for shader" | 532 | |
395 | " creation.\n"); | 533 | /** |
396 | goto out_unlock; | 534 | * vmw_compat_shader_free - Free a compat shader. |
535 | * | ||
536 | * @man: Pointer to the compat shader manager. | ||
537 | * @entry: Pointer to a struct vmw_compat_shader. | ||
538 | * | ||
539 | * Frees a struct vmw_compat_shder entry and drops its reference to the | ||
540 | * guest backed shader. | ||
541 | */ | ||
542 | static void vmw_compat_shader_free(struct vmw_compat_shader_manager *man, | ||
543 | struct vmw_compat_shader *entry) | ||
544 | { | ||
545 | list_del(&entry->head); | ||
546 | WARN_ON(drm_ht_remove_item(&man->shaders, &entry->hash)); | ||
547 | WARN_ON(ttm_ref_object_base_unref(entry->tfile, entry->handle, | ||
548 | TTM_REF_USAGE)); | ||
549 | kfree(entry); | ||
550 | } | ||
551 | |||
552 | /** | ||
553 | * vmw_compat_shaders_commit - Commit a list of compat shader actions. | ||
554 | * | ||
555 | * @man: Pointer to the compat shader manager. | ||
556 | * @list: Caller's list of compat shader actions. | ||
557 | * | ||
558 | * This function commits a list of compat shader additions or removals. | ||
559 | * It is typically called when the execbuf ioctl call triggering these | ||
560 | * actions has commited the fifo contents to the device. | ||
561 | */ | ||
562 | void vmw_compat_shaders_commit(struct vmw_compat_shader_manager *man, | ||
563 | struct list_head *list) | ||
564 | { | ||
565 | struct vmw_compat_shader *entry, *next; | ||
566 | |||
567 | list_for_each_entry_safe(entry, next, list, head) { | ||
568 | list_del(&entry->head); | ||
569 | switch (entry->state) { | ||
570 | case VMW_COMPAT_ADD: | ||
571 | entry->state = VMW_COMPAT_COMMITED; | ||
572 | list_add_tail(&entry->head, &man->list); | ||
573 | break; | ||
574 | case VMW_COMPAT_DEL: | ||
575 | ttm_ref_object_base_unref(entry->tfile, entry->handle, | ||
576 | TTM_REF_USAGE); | ||
577 | kfree(entry); | ||
578 | break; | ||
579 | default: | ||
580 | BUG(); | ||
581 | break; | ||
582 | } | ||
397 | } | 583 | } |
584 | } | ||
398 | 585 | ||
399 | ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); | 586 | /** |
400 | if (unlikely(ushader == NULL)) { | 587 | * vmw_compat_shaders_revert - Revert a list of compat shader actions |
401 | ttm_mem_global_free(vmw_mem_glob(dev_priv), | 588 | * |
402 | vmw_user_shader_size); | 589 | * @man: Pointer to the compat shader manager. |
403 | ret = -ENOMEM; | 590 | * @list: Caller's list of compat shader actions. |
404 | goto out_unlock; | 591 | * |
592 | * This function reverts a list of compat shader additions or removals. | ||
593 | * It is typically called when the execbuf ioctl call triggering these | ||
594 | * actions failed for some reason, and the command stream was never | ||
595 | * submitted. | ||
596 | */ | ||
597 | void vmw_compat_shaders_revert(struct vmw_compat_shader_manager *man, | ||
598 | struct list_head *list) | ||
599 | { | ||
600 | struct vmw_compat_shader *entry, *next; | ||
601 | int ret; | ||
602 | |||
603 | list_for_each_entry_safe(entry, next, list, head) { | ||
604 | switch (entry->state) { | ||
605 | case VMW_COMPAT_ADD: | ||
606 | vmw_compat_shader_free(man, entry); | ||
607 | break; | ||
608 | case VMW_COMPAT_DEL: | ||
609 | ret = drm_ht_insert_item(&man->shaders, &entry->hash); | ||
610 | list_del(&entry->head); | ||
611 | list_add_tail(&entry->head, &man->list); | ||
612 | entry->state = VMW_COMPAT_COMMITED; | ||
613 | break; | ||
614 | default: | ||
615 | BUG(); | ||
616 | break; | ||
617 | } | ||
405 | } | 618 | } |
619 | } | ||
406 | 620 | ||
407 | res = &ushader->shader.res; | 621 | /** |
408 | ushader->base.shareable = false; | 622 | * vmw_compat_shader_remove - Stage a compat shader for removal. |
409 | ushader->base.tfile = NULL; | 623 | * |
624 | * @man: Pointer to the compat shader manager | ||
625 | * @user_key: The key that is used to identify the shader. The key is | ||
626 | * unique to the shader type. | ||
627 | * @shader_type: Shader type. | ||
628 | * @list: Caller's list of staged shader actions. | ||
629 | * | ||
630 | * This function stages a compat shader for removal and removes the key from | ||
631 | * the shader manager's hash table. If the shader was previously only staged | ||
632 | * for addition it is completely removed (But the execbuf code may keep a | ||
633 | * reference if it was bound to a context between addition and removal). If | ||
634 | * it was previously commited to the manager, it is staged for removal. | ||
635 | */ | ||
636 | int vmw_compat_shader_remove(struct vmw_compat_shader_manager *man, | ||
637 | u32 user_key, SVGA3dShaderType shader_type, | ||
638 | struct list_head *list) | ||
639 | { | ||
640 | struct vmw_compat_shader *entry; | ||
641 | struct drm_hash_item *hash; | ||
642 | int ret; | ||
410 | 643 | ||
411 | /* | 644 | ret = drm_ht_find_item(&man->shaders, user_key | (shader_type << 24), |
412 | * From here on, the destructor takes over resource freeing. | 645 | &hash); |
413 | */ | 646 | if (likely(ret != 0)) |
647 | return -EINVAL; | ||
414 | 648 | ||
415 | ret = vmw_gb_shader_init(dev_priv, res, arg->size, | 649 | entry = drm_hash_entry(hash, struct vmw_compat_shader, hash); |
416 | arg->offset, shader_type, buffer, | 650 | |
417 | vmw_user_shader_free); | 651 | switch (entry->state) { |
652 | case VMW_COMPAT_ADD: | ||
653 | vmw_compat_shader_free(man, entry); | ||
654 | break; | ||
655 | case VMW_COMPAT_COMMITED: | ||
656 | (void) drm_ht_remove_item(&man->shaders, &entry->hash); | ||
657 | list_del(&entry->head); | ||
658 | entry->state = VMW_COMPAT_DEL; | ||
659 | list_add_tail(&entry->head, list); | ||
660 | break; | ||
661 | default: | ||
662 | BUG(); | ||
663 | break; | ||
664 | } | ||
665 | |||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | /** | ||
670 | * vmw_compat_shader_add - Create a compat shader and add the | ||
671 | * key to the manager | ||
672 | * | ||
673 | * @man: Pointer to the compat shader manager | ||
674 | * @user_key: The key that is used to identify the shader. The key is | ||
675 | * unique to the shader type. | ||
676 | * @bytecode: Pointer to the bytecode of the shader. | ||
677 | * @shader_type: Shader type. | ||
678 | * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is | ||
679 | * to be created with. | ||
680 | * @list: Caller's list of staged shader actions. | ||
681 | * | ||
682 | * Note that only the key is added to the shader manager's hash table. | ||
683 | * The shader is not yet added to the shader manager's list of shaders. | ||
684 | */ | ||
685 | int vmw_compat_shader_add(struct vmw_compat_shader_manager *man, | ||
686 | u32 user_key, const void *bytecode, | ||
687 | SVGA3dShaderType shader_type, | ||
688 | size_t size, | ||
689 | struct ttm_object_file *tfile, | ||
690 | struct list_head *list) | ||
691 | { | ||
692 | struct vmw_dma_buffer *buf; | ||
693 | struct ttm_bo_kmap_obj map; | ||
694 | bool is_iomem; | ||
695 | struct vmw_compat_shader *compat; | ||
696 | u32 handle; | ||
697 | int ret; | ||
698 | |||
699 | if (user_key > ((1 << 24) - 1) || (unsigned) shader_type > 16) | ||
700 | return -EINVAL; | ||
701 | |||
702 | /* Allocate and pin a DMA buffer */ | ||
703 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); | ||
704 | if (unlikely(buf == NULL)) | ||
705 | return -ENOMEM; | ||
706 | |||
707 | ret = vmw_dmabuf_init(man->dev_priv, buf, size, &vmw_sys_ne_placement, | ||
708 | true, vmw_dmabuf_bo_free); | ||
418 | if (unlikely(ret != 0)) | 709 | if (unlikely(ret != 0)) |
419 | goto out_unlock; | 710 | goto out; |
420 | 711 | ||
421 | tmp = vmw_resource_reference(res); | 712 | ret = ttm_bo_reserve(&buf->base, false, true, false, NULL); |
422 | ret = ttm_base_object_init(tfile, &ushader->base, false, | 713 | if (unlikely(ret != 0)) |
423 | VMW_RES_SHADER, | 714 | goto no_reserve; |
424 | &vmw_user_shader_base_release, NULL); | ||
425 | 715 | ||
716 | /* Map and copy shader bytecode. */ | ||
717 | ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT, | ||
718 | &map); | ||
426 | if (unlikely(ret != 0)) { | 719 | if (unlikely(ret != 0)) { |
427 | vmw_resource_unreference(&tmp); | 720 | ttm_bo_unreserve(&buf->base); |
428 | goto out_err; | 721 | goto no_reserve; |
429 | } | 722 | } |
430 | 723 | ||
431 | arg->shader_handle = ushader->base.hash.key; | 724 | memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size); |
432 | out_err: | 725 | WARN_ON(is_iomem); |
433 | vmw_resource_unreference(&res); | 726 | |
434 | out_unlock: | 727 | ttm_bo_kunmap(&map); |
435 | ttm_read_unlock(&vmaster->lock); | 728 | ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, false, true); |
436 | out_bad_arg: | 729 | WARN_ON(ret != 0); |
437 | vmw_dmabuf_unreference(&buffer); | 730 | ttm_bo_unreserve(&buf->base); |
731 | |||
732 | /* Create a guest-backed shader container backed by the dma buffer */ | ||
733 | ret = vmw_shader_alloc(man->dev_priv, buf, size, 0, shader_type, | ||
734 | tfile, &handle); | ||
735 | vmw_dmabuf_unreference(&buf); | ||
736 | if (unlikely(ret != 0)) | ||
737 | goto no_reserve; | ||
738 | /* | ||
739 | * Create a compat shader structure and stage it for insertion | ||
740 | * in the manager | ||
741 | */ | ||
742 | compat = kzalloc(sizeof(*compat), GFP_KERNEL); | ||
743 | if (compat == NULL) | ||
744 | goto no_compat; | ||
745 | |||
746 | compat->hash.key = user_key | (shader_type << 24); | ||
747 | ret = drm_ht_insert_item(&man->shaders, &compat->hash); | ||
748 | if (unlikely(ret != 0)) | ||
749 | goto out_invalid_key; | ||
750 | |||
751 | compat->state = VMW_COMPAT_ADD; | ||
752 | compat->handle = handle; | ||
753 | compat->tfile = tfile; | ||
754 | list_add_tail(&compat->head, list); | ||
438 | 755 | ||
756 | return 0; | ||
757 | |||
758 | out_invalid_key: | ||
759 | kfree(compat); | ||
760 | no_compat: | ||
761 | ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); | ||
762 | no_reserve: | ||
763 | out: | ||
439 | return ret; | 764 | return ret; |
765 | } | ||
766 | |||
767 | /** | ||
768 | * vmw_compat_shader_man_create - Create a compat shader manager | ||
769 | * | ||
770 | * @dev_priv: Pointer to a device private structure. | ||
771 | * | ||
772 | * Typically done at file open time. If successful returns a pointer to a | ||
773 | * compat shader manager. Otherwise returns an error pointer. | ||
774 | */ | ||
775 | struct vmw_compat_shader_manager * | ||
776 | vmw_compat_shader_man_create(struct vmw_private *dev_priv) | ||
777 | { | ||
778 | struct vmw_compat_shader_manager *man; | ||
779 | int ret; | ||
780 | |||
781 | man = kzalloc(sizeof(*man), GFP_KERNEL); | ||
782 | |||
783 | man->dev_priv = dev_priv; | ||
784 | INIT_LIST_HEAD(&man->list); | ||
785 | ret = drm_ht_create(&man->shaders, VMW_COMPAT_SHADER_HT_ORDER); | ||
786 | if (ret == 0) | ||
787 | return man; | ||
788 | |||
789 | kfree(man); | ||
790 | return ERR_PTR(ret); | ||
791 | } | ||
792 | |||
793 | /** | ||
794 | * vmw_compat_shader_man_destroy - Destroy a compat shader manager | ||
795 | * | ||
796 | * @man: Pointer to the shader manager to destroy. | ||
797 | * | ||
798 | * Typically done at file close time. | ||
799 | */ | ||
800 | void vmw_compat_shader_man_destroy(struct vmw_compat_shader_manager *man) | ||
801 | { | ||
802 | struct vmw_compat_shader *entry, *next; | ||
803 | |||
804 | mutex_lock(&man->dev_priv->cmdbuf_mutex); | ||
805 | list_for_each_entry_safe(entry, next, &man->list, head) | ||
806 | vmw_compat_shader_free(man, entry); | ||
440 | 807 | ||
808 | mutex_unlock(&man->dev_priv->cmdbuf_mutex); | ||
809 | kfree(man); | ||
441 | } | 810 | } |