diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-01-30 23:57:33 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-02-20 01:00:48 -0500 |
commit | e18c080fb8695d038f69c26c248f5ecbd9e8aa77 (patch) | |
tree | 74e191678bb9ba028d85e219863ddb706f4e6fc8 /drivers | |
parent | a2fa297378c54e9b8b8ad355e34c9fbed730250b (diff) |
drm/nouveau/fence/nv84-: put processes to sleep while waiting on fences
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_dma.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.c | 76 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv84_fence.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_fence.c | 8 |
5 files changed, 92 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index 5c2e22932d1c..690d5930ce32 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h | |||
@@ -191,7 +191,7 @@ WIND_RING(struct nouveau_channel *chan) | |||
191 | #define NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG 0x00000002 | 191 | #define NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG 0x00000002 |
192 | #define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL 0x00000004 | 192 | #define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL 0x00000004 |
193 | #define NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD 0x00001000 | 193 | #define NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD 0x00001000 |
194 | #define NV84_SUBCHAN_NOTIFY_INTR 0x00000020 | 194 | #define NV84_SUBCHAN_UEVENT 0x00000020 |
195 | #define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024 | 195 | #define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024 |
196 | #define NV10_SUBCHAN_REF_CNT 0x00000050 | 196 | #define NV10_SUBCHAN_REF_CNT 0x00000050 |
197 | #define NVSW_SUBCHAN_PAGE_FLIP 0x00000054 | 197 | #define NVSW_SUBCHAN_PAGE_FLIP 0x00000054 |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index b6b8e49ac68f..b7349a636546 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include "nouveau_dma.h" | 33 | #include "nouveau_dma.h" |
34 | #include "nouveau_fence.h" | 34 | #include "nouveau_fence.h" |
35 | 35 | ||
36 | #include <engine/fifo.h> | ||
37 | |||
36 | void | 38 | void |
37 | nouveau_fence_context_del(struct nouveau_fence_chan *fctx) | 39 | nouveau_fence_context_del(struct nouveau_fence_chan *fctx) |
38 | { | 40 | { |
@@ -107,13 +109,87 @@ nouveau_fence_done(struct nouveau_fence *fence) | |||
107 | return !fence->channel; | 109 | return !fence->channel; |
108 | } | 110 | } |
109 | 111 | ||
112 | struct nouveau_fence_uevent { | ||
113 | struct nouveau_eventh handler; | ||
114 | struct nouveau_fence_priv *priv; | ||
115 | }; | ||
116 | |||
117 | static int | ||
118 | nouveau_fence_wait_uevent_handler(struct nouveau_eventh *event, int index) | ||
119 | { | ||
120 | struct nouveau_fence_uevent *uevent = | ||
121 | container_of(event, struct nouveau_fence_uevent, handler); | ||
122 | wake_up_all(&uevent->priv->waiting); | ||
123 | return NVKM_EVENT_KEEP; | ||
124 | } | ||
125 | |||
126 | static int | ||
127 | nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) | ||
128 | |||
129 | { | ||
130 | struct nouveau_channel *chan = fence->channel; | ||
131 | struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device); | ||
132 | struct nouveau_fence_priv *priv = chan->drm->fence; | ||
133 | struct nouveau_fence_uevent uevent = { | ||
134 | .handler.func = nouveau_fence_wait_uevent_handler, | ||
135 | .priv = priv, | ||
136 | }; | ||
137 | int ret = 0; | ||
138 | |||
139 | nouveau_event_get(pfifo->uevent, 0, &uevent.handler); | ||
140 | |||
141 | if (fence->timeout) { | ||
142 | unsigned long timeout = fence->timeout - jiffies; | ||
143 | |||
144 | if (time_before(jiffies, fence->timeout)) { | ||
145 | if (intr) { | ||
146 | ret = wait_event_interruptible_timeout( | ||
147 | priv->waiting, | ||
148 | nouveau_fence_done(fence), | ||
149 | timeout); | ||
150 | } else { | ||
151 | ret = wait_event_timeout(priv->waiting, | ||
152 | nouveau_fence_done(fence), | ||
153 | timeout); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | if (ret >= 0) { | ||
158 | fence->timeout = jiffies + ret; | ||
159 | if (time_after_eq(jiffies, fence->timeout)) | ||
160 | ret = -EBUSY; | ||
161 | } | ||
162 | } else { | ||
163 | if (intr) { | ||
164 | ret = wait_event_interruptible(priv->waiting, | ||
165 | nouveau_fence_done(fence)); | ||
166 | } else { | ||
167 | wait_event(priv->waiting, nouveau_fence_done(fence)); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | nouveau_event_put(pfifo->uevent, 0, &uevent.handler); | ||
172 | if (unlikely(ret < 0)) | ||
173 | return ret; | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
110 | int | 178 | int |
111 | nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) | 179 | nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) |
112 | { | 180 | { |
181 | struct nouveau_channel *chan = fence->channel; | ||
182 | struct nouveau_fence_priv *priv = chan ? chan->drm->fence : NULL; | ||
113 | unsigned long sleep_time = NSEC_PER_MSEC / 1000; | 183 | unsigned long sleep_time = NSEC_PER_MSEC / 1000; |
114 | ktime_t t; | 184 | ktime_t t; |
115 | int ret = 0; | 185 | int ret = 0; |
116 | 186 | ||
187 | while (priv && priv->uevent && lazy && !nouveau_fence_done(fence)) { | ||
188 | ret = nouveau_fence_wait_uevent(fence, intr); | ||
189 | if (ret < 0) | ||
190 | return ret; | ||
191 | } | ||
192 | |||
117 | while (!nouveau_fence_done(fence)) { | 193 | while (!nouveau_fence_done(fence)) { |
118 | if (fence->timeout && time_after_eq(jiffies, fence->timeout)) { | 194 | if (fence->timeout && time_after_eq(jiffies, fence->timeout)) { |
119 | ret = -EBUSY; | 195 | ret = -EBUSY; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index cdb83acdffe2..be6166eb966d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h | |||
@@ -43,6 +43,9 @@ struct nouveau_fence_priv { | |||
43 | int (*sync)(struct nouveau_fence *, struct nouveau_channel *, | 43 | int (*sync)(struct nouveau_fence *, struct nouveau_channel *, |
44 | struct nouveau_channel *); | 44 | struct nouveau_channel *); |
45 | u32 (*read)(struct nouveau_channel *); | 45 | u32 (*read)(struct nouveau_channel *); |
46 | |||
47 | wait_queue_head_t waiting; | ||
48 | bool uevent; | ||
46 | }; | 49 | }; |
47 | 50 | ||
48 | #define nouveau_fence(drm) ((struct nouveau_fence_priv *)(drm)->fence) | 51 | #define nouveau_fence(drm) ((struct nouveau_fence_priv *)(drm)->fence) |
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index c686650584b6..e64e8154a5af 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c | |||
@@ -47,15 +47,16 @@ nv84_fence_emit(struct nouveau_fence *fence) | |||
47 | { | 47 | { |
48 | struct nouveau_channel *chan = fence->channel; | 48 | struct nouveau_channel *chan = fence->channel; |
49 | struct nouveau_fifo_chan *fifo = (void *)chan->object; | 49 | struct nouveau_fifo_chan *fifo = (void *)chan->object; |
50 | int ret = RING_SPACE(chan, 7); | 50 | int ret = RING_SPACE(chan, 8); |
51 | if (ret == 0) { | 51 | if (ret == 0) { |
52 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); | 52 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); |
53 | OUT_RING (chan, NvSema); | 53 | OUT_RING (chan, NvSema); |
54 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 54 | BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 5); |
55 | OUT_RING (chan, upper_32_bits(fifo->chid * 16)); | 55 | OUT_RING (chan, upper_32_bits(fifo->chid * 16)); |
56 | OUT_RING (chan, lower_32_bits(fifo->chid * 16)); | 56 | OUT_RING (chan, lower_32_bits(fifo->chid * 16)); |
57 | OUT_RING (chan, fence->sequence); | 57 | OUT_RING (chan, fence->sequence); |
58 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); | 58 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); |
59 | OUT_RING (chan, 0x00000000); | ||
59 | FIRE_RING (chan); | 60 | FIRE_RING (chan); |
60 | } | 61 | } |
61 | return ret; | 62 | return ret; |
@@ -174,6 +175,9 @@ nv84_fence_create(struct nouveau_drm *drm) | |||
174 | priv->base.sync = nv84_fence_sync; | 175 | priv->base.sync = nv84_fence_sync; |
175 | priv->base.read = nv84_fence_read; | 176 | priv->base.read = nv84_fence_read; |
176 | 177 | ||
178 | init_waitqueue_head(&priv->base.waiting); | ||
179 | priv->base.uevent = true; | ||
180 | |||
177 | ret = nouveau_gpuobj_new(drm->device, NULL, chan * 16, 0x1000, 0, | 181 | ret = nouveau_gpuobj_new(drm->device, NULL, chan * 16, 0x1000, 0, |
178 | &priv->mem); | 182 | &priv->mem); |
179 | if (ret) | 183 | if (ret) |
diff --git a/drivers/gpu/drm/nouveau/nvc0_fence.c b/drivers/gpu/drm/nouveau/nvc0_fence.c index 2a56b1b551cb..d8ed2c5f4fab 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fence.c +++ b/drivers/gpu/drm/nouveau/nvc0_fence.c | |||
@@ -62,13 +62,14 @@ nvc0_fence_emit(struct nouveau_fence *fence) | |||
62 | u64 addr = fctx->vma.offset + fifo->chid * 16; | 62 | u64 addr = fctx->vma.offset + fifo->chid * 16; |
63 | int ret; | 63 | int ret; |
64 | 64 | ||
65 | ret = RING_SPACE(chan, 5); | 65 | ret = RING_SPACE(chan, 6); |
66 | if (ret == 0) { | 66 | if (ret == 0) { |
67 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); | 67 | BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 5); |
68 | OUT_RING (chan, upper_32_bits(addr)); | 68 | OUT_RING (chan, upper_32_bits(addr)); |
69 | OUT_RING (chan, lower_32_bits(addr)); | 69 | OUT_RING (chan, lower_32_bits(addr)); |
70 | OUT_RING (chan, fence->sequence); | 70 | OUT_RING (chan, fence->sequence); |
71 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); | 71 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); |
72 | OUT_RING (chan, 0x00000000); | ||
72 | FIRE_RING (chan); | 73 | FIRE_RING (chan); |
73 | } | 74 | } |
74 | 75 | ||
@@ -217,6 +218,9 @@ nvc0_fence_create(struct nouveau_drm *drm) | |||
217 | priv->base.sync = nvc0_fence_sync; | 218 | priv->base.sync = nvc0_fence_sync; |
218 | priv->base.read = nvc0_fence_read; | 219 | priv->base.read = nvc0_fence_read; |
219 | 220 | ||
221 | init_waitqueue_head(&priv->base.waiting); | ||
222 | priv->base.uevent = true; | ||
223 | |||
220 | ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0, | 224 | ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0, |
221 | TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo); | 225 | TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo); |
222 | if (ret == 0) { | 226 | if (ret == 0) { |