aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorFrancisco Jerez <currojerez@riseup.net>2010-10-20 17:35:40 -0400
committerBen Skeggs <bskeggs@redhat.com>2010-12-03 00:11:12 -0500
commit332b242f47786d1a43bd7a19a0513dd5d493db8e (patch)
treef6681c1513c58db54f71c64184ebc033a14c49fe /drivers/gpu
parent042206c0cd4924879c4292c5ffa2bf1e8023ae5a (diff)
drm/nouveau: Implement the pageflip ioctl.
nv0x-nv4x should be mostly fine, nv50 doesn't work yet. Signed-off-by: Francisco Jerez <currojerez@riseup.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c180
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h16
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c3
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c1
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c16
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c8
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c1
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c16
13 files changed, 264 insertions, 9 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index c09928322eb9..cdc8f544d47f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -942,6 +942,18 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
942 return ttm_bo_validate(bo, &nvbo->placement, false, true, false); 942 return ttm_bo_validate(bo, &nvbo->placement, false, true, false);
943} 943}
944 944
945void
946nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence)
947{
948 spin_lock(&nvbo->bo.bdev->fence_lock);
949 __nouveau_fence_unref(&nvbo->bo.sync_obj);
950
951 if (likely(fence))
952 nvbo->bo.sync_obj = nouveau_fence_ref(fence);
953
954 spin_unlock(&nvbo->bo.bdev->fence_lock);
955}
956
945struct ttm_bo_driver nouveau_bo_driver = { 957struct ttm_bo_driver nouveau_bo_driver = {
946 .create_ttm_backend_entry = nouveau_bo_create_ttm_backend_entry, 958 .create_ttm_backend_entry = nouveau_bo_create_ttm_backend_entry,
947 .invalidate_caches = nouveau_bo_invalidate_caches, 959 .invalidate_caches = nouveau_bo_invalidate_caches,
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index c9cdbd786dae..11b2370e16da 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -148,6 +148,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
148 148
149 NV_DEBUG(dev, "initialising channel %d\n", chan->id); 149 NV_DEBUG(dev, "initialising channel %d\n", chan->id);
150 INIT_LIST_HEAD(&chan->nvsw.vbl_wait); 150 INIT_LIST_HEAD(&chan->nvsw.vbl_wait);
151 INIT_LIST_HEAD(&chan->nvsw.flip);
151 INIT_LIST_HEAD(&chan->fence.pending); 152 INIT_LIST_HEAD(&chan->fence.pending);
152 153
153 /* Allocate DMA push buffer */ 154 /* Allocate DMA push buffer */
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index f8987bcb7f51..505c6bfb4d75 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -30,6 +30,8 @@
30#include "nouveau_fb.h" 30#include "nouveau_fb.h"
31#include "nouveau_fbcon.h" 31#include "nouveau_fbcon.h"
32#include "nouveau_hw.h" 32#include "nouveau_hw.h"
33#include "nouveau_crtc.h"
34#include "nouveau_dma.h"
33 35
34static void 36static void
35nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) 37nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
@@ -131,3 +133,181 @@ nouveau_vblank_disable(struct drm_device *dev, int crtc)
131 else 133 else
132 NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0); 134 NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
133} 135}
136
137static int
138nouveau_page_flip_reserve(struct nouveau_bo *old_bo,
139 struct nouveau_bo *new_bo)
140{
141 int ret;
142
143 ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
144 if (ret)
145 return ret;
146
147 ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
148 if (ret)
149 goto fail;
150
151 ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0);
152 if (ret)
153 goto fail_unreserve;
154
155 return 0;
156
157fail_unreserve:
158 ttm_bo_unreserve(&new_bo->bo);
159fail:
160 nouveau_bo_unpin(new_bo);
161 return ret;
162}
163
164static void
165nouveau_page_flip_unreserve(struct nouveau_bo *old_bo,
166 struct nouveau_bo *new_bo,
167 struct nouveau_fence *fence)
168{
169 nouveau_bo_fence(new_bo, fence);
170 ttm_bo_unreserve(&new_bo->bo);
171
172 nouveau_bo_fence(old_bo, fence);
173 ttm_bo_unreserve(&old_bo->bo);
174
175 nouveau_bo_unpin(old_bo);
176}
177
178static int
179nouveau_page_flip_emit(struct nouveau_channel *chan,
180 struct nouveau_bo *old_bo,
181 struct nouveau_bo *new_bo,
182 struct nouveau_page_flip_state *s,
183 struct nouveau_fence **pfence)
184{
185 struct drm_device *dev = chan->dev;
186 unsigned long flags;
187 int ret;
188
189 /* Queue it to the pending list */
190 spin_lock_irqsave(&dev->event_lock, flags);
191 list_add_tail(&s->head, &chan->nvsw.flip);
192 spin_unlock_irqrestore(&dev->event_lock, flags);
193
194 /* Synchronize with the old framebuffer */
195 ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan);
196 if (ret)
197 goto fail;
198
199 /* Emit the pageflip */
200 ret = RING_SPACE(chan, 2);
201 if (ret)
202 goto fail;
203
204 BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
205 OUT_RING(chan, 0);
206 FIRE_RING(chan);
207
208 ret = nouveau_fence_new(chan, pfence, true);
209 if (ret)
210 goto fail;
211
212 return 0;
213fail:
214 spin_lock_irqsave(&dev->event_lock, flags);
215 list_del(&s->head);
216 spin_unlock_irqrestore(&dev->event_lock, flags);
217 return ret;
218}
219
220int
221nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
222 struct drm_pending_vblank_event *event)
223{
224 struct drm_device *dev = crtc->dev;
225 struct drm_nouveau_private *dev_priv = dev->dev_private;
226 struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
227 struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
228 struct nouveau_page_flip_state *s;
229 struct nouveau_channel *chan;
230 struct nouveau_fence *fence;
231 int ret;
232
233 if (dev_priv->engine.graph.accel_blocked)
234 return -ENODEV;
235
236 s = kzalloc(sizeof(*s), GFP_KERNEL);
237 if (!s)
238 return -ENOMEM;
239
240 /* Don't let the buffers go away while we flip */
241 ret = nouveau_page_flip_reserve(old_bo, new_bo);
242 if (ret)
243 goto fail_free;
244
245 /* Initialize a page flip struct */
246 *s = (struct nouveau_page_flip_state)
247 { { }, s->event, nouveau_crtc(crtc)->index,
248 fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y,
249 new_bo->bo.offset };
250
251 /* Choose the channel the flip will be handled in */
252 chan = nouveau_fence_channel(new_bo->bo.sync_obj);
253 if (!chan)
254 chan = nouveau_channel_get_unlocked(dev_priv->channel);
255 mutex_lock(&chan->mutex);
256
257 /* Emit a page flip */
258 ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
259 nouveau_channel_put(&chan);
260 if (ret)
261 goto fail_unreserve;
262
263 /* Update the crtc struct and cleanup */
264 crtc->fb = fb;
265
266 nouveau_page_flip_unreserve(old_bo, new_bo, fence);
267 nouveau_fence_unref(&fence);
268 return 0;
269
270fail_unreserve:
271 nouveau_page_flip_unreserve(old_bo, new_bo, NULL);
272fail_free:
273 kfree(s);
274 return ret;
275}
276
277int
278nouveau_finish_page_flip(struct nouveau_channel *chan,
279 struct nouveau_page_flip_state *ps)
280{
281 struct drm_device *dev = chan->dev;
282 struct nouveau_page_flip_state *s;
283 unsigned long flags;
284
285 spin_lock_irqsave(&dev->event_lock, flags);
286
287 if (list_empty(&chan->nvsw.flip)) {
288 NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
289 spin_unlock_irqrestore(&dev->event_lock, flags);
290 return -EINVAL;
291 }
292
293 s = list_first_entry(&chan->nvsw.flip,
294 struct nouveau_page_flip_state, head);
295 if (s->event) {
296 struct drm_pending_vblank_event *e = s->event;
297 struct timeval now;
298
299 do_gettimeofday(&now);
300 e->event.sequence = 0;
301 e->event.tv_sec = now.tv_sec;
302 e->event.tv_usec = now.tv_usec;
303 list_add_tail(&e->base.link, &e->base.file_priv->event_list);
304 wake_up_interruptible(&e->base.file_priv->event_wait);
305 }
306
307 list_del(&s->head);
308 *ps = *s;
309 kfree(s);
310
311 spin_unlock_irqrestore(&dev->event_lock, flags);
312 return 0;
313}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 7cf034fd5cd0..2bb1f1572a55 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -166,6 +166,13 @@ struct nouveau_gpuobj {
166 void *priv; 166 void *priv;
167}; 167};
168 168
169struct nouveau_page_flip_state {
170 struct list_head head;
171 struct drm_pending_vblank_event *event;
172 int crtc, bpp, pitch, x, y;
173 uint64_t offset;
174};
175
169struct nouveau_channel { 176struct nouveau_channel {
170 struct drm_device *dev; 177 struct drm_device *dev;
171 int id; 178 int id;
@@ -253,6 +260,7 @@ struct nouveau_channel {
253 uint32_t vblsem_offset; 260 uint32_t vblsem_offset;
254 uint32_t vblsem_rval; 261 uint32_t vblsem_rval;
255 struct list_head vbl_wait; 262 struct list_head vbl_wait;
263 struct list_head flip;
256 } nvsw; 264 } nvsw;
257 265
258 struct { 266 struct {
@@ -1076,6 +1084,8 @@ extern void nv04_graph_destroy_context(struct nouveau_channel *);
1076extern int nv04_graph_load_context(struct nouveau_channel *); 1084extern int nv04_graph_load_context(struct nouveau_channel *);
1077extern int nv04_graph_unload_context(struct drm_device *); 1085extern int nv04_graph_unload_context(struct drm_device *);
1078extern void nv04_graph_context_switch(struct drm_device *); 1086extern void nv04_graph_context_switch(struct drm_device *);
1087extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
1088 u32 class, u32 mthd, u32 data);
1079 1089
1080/* nv10_graph.c */ 1090/* nv10_graph.c */
1081extern int nv10_graph_init(struct drm_device *); 1091extern int nv10_graph_init(struct drm_device *);
@@ -1249,6 +1259,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index);
1249extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); 1259extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
1250extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); 1260extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
1251extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); 1261extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val);
1262extern void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *);
1252 1263
1253/* nouveau_fence.c */ 1264/* nouveau_fence.c */
1254struct nouveau_fence; 1265struct nouveau_fence;
@@ -1315,6 +1326,10 @@ extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
1315/* nouveau_display.c */ 1326/* nouveau_display.c */
1316int nouveau_vblank_enable(struct drm_device *dev, int crtc); 1327int nouveau_vblank_enable(struct drm_device *dev, int crtc);
1317void nouveau_vblank_disable(struct drm_device *dev, int crtc); 1328void nouveau_vblank_disable(struct drm_device *dev, int crtc);
1329int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
1330 struct drm_pending_vblank_event *event);
1331int nouveau_finish_page_flip(struct nouveau_channel *,
1332 struct nouveau_page_flip_state *);
1318 1333
1319/* nv10_gpio.c */ 1334/* nv10_gpio.c */
1320int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); 1335int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
@@ -1514,5 +1529,6 @@ nv_match_device(struct drm_device *dev, unsigned device,
1514#define NV_SW_VBLSEM_OFFSET 0x00000400 1529#define NV_SW_VBLSEM_OFFSET 0x00000400
1515#define NV_SW_VBLSEM_RELEASE_VALUE 0x00000404 1530#define NV_SW_VBLSEM_RELEASE_VALUE 0x00000404
1516#define NV_SW_VBLSEM_RELEASE 0x00000408 1531#define NV_SW_VBLSEM_RELEASE 0x00000408
1532#define NV_SW_PAGE_FLIP 0x00000500
1517 1533
1518#endif /* __NOUVEAU_DRV_H__ */ 1534#endif /* __NOUVEAU_DRV_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index de8535b58710..9886b644f27d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -231,15 +231,8 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
231 231
232 list_for_each_safe(entry, tmp, list) { 232 list_for_each_safe(entry, tmp, list) {
233 nvbo = list_entry(entry, struct nouveau_bo, entry); 233 nvbo = list_entry(entry, struct nouveau_bo, entry);
234 if (likely(fence)) { 234
235 struct nouveau_fence *prev_fence; 235 nouveau_bo_fence(nvbo, fence);
236
237 spin_lock(&nvbo->bo.bdev->fence_lock);
238 prev_fence = nvbo->bo.sync_obj;
239 nvbo->bo.sync_obj = nouveau_fence_ref(fence);
240 spin_unlock(&nvbo->bo.bdev->fence_lock);
241 nouveau_fence_unref(&prev_fence);
242 }
243 236
244 if (unlikely(nvbo->validate_mapped)) { 237 if (unlikely(nvbo->validate_mapped)) {
245 ttm_bo_kunmap(&nvbo->kmap); 238 ttm_bo_kunmap(&nvbo->kmap);
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index d72aa8d19a19..ec9d193b6f61 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -1090,6 +1090,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
1090 case NOUVEAU_GETPARAM_HAS_BO_USAGE: 1090 case NOUVEAU_GETPARAM_HAS_BO_USAGE:
1091 getparam->value = 1; 1091 getparam->value = 1;
1092 break; 1092 break;
1093 case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
1094 getparam->value = (dev_priv->card_type < NV_50);
1095 break;
1093 case NOUVEAU_GETPARAM_GRAPH_UNITS: 1096 case NOUVEAU_GETPARAM_GRAPH_UNITS:
1094 /* NV40 and NV50 versions are quite different, but register 1097 /* NV40 and NV50 versions are quite different, but register
1095 * address is the same. User is supposed to know the card 1098 * address is the same. User is supposed to know the card
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index b61a7ff8b7b7..e4aea721971f 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -989,6 +989,7 @@ static const struct drm_crtc_funcs nv04_crtc_funcs = {
989 .cursor_move = nv04_crtc_cursor_move, 989 .cursor_move = nv04_crtc_cursor_move,
990 .gamma_set = nv_crtc_gamma_set, 990 .gamma_set = nv_crtc_gamma_set,
991 .set_config = drm_crtc_helper_set_config, 991 .set_config = drm_crtc_helper_set_config,
992 .page_flip = nouveau_crtc_page_flip,
992 .destroy = nv_crtc_destroy, 993 .destroy = nv_crtc_destroy,
993}; 994};
994 995
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index 81aba097ef95..239519aefce6 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -26,6 +26,7 @@
26#include "drm.h" 26#include "drm.h"
27#include "nouveau_drm.h" 27#include "nouveau_drm.h"
28#include "nouveau_drv.h" 28#include "nouveau_drv.h"
29#include "nouveau_hw.h"
29 30
30static int nv04_graph_register(struct drm_device *dev); 31static int nv04_graph_register(struct drm_device *dev);
31 32
@@ -553,6 +554,20 @@ nv04_graph_mthd_set_ref(struct nouveau_channel *chan,
553 return 0; 554 return 0;
554} 555}
555 556
557int
558nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
559 u32 class, u32 mthd, u32 data)
560{
561 struct drm_device *dev = chan->dev;
562 struct nouveau_page_flip_state s;
563
564 if (!nouveau_finish_page_flip(chan, &s))
565 nv_set_crtc_base(dev, s.crtc,
566 s.offset + s.y * s.pitch + s.x * s.bpp / 8);
567
568 return 0;
569}
570
556/* 571/*
557 * Software methods, why they are needed, and how they all work: 572 * Software methods, why they are needed, and how they all work:
558 * 573 *
@@ -1204,6 +1219,7 @@ nv04_graph_register(struct drm_device *dev)
1204 /* nvsw */ 1219 /* nvsw */
1205 NVOBJ_CLASS(dev, 0x506e, SW); 1220 NVOBJ_CLASS(dev, 0x506e, SW);
1206 NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref); 1221 NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref);
1222 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
1207 1223
1208 dev_priv->engine.graph.registered = true; 1224 dev_priv->engine.graph.registered = true;
1209 return 0; 1225 return 0;
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index a571bfd4471b..3fbb49dfc09c 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -1113,6 +1113,10 @@ nv10_graph_register(struct drm_device *dev)
1113 NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable); 1113 NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
1114 } 1114 }
1115 1115
1116 /* nvsw */
1117 NVOBJ_CLASS(dev, 0x506e, SW);
1118 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
1119
1116 dev_priv->engine.graph.registered = true; 1120 dev_priv->engine.graph.registered = true;
1117 return 0; 1121 return 0;
1118} 1122}
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index 7720bccb3c98..51b9dd12949d 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -801,6 +801,10 @@ nv20_graph_register(struct drm_device *dev)
801 else 801 else
802 NVOBJ_CLASS(dev, 0x0597, GR); 802 NVOBJ_CLASS(dev, 0x0597, GR);
803 803
804 /* nvsw */
805 NVOBJ_CLASS(dev, 0x506e, SW);
806 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
807
804 dev_priv->engine.graph.registered = true; 808 dev_priv->engine.graph.registered = true;
805 return 0; 809 return 0;
806} 810}
@@ -841,6 +845,10 @@ nv30_graph_register(struct drm_device *dev)
841 if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f))) 845 if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
842 NVOBJ_CLASS(dev, 0x0497, GR); 846 NVOBJ_CLASS(dev, 0x0497, GR);
843 847
848 /* nvsw */
849 NVOBJ_CLASS(dev, 0x506e, SW);
850 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
851
844 dev_priv->engine.graph.registered = true; 852 dev_priv->engine.graph.registered = true;
845 return 0; 853 return 0;
846} 854}
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index b9361e28687c..159bdcd757d4 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -446,6 +446,10 @@ nv40_graph_register(struct drm_device *dev)
446 else 446 else
447 NVOBJ_CLASS(dev, 0x4097, GR); 447 NVOBJ_CLASS(dev, 0x4097, GR);
448 448
449 /* nvsw */
450 NVOBJ_CLASS(dev, 0x506e, SW);
451 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
452
449 dev_priv->engine.graph.registered = true; 453 dev_priv->engine.graph.registered = true;
450 return 0; 454 return 0;
451} 455}
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 56476d0c6de8..1225ea0a841b 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -437,6 +437,7 @@ static const struct drm_crtc_funcs nv50_crtc_funcs = {
437 .cursor_move = nv50_crtc_cursor_move, 437 .cursor_move = nv50_crtc_cursor_move,
438 .gamma_set = nv50_crtc_gamma_set, 438 .gamma_set = nv50_crtc_gamma_set,
439 .set_config = drm_crtc_helper_set_config, 439 .set_config = drm_crtc_helper_set_config,
440 .page_flip = nouveau_crtc_page_flip,
440 .destroy = nv50_crtc_destroy, 441 .destroy = nv50_crtc_destroy,
441}; 442};
442 443
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index ac7f62d524bb..6d81f4dab37d 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -29,6 +29,8 @@
29#include "nouveau_drv.h" 29#include "nouveau_drv.h"
30#include "nouveau_ramht.h" 30#include "nouveau_ramht.h"
31#include "nouveau_grctx.h" 31#include "nouveau_grctx.h"
32#include "nouveau_dma.h"
33#include "nv50_evo.h"
32 34
33static int nv50_graph_register(struct drm_device *); 35static int nv50_graph_register(struct drm_device *);
34 36
@@ -390,6 +392,19 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan,
390} 392}
391 393
392static int 394static int
395nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
396 u32 class, u32 mthd, u32 data)
397{
398 struct nouveau_page_flip_state s;
399
400 if (!nouveau_finish_page_flip(chan, &s)) {
401 /* XXX - Do something here */
402 }
403
404 return 0;
405}
406
407static int
393nv50_graph_register(struct drm_device *dev) 408nv50_graph_register(struct drm_device *dev)
394{ 409{
395 struct drm_nouveau_private *dev_priv = dev->dev_private; 410 struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -402,6 +417,7 @@ nv50_graph_register(struct drm_device *dev)
402 NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset); 417 NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
403 NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val); 418 NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
404 NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release); 419 NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
420 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
405 421
406 NVOBJ_CLASS(dev, 0x0030, GR); /* null */ 422 NVOBJ_CLASS(dev, 0x0030, GR); /* null */
407 NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */ 423 NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */