diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2012-02-09 10:56:42 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-02-13 07:01:32 -0500 |
commit | 6b82ef50d8617f3fcd51dda9d89d973fe3bc65b8 (patch) | |
tree | 960fa96955cadb1597f50f8c4138cf27b9229480 /drivers | |
parent | 8b7de6aa84682a3396544fd88cd457f95484573a (diff) |
vmwgfx: Clean up pending event references to struct drm_file objects on close
Pending events may have stale pointer references to struct drm_file objects
after a file has been closed, but before the event is supposed to be
attached to the drm file. Remove such events on file close.
Tested with "modetest".
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 60 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fence.h | 3 |
4 files changed, 73 insertions, 2 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index f390f5f9cb68..28f59a3c38d9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
@@ -688,6 +688,15 @@ static int vmw_driver_unload(struct drm_device *dev) | |||
688 | return 0; | 688 | return 0; |
689 | } | 689 | } |
690 | 690 | ||
691 | static void vmw_preclose(struct drm_device *dev, | ||
692 | struct drm_file *file_priv) | ||
693 | { | ||
694 | struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); | ||
695 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
696 | |||
697 | vmw_event_fence_fpriv_gone(dev_priv->fman, &vmw_fp->fence_events); | ||
698 | } | ||
699 | |||
691 | static void vmw_postclose(struct drm_device *dev, | 700 | static void vmw_postclose(struct drm_device *dev, |
692 | struct drm_file *file_priv) | 701 | struct drm_file *file_priv) |
693 | { | 702 | { |
@@ -710,6 +719,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv) | |||
710 | if (unlikely(vmw_fp == NULL)) | 719 | if (unlikely(vmw_fp == NULL)) |
711 | return ret; | 720 | return ret; |
712 | 721 | ||
722 | INIT_LIST_HEAD(&vmw_fp->fence_events); | ||
713 | vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10); | 723 | vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10); |
714 | if (unlikely(vmw_fp->tfile == NULL)) | 724 | if (unlikely(vmw_fp->tfile == NULL)) |
715 | goto out_no_tfile; | 725 | goto out_no_tfile; |
@@ -1102,6 +1112,7 @@ static struct drm_driver driver = { | |||
1102 | .master_set = vmw_master_set, | 1112 | .master_set = vmw_master_set, |
1103 | .master_drop = vmw_master_drop, | 1113 | .master_drop = vmw_master_drop, |
1104 | .open = vmw_driver_open, | 1114 | .open = vmw_driver_open, |
1115 | .preclose = vmw_preclose, | ||
1105 | .postclose = vmw_postclose, | 1116 | .postclose = vmw_postclose, |
1106 | .fops = &vmwgfx_driver_fops, | 1117 | .fops = &vmwgfx_driver_fops, |
1107 | .name = VMWGFX_DRIVER_NAME, | 1118 | .name = VMWGFX_DRIVER_NAME, |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 7f09db178fce..93505ce0ed10 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
@@ -62,6 +62,7 @@ | |||
62 | struct vmw_fpriv { | 62 | struct vmw_fpriv { |
63 | struct drm_master *locked_master; | 63 | struct drm_master *locked_master; |
64 | struct ttm_object_file *tfile; | 64 | struct ttm_object_file *tfile; |
65 | struct list_head fence_events; | ||
65 | }; | 66 | }; |
66 | 67 | ||
67 | struct vmw_dma_buffer { | 68 | struct vmw_dma_buffer { |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index ea9d0450b8a7..f2fb8f15e2f1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | |||
@@ -70,6 +70,7 @@ struct vmw_user_fence { | |||
70 | */ | 70 | */ |
71 | struct vmw_event_fence_action { | 71 | struct vmw_event_fence_action { |
72 | struct vmw_fence_action action; | 72 | struct vmw_fence_action action; |
73 | struct list_head fpriv_head; | ||
73 | 74 | ||
74 | struct drm_pending_event *event; | 75 | struct drm_pending_event *event; |
75 | struct vmw_fence_obj *fence; | 76 | struct vmw_fence_obj *fence; |
@@ -783,6 +784,43 @@ int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data, | |||
783 | TTM_REF_USAGE); | 784 | TTM_REF_USAGE); |
784 | } | 785 | } |
785 | 786 | ||
787 | /** | ||
788 | * vmw_event_fence_fpriv_gone - Remove references to struct drm_file objects | ||
789 | * | ||
790 | * @fman: Pointer to a struct vmw_fence_manager | ||
791 | * @event_list: Pointer to linked list of struct vmw_event_fence_action objects | ||
792 | * with pointers to a struct drm_file object about to be closed. | ||
793 | * | ||
794 | * This function removes all pending fence events with references to a | ||
795 | * specific struct drm_file object about to be closed. The caller is required | ||
796 | * to pass a list of all struct vmw_event_fence_action objects with such | ||
797 | * events attached. This function is typically called before the | ||
798 | * struct drm_file object's event management is taken down. | ||
799 | */ | ||
800 | void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman, | ||
801 | struct list_head *event_list) | ||
802 | { | ||
803 | struct vmw_event_fence_action *eaction; | ||
804 | struct drm_pending_event *event; | ||
805 | unsigned long irq_flags; | ||
806 | |||
807 | while (1) { | ||
808 | spin_lock_irqsave(&fman->lock, irq_flags); | ||
809 | if (list_empty(event_list)) | ||
810 | goto out_unlock; | ||
811 | eaction = list_first_entry(event_list, | ||
812 | struct vmw_event_fence_action, | ||
813 | fpriv_head); | ||
814 | list_del_init(&eaction->fpriv_head); | ||
815 | event = eaction->event; | ||
816 | eaction->event = NULL; | ||
817 | spin_unlock_irqrestore(&fman->lock, irq_flags); | ||
818 | event->destroy(event); | ||
819 | } | ||
820 | out_unlock: | ||
821 | spin_unlock_irqrestore(&fman->lock, irq_flags); | ||
822 | } | ||
823 | |||
786 | 824 | ||
787 | /** | 825 | /** |
788 | * vmw_event_fence_action_seq_passed | 826 | * vmw_event_fence_action_seq_passed |
@@ -800,9 +838,14 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action) | |||
800 | struct vmw_event_fence_action *eaction = | 838 | struct vmw_event_fence_action *eaction = |
801 | container_of(action, struct vmw_event_fence_action, action); | 839 | container_of(action, struct vmw_event_fence_action, action); |
802 | struct drm_device *dev = eaction->dev; | 840 | struct drm_device *dev = eaction->dev; |
803 | struct drm_file *file_priv = eaction->event->file_priv; | 841 | struct drm_pending_event *event = eaction->event; |
842 | struct drm_file *file_priv; | ||
804 | unsigned long irq_flags; | 843 | unsigned long irq_flags; |
805 | 844 | ||
845 | if (unlikely(event == NULL)) | ||
846 | return; | ||
847 | |||
848 | file_priv = event->file_priv; | ||
806 | spin_lock_irqsave(&dev->event_lock, irq_flags); | 849 | spin_lock_irqsave(&dev->event_lock, irq_flags); |
807 | 850 | ||
808 | if (likely(eaction->tv_sec != NULL)) { | 851 | if (likely(eaction->tv_sec != NULL)) { |
@@ -813,7 +856,9 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action) | |||
813 | *eaction->tv_usec = tv.tv_usec; | 856 | *eaction->tv_usec = tv.tv_usec; |
814 | } | 857 | } |
815 | 858 | ||
859 | list_del_init(&eaction->fpriv_head); | ||
816 | list_add_tail(&eaction->event->link, &file_priv->event_list); | 860 | list_add_tail(&eaction->event->link, &file_priv->event_list); |
861 | eaction->event = NULL; | ||
817 | wake_up_all(&file_priv->event_wait); | 862 | wake_up_all(&file_priv->event_wait); |
818 | spin_unlock_irqrestore(&dev->event_lock, irq_flags); | 863 | spin_unlock_irqrestore(&dev->event_lock, irq_flags); |
819 | } | 864 | } |
@@ -831,6 +876,12 @@ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action) | |||
831 | { | 876 | { |
832 | struct vmw_event_fence_action *eaction = | 877 | struct vmw_event_fence_action *eaction = |
833 | container_of(action, struct vmw_event_fence_action, action); | 878 | container_of(action, struct vmw_event_fence_action, action); |
879 | struct vmw_fence_manager *fman = eaction->fence->fman; | ||
880 | unsigned long irq_flags; | ||
881 | |||
882 | spin_lock_irqsave(&fman->lock, irq_flags); | ||
883 | list_del(&eaction->fpriv_head); | ||
884 | spin_unlock_irqrestore(&fman->lock, irq_flags); | ||
834 | 885 | ||
835 | vmw_fence_obj_unreference(&eaction->fence); | 886 | vmw_fence_obj_unreference(&eaction->fence); |
836 | kfree(eaction); | 887 | kfree(eaction); |
@@ -910,7 +961,8 @@ int vmw_event_fence_action_queue(struct drm_file *file_priv, | |||
910 | { | 961 | { |
911 | struct vmw_event_fence_action *eaction; | 962 | struct vmw_event_fence_action *eaction; |
912 | struct vmw_fence_manager *fman = fence->fman; | 963 | struct vmw_fence_manager *fman = fence->fman; |
913 | 964 | struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); | |
965 | unsigned long irq_flags; | ||
914 | 966 | ||
915 | eaction = kzalloc(sizeof(*eaction), GFP_KERNEL); | 967 | eaction = kzalloc(sizeof(*eaction), GFP_KERNEL); |
916 | if (unlikely(eaction == NULL)) | 968 | if (unlikely(eaction == NULL)) |
@@ -927,6 +979,10 @@ int vmw_event_fence_action_queue(struct drm_file *file_priv, | |||
927 | eaction->tv_sec = tv_sec; | 979 | eaction->tv_sec = tv_sec; |
928 | eaction->tv_usec = tv_usec; | 980 | eaction->tv_usec = tv_usec; |
929 | 981 | ||
982 | spin_lock_irqsave(&fman->lock, irq_flags); | ||
983 | list_add_tail(&eaction->fpriv_head, &vmw_fp->fence_events); | ||
984 | spin_unlock_irqrestore(&fman->lock, irq_flags); | ||
985 | |||
930 | vmw_fence_obj_add_action(fence, &eaction->action); | 986 | vmw_fence_obj_add_action(fence, &eaction->action); |
931 | 987 | ||
932 | return 0; | 988 | return 0; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h index 0854a2096b55..8767fc13265d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h | |||
@@ -109,5 +109,8 @@ extern int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data, | |||
109 | struct drm_file *file_priv); | 109 | struct drm_file *file_priv); |
110 | extern int vmw_fence_event_ioctl(struct drm_device *dev, void *data, | 110 | extern int vmw_fence_event_ioctl(struct drm_device *dev, void *data, |
111 | struct drm_file *file_priv); | 111 | struct drm_file *file_priv); |
112 | extern void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman, | ||
113 | struct list_head *event_list); | ||
114 | |||
112 | 115 | ||
113 | #endif /* _VMWGFX_FENCE_H_ */ | 116 | #endif /* _VMWGFX_FENCE_H_ */ |