summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
diff options
context:
space:
mode:
authorKonsta Holtta <kholtta@nvidia.com>2014-10-31 04:47:00 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:11:58 -0400
commit7bb9fe2748d3324915108af85e6014da367071f6 (patch)
treeb95b11407d99657318b7a669891102a530b18323 /drivers/gpu/nvgpu/gk20a/channel_gk20a.c
parent14577a339ccc160ed58f8d936ebcbd96dba3b6ca (diff)
gpu: nvgpu: protect channel update callback access
Protect callback races from spurious gk20a channel updates by testing if the channel update callback still exists when in the scheduled work (instead of only when scheduling the work to the queue), and by canceling the work when the channel is freed. Protect access to the callback and its data by accessing them together inside spinlock-protected regions. Bug 200051384 Change-Id: Ib4e1571c35f662195e1dec1e362df32ddc099eb3 Signed-off-by: Konsta Holtta <kholtta@nvidia.com> Reviewed-on: http://git-master/r/592026 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/channel_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
index f554cf77..f48ef35f 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
@@ -682,8 +682,11 @@ void gk20a_free_channel(struct channel_gk20a *ch, bool finish)
682 else 682 else
683 gk20a_vm_put(ch_vm); 683 gk20a_vm_put(ch_vm);
684 684
685 spin_lock(&ch->update_fn_lock);
685 ch->update_fn = NULL; 686 ch->update_fn = NULL;
686 ch->update_fn_data = NULL; 687 ch->update_fn_data = NULL;
688 spin_unlock(&ch->update_fn_lock);
689 cancel_work_sync(&ch->update_fn_work);
687 690
688unbind: 691unbind:
689 if (gk20a_is_channel_marked_as_tsg(ch)) 692 if (gk20a_is_channel_marked_as_tsg(ch))
@@ -745,7 +748,16 @@ static void gk20a_channel_update_runcb_fn(struct work_struct *work)
745{ 748{
746 struct channel_gk20a *ch = 749 struct channel_gk20a *ch =
747 container_of(work, struct channel_gk20a, update_fn_work); 750 container_of(work, struct channel_gk20a, update_fn_work);
748 ch->update_fn(ch, ch->update_fn_data); 751 void (*update_fn)(struct channel_gk20a *, void *);
752 void *update_fn_data;
753
754 spin_lock(&ch->update_fn_lock);
755 update_fn = ch->update_fn;
756 update_fn_data = ch->update_fn_data;
757 spin_unlock(&ch->update_fn_lock);
758
759 if (update_fn)
760 update_fn(ch, update_fn_data);
749} 761}
750 762
751struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g, 763struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g,
@@ -755,8 +767,10 @@ struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g,
755 struct channel_gk20a *ch = gk20a_open_new_channel(g); 767 struct channel_gk20a *ch = gk20a_open_new_channel(g);
756 768
757 if (ch) { 769 if (ch) {
770 spin_lock(&ch->update_fn_lock);
758 ch->update_fn = update_fn; 771 ch->update_fn = update_fn;
759 ch->update_fn_data = update_fn_data; 772 ch->update_fn_data = update_fn_data;
773 spin_unlock(&ch->update_fn_lock);
760 } 774 }
761 775
762 return ch; 776 return ch;
@@ -811,7 +825,7 @@ struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g)
811 825
812 ch->update_fn = NULL; 826 ch->update_fn = NULL;
813 ch->update_fn_data = NULL; 827 ch->update_fn_data = NULL;
814 828 spin_lock_init(&ch->update_fn_lock);
815 INIT_WORK(&ch->update_fn_work, gk20a_channel_update_runcb_fn); 829 INIT_WORK(&ch->update_fn_work, gk20a_channel_update_runcb_fn);
816 830
817 return ch; 831 return ch;