diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-05-04 02:25:47 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-05-24 02:55:58 -0400 |
commit | 906c033e276877c1374c9159976b05746af3c86d (patch) | |
tree | f7e03b7148cf9f5caad6ac72b33e0354e94aad41 /drivers/gpu/drm/nouveau | |
parent | 299bee10fb228fce4a3fc5dd89f32787a6e58fe5 (diff) |
drm/nouveau/fence: fix a race where fence->channel can disappear
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_fence.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv10_fence.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv84_fence.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_fence.c | 5 |
6 files changed, 26 insertions, 15 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 4ba41a45114f..3c180493dab8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c | |||
@@ -147,15 +147,19 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) | |||
147 | int | 147 | int |
148 | nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) | 148 | nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) |
149 | { | 149 | { |
150 | struct nouveau_channel *prev = fence ? fence->channel : NULL; | ||
151 | struct drm_device *dev = chan->dev; | 150 | struct drm_device *dev = chan->dev; |
152 | struct nouveau_fence_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FENCE); | 151 | struct nouveau_fence_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FENCE); |
152 | struct nouveau_channel *prev; | ||
153 | int ret = 0; | 153 | int ret = 0; |
154 | 154 | ||
155 | if (unlikely(prev && prev != chan && !nouveau_fence_done(fence))) { | 155 | prev = fence ? nouveau_channel_get_unlocked(fence->channel) : NULL; |
156 | ret = priv->sync(fence, chan); | 156 | if (prev) { |
157 | if (unlikely(ret)) | 157 | if (unlikely(prev != chan && !nouveau_fence_done(fence))) { |
158 | ret = nouveau_fence_wait(fence, true, false); | 158 | ret = priv->sync(fence, prev, chan); |
159 | if (unlikely(ret)) | ||
160 | ret = nouveau_fence_wait(fence, true, false); | ||
161 | } | ||
162 | nouveau_channel_put_unlocked(&prev); | ||
159 | } | 163 | } |
160 | 164 | ||
161 | return ret; | 165 | return ret; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index ec9afa775ea7..82ba733393ae 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h | |||
@@ -34,7 +34,8 @@ struct nouveau_fence_chan { | |||
34 | struct nouveau_fence_priv { | 34 | struct nouveau_fence_priv { |
35 | struct nouveau_exec_engine engine; | 35 | struct nouveau_exec_engine engine; |
36 | int (*emit)(struct nouveau_fence *); | 36 | int (*emit)(struct nouveau_fence *); |
37 | int (*sync)(struct nouveau_fence *, struct nouveau_channel *); | 37 | int (*sync)(struct nouveau_fence *, struct nouveau_channel *, |
38 | struct nouveau_channel *); | ||
38 | u32 (*read)(struct nouveau_channel *); | 39 | u32 (*read)(struct nouveau_channel *); |
39 | }; | 40 | }; |
40 | 41 | ||
diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c index 08bd2ceaefef..abe89db6de24 100644 --- a/drivers/gpu/drm/nouveau/nv04_fence.c +++ b/drivers/gpu/drm/nouveau/nv04_fence.c | |||
@@ -51,7 +51,8 @@ nv04_fence_emit(struct nouveau_fence *fence) | |||
51 | } | 51 | } |
52 | 52 | ||
53 | static int | 53 | static int |
54 | nv04_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) | 54 | nv04_fence_sync(struct nouveau_fence *fence, |
55 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
55 | { | 56 | { |
56 | return -ENODEV; | 57 | return -ENODEV; |
57 | } | 58 | } |
diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c index 10831eaff958..8a1b75009185 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.c +++ b/drivers/gpu/drm/nouveau/nv10_fence.c | |||
@@ -52,17 +52,19 @@ nv10_fence_emit(struct nouveau_fence *fence) | |||
52 | return ret; | 52 | return ret; |
53 | } | 53 | } |
54 | 54 | ||
55 | |||
55 | static int | 56 | static int |
56 | nv10_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) | 57 | nv10_fence_sync(struct nouveau_fence *fence, |
58 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
57 | { | 59 | { |
58 | return -ENODEV; | 60 | return -ENODEV; |
59 | } | 61 | } |
60 | 62 | ||
61 | static int | 63 | static int |
62 | nv17_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) | 64 | nv17_fence_sync(struct nouveau_fence *fence, |
65 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
63 | { | 66 | { |
64 | struct nv10_fence_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_FENCE); | 67 | struct nv10_fence_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_FENCE); |
65 | struct nouveau_channel *prev = fence->channel; | ||
66 | u32 value; | 68 | u32 value; |
67 | int ret; | 69 | int ret; |
68 | 70 | ||
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index d23dbc06f436..0ac98c0efc71 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c | |||
@@ -55,16 +55,18 @@ nv84_fence_emit(struct nouveau_fence *fence) | |||
55 | return ret; | 55 | return ret; |
56 | } | 56 | } |
57 | 57 | ||
58 | |||
58 | static int | 59 | static int |
59 | nv84_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) | 60 | nv84_fence_sync(struct nouveau_fence *fence, |
61 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
60 | { | 62 | { |
61 | int ret = RING_SPACE(chan, 7); | 63 | int ret = RING_SPACE(chan, 7); |
62 | if (ret == 0) { | 64 | if (ret == 0) { |
63 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); | 65 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); |
64 | OUT_RING (chan, NvSema); | 66 | OUT_RING (chan, NvSema); |
65 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 67 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); |
66 | OUT_RING (chan, upper_32_bits(fence->channel->id * 16)); | 68 | OUT_RING (chan, upper_32_bits(prev->id * 16)); |
67 | OUT_RING (chan, lower_32_bits(fence->channel->id * 16)); | 69 | OUT_RING (chan, lower_32_bits(prev->id * 16)); |
68 | OUT_RING (chan, fence->sequence); | 70 | OUT_RING (chan, fence->sequence); |
69 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL); | 71 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL); |
70 | FIRE_RING (chan); | 72 | FIRE_RING (chan); |
diff --git a/drivers/gpu/drm/nouveau/nvc0_fence.c b/drivers/gpu/drm/nouveau/nvc0_fence.c index 41545f15c4d0..817228cd1a95 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fence.c +++ b/drivers/gpu/drm/nouveau/nvc0_fence.c | |||
@@ -60,10 +60,11 @@ nvc0_fence_emit(struct nouveau_fence *fence) | |||
60 | } | 60 | } |
61 | 61 | ||
62 | static int | 62 | static int |
63 | nvc0_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) | 63 | nvc0_fence_sync(struct nouveau_fence *fence, |
64 | struct nouveau_channel *prev, struct nouveau_channel *chan) | ||
64 | { | 65 | { |
65 | struct nvc0_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE]; | 66 | struct nvc0_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE]; |
66 | u64 addr = fctx->vma.offset + fence->channel->id * 16; | 67 | u64 addr = fctx->vma.offset + prev->id * 16; |
67 | int ret; | 68 | int ret; |
68 | 69 | ||
69 | ret = RING_SPACE(chan, 5); | 70 | ret = RING_SPACE(chan, 5); |