From 992dc9ae61f86db3b8ef9f8d6b7df898c90e8c08 Mon Sep 17 00:00:00 2001 From: David John Date: Thu, 31 Dec 2009 12:00:46 +0530 Subject: drm: Keep disabled outputs disabled after suspend / resume With the current DRM code, an output that has been powered off from userspace will automatically power back on when resuming from suspend. This patch fixes this behaviour. Tested only with the Intel i915 driver on an Intel GM45 Express chipset. Signed-off-by: David John Reviewed-by: Jesse Barnes Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 4231d6db72e..aba79c49458 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -216,7 +216,7 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) EXPORT_SYMBOL(drm_helper_crtc_in_use); /** - * drm_disable_unused_functions - disable unused objects + * drm_helper_disable_unused_functions - disable unused objects * @dev: DRM device * * LOCKING: @@ -1162,6 +1162,9 @@ EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); int drm_helper_resume_force_mode(struct drm_device *dev) { struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_crtc_helper_funcs *crtc_funcs; int ret; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -1174,6 +1177,25 @@ int drm_helper_resume_force_mode(struct drm_device *dev) if (ret == false) DRM_ERROR("failed to set mode on crtc %p\n", crtc); + + /* Turn off outputs that were already powered off */ + if (drm_helper_choose_crtc_dpms(crtc)) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if(encoder->crtc != crtc) + continue; + + encoder_funcs = encoder->helper_private; + if (encoder_funcs->dpms) + (*encoder_funcs->dpms) (encoder, + drm_helper_choose_encoder_dpms(encoder)); + + crtc_funcs = crtc->helper_private; + if (crtc_funcs->dpms) + (*crtc_funcs->dpms) (crtc, + drm_helper_choose_crtc_dpms(crtc)); + } + } } /* disable the unused connectors while restoring the modesetting */ drm_helper_disable_unused_functions(dev); -- cgit v1.2.3 From 7751b8cb754f1bc48b20c1145d43c7651d4951fd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 8 Jan 2010 09:27:08 +1000 Subject: drm/kms/fb: check for depth changes from userspace for resizing. If userspace (plymouth in this case) asks for a deeper depth, refuse it as well due to lack of resizing. This fixes an issue since < 32MB cards went to 8bpp and plymouth crashes on startup. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 100ee48760b..1c2b7d44ec0 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -606,11 +606,10 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, return -EINVAL; /* Need to resize the fb object !!! */ - if (var->xres > fb->width || var->yres > fb->height) { - DRM_ERROR("Requested width/height is greater than current fb " - "object %dx%d > %dx%d\n", var->xres, var->yres, - fb->width, fb->height); - DRM_ERROR("Need resizing code.\n"); + if (var->bits_per_pixel > fb->bits_per_pixel || var->xres > fb->width || var->yres > fb->height) { + DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb " + "object %dx%d-%d > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel, + fb->width, fb->height, fb->bits_per_pixel); return -EINVAL; } -- cgit v1.2.3 From 588d7d1268658b6a010eb7415bff2f936c51acf7 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 13 Dec 2009 20:07:42 +0100 Subject: drm/nouveau: Add cache_flush/pull fifo engine functions. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 ++++ drivers/gpu/drm/nouveau/nouveau_state.c | 10 ++++++++++ drivers/gpu/drm/nouveau/nv04_fifo.c | 34 +++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5f8cbb79c49..48d0ad9434a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -292,6 +292,8 @@ struct nouveau_fifo_engine { void (*disable)(struct drm_device *); void (*enable)(struct drm_device *); bool (*reassign)(struct drm_device *, bool enable); + bool (*cache_flush)(struct drm_device *dev); + bool (*cache_pull)(struct drm_device *dev, bool enable); int (*channel_id)(struct drm_device *); @@ -889,6 +891,8 @@ extern int nv04_fifo_init(struct drm_device *); extern void nv04_fifo_disable(struct drm_device *); extern void nv04_fifo_enable(struct drm_device *); extern bool nv04_fifo_reassign(struct drm_device *, bool); +extern bool nv04_fifo_cache_flush(struct drm_device *); +extern bool nv04_fifo_cache_pull(struct drm_device *, bool); extern int nv04_fifo_channel_id(struct drm_device *); extern int nv04_fifo_create_context(struct nouveau_channel *); extern void nv04_fifo_destroy_context(struct nouveau_channel *); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e76ec2d207a..9f988431f34 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -76,6 +76,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv04_fifo_channel_id; engine->fifo.create_context = nv04_fifo_create_context; engine->fifo.destroy_context = nv04_fifo_destroy_context; @@ -115,6 +117,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; @@ -154,6 +158,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; @@ -193,6 +199,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; @@ -233,6 +241,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; + engine->fifo.cache_flush = nv04_fifo_cache_flush; + engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv40_fifo_create_context; engine->fifo.destroy_context = nv40_fifo_destroy_context; diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c index 0c3cd53c731..f31347b8c9b 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c @@ -71,6 +71,40 @@ nv04_fifo_reassign(struct drm_device *dev, bool enable) return (reassign == 1); } +bool +nv04_fifo_cache_flush(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + uint64_t start = ptimer->read(dev); + + do { + if (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) == + nv_rd32(dev, NV03_PFIFO_CACHE1_PUT)) + return true; + + } while (ptimer->read(dev) - start < 100000000); + + NV_ERROR(dev, "Timeout flushing the PFIFO cache.\n"); + + return false; +} + +bool +nv04_fifo_cache_pull(struct drm_device *dev, bool enable) +{ + uint32_t pull = nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0); + + if (enable) { + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull | 1); + } else { + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull & ~1); + nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); + } + + return !!(pull & 1); +} + int nv04_fifo_channel_id(struct drm_device *dev) { -- cgit v1.2.3 From cb00f7c1419d09ee0daf7d8bed86f253d98db7b4 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 16 Dec 2009 12:12:27 +0100 Subject: drm/nouveau: Pre-G80 tiling support. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_drv.h | 18 +++++ drivers/gpu/drm/nouveau/nouveau_reg.h | 16 ++--- drivers/gpu/drm/nouveau/nouveau_state.c | 8 +++ drivers/gpu/drm/nouveau/nv10_fb.c | 32 +++++++-- drivers/gpu/drm/nouveau/nv10_graph.c | 28 +++++--- drivers/gpu/drm/nouveau/nv20_graph.c | 61 ++++++++--------- drivers/gpu/drm/nouveau/nv40_fb.c | 53 +++++++++------ drivers/gpu/drm/nouveau/nv40_graph.c | 116 +++++++++++++------------------- 8 files changed, 185 insertions(+), 147 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 48d0ad9434a..446a92ad2ee 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -277,8 +277,13 @@ struct nouveau_timer_engine { }; struct nouveau_fb_engine { + int num_tiles; + int (*init)(struct drm_device *dev); void (*takedown)(struct drm_device *dev); + + void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch); }; struct nouveau_fifo_engine { @@ -332,6 +337,9 @@ struct nouveau_pgraph_engine { void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*unload_context)(struct drm_device *); + + void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch); }; struct nouveau_engine { @@ -881,10 +889,14 @@ extern void nv04_fb_takedown(struct drm_device *); /* nv10_fb.c */ extern int nv10_fb_init(struct drm_device *); extern void nv10_fb_takedown(struct drm_device *); +extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv40_fb.c */ extern int nv40_fb_init(struct drm_device *); extern void nv40_fb_takedown(struct drm_device *); +extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv04_fifo.c */ extern int nv04_fifo_init(struct drm_device *); @@ -945,6 +957,8 @@ extern void nv10_graph_destroy_context(struct nouveau_channel *); extern int nv10_graph_load_context(struct nouveau_channel *); extern int nv10_graph_unload_context(struct drm_device *); extern void nv10_graph_context_switch(struct drm_device *); +extern void nv10_graph_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv20_graph.c */ extern struct nouveau_pgraph_object_class nv20_graph_grclass[]; @@ -956,6 +970,8 @@ extern int nv20_graph_unload_context(struct drm_device *); extern int nv20_graph_init(struct drm_device *); extern void nv20_graph_takedown(struct drm_device *); extern int nv30_graph_init(struct drm_device *); +extern void nv20_graph_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv40_graph.c */ extern struct nouveau_pgraph_object_class nv40_graph_grclass[]; @@ -967,6 +983,8 @@ extern void nv40_graph_destroy_context(struct nouveau_channel *); extern int nv40_graph_load_context(struct nouveau_channel *); extern int nv40_graph_unload_context(struct drm_device *); extern void nv40_grctx_init(struct nouveau_grctx *); +extern void nv40_graph_set_region_tiling(struct drm_device *, int, uint32_t, + uint32_t, uint32_t); /* nv50_graph.c */ extern struct nouveau_pgraph_object_class nv50_graph_grclass[]; diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index fa1b0e7165b..251f1b3b38b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -349,19 +349,19 @@ #define NV04_PGRAPH_BLEND 0x00400824 #define NV04_PGRAPH_STORED_FMT 0x00400830 #define NV04_PGRAPH_PATT_COLORRAM 0x00400900 -#define NV40_PGRAPH_TILE0(i) (0x00400900 + (i*16)) -#define NV40_PGRAPH_TLIMIT0(i) (0x00400904 + (i*16)) -#define NV40_PGRAPH_TSIZE0(i) (0x00400908 + (i*16)) -#define NV40_PGRAPH_TSTATUS0(i) (0x0040090C + (i*16)) +#define NV20_PGRAPH_TILE(i) (0x00400900 + (i*16)) +#define NV20_PGRAPH_TLIMIT(i) (0x00400904 + (i*16)) +#define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16)) +#define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16)) #define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16)) #define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16)) #define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16)) #define NV10_PGRAPH_TSTATUS(i) (0x00400B0C + (i*16)) #define NV04_PGRAPH_U_RAM 0x00400D00 -#define NV47_PGRAPH_TILE0(i) (0x00400D00 + (i*16)) -#define NV47_PGRAPH_TLIMIT0(i) (0x00400D04 + (i*16)) -#define NV47_PGRAPH_TSIZE0(i) (0x00400D08 + (i*16)) -#define NV47_PGRAPH_TSTATUS0(i) (0x00400D0C + (i*16)) +#define NV47_PGRAPH_TILE(i) (0x00400D00 + (i*16)) +#define NV47_PGRAPH_TLIMIT(i) (0x00400D04 + (i*16)) +#define NV47_PGRAPH_TSIZE(i) (0x00400D08 + (i*16)) +#define NV47_PGRAPH_TSTATUS(i) (0x00400D0C + (i*16)) #define NV04_PGRAPH_V_RAM 0x00400D40 #define NV04_PGRAPH_W_RAM 0x00400D80 #define NV10_PGRAPH_COMBINER0_IN_ALPHA 0x00400E40 diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 9f988431f34..6a459139910 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -102,6 +102,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; + engine->fb.set_region_tiling = nv10_fb_set_region_tiling; engine->graph.grclass = nv10_graph_grclass; engine->graph.init = nv10_graph_init; engine->graph.takedown = nv10_graph_takedown; @@ -111,6 +112,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.fifo_access = nv04_graph_fifo_access; engine->graph.load_context = nv10_graph_load_context; engine->graph.unload_context = nv10_graph_unload_context; + engine->graph.set_region_tiling = nv10_graph_set_region_tiling; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; @@ -143,6 +145,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; + engine->fb.set_region_tiling = nv10_fb_set_region_tiling; engine->graph.grclass = nv20_graph_grclass; engine->graph.init = nv20_graph_init; engine->graph.takedown = nv20_graph_takedown; @@ -152,6 +155,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.fifo_access = nv04_graph_fifo_access; engine->graph.load_context = nv20_graph_load_context; engine->graph.unload_context = nv20_graph_unload_context; + engine->graph.set_region_tiling = nv20_graph_set_region_tiling; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; @@ -184,6 +188,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; + engine->fb.set_region_tiling = nv10_fb_set_region_tiling; engine->graph.grclass = nv30_graph_grclass; engine->graph.init = nv30_graph_init; engine->graph.takedown = nv20_graph_takedown; @@ -193,6 +198,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv20_graph_destroy_context; engine->graph.load_context = nv20_graph_load_context; engine->graph.unload_context = nv20_graph_unload_context; + engine->graph.set_region_tiling = nv20_graph_set_region_tiling; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; @@ -226,6 +232,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv40_fb_init; engine->fb.takedown = nv40_fb_takedown; + engine->fb.set_region_tiling = nv40_fb_set_region_tiling; engine->graph.grclass = nv40_graph_grclass; engine->graph.init = nv40_graph_init; engine->graph.takedown = nv40_graph_takedown; @@ -235,6 +242,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv40_graph_destroy_context; engine->graph.load_context = nv40_graph_load_context; engine->graph.unload_context = nv40_graph_unload_context; + engine->graph.set_region_tiling = nv40_graph_set_region_tiling; engine->fifo.channels = 32; engine->fifo.init = nv40_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; diff --git a/drivers/gpu/drm/nouveau/nv10_fb.c b/drivers/gpu/drm/nouveau/nv10_fb.c index 79e2d104d70..cc5cda44e50 100644 --- a/drivers/gpu/drm/nouveau/nv10_fb.c +++ b/drivers/gpu/drm/nouveau/nv10_fb.c @@ -3,17 +3,37 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +void +nv10_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) { + if (dev_priv->card_type >= NV_20) + addr |= 1; + else + addr |= 1 << 31; + } + + nv_wr32(dev, NV10_PFB_TLIMIT(i), limit); + nv_wr32(dev, NV10_PFB_TSIZE(i), pitch); + nv_wr32(dev, NV10_PFB_TILE(i), addr); +} + int nv10_fb_init(struct drm_device *dev) { - uint32_t fb_bar_size; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; int i; - fb_bar_size = drm_get_resource_len(dev, 0) - 1; - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - nv_wr32(dev, NV10_PFB_TILE(i), 0); - nv_wr32(dev, NV10_PFB_TLIMIT(i), fb_bar_size); - } + pfb->num_tiles = NV10_PFB_TILE__SIZE; + + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->num_tiles; i++) + pfb->set_region_tiling(dev, i, 0, 0, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index 6870e0ee2e7..fcf2cdd1949 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -807,6 +807,20 @@ void nv10_graph_destroy_context(struct nouveau_channel *chan) chan->pgraph_ctx = NULL; } +void +nv10_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) + addr |= 1 << 31; + + nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV10_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV10_PGRAPH_TILE(i), addr); +} + int nv10_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -838,17 +852,9 @@ int nv10_graph_init(struct drm_device *dev) } else nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000); - /* copy tile info from PFB */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - nv_wr32(dev, NV10_PGRAPH_TILE(i), - nv_rd32(dev, NV10_PFB_TILE(i))); - nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), - nv_rd32(dev, NV10_PFB_TLIMIT(i))); - nv_wr32(dev, NV10_PGRAPH_TSIZE(i), - nv_rd32(dev, NV10_PFB_TSIZE(i))); - nv_wr32(dev, NV10_PGRAPH_TSTATUS(i), - nv_rd32(dev, NV10_PFB_TSTATUS(i))); - } + /* Turn all the tiling regions off. */ + for (i = 0; i < NV10_PFB_TILE__SIZE; i++) + nv10_graph_set_region_tiling(dev, i, 0, 0, 0); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH1, 0x00000000); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH2, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index 18ba74f1970..d6fc0a82f03 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -514,6 +514,27 @@ nv20_graph_rdi(struct drm_device *dev) nouveau_wait_for_idle(dev); } +void +nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) + addr |= 1; + + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); + + nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, limit); + nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, pitch); + nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, addr); +} + int nv20_graph_init(struct drm_device *dev) { @@ -572,27 +593,10 @@ nv20_graph_init(struct drm_device *dev) nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030); } - /* copy tile info from PFB */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - nv_wr32(dev, 0x00400904 + i * 0x10, - nv_rd32(dev, NV10_PFB_TLIMIT(i))); - /* which is NV40_PGRAPH_TLIMIT0(i) ?? */ - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + i * 4); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, - nv_rd32(dev, NV10_PFB_TLIMIT(i))); - nv_wr32(dev, 0x00400908 + i * 0x10, - nv_rd32(dev, NV10_PFB_TSIZE(i))); - /* which is NV40_PGRAPH_TSIZE0(i) ?? */ - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + i * 4); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, - nv_rd32(dev, NV10_PFB_TSIZE(i))); - nv_wr32(dev, 0x00400900 + i * 0x10, - nv_rd32(dev, NV10_PFB_TILE(i))); - /* which is NV40_PGRAPH_TILE0(i) ?? */ - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + i * 4); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, - nv_rd32(dev, NV10_PFB_TILE(i))); - } + /* Turn all the tiling regions off. */ + for (i = 0; i < NV10_PFB_TILE__SIZE; i++) + nv20_graph_set_region_tiling(dev, i, 0, 0, 0); + for (i = 0; i < 8; i++) { nv_wr32(dev, 0x400980 + i * 4, nv_rd32(dev, 0x100300 + i * 4)); nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0090 + i * 4); @@ -704,18 +708,9 @@ nv30_graph_init(struct drm_device *dev) nv_wr32(dev, 0x4000c0, 0x00000016); - /* copy tile info from PFB */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - nv_wr32(dev, 0x00400904 + i * 0x10, - nv_rd32(dev, NV10_PFB_TLIMIT(i))); - /* which is NV40_PGRAPH_TLIMIT0(i) ?? */ - nv_wr32(dev, 0x00400908 + i * 0x10, - nv_rd32(dev, NV10_PFB_TSIZE(i))); - /* which is NV40_PGRAPH_TSIZE0(i) ?? */ - nv_wr32(dev, 0x00400900 + i * 0x10, - nv_rd32(dev, NV10_PFB_TILE(i))); - /* which is NV40_PGRAPH_TILE0(i) ?? */ - } + /* Turn all the tiling regions off. */ + for (i = 0; i < NV10_PFB_TILE__SIZE; i++) + nv20_graph_set_region_tiling(dev, i, 0, 0, 0); nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100); nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF); diff --git a/drivers/gpu/drm/nouveau/nv40_fb.c b/drivers/gpu/drm/nouveau/nv40_fb.c index ca1d27107a8..3cd07d8d5bd 100644 --- a/drivers/gpu/drm/nouveau/nv40_fb.c +++ b/drivers/gpu/drm/nouveau/nv40_fb.c @@ -3,12 +3,37 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +void +nv40_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) + addr |= 1; + + switch (dev_priv->chipset) { + case 0x40: + nv_wr32(dev, NV10_PFB_TLIMIT(i), limit); + nv_wr32(dev, NV10_PFB_TSIZE(i), pitch); + nv_wr32(dev, NV10_PFB_TILE(i), addr); + break; + + default: + nv_wr32(dev, NV40_PFB_TLIMIT(i), limit); + nv_wr32(dev, NV40_PFB_TSIZE(i), pitch); + nv_wr32(dev, NV40_PFB_TILE(i), addr); + break; + } +} + int nv40_fb_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t fb_bar_size, tmp; - int num_tiles; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + uint32_t tmp; int i; /* This is strictly a NV4x register (don't know about NV5x). */ @@ -23,35 +48,23 @@ nv40_fb_init(struct drm_device *dev) case 0x45: tmp = nv_rd32(dev, NV10_PFB_CLOSE_PAGE2); nv_wr32(dev, NV10_PFB_CLOSE_PAGE2, tmp & ~(1 << 15)); - num_tiles = NV10_PFB_TILE__SIZE; + pfb->num_tiles = NV10_PFB_TILE__SIZE; break; case 0x46: /* G72 */ case 0x47: /* G70 */ case 0x49: /* G71 */ case 0x4b: /* G73 */ case 0x4c: /* C51 (G7X version) */ - num_tiles = NV40_PFB_TILE__SIZE_1; + pfb->num_tiles = NV40_PFB_TILE__SIZE_1; break; default: - num_tiles = NV40_PFB_TILE__SIZE_0; + pfb->num_tiles = NV40_PFB_TILE__SIZE_0; break; } - fb_bar_size = drm_get_resource_len(dev, 0) - 1; - switch (dev_priv->chipset) { - case 0x40: - for (i = 0; i < num_tiles; i++) { - nv_wr32(dev, NV10_PFB_TILE(i), 0); - nv_wr32(dev, NV10_PFB_TLIMIT(i), fb_bar_size); - } - break; - default: - for (i = 0; i < num_tiles; i++) { - nv_wr32(dev, NV40_PFB_TILE(i), 0); - nv_wr32(dev, NV40_PFB_TLIMIT(i), fb_bar_size); - } - break; - } + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->num_tiles; i++) + pfb->set_region_tiling(dev, i, 0, 0, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 2b332bb55ac..53e8afe1dcd 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -181,6 +181,48 @@ nv40_graph_unload_context(struct drm_device *dev) return ret; } +void +nv40_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t limit = max(1u, addr + size) - 1; + + if (pitch) + addr |= 1; + + switch (dev_priv->chipset) { + case 0x44: + case 0x4a: + case 0x4e: + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); + break; + + case 0x46: + case 0x47: + case 0x49: + case 0x4b: + nv_wr32(dev, NV47_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV47_PGRAPH_TILE(i), addr); + nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch); + nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit); + nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr); + break; + + default: + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); + nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); + nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch); + nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit); + nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr); + break; + } +} + /* * G70 0x47 * G71 0x49 @@ -195,7 +237,8 @@ nv40_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = (struct drm_nouveau_private *)dev->dev_private; - uint32_t vramsz, tmp; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + uint32_t vramsz; int i, j; nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & @@ -292,74 +335,9 @@ nv40_graph_init(struct drm_device *dev) nv_wr32(dev, 0x400b38, 0x2ffff800); nv_wr32(dev, 0x400b3c, 0x00006000); - /* copy tile info from PFB */ - switch (dev_priv->chipset) { - case 0x40: /* vanilla NV40 */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { - tmp = nv_rd32(dev, NV10_PFB_TILE(i)); - nv_wr32(dev, NV40_PGRAPH_TILE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tmp); - tmp = nv_rd32(dev, NV10_PFB_TLIMIT(i)); - nv_wr32(dev, NV40_PGRAPH_TLIMIT0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tmp); - tmp = nv_rd32(dev, NV10_PFB_TSIZE(i)); - nv_wr32(dev, NV40_PGRAPH_TSIZE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tmp); - tmp = nv_rd32(dev, NV10_PFB_TSTATUS(i)); - nv_wr32(dev, NV40_PGRAPH_TSTATUS0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSTATUS1(i), tmp); - } - break; - case 0x44: - case 0x4a: - case 0x4e: /* NV44-based cores don't have 0x406900? */ - for (i = 0; i < NV40_PFB_TILE__SIZE_0; i++) { - tmp = nv_rd32(dev, NV40_PFB_TILE(i)); - nv_wr32(dev, NV40_PGRAPH_TILE0(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TLIMIT(i)); - nv_wr32(dev, NV40_PGRAPH_TLIMIT0(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSIZE(i)); - nv_wr32(dev, NV40_PGRAPH_TSIZE0(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSTATUS(i)); - nv_wr32(dev, NV40_PGRAPH_TSTATUS0(i), tmp); - } - break; - case 0x46: - case 0x47: - case 0x49: - case 0x4b: /* G7X-based cores */ - for (i = 0; i < NV40_PFB_TILE__SIZE_1; i++) { - tmp = nv_rd32(dev, NV40_PFB_TILE(i)); - nv_wr32(dev, NV47_PGRAPH_TILE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TLIMIT(i)); - nv_wr32(dev, NV47_PGRAPH_TLIMIT0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSIZE(i)); - nv_wr32(dev, NV47_PGRAPH_TSIZE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSTATUS(i)); - nv_wr32(dev, NV47_PGRAPH_TSTATUS0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSTATUS1(i), tmp); - } - break; - default: /* everything else */ - for (i = 0; i < NV40_PFB_TILE__SIZE_0; i++) { - tmp = nv_rd32(dev, NV40_PFB_TILE(i)); - nv_wr32(dev, NV40_PGRAPH_TILE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TLIMIT(i)); - nv_wr32(dev, NV40_PGRAPH_TLIMIT0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSIZE(i)); - nv_wr32(dev, NV40_PGRAPH_TSIZE0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tmp); - tmp = nv_rd32(dev, NV40_PFB_TSTATUS(i)); - nv_wr32(dev, NV40_PGRAPH_TSTATUS0(i), tmp); - nv_wr32(dev, NV40_PGRAPH_TSTATUS1(i), tmp); - } - break; - } + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->num_tiles; i++) + nv40_graph_set_region_tiling(dev, i, 0, 0, 0); /* begin RAM config */ vramsz = drm_get_resource_len(dev, 0) - 1; -- cgit v1.2.3 From a0af9add499cf29a16707b7b148842992077f4cb Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 11 Dec 2009 16:51:09 +0100 Subject: drm/nouveau: Make the MM aware of pre-G80 tiling. This commit has also the following 3 bugfix commits squashed into it from the nouveau git tree: drm/nouveau: Fix up the tiling alignment restrictions for nv1x. drm/nouveau: Fix up the nv2x tiling alignment restrictions. drm/nv50: fix align typo for g9x Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_bo.c | 221 ++++++++++++++++++++++++---------- drivers/gpu/drm/nouveau/nouveau_drv.h | 22 ++++ drivers/gpu/drm/nouveau/nouveau_mem.c | 87 +++++++++++++ 3 files changed, 265 insertions(+), 65 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 0cad6d834eb..1d6036fabd5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -37,6 +37,7 @@ static void nouveau_bo_del_ttm(struct ttm_buffer_object *bo) { struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct drm_device *dev = dev_priv->dev; struct nouveau_bo *nvbo = nouveau_bo(bo); ttm_bo_kunmap(&nvbo->kmap); @@ -44,12 +45,83 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) if (unlikely(nvbo->gem)) DRM_ERROR("bo %p still attached to GEM object\n", bo); + if (nvbo->tile) + nv10_mem_expire_tiling(dev, nvbo->tile, NULL); + spin_lock(&dev_priv->ttm.bo_list_lock); list_del(&nvbo->head); spin_unlock(&dev_priv->ttm.bo_list_lock); kfree(nvbo); } +static void +nouveau_bo_fixup_align(struct drm_device *dev, + uint32_t tile_mode, uint32_t tile_flags, + int *align, int *size) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + /* + * Some of the tile_flags have a periodic structure of N*4096 bytes, + * align to to that as well as the page size. Overallocate memory to + * avoid corruption of other buffer objects. + */ + if (dev_priv->card_type == NV_50) { + switch (tile_flags) { + case 0x1800: + case 0x2800: + case 0x4800: + case 0x7a00: + if (dev_priv->chipset >= 0xA0) { + /* This is based on high end cards with 448 bits + * memory bus, could be different elsewhere.*/ + *size += 6 * 28672; + /* 8 * 28672 is the actual alignment requirement + * but we must also align to page size. */ + *align = 2 * 8 * 28672; + } else if (dev_priv->chipset >= 0x90) { + *size += 3 * 16384; + *align = 12 * 16384; + } else { + *size += 3 * 8192; + /* 12 * 8192 is the actual alignment requirement + * but we must also align to page size. */ + *align = 2 * 12 * 8192; + } + break; + default: + break; + } + + } else { + if (tile_mode) { + if (dev_priv->chipset >= 0x40) { + *align = 65536; + *size = roundup(*size, 64 * tile_mode); + + } else if (dev_priv->chipset >= 0x30) { + *align = 32768; + *size = roundup(*size, 64 * tile_mode); + + } else if (dev_priv->chipset >= 0x20) { + *align = 16384; + *size = roundup(*size, 64 * tile_mode); + + } else if (dev_priv->chipset >= 0x10) { + *align = 16384; + *size = roundup(*size, 32 * tile_mode); + } + } + } + + *size = ALIGN(*size, PAGE_SIZE); + + if (dev_priv->card_type == NV_50) { + *size = ALIGN(*size, 65536); + *align = max(65536, *align); + } +} + int nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, int size, int align, uint32_t flags, uint32_t tile_mode, @@ -70,46 +142,9 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->tile_mode = tile_mode; nvbo->tile_flags = tile_flags; - /* - * Some of the tile_flags have a periodic structure of N*4096 bytes, - * align to to that as well as the page size. Overallocate memory to - * avoid corruption of other buffer objects. - */ - switch (tile_flags) { - case 0x1800: - case 0x2800: - case 0x4800: - case 0x7a00: - if (dev_priv->chipset >= 0xA0) { - /* This is based on high end cards with 448 bits - * memory bus, could be different elsewhere.*/ - size += 6 * 28672; - /* 8 * 28672 is the actual alignment requirement, - * but we must also align to page size. */ - align = 2 * 8 * 28672; - } else if (dev_priv->chipset >= 0x90) { - size += 3 * 16384; - align = 12 * 16834; - } else { - size += 3 * 8192; - /* 12 * 8192 is the actual alignment requirement, - * but we must also align to page size. */ - align = 2 * 12 * 8192; - } - break; - default: - break; - } - + nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size); align >>= PAGE_SHIFT; - size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); - if (dev_priv->card_type == NV_50) { - size = (size + 65535) & ~65535; - if (align < (65536 / PAGE_SIZE)) - align = (65536 / PAGE_SIZE); - } - if (flags & TTM_PL_FLAG_VRAM) nvbo->placements[n++] = TTM_PL_FLAG_VRAM | TTM_PL_MASK_CACHING; if (flags & TTM_PL_FLAG_TT) @@ -421,6 +456,7 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) /* GPU-assisted copy using NV_MEMORY_TO_MEMORY_FORMAT, can access * TTM_PL_{VRAM,TT} directly. */ + static int nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, struct nouveau_bo *nvbo, bool evict, bool no_wait, @@ -455,11 +491,12 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, } static int -nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, int no_wait, - struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) +nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, + int no_wait, struct ttm_mem_reg *new_mem) { struct nouveau_bo *nvbo = nouveau_bo(bo); struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct ttm_mem_reg *old_mem = &bo->mem; struct nouveau_channel *chan; uint64_t src_offset, dst_offset; uint32_t page_count; @@ -559,7 +596,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) goto out; - ret = nouveau_bo_move_m2mf(bo, true, no_wait, &bo->mem, &tmp_mem); + ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait, &tmp_mem); if (ret) goto out; @@ -597,7 +634,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) goto out; - ret = nouveau_bo_move_m2mf(bo, true, no_wait, &bo->mem, new_mem); + ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait, new_mem); if (ret) goto out; @@ -612,52 +649,106 @@ out: } static int -nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, - bool no_wait, struct ttm_mem_reg *new_mem) +nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, + struct nouveau_tile_reg **new_tile) { struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); - struct nouveau_bo *nvbo = nouveau_bo(bo); struct drm_device *dev = dev_priv->dev; - struct ttm_mem_reg *old_mem = &bo->mem; + struct nouveau_bo *nvbo = nouveau_bo(bo); + uint64_t offset; int ret; - if (dev_priv->card_type == NV_50 && new_mem->mem_type == TTM_PL_VRAM && - !nvbo->no_vm) { - uint64_t offset = new_mem->mm_node->start << PAGE_SHIFT; + if (nvbo->no_vm || new_mem->mem_type != TTM_PL_VRAM) { + /* Nothing to do. */ + *new_tile = NULL; + return 0; + } + + offset = new_mem->mm_node->start << PAGE_SHIFT; + if (dev_priv->card_type == NV_50) { ret = nv50_mem_vm_bind_linear(dev, offset + dev_priv->vm_vram_base, new_mem->size, nvbo->tile_flags, offset); if (ret) return ret; + + } else if (dev_priv->card_type >= NV_10) { + *new_tile = nv10_mem_set_tiling(dev, offset, new_mem->size, + nvbo->tile_mode); } + return 0; +} + +static void +nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo, + struct nouveau_tile_reg *new_tile, + struct nouveau_tile_reg **old_tile) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct drm_device *dev = dev_priv->dev; + + if (dev_priv->card_type >= NV_10 && + dev_priv->card_type < NV_50) { + if (*old_tile) + nv10_mem_expire_tiling(dev, *old_tile, bo->sync_obj); + + *old_tile = new_tile; + } +} + +static int +nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, + bool no_wait, struct ttm_mem_reg *new_mem) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct nouveau_bo *nvbo = nouveau_bo(bo); + struct ttm_mem_reg *old_mem = &bo->mem; + struct nouveau_tile_reg *new_tile = NULL; + int ret = 0; + + ret = nouveau_bo_vm_bind(bo, new_mem, &new_tile); + if (ret) + return ret; + + /* Software copy if the card isn't up and running yet. */ if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE || - !dev_priv->channel) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + !dev_priv->channel) { + ret = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + goto out; + } + /* Fake bo copy. */ if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) { BUG_ON(bo->mem.mm_node != NULL); bo->mem = *new_mem; new_mem->mm_node = NULL; - return 0; + goto out; } - if (new_mem->mem_type == TTM_PL_SYSTEM) { - if (old_mem->mem_type == TTM_PL_SYSTEM) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); - if (nouveau_bo_move_flipd(bo, evict, intr, no_wait, new_mem)) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } else if (old_mem->mem_type == TTM_PL_SYSTEM) { - if (nouveau_bo_move_flips(bo, evict, intr, no_wait, new_mem)) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } else { - if (nouveau_bo_move_m2mf(bo, evict, no_wait, old_mem, new_mem)) - return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } + /* Hardware assisted copy. */ + if (new_mem->mem_type == TTM_PL_SYSTEM) + ret = nouveau_bo_move_flipd(bo, evict, intr, no_wait, new_mem); + else if (old_mem->mem_type == TTM_PL_SYSTEM) + ret = nouveau_bo_move_flips(bo, evict, intr, no_wait, new_mem); + else + ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait, new_mem); - return 0; + if (!ret) + goto out; + + /* Fallback to software copy. */ + ret = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + +out: + if (ret) + nouveau_bo_vm_cleanup(bo, NULL, &new_tile); + else + nouveau_bo_vm_cleanup(bo, new_tile, &nvbo->tile); + + return ret; } static int diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 446a92ad2ee..9c9815bf505 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -59,11 +59,19 @@ struct nouveau_grctx; #define MAX_NUM_DCB_ENTRIES 16 #define NOUVEAU_MAX_CHANNEL_NR 128 +#define NOUVEAU_MAX_TILE_NR 15 #define NV50_VM_MAX_VRAM (2*1024*1024*1024ULL) #define NV50_VM_BLOCK (512*1024*1024ULL) #define NV50_VM_VRAM_NR (NV50_VM_MAX_VRAM / NV50_VM_BLOCK) +struct nouveau_tile_reg { + struct nouveau_fence *fence; + uint32_t addr; + uint32_t size; + bool used; +}; + struct nouveau_bo { struct ttm_buffer_object bo; struct ttm_placement placement; @@ -83,6 +91,7 @@ struct nouveau_bo { uint32_t tile_mode; uint32_t tile_flags; + struct nouveau_tile_reg *tile; struct drm_gem_object *gem; struct drm_file *cpu_filp; @@ -558,6 +567,12 @@ struct drm_nouveau_private { unsigned long sg_handle; } gart_info; + /* nv10-nv40 tiling regions */ + struct { + struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR]; + spinlock_t lock; + } tile; + /* G8x/G9x virtual address space */ uint64_t vm_gart_base; uint64_t vm_gart_size; @@ -695,6 +710,13 @@ extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); extern int nouveau_mem_init(struct drm_device *); extern int nouveau_mem_init_agp(struct drm_device *); extern void nouveau_mem_close(struct drm_device *); +extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev, + uint32_t addr, + uint32_t size, + uint32_t pitch); +extern void nv10_mem_expire_tiling(struct drm_device *dev, + struct nouveau_tile_reg *tile, + struct nouveau_fence *fence); extern int nv50_mem_vm_bind_linear(struct drm_device *, uint64_t virt, uint32_t size, uint32_t flags, uint64_t phys); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 5158a12f784..fb9bdd6edf1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -191,6 +191,92 @@ void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap) } } +/* + * NV10-NV40 tiling helpers + */ + +static void +nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + + tile->addr = addr; + tile->size = size; + tile->used = !!pitch; + nouveau_fence_unref((void **)&tile->fence); + + if (!pfifo->cache_flush(dev)) + return; + + pfifo->reassign(dev, false); + pfifo->cache_flush(dev); + pfifo->cache_pull(dev, false); + + nouveau_wait_for_idle(dev); + + pgraph->set_region_tiling(dev, i, addr, size, pitch); + pfb->set_region_tiling(dev, i, addr, size, pitch); + + pfifo->cache_pull(dev, true); + pfifo->reassign(dev, true); +} + +struct nouveau_tile_reg * +nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, + uint32_t pitch) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct nouveau_tile_reg *tile = dev_priv->tile.reg, *found = NULL; + int i; + + spin_lock(&dev_priv->tile.lock); + + for (i = 0; i < pfb->num_tiles; i++) { + if (tile[i].used) + /* Tile region in use. */ + continue; + + if (tile[i].fence && + !nouveau_fence_signalled(tile[i].fence, NULL)) + /* Pending tile region. */ + continue; + + if (max(tile[i].addr, addr) < + min(tile[i].addr + tile[i].size, addr + size)) + /* Kill an intersecting tile region. */ + nv10_mem_set_region_tiling(dev, i, 0, 0, 0); + + if (pitch && !found) { + /* Free tile region. */ + nv10_mem_set_region_tiling(dev, i, addr, size, pitch); + found = &tile[i]; + } + } + + spin_unlock(&dev_priv->tile.lock); + + return found; +} + +void +nv10_mem_expire_tiling(struct drm_device *dev, struct nouveau_tile_reg *tile, + struct nouveau_fence *fence) +{ + if (fence) { + /* Mark it as pending. */ + tile->fence = fence; + nouveau_fence_ref(fence); + } + + tile->used = false; +} + /* * NV50 VM helpers */ @@ -513,6 +599,7 @@ nouveau_mem_init(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->ttm.bo_list); spin_lock_init(&dev_priv->ttm.bo_list_lock); + spin_lock_init(&dev_priv->tile.lock); dev_priv->fb_available_size = nouveau_mem_fb_amount(dev); -- cgit v1.2.3 From cea7789f2a680893e812776dd7202dd50475f9d2 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 16 Dec 2009 12:27:11 +0100 Subject: drm/i2c/ch7006: Drop build time dependency to nouveau. This partially reverts e4b41066, as this driver is intended to be useful with any KMS driver for suitable hardware. The missing build dependency that commit workarounded was DRM_KMS_HELPER. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index b1bc1ea182b..1175429da10 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -30,12 +30,11 @@ config DRM_NOUVEAU_DEBUG via debugfs. menu "I2C encoder or helper chips" - depends on DRM && I2C + depends on DRM && DRM_KMS_HELPER && I2C config DRM_I2C_CH7006 tristate "Chrontel ch7006 TV encoder" - depends on DRM_NOUVEAU - default m + default m if DRM_NOUVEAU help Support for Chrontel ch7006 and similar TV encoders, found on some nVidia video cards. -- cgit v1.2.3 From 77e2b5ed83864f0a58e2cd046b15aab6865babfb Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 16 Dec 2009 19:05:00 +0100 Subject: drm/nouveau: Fix "general protection fault" in the flipd/flips eviction path. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_bo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 1d6036fabd5..365fc650817 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -584,7 +584,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, placement.fpfn = placement.lpfn = 0; placement.num_placement = placement.num_busy_placement = 1; - placement.placement = &placement_memtype; + placement.placement = placement.busy_placement = &placement_memtype; tmp_mem = *new_mem; tmp_mem.mm_node = NULL; @@ -622,7 +622,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, placement.fpfn = placement.lpfn = 0; placement.num_placement = placement.num_busy_placement = 1; - placement.placement = &placement_memtype; + placement.placement = placement.busy_placement = &placement_memtype; tmp_mem = *new_mem; tmp_mem.mm_node = NULL; -- cgit v1.2.3 From 27f691a69d411b9b2093163cdd27780f9c927422 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 16 Dec 2009 19:05:38 +0100 Subject: drm/nouveau: No need to force evict=true when swapping evicted BOs back in. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 365fc650817..73af53fe75a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -634,7 +634,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) goto out; - ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait, new_mem); + ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait, new_mem); if (ret) goto out; -- cgit v1.2.3 From 8dea4a1935fabbc5fcea6016d6670e6bc06de198 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 16 Dec 2009 19:03:28 +0100 Subject: drm/nouveau: Drop redundant placement initialization. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_bo.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 73af53fe75a..5fd462f4940 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -130,7 +130,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_bo *nvbo; - int ret, n = 0; + int ret = 0; nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL); if (!nvbo) @@ -145,19 +145,11 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size); align >>= PAGE_SHIFT; - if (flags & TTM_PL_FLAG_VRAM) - nvbo->placements[n++] = TTM_PL_FLAG_VRAM | TTM_PL_MASK_CACHING; - if (flags & TTM_PL_FLAG_TT) - nvbo->placements[n++] = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; nvbo->placement.fpfn = 0; nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0; - nvbo->placement.placement = nvbo->placements; - nvbo->placement.busy_placement = nvbo->placements; - nvbo->placement.num_placement = n; - nvbo->placement.num_busy_placement = n; + nouveau_bo_placement_set(nvbo, flags); nvbo->channel = chan; - nouveau_bo_placement_set(nvbo, flags); ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size, ttm_bo_type_device, &nvbo->placement, align, 0, false, NULL, size, nouveau_bo_del_ttm); -- cgit v1.2.3 From 75c722d7ea70b791d179ec900e7c88bd6d5fd71e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 21 Dec 2009 12:16:52 +1000 Subject: drm/nv50: ignore vbios table's claim to the contrary if EDID says >8bpc Should fix dim panel issues reported on Dell M6400/M6500. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index a9263d92a23..90f0bf59fbc 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -690,9 +690,21 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent, int pxclk) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_connector *nv_connector = NULL; + struct drm_encoder *encoder; struct nvbios *bios = &dev_priv->VBIOS; uint32_t mc, script = 0, or; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + + if (nv_encoder->dcb != dcbent) + continue; + + nv_connector = nouveau_encoder_connector_get(nv_encoder); + break; + } + or = ffs(dcbent->or) - 1; mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or); switch (dcbent->type) { @@ -711,6 +723,11 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent, } else if (bios->fp.strapless_is_24bit & 1) script |= 0x0200; + + if (nv_connector && nv_connector->edid && + (nv_connector->edid->revision >= 4) && + (nv_connector->edid->input & 0x70) >= 0x20) + script |= 0x0200; } if (nouveau_uscript_lvds >= 0) { -- cgit v1.2.3 From 3033f14d6538e0e7c3c53d3ed1ff6cec28260b98 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Mon, 21 Dec 2009 23:00:41 +0100 Subject: drm/nv50: fix fillrect color struct fb_fillrect->color is not a color, but index into pseudo_palette array Signed-off-by: Marcin Slusarz Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_fbcon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 6bcc6d39e9b..c966ef83485 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -10,6 +10,7 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) struct drm_device *dev = par->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; + uint32_t color = ((uint32_t *) info->pseudo_palette)[rect->color]; if (info->state != FBINFO_STATE_RUNNING) return; @@ -31,7 +32,7 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) OUT_RING(chan, 1); } BEGIN_RING(chan, NvSub2D, 0x0588, 1); - OUT_RING(chan, rect->color); + OUT_RING(chan, color); BEGIN_RING(chan, NvSub2D, 0x0600, 4); OUT_RING(chan, rect->dx); OUT_RING(chan, rect->dy); -- cgit v1.2.3 From 11d6eb2af53395b25e1d6b8b79bb9a999c3e4c4d Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 17 Dec 2009 18:52:44 +0100 Subject: drm/nouveau: Clean up the nv17-nv4x load detection code a bit. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_drv.h | 6 +----- drivers/gpu/drm/nouveau/nv04_dac.c | 35 +++++++++++++++++++---------------- drivers/gpu/drm/nouveau/nv17_tv.c | 27 +++++++++++++++++---------- 3 files changed, 37 insertions(+), 31 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 9c9815bf505..7da88a92c83 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1074,8 +1074,7 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, /* nv04_dac.c */ extern int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry); -extern enum drm_connector_status nv17_dac_detect(struct drm_encoder *encoder, - struct drm_connector *connector); +extern uint32_t nv17_dac_sample_load(struct drm_encoder *encoder); extern int nv04_dac_output_offset(struct drm_encoder *encoder); extern void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable); @@ -1093,9 +1092,6 @@ extern int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry); /* nv17_tv.c */ extern int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry); -extern enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, - struct drm_connector *connector, - uint32_t pin_mask); /* nv04_display.c */ extern int nv04_display_create(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c index d9f32879ba3..d0e038d2894 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c @@ -212,16 +212,15 @@ out: return connector_status_disconnected; } -enum drm_connector_status nv17_dac_detect(struct drm_encoder *encoder, - struct drm_connector *connector) +uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; - uint32_t testval, regoffset = nv04_dac_output_offset(encoder); + uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, saved_rtest_ctrl, saved_gpio0, saved_gpio1, temp, routput; - int head, present = 0; + int head; #define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20) if (dcb->type == OUTPUT_TV) { @@ -287,13 +286,7 @@ enum drm_connector_status nv17_dac_detect(struct drm_encoder *encoder, temp | NV_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED); msleep(5); - temp = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); - - if (dcb->type == OUTPUT_TV) - present = (nv17_tv_detect(encoder, connector, temp) - == connector_status_connected); - else - present = temp & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI; + sample = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL); NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL, @@ -310,15 +303,25 @@ enum drm_connector_status nv17_dac_detect(struct drm_encoder *encoder, nv17_gpio_set(dev, DCB_GPIO_TVDAC1, saved_gpio1); nv17_gpio_set(dev, DCB_GPIO_TVDAC0, saved_gpio0); - if (present) { - NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); + return sample; +} + +static enum drm_connector_status +nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; + uint32_t sample = nv17_dac_sample_load(encoder); + + if (sample & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { + NV_INFO(dev, "Load detected on output %c\n", + '@' + ffs(dcb->or)); return connector_status_connected; + } else { + return connector_status_disconnected; } - - return connector_status_disconnected; } - static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 81c01353a9f..5fa4242e4c7 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -33,13 +33,15 @@ #include "nouveau_hw.h" #include "nv17_tv.h" -enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, - struct drm_connector *connector, - uint32_t pin_mask) +static enum drm_connector_status +nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) { + struct drm_device *dev = encoder->dev; + struct drm_mode_config *conf = &dev->mode_config; struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); + struct dcb_entry *dcb = tv_enc->base.dcb; - tv_enc->pin_mask = pin_mask >> 28 & 0xe; + tv_enc->pin_mask = nv17_dac_sample_load(encoder) >> 28 & 0xe; switch (tv_enc->pin_mask) { case 0x2: @@ -50,7 +52,7 @@ enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO; break; case 0xe: - if (nouveau_encoder(encoder)->dcb->tvconf.has_component_output) + if (dcb->tvconf.has_component_output) tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Component; else tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_SCART; @@ -61,11 +63,16 @@ enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, } drm_connector_property_set_value(connector, - encoder->dev->mode_config.tv_subconnector_property, - tv_enc->subconnector); + conf->tv_subconnector_property, + tv_enc->subconnector); - return tv_enc->subconnector ? connector_status_connected : - connector_status_disconnected; + if (tv_enc->subconnector) { + NV_INFO(dev, "Load detected on output %c\n", + '@' + ffs(dcb->or)); + return connector_status_connected; + } else { + return connector_status_disconnected; + } } static const struct { @@ -633,7 +640,7 @@ static struct drm_encoder_helper_funcs nv17_tv_helper_funcs = { .prepare = nv17_tv_prepare, .commit = nv17_tv_commit, .mode_set = nv17_tv_mode_set, - .detect = nv17_dac_detect, + .detect = nv17_tv_detect, }; static struct drm_encoder_slave_funcs nv17_tv_slave_funcs = { -- cgit v1.2.3 From 0829168b474663d8b13f6105368dbbf4a1a03256 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 17 Dec 2009 18:57:44 +0100 Subject: drm/nouveau: Implement nv42-nv43 TV load detection. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nv17_tv.c | 90 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 5fa4242e4c7..58b917c3341 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -33,15 +33,103 @@ #include "nouveau_hw.h" #include "nv17_tv.h" +static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t testval, regoffset = nv04_dac_output_offset(encoder); + uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end, + fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c; + uint32_t sample = 0; + int head; + +#define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20) + testval = RGB_TEST_DATA(0x82, 0xeb, 0x82); + if (dev_priv->vbios->tvdactestval) + testval = dev_priv->vbios->tvdactestval; + + dacclk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); + head = (dacclk & 0x100) >> 8; + + /* Save the previous state. */ + gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1); + gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0); + fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL); + fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START); + fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END); + fp_control = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL); + test_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); + ctv_1c = NVReadRAMDAC(dev, head, 0x680c1c); + ctv_14 = NVReadRAMDAC(dev, head, 0x680c14); + ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c); + + /* Prepare the DAC for load detection. */ + nv17_gpio_set(dev, DCB_GPIO_TVDAC1, true); + nv17_gpio_set(dev, DCB_GPIO_TVDAC0, true); + + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, 1183); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL, + NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | + NV_PRAMDAC_FP_TG_CONTROL_WIDTH_12 | + NV_PRAMDAC_FP_TG_CONTROL_READ_PROG | + NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | + NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS); + + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, 0); + + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, + (dacclk & ~0xff) | 0x22); + msleep(1); + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, + (dacclk & ~0xff) | 0x21); + + NVWriteRAMDAC(dev, head, 0x680c1c, 1 << 20); + NVWriteRAMDAC(dev, head, 0x680c14, 4 << 16); + + /* Sample pin 0x4 (usually S-video luma). */ + NVWriteRAMDAC(dev, head, 0x680c6c, testval >> 10 & 0x3ff); + msleep(20); + sample |= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset) + & 0x4 << 28; + + /* Sample the remaining pins. */ + NVWriteRAMDAC(dev, head, 0x680c6c, testval & 0x3ff); + msleep(20); + sample |= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset) + & 0xa << 28; + + /* Restore the previous state. */ + NVWriteRAMDAC(dev, head, 0x680c1c, ctv_1c); + NVWriteRAMDAC(dev, head, 0x680c14, ctv_14); + NVWriteRAMDAC(dev, head, 0x680c6c, ctv_6c); + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, dacclk); + NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, test_ctrl); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL, fp_control); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start); + NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal); + nv17_gpio_set(dev, DCB_GPIO_TVDAC1, gpio1); + nv17_gpio_set(dev, DCB_GPIO_TVDAC0, gpio0); + + return sample; +} + static enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_mode_config *conf = &dev->mode_config; struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); struct dcb_entry *dcb = tv_enc->base.dcb; - tv_enc->pin_mask = nv17_dac_sample_load(encoder) >> 28 & 0xe; + if (dev_priv->chipset == 0x42 || + dev_priv->chipset == 0x43) + tv_enc->pin_mask = nv42_tv_sample_load(encoder) >> 28 & 0xe; + else + tv_enc->pin_mask = nv17_dac_sample_load(encoder) >> 28 & 0xe; switch (tv_enc->pin_mask) { case 0x2: -- cgit v1.2.3 From 111b459af191891f49682f21e11f348703cd8bdd Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 22 Dec 2009 18:24:09 +0100 Subject: drm/nouveau: Don't skip card take down on nv0x. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 6a459139910..a6b573e8982 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -722,8 +722,8 @@ static void nouveau_close(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - /* In the case of an error dev_priv may not be be allocated yet */ - if (dev_priv && dev_priv->card_type) + /* In the case of an error dev_priv may not be allocated yet */ + if (dev_priv) nouveau_card_takedown(dev); } -- cgit v1.2.3 From 1c7059e4f36e76c72cefbb6c9bd2bcf45c12e777 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 25 Dec 2009 18:51:17 +0100 Subject: drm/nouveau: better alignment of bo sizes and use roundup instead of ALIGN - Aligning to block size should ensure that the extra size is enough. - Using roundup, because not all sizes are powers of two. Signed-off-by: Maarten Maathuis --- drivers/gpu/drm/nouveau/nouveau_bo.c | 8 ++++++-- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 5fd462f4940..a0c9e00e706 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -73,6 +73,7 @@ nouveau_bo_fixup_align(struct drm_device *dev, case 0x4800: case 0x7a00: if (dev_priv->chipset >= 0xA0) { + *size = roundup(*size, 28672); /* This is based on high end cards with 448 bits * memory bus, could be different elsewhere.*/ *size += 6 * 28672; @@ -80,9 +81,11 @@ nouveau_bo_fixup_align(struct drm_device *dev, * but we must also align to page size. */ *align = 2 * 8 * 28672; } else if (dev_priv->chipset >= 0x90) { + *size = roundup(*size, 16384); *size += 3 * 16384; *align = 12 * 16384; } else { + *size = roundup(*size, 8192); *size += 3 * 8192; /* 12 * 8192 is the actual alignment requirement * but we must also align to page size. */ @@ -114,10 +117,11 @@ nouveau_bo_fixup_align(struct drm_device *dev, } } - *size = ALIGN(*size, PAGE_SIZE); + /* ALIGN works only on powers of two. */ + *size = roundup(*size, PAGE_SIZE); if (dev_priv->card_type == NV_50) { - *size = ALIGN(*size, 65536); + *size = roundup(*size, 65536); *align = max(65536, *align); } } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 84af25c238b..44cbbeeb774 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -212,11 +212,11 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, mode_cmd.bpp = surface_bpp; mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3); - mode_cmd.pitch = ALIGN(mode_cmd.pitch, 256); + mode_cmd.pitch = roundup(mode_cmd.pitch, 256); mode_cmd.depth = surface_depth; size = mode_cmd.pitch * mode_cmd.height; - size = ALIGN(size, PAGE_SIZE); + size = roundup(size, PAGE_SIZE); ret = nouveau_gem_new(dev, dev_priv->channel, size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, false, true, &nvbo); -- cgit v1.2.3 From a510604df9444a2a1bdecafc048749e0f35816b5 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 26 Dec 2009 21:46:36 +0100 Subject: drm/nv50: make the blocksize depend on vram size - This should be better than what we have now. - I'm less sure about the non power of two path. Signed-off-by: Maarten Maathuis --- drivers/gpu/drm/nouveau/nouveau_bo.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index a0c9e00e706..e342a418d43 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -33,6 +33,8 @@ #include "nouveau_drv.h" #include "nouveau_dma.h" +#include + static void nouveau_bo_del_ttm(struct ttm_buffer_object *bo) { @@ -67,29 +69,29 @@ nouveau_bo_fixup_align(struct drm_device *dev, * avoid corruption of other buffer objects. */ if (dev_priv->card_type == NV_50) { + uint32_t block_size = nouveau_mem_fb_amount(dev) >> 15; + int i; + switch (tile_flags) { case 0x1800: case 0x2800: case 0x4800: case 0x7a00: - if (dev_priv->chipset >= 0xA0) { - *size = roundup(*size, 28672); - /* This is based on high end cards with 448 bits - * memory bus, could be different elsewhere.*/ - *size += 6 * 28672; - /* 8 * 28672 is the actual alignment requirement - * but we must also align to page size. */ - *align = 2 * 8 * 28672; - } else if (dev_priv->chipset >= 0x90) { - *size = roundup(*size, 16384); - *size += 3 * 16384; - *align = 12 * 16384; + *size = roundup(*size, block_size); + if (is_power_of_2(block_size)) { + *size += 3 * block_size; + for (i = 1; i < 10; i++) { + *align = 12 * i * block_size; + if (!(*align % 65536)) + break; + } } else { - *size = roundup(*size, 8192); - *size += 3 * 8192; - /* 12 * 8192 is the actual alignment requirement - * but we must also align to page size. */ - *align = 2 * 12 * 8192; + *size += 6 * block_size; + for (i = 1; i < 10; i++) { + *align = 8 * i * block_size; + if (!(*align % 65536)) + break; + } } break; default: -- cgit v1.2.3 From f03a314b4671407c4ff69a2d85e72413e8064c48 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 26 Dec 2009 02:42:45 +0100 Subject: drm/nouveau: Allocate a per-channel instance of NV_SW. It will be useful for various synchronization purposes, mostly stolen from "[PATCH] drm/nv50: synchronize user channel after buffer object move on kernel channel" by Maarten Maathuis. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_channel.c | 4 +++- drivers/gpu/drm/nouveau/nouveau_dma.c | 17 +++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_dma.h | 10 ++++++---- drivers/gpu/drm/nouveau/nouveau_drv.h | 20 +++++++++++--------- drivers/gpu/drm/nouveau/nouveau_object.c | 2 +- drivers/gpu/drm/nouveau/nv04_fbcon.c | 19 ++++++++++--------- 6 files changed, 48 insertions(+), 24 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 9aaa972f882..4f378b68fe7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -414,7 +414,9 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, init->subchan[0].grclass = 0x0039; else init->subchan[0].grclass = 0x5039; - init->nr_subchan = 1; + init->subchan[1].handle = NvSw; + init->subchan[1].grclass = NV_SW; + init->nr_subchan = 2; /* Named memory object area */ ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem, diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 703553687b2..f1fd3f2b981 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -35,6 +35,7 @@ nouveau_dma_init(struct nouveau_channel *chan) struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *m2mf = NULL; + struct nouveau_gpuobj *nvsw = NULL; int ret, i; /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */ @@ -47,6 +48,15 @@ nouveau_dma_init(struct nouveau_channel *chan) if (ret) return ret; + /* Create an NV_SW object for various sync purposes */ + ret = nouveau_gpuobj_sw_new(chan, NV_SW, &nvsw); + if (ret) + return ret; + + ret = nouveau_gpuobj_ref_add(dev, chan, NvSw, nvsw, NULL); + if (ret) + return ret; + /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */ ret = nouveau_notifier_alloc(chan, NvNotify0, 32, &chan->m2mf_ntfy); if (ret) @@ -87,6 +97,13 @@ nouveau_dma_init(struct nouveau_channel *chan) BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1); OUT_RING(chan, NvNotify0); + /* Initialise NV_SW */ + ret = RING_SPACE(chan, 2); + if (ret) + return ret; + BEGIN_RING(chan, NvSubSw, 0, 1); + OUT_RING(chan, NvSw); + /* Sit back and pray the channel works.. */ FIRE_RING(chan); diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index 04e85d8f757..dabfd655f93 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -46,10 +46,11 @@ /* Hardcoded object assignments to subchannels (subchannel id). */ enum { NvSubM2MF = 0, - NvSub2D = 1, - NvSubCtxSurf2D = 1, - NvSubGdiRect = 2, - NvSubImageBlit = 3 + NvSubSw = 1, + NvSub2D = 2, + NvSubCtxSurf2D = 2, + NvSubGdiRect = 3, + NvSubImageBlit = 4 }; /* Object handles. */ @@ -67,6 +68,7 @@ enum { NvClipRect = 0x8000000b, NvGdiRect = 0x8000000c, NvImageBlit = 0x8000000d, + NvSw = 0x8000000e, /* G80+ display objects */ NvEvoVRAM = 0x01000000, diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 7da88a92c83..9181eaefe91 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -788,6 +788,8 @@ extern int nouveau_gpuobj_gart_dma_new(struct nouveau_channel *, uint32_t *o_ret); extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class, struct nouveau_gpuobj **); +extern int nouveau_gpuobj_sw_new(struct nouveau_channel *, int class, + struct nouveau_gpuobj **); extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data, @@ -1330,14 +1332,14 @@ nv_two_reg_pll(struct drm_device *dev) return false; } -#define NV50_NVSW 0x0000506e -#define NV50_NVSW_DMA_SEMAPHORE 0x00000060 -#define NV50_NVSW_SEMAPHORE_OFFSET 0x00000064 -#define NV50_NVSW_SEMAPHORE_ACQUIRE 0x00000068 -#define NV50_NVSW_SEMAPHORE_RELEASE 0x0000006c -#define NV50_NVSW_DMA_VBLSEM 0x0000018c -#define NV50_NVSW_VBLSEM_OFFSET 0x00000400 -#define NV50_NVSW_VBLSEM_RELEASE_VALUE 0x00000404 -#define NV50_NVSW_VBLSEM_RELEASE 0x00000408 +#define NV_SW 0x0000506e +#define NV_SW_DMA_SEMAPHORE 0x00000060 +#define NV_SW_SEMAPHORE_OFFSET 0x00000064 +#define NV_SW_SEMAPHORE_ACQUIRE 0x00000068 +#define NV_SW_SEMAPHORE_RELEASE 0x0000006c +#define NV_SW_DMA_VBLSEM 0x0000018c +#define NV_SW_VBLSEM_OFFSET 0x00000400 +#define NV_SW_VBLSEM_RELEASE_VALUE 0x00000404 +#define NV_SW_VBLSEM_RELEASE 0x00000408 #endif /* __NOUVEAU_DRV_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 93379bb81be..6c2cf81716d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -881,7 +881,7 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, return 0; } -static int +int nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, struct nouveau_gpuobj **gpuobj_ret) { diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 09a31071ee5..d2d7f0838dc 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -184,6 +184,7 @@ nv04_fbcon_accel_init(struct fb_info *info) struct drm_device *dev = par->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; + const int sub = NvSubCtxSurf2D; int surface_fmt, pattern_fmt, rect_fmt; int ret; @@ -247,25 +248,25 @@ nv04_fbcon_accel_init(struct fb_info *info) return 0; } - BEGIN_RING(chan, 1, 0x0000, 1); + BEGIN_RING(chan, sub, 0x0000, 1); OUT_RING(chan, NvCtxSurf2D); - BEGIN_RING(chan, 1, 0x0184, 2); + BEGIN_RING(chan, sub, 0x0184, 2); OUT_RING(chan, NvDmaFB); OUT_RING(chan, NvDmaFB); - BEGIN_RING(chan, 1, 0x0300, 4); + BEGIN_RING(chan, sub, 0x0300, 4); OUT_RING(chan, surface_fmt); OUT_RING(chan, info->fix.line_length | (info->fix.line_length << 16)); OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base); OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base); - BEGIN_RING(chan, 1, 0x0000, 1); + BEGIN_RING(chan, sub, 0x0000, 1); OUT_RING(chan, NvRop); - BEGIN_RING(chan, 1, 0x0300, 1); + BEGIN_RING(chan, sub, 0x0300, 1); OUT_RING(chan, 0x55); - BEGIN_RING(chan, 1, 0x0000, 1); + BEGIN_RING(chan, sub, 0x0000, 1); OUT_RING(chan, NvImagePatt); - BEGIN_RING(chan, 1, 0x0300, 8); + BEGIN_RING(chan, sub, 0x0300, 8); OUT_RING(chan, pattern_fmt); #ifdef __BIG_ENDIAN OUT_RING(chan, 2); @@ -279,9 +280,9 @@ nv04_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, ~0); OUT_RING(chan, ~0); - BEGIN_RING(chan, 1, 0x0000, 1); + BEGIN_RING(chan, sub, 0x0000, 1); OUT_RING(chan, NvClipRect); - BEGIN_RING(chan, 1, 0x0300, 2); + BEGIN_RING(chan, sub, 0x0300, 2); OUT_RING(chan, 0); OUT_RING(chan, (info->var.yres_virtual << 16) | info->var.xres_virtual); -- cgit v1.2.3 From 8c032ce73ef3a9e5a14c35ea3de19f1b9a8d7c0d Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 26 Dec 2009 02:09:36 +0100 Subject: drm/nouveau: Use the software object for fencing. This should avoid a race condition on nv0x, if we're doing it with actual PGRAPH objects and a there's a fence within the FIFO DMA fetch area when a context switch kicks in. In that case we get an ILLEGAL_MTHD interrupt as expected, but the values in PGRAPH_TRAPPED_ADDR aren't calculated correctly and they're almost useless (e.g. you can see ILLEGAL_MTHDs for the now inactive channel, with a wrong offset/data pair). Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_fence.c | 2 +- drivers/gpu/drm/nouveau/nv04_graph.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index dacac9a0842..faddf53ff9e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -142,7 +142,7 @@ nouveau_fence_emit(struct nouveau_fence *fence) list_add_tail(&fence->entry, &chan->fence.pending); spin_unlock_irqrestore(&chan->fence.lock, flags); - BEGIN_RING(chan, NvSubM2MF, USE_REFCNT ? 0x0050 : 0x0150, 1); + BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1); OUT_RING(chan, fence->sequence); FIRE_RING(chan); diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index d561d773c0f..82c77f9d469 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -547,7 +547,7 @@ nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass, return 0; } -static struct nouveau_pgraph_object_method nv04_graph_mthds_m2mf[] = { +static struct nouveau_pgraph_object_method nv04_graph_mthds_sw[] = { { 0x0150, nv04_graph_mthd_set_ref }, {} }; @@ -558,7 +558,7 @@ static struct nouveau_pgraph_object_method nv04_graph_mthds_set_operation[] = { }; struct nouveau_pgraph_object_class nv04_graph_grclass[] = { - { 0x0039, false, nv04_graph_mthds_m2mf }, + { 0x0039, false, NULL }, { 0x004a, false, nv04_graph_mthds_set_operation }, /* gdirect */ { 0x005f, false, nv04_graph_mthds_set_operation }, /* imageblit */ { 0x0061, false, nv04_graph_mthds_set_operation }, /* ifc */ @@ -574,6 +574,7 @@ struct nouveau_pgraph_object_class nv04_graph_grclass[] = { { 0x0053, false, NULL }, /* surf3d */ { 0x0054, false, NULL }, /* tex_tri */ { 0x0055, false, NULL }, /* multitex_tri */ + { 0x506e, true, nv04_graph_mthds_sw }, {} }; -- cgit v1.2.3 From be9721a951bd5ee6346dd2f3eed8a6fd1761c186 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 26 Dec 2009 14:39:46 +0100 Subject: drm/nv04: Context switching fixes. Signed-off-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nv04_graph.c | 152 ++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 74 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index 82c77f9d469..98f3b40318d 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -28,6 +28,10 @@ #include "nouveau_drv.h" static uint32_t nv04_graph_ctx_regs[] = { + 0x0040053c, + 0x00400544, + 0x00400540, + 0x00400548, NV04_PGRAPH_CTX_SWITCH1, NV04_PGRAPH_CTX_SWITCH2, NV04_PGRAPH_CTX_SWITCH3, @@ -102,69 +106,69 @@ static uint32_t nv04_graph_ctx_regs[] = { NV04_PGRAPH_PATT_COLOR0, NV04_PGRAPH_PATT_COLOR1, NV04_PGRAPH_PATT_COLORRAM+0x00, - NV04_PGRAPH_PATT_COLORRAM+0x01, - NV04_PGRAPH_PATT_COLORRAM+0x02, - NV04_PGRAPH_PATT_COLORRAM+0x03, NV04_PGRAPH_PATT_COLORRAM+0x04, - NV04_PGRAPH_PATT_COLORRAM+0x05, - NV04_PGRAPH_PATT_COLORRAM+0x06, - NV04_PGRAPH_PATT_COLORRAM+0x07, NV04_PGRAPH_PATT_COLORRAM+0x08, - NV04_PGRAPH_PATT_COLORRAM+0x09, - NV04_PGRAPH_PATT_COLORRAM+0x0A, - NV04_PGRAPH_PATT_COLORRAM+0x0B, - NV04_PGRAPH_PATT_COLORRAM+0x0C, - NV04_PGRAPH_PATT_COLORRAM+0x0D, - NV04_PGRAPH_PATT_COLORRAM+0x0E, - NV04_PGRAPH_PATT_COLORRAM+0x0F, + NV04_PGRAPH_PATT_COLORRAM+0x0c, NV04_PGRAPH_PATT_COLORRAM+0x10, - NV04_PGRAPH_PATT_COLORRAM+0x11, - NV04_PGRAPH_PATT_COLORRAM+0x12, - NV04_PGRAPH_PATT_COLORRAM+0x13, NV04_PGRAPH_PATT_COLORRAM+0x14, - NV04_PGRAPH_PATT_COLORRAM+0x15, - NV04_PGRAPH_PATT_COLORRAM+0x16, - NV04_PGRAPH_PATT_COLORRAM+0x17, NV04_PGRAPH_PATT_COLORRAM+0x18, - NV04_PGRAPH_PATT_COLORRAM+0x19, - NV04_PGRAPH_PATT_COLORRAM+0x1A, - NV04_PGRAPH_PATT_COLORRAM+0x1B, - NV04_PGRAPH_PATT_COLORRAM+0x1C, - NV04_PGRAPH_PATT_COLORRAM+0x1D, - NV04_PGRAPH_PATT_COLORRAM+0x1E, - NV04_PGRAPH_PATT_COLORRAM+0x1F, + NV04_PGRAPH_PATT_COLORRAM+0x1c, NV04_PGRAPH_PATT_COLORRAM+0x20, - NV04_PGRAPH_PATT_COLORRAM+0x21, - NV04_PGRAPH_PATT_COLORRAM+0x22, - NV04_PGRAPH_PATT_COLORRAM+0x23, NV04_PGRAPH_PATT_COLORRAM+0x24, - NV04_PGRAPH_PATT_COLORRAM+0x25, - NV04_PGRAPH_PATT_COLORRAM+0x26, - NV04_PGRAPH_PATT_COLORRAM+0x27, NV04_PGRAPH_PATT_COLORRAM+0x28, - NV04_PGRAPH_PATT_COLORRAM+0x29, - NV04_PGRAPH_PATT_COLORRAM+0x2A, - NV04_PGRAPH_PATT_COLORRAM+0x2B, - NV04_PGRAPH_PATT_COLORRAM+0x2C, - NV04_PGRAPH_PATT_COLORRAM+0x2D, - NV04_PGRAPH_PATT_COLORRAM+0x2E, - NV04_PGRAPH_PATT_COLORRAM+0x2F, + NV04_PGRAPH_PATT_COLORRAM+0x2c, NV04_PGRAPH_PATT_COLORRAM+0x30, - NV04_PGRAPH_PATT_COLORRAM+0x31, - NV04_PGRAPH_PATT_COLORRAM+0x32, - NV04_PGRAPH_PATT_COLORRAM+0x33, NV04_PGRAPH_PATT_COLORRAM+0x34, - NV04_PGRAPH_PATT_COLORRAM+0x35, - NV04_PGRAPH_PATT_COLORRAM+0x36, - NV04_PGRAPH_PATT_COLORRAM+0x37, NV04_PGRAPH_PATT_COLORRAM+0x38, - NV04_PGRAPH_PATT_COLORRAM+0x39, - NV04_PGRAPH_PATT_COLORRAM+0x3A, - NV04_PGRAPH_PATT_COLORRAM+0x3B, - NV04_PGRAPH_PATT_COLORRAM+0x3C, - NV04_PGRAPH_PATT_COLORRAM+0x3D, - NV04_PGRAPH_PATT_COLORRAM+0x3E, - NV04_PGRAPH_PATT_COLORRAM+0x3F, + NV04_PGRAPH_PATT_COLORRAM+0x3c, + NV04_PGRAPH_PATT_COLORRAM+0x40, + NV04_PGRAPH_PATT_COLORRAM+0x44, + NV04_PGRAPH_PATT_COLORRAM+0x48, + NV04_PGRAPH_PATT_COLORRAM+0x4c, + NV04_PGRAPH_PATT_COLORRAM+0x50, + NV04_PGRAPH_PATT_COLORRAM+0x54, + NV04_PGRAPH_PATT_COLORRAM+0x58, + NV04_PGRAPH_PATT_COLORRAM+0x5c, + NV04_PGRAPH_PATT_COLORRAM+0x60, + NV04_PGRAPH_PATT_COLORRAM+0x64, + NV04_PGRAPH_PATT_COLORRAM+0x68, + NV04_PGRAPH_PATT_COLORRAM+0x6c, + NV04_PGRAPH_PATT_COLORRAM+0x70, + NV04_PGRAPH_PATT_COLORRAM+0x74, + NV04_PGRAPH_PATT_COLORRAM+0x78, + NV04_PGRAPH_PATT_COLORRAM+0x7c, + NV04_PGRAPH_PATT_COLORRAM+0x80, + NV04_PGRAPH_PATT_COLORRAM+0x84, + NV04_PGRAPH_PATT_COLORRAM+0x88, + NV04_PGRAPH_PATT_COLORRAM+0x8c, + NV04_PGRAPH_PATT_COLORRAM+0x90, + NV04_PGRAPH_PATT_COLORRAM+0x94, + NV04_PGRAPH_PATT_COLORRAM+0x98, + NV04_PGRAPH_PATT_COLORRAM+0x9c, + NV04_PGRAPH_PATT_COLORRAM+0xa0, + NV04_PGRAPH_PATT_COLORRAM+0xa4, + NV04_PGRAPH_PATT_COLORRAM+0xa8, + NV04_PGRAPH_PATT_COLORRAM+0xac, + NV04_PGRAPH_PATT_COLORRAM+0xb0, + NV04_PGRAPH_PATT_COLORRAM+0xb4, + NV04_PGRAPH_PATT_COLORRAM+0xb8, + NV04_PGRAPH_PATT_COLORRAM+0xbc, + NV04_PGRAPH_PATT_COLORRAM+0xc0, + NV04_PGRAPH_PATT_COLORRAM+0xc4, + NV04_PGRAPH_PATT_COLORRAM+0xc8, + NV04_PGRAPH_PATT_COLORRAM+0xcc, + NV04_PGRAPH_PATT_COLORRAM+0xd0, + NV04_PGRAPH_PATT_COLORRAM+0xd4, + NV04_PGRAPH_PATT_COLORRAM+0xd8, + NV04_PGRAPH_PATT_COLORRAM+0xdc, + NV04_PGRAPH_PATT_COLORRAM+0xe0, + NV04_PGRAPH_PATT_COLORRAM+0xe4, + NV04_PGRAPH_PATT_COLORRAM+0xe8, + NV04_PGRAPH_PATT_COLORRAM+0xec, + NV04_PGRAPH_PATT_COLORRAM+0xf0, + NV04_PGRAPH_PATT_COLORRAM+0xf4, + NV04_PGRAPH_PATT_COLORRAM+0xf8, + NV04_PGRAPH_PATT_COLORRAM+0xfc, NV04_PGRAPH_PATTERN, 0x0040080c, NV04_PGRAPH_PATTERN_SHAPE, @@ -247,14 +251,6 @@ static uint32_t nv04_graph_ctx_regs[] = { 0x004004f8, 0x0040047c, 0x004004fc, - 0x0040053c, - 0x00400544, - 0x00400540, - 0x00400548, - 0x00400560, - 0x00400568, - 0x00400564, - 0x0040056c, 0x00400534, 0x00400538, 0x00400514, @@ -341,9 +337,8 @@ static uint32_t nv04_graph_ctx_regs[] = { 0x00400500, 0x00400504, NV04_PGRAPH_VALID1, - NV04_PGRAPH_VALID2 - - + NV04_PGRAPH_VALID2, + NV04_PGRAPH_DEBUG_3 }; struct graph_state { @@ -388,6 +383,18 @@ nv04_graph_context_switch(struct drm_device *dev) pgraph->fifo_access(dev, true); } +static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) { + if (nv04_graph_ctx_regs[i] == reg) + return &ctx->nv04[i]; + } + + return NULL; +} + int nv04_graph_create_context(struct nouveau_channel *chan) { struct graph_state *pgraph_ctx; @@ -398,15 +405,8 @@ int nv04_graph_create_context(struct nouveau_channel *chan) if (pgraph_ctx == NULL) return -ENOMEM; - /* dev_priv->fifos[channel].pgraph_ctx_user = channel << 24; */ - pgraph_ctx->nv04[0] = 0x0001ffff; - /* is it really needed ??? */ -#if 0 - dev_priv->fifos[channel].pgraph_ctx[1] = - nv_rd32(dev, NV_PGRAPH_DEBUG_4); - dev_priv->fifos[channel].pgraph_ctx[2] = - nv_rd32(dev, 0x004006b0); -#endif + *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; + return 0; } @@ -429,9 +429,13 @@ int nv04_graph_load_context(struct nouveau_channel *chan) nv_wr32(dev, nv04_graph_ctx_regs[i], pgraph_ctx->nv04[i]); nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL, 0x10010100); - nv_wr32(dev, NV04_PGRAPH_CTX_USER, chan->id << 24); + + tmp = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff; + nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp | chan->id << 24); + tmp = nv_rd32(dev, NV04_PGRAPH_FFINTFC_ST2); nv_wr32(dev, NV04_PGRAPH_FFINTFC_ST2, tmp & 0x000fffff); + return 0; } @@ -494,7 +498,7 @@ int nv04_graph_init(struct drm_device *dev) nv_wr32(dev, NV04_PGRAPH_STATE , 0xFFFFFFFF); nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL , 0x10000100); tmp = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff; - tmp |= dev_priv->engine.fifo.channels << 24; + tmp |= (dev_priv->engine.fifo.channels - 1) << 24; nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp); /* These don't belong here, they're part of a per-channel context */ -- cgit v1.2.3 From bf5302b9496b25fe80ffa8a4fd191ad95c217864 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 4 Jan 2010 09:10:55 +1000 Subject: drm/nouveau: fix handling of fbcon colours in 8bpp Depending on the visual, the colours handed to us in fillrect() can either be an actual colour, or an index into the pseudo-palette. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_fbcon.c | 7 +++++-- drivers/gpu/drm/nouveau/nv50_fbcon.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index d2d7f0838dc..bd08a0dc984 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -62,7 +62,6 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) struct drm_device *dev = par->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; - uint32_t color = ((uint32_t *) info->pseudo_palette)[rect->color]; if (info->state != FBINFO_STATE_RUNNING) return; @@ -80,7 +79,11 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1); OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3); BEGIN_RING(chan, NvSubGdiRect, 0x03fc, 1); - OUT_RING(chan, color); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]); + else + OUT_RING(chan, rect->color); BEGIN_RING(chan, NvSubGdiRect, 0x0400, 2); OUT_RING(chan, (rect->dx << 16) | rect->dy); OUT_RING(chan, (rect->width << 16) | rect->height); diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index c966ef83485..cc34356ab0b 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -10,7 +10,6 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) struct drm_device *dev = par->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; - uint32_t color = ((uint32_t *) info->pseudo_palette)[rect->color]; if (info->state != FBINFO_STATE_RUNNING) return; @@ -32,7 +31,11 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) OUT_RING(chan, 1); } BEGIN_RING(chan, NvSub2D, 0x0588, 1); - OUT_RING(chan, color); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]); + else + OUT_RING(chan, rect->color); BEGIN_RING(chan, NvSub2D, 0x0600, 4); OUT_RING(chan, rect->dx); OUT_RING(chan, rect->dy); -- cgit v1.2.3 From 61768bf1e694056cb41029b60e1270bf2578a83f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 4 Jan 2010 12:53:01 +1000 Subject: drm/nouveau: remove unused nouveau_channel_idle() function Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 41 ------------------------------- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 - 2 files changed, 42 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 4f378b68fe7..d1c7f8c911c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -235,47 +235,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, return 0; } -int -nouveau_channel_idle(struct nouveau_channel *chan) -{ - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->engine; - uint32_t caches; - int idle; - - if (!chan) { - NV_ERROR(dev, "no channel...\n"); - return 1; - } - - caches = nv_rd32(dev, NV03_PFIFO_CACHES); - nv_wr32(dev, NV03_PFIFO_CACHES, caches & ~1); - - if (engine->fifo.channel_id(dev) != chan->id) { - struct nouveau_gpuobj *ramfc = - chan->ramfc ? chan->ramfc->gpuobj : NULL; - - if (!ramfc) { - NV_ERROR(dev, "No RAMFC for channel %d\n", chan->id); - return 1; - } - - engine->instmem.prepare_access(dev, false); - if (nv_ro32(dev, ramfc, 0) != nv_ro32(dev, ramfc, 1)) - idle = 0; - else - idle = 1; - engine->instmem.finish_access(dev); - } else { - idle = (nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET) == - nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); - } - - nv_wr32(dev, NV03_PFIFO_CACHES, caches); - return idle; -} - /* stops a fifo */ void nouveau_channel_free(struct nouveau_channel *chan) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 9181eaefe91..4087a9a20ba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -745,7 +745,6 @@ extern int nouveau_channel_alloc(struct drm_device *dev, struct drm_file *file_priv, uint32_t fb_ctxdma, uint32_t tt_ctxdma); extern void nouveau_channel_free(struct nouveau_channel *); -extern int nouveau_channel_idle(struct nouveau_channel *chan); /* nouveau_object.c */ extern int nouveau_gpuobj_early_init(struct drm_device *); -- cgit v1.2.3 From 846975a97b098bbbf1232a01a3a5723a4bddd9e7 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Mon, 4 Jan 2010 19:25:09 +0100 Subject: drm/nouveau: create function for "dealing" with gpu lockup It's mostly a cleanup, but in nv50_fbcon_accel_init gpu lockup message was printed, but HWACCEL_DISBALED flag was not set. Signed-off-by: Marcin Slusarz Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 15 +++++++++++---- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 1 + drivers/gpu/drm/nouveau/nv04_fbcon.c | 15 +++++---------- drivers/gpu/drm/nouveau/nv50_fbcon.c | 17 +++++------------ 4 files changed, 22 insertions(+), 26 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 44cbbeeb774..0b05c869e0e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -64,8 +64,7 @@ nouveau_fbcon_sync(struct fb_info *info) return 0; if (RING_SPACE(chan, 4)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); return 0; } @@ -86,8 +85,7 @@ nouveau_fbcon_sync(struct fb_info *info) } if (ret) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); return 0; } @@ -380,3 +378,12 @@ nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb) return 0; } + +void nouveau_fbcon_gpu_lockup(struct fb_info *info) +{ + struct nouveau_fbcon_par *par = info->par; + struct drm_device *dev = par->dev; + + NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); + info->flags |= FBINFO_HWACCEL_DISABLED; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 8531140fedb..462e0b87b4b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -43,5 +43,6 @@ void nouveau_fbcon_zfill(struct drm_device *dev); int nv04_fbcon_accel_init(struct fb_info *info); int nv50_fbcon_accel_init(struct fb_info *info); +void nouveau_fbcon_gpu_lockup(struct fb_info *info); #endif /* __NV50_FBCON_H__ */ diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index bd08a0dc984..d910873c136 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -39,8 +39,7 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) return; if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 4)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -67,8 +66,7 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) return; if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 7)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -112,8 +110,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) } if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 8)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -147,8 +144,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) int iter_len = dsize > 128 ? 128 : dsize; if (RING_SPACE(chan, iter_len + 1)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); cfb_imageblit(info, image); return; } @@ -246,8 +242,7 @@ nv04_fbcon_accel_init(struct fb_info *info) return ret; if (RING_SPACE(chan, 49)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index cc34356ab0b..e4f279ee61c 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -16,9 +16,7 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -60,9 +58,7 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) return; if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 12)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -105,8 +101,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) } if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 11)) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); } if (info->flags & FBINFO_HWACCEL_DISABLED) { @@ -139,9 +134,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) int push = dwords > 2047 ? 2047 : dwords; if (RING_SPACE(chan, push + 1)) { - NV_ERROR(dev, - "GPU lockup - switching to software fbcon\n"); - info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_gpu_lockup(info); cfb_imageblit(info, image); return; } @@ -203,7 +196,7 @@ nv50_fbcon_accel_init(struct fb_info *info) ret = RING_SPACE(chan, 59); if (ret) { - NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); + nouveau_fbcon_gpu_lockup(info); return ret; } -- cgit v1.2.3 From 7fb8ec8e2bedc8381243cf4bdc4cfa8e657397a8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 5 Jan 2010 09:41:05 +1000 Subject: drm/nv50: restore correct cache1 get/put address on fifoctx load Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_fifo.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index b7282284f08..39caf167587 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -384,8 +384,8 @@ nv50_fifo_load_context(struct nouveau_channel *chan) nv_wr32(dev, NV40_PFIFO_CACHE1_DATA(ptr), nv_ro32(dev, cache, (ptr * 2) + 1)); } - nv_wr32(dev, 0x3210, cnt << 2); - nv_wr32(dev, 0x3270, 0); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, cnt << 2); + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); /* guessing that all the 0x34xx regs aren't on NV50 */ if (!IS_G80) { @@ -398,8 +398,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan) dev_priv->engine.instmem.finish_access(dev); - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16)); return 0; } -- cgit v1.2.3 From bbb8c3d8820893694a3567716adb3b6f6ba2b7d0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 4 Jan 2010 15:52:20 +1000 Subject: drm/nouveau: have ttm's fault handler called directly There's no good reason for us to have our own anymore, this is left over from an early port to these TTM interfaces. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_ttm.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 187eb84e4da..c385d50f041 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -28,45 +28,17 @@ #include "nouveau_drv.h" -static struct vm_operations_struct nouveau_ttm_vm_ops; -static const struct vm_operations_struct *ttm_vm_ops; - -static int -nouveau_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct ttm_buffer_object *bo = vma->vm_private_data; - int ret; - - if (unlikely(bo == NULL)) - return VM_FAULT_NOPAGE; - - ret = ttm_vm_ops->fault(vma, vmf); - return ret; -} - int nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *file_priv = filp->private_data; struct drm_nouveau_private *dev_priv = file_priv->minor->dev->dev_private; - int ret; if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) return drm_mmap(filp, vma); - ret = ttm_bo_mmap(filp, vma, &dev_priv->ttm.bdev); - if (unlikely(ret != 0)) - return ret; - - if (unlikely(ttm_vm_ops == NULL)) { - ttm_vm_ops = vma->vm_ops; - nouveau_ttm_vm_ops = *ttm_vm_ops; - nouveau_ttm_vm_ops.fault = &nouveau_ttm_fault; - } - - vma->vm_ops = &nouveau_ttm_vm_ops; - return 0; + return ttm_bo_mmap(filp, vma, &dev_priv->ttm.bdev); } static int -- cgit v1.2.3 From 7978b9cfa59133a34aaad420e447c2a29d5c6152 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 6 Jan 2010 12:00:02 +1000 Subject: drm/nv50: prevent a possible ctxprog hang The below is mainly an educated guess at what's going on, docs would sure be handy... NVIDIA? :P It appears it's possible for a ctxprog to run even while a GPU exception is pending. The GF8 and up ctxprogs appear to have a small snippet of code which detects this, and stalls the ctxprog until it's been handled, which essentially looks like: if (r2 & 0x00008000) { r0 |= 0x80000000; while (r0 & 0x80000000) {} } I don't know of any way that flag would get cleared unless the driver intervenes (and indeed, in the cases I've seen the hang, nothing steps in to automagically clear it for us). This patch causes the driver to clear the flag during the PGRAPH IRQ handler. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 370c72c968d..919a619ca7f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -635,6 +635,7 @@ nv50_pgraph_irq_handler(struct drm_device *dev) if ((nv_rd32(dev, 0x400500) & isb) != isb) nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | isb); + nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); } nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); -- cgit v1.2.3 From 234896a7671c23233230622728f6942b3d1c098e Mon Sep 17 00:00:00 2001 From: Luca Barbieri Date: Wed, 6 Jan 2010 04:02:45 +0100 Subject: drm/nouveau: Fix null deref in nouveau_fence_emit due to deleted fence Currently Nouveau will unvalidate all buffers if it is forced to wait on one, and then start revalidating from the beginning. While doing so, it destroys the operation fence, causing nouveau_fence_emit to crash. This patch fixes this bug by taking the fence object out of validate_op and creating it just before emit. The fence pointer is initialized to 0 and unref'ed unconditionally. In addition to fixing the bug, this prevents its reintroduction and simplifies the code. Signed-off-by: Luca Barbieri Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 18fd8ac9fca..2009db2426c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -220,7 +220,6 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains, } struct validate_op { - struct nouveau_fence *fence; struct list_head vram_list; struct list_head gart_list; struct list_head both_list; @@ -252,17 +251,11 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence) } static void -validate_fini(struct validate_op *op, bool success) +validate_fini(struct validate_op *op, struct nouveau_fence* fence) { - struct nouveau_fence *fence = op->fence; - - if (unlikely(!success)) - op->fence = NULL; - - validate_fini_list(&op->vram_list, op->fence); - validate_fini_list(&op->gart_list, op->fence); - validate_fini_list(&op->both_list, op->fence); - nouveau_fence_unref((void *)&fence); + validate_fini_list(&op->vram_list, fence); + validate_fini_list(&op->gart_list, fence); + validate_fini_list(&op->both_list, fence); } static int @@ -420,10 +413,6 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, INIT_LIST_HEAD(&op->gart_list); INIT_LIST_HEAD(&op->both_list); - ret = nouveau_fence_new(chan, &op->fence, false); - if (ret) - return ret; - if (nr_buffers == 0) return 0; @@ -541,6 +530,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, struct drm_nouveau_gem_pushbuf_bo *bo = NULL; struct nouveau_channel *chan; struct validate_op op; + struct nouveau_fence* fence = 0; uint32_t *pushbuf = NULL; int ret = 0, do_reloc = 0, i; @@ -597,7 +587,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, OUT_RINGp(chan, pushbuf, req->nr_dwords); - ret = nouveau_fence_emit(op.fence); + ret = nouveau_fence_new(chan, &fence, true); if (ret) { NV_ERROR(dev, "error fencing pushbuf: %d\n", ret); WIND_RING(chan); @@ -605,7 +595,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, } if (nouveau_gem_pushbuf_sync(chan)) { - ret = nouveau_fence_wait(op.fence, NULL, false, false); + ret = nouveau_fence_wait(fence, NULL, false, false); if (ret) { for (i = 0; i < req->nr_dwords; i++) NV_ERROR(dev, "0x%08x\n", pushbuf[i]); @@ -614,7 +604,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, } out: - validate_fini(&op, ret == 0); + validate_fini(&op, fence); + nouveau_fence_unref((void**)&fence); mutex_unlock(&dev->struct_mutex); kfree(pushbuf); kfree(bo); @@ -634,6 +625,7 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data, struct drm_gem_object *gem; struct nouveau_bo *pbbo; struct validate_op op; + struct nouveau_fence* fence = 0; int i, ret = 0, do_reloc = 0; NOUVEAU_CHECK_INITIALISED_WITH_RETURN; @@ -772,7 +764,7 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data, OUT_RING(chan, 0); } - ret = nouveau_fence_emit(op.fence); + ret = nouveau_fence_new(chan, &fence, true); if (ret) { NV_ERROR(dev, "error fencing pushbuf: %d\n", ret); WIND_RING(chan); @@ -780,7 +772,8 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data, } out: - validate_fini(&op, ret == 0); + validate_fini(&op, fence); + nouveau_fence_unref((void**)&fence); mutex_unlock(&dev->struct_mutex); kfree(bo); -- cgit v1.2.3 From 1dee7a930bfddd69825fca3e3f9541c8a5333876 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 7 Jan 2010 13:47:57 +1000 Subject: drm/nv04: differentiate between nv04/nv05 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index a6b573e8982..09b9a46dfc0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -642,7 +642,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->chipset = (reg0 & 0xff00000) >> 20; /* NV04 or NV05 */ } else if ((reg0 & 0xff00fff0) == 0x20004000) { - dev_priv->chipset = 0x04; + if (reg0 & 0x00f00000) + dev_priv->chipset = 0x05; + else + dev_priv->chipset = 0x04; } else dev_priv->chipset = 0xff; -- cgit v1.2.3 From dff36321497b1130085820c81a44779b065c8d7e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 8 Jan 2010 10:53:40 +1000 Subject: drm/nouveau: use dma.max rather than pushbuf size for checking GET validity Some upcoming G80 DMA changes will depend on this, but it's split out for bisectibility just in case it causes some unexpected issues. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index f1fd3f2b981..3f7f78e03d4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -130,7 +130,7 @@ READ_GET(struct nouveau_channel *chan, uint32_t *get) val = nvchan_rd32(chan, chan->user_get); if (val < chan->pushbuf_base || - val >= chan->pushbuf_base + chan->pushbuf_bo->bo.mem.size) { + val > chan->pushbuf_base + (chan->dma.max << 2)) { /* meaningless to dma_wait() except to know whether the * GPU has stalled or not */ -- cgit v1.2.3 From 75c99da6cdd0ec9d70747f9ced3e85b2dd955cdf Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 8 Jan 2010 10:57:39 +1000 Subject: drm/nouveau: initialise DMA tracking parameters earlier Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 2 ++ drivers/gpu/drm/nouveau/nouveau_dma.c | 15 +++++++++------ drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index d1c7f8c911c..343d718a966 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -158,6 +158,8 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, return ret; } + nouveau_dma_pre_init(chan); + /* Locate channel's user control regs */ if (dev_priv->card_type < NV_40) user = NV03_USER(channel); diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 3f7f78e03d4..7afbe8b40d5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -29,6 +29,15 @@ #include "nouveau_drv.h" #include "nouveau_dma.h" +void +nouveau_dma_pre_init(struct nouveau_channel *chan) +{ + chan->dma.max = (chan->pushbuf_bo->bo.mem.size >> 2) - 2; + chan->dma.put = 0; + chan->dma.cur = chan->dma.put; + chan->dma.free = chan->dma.max - chan->dma.cur; +} + int nouveau_dma_init(struct nouveau_channel *chan) { @@ -74,12 +83,6 @@ nouveau_dma_init(struct nouveau_channel *chan) return ret; } - /* Initialise DMA vars */ - chan->dma.max = (chan->pushbuf_bo->bo.mem.size >> 2) - 2; - chan->dma.put = 0; - chan->dma.cur = chan->dma.put; - chan->dma.free = chan->dma.max - chan->dma.cur; - /* Insert NOPS for NOUVEAU_DMA_SKIPS */ ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); if (ret) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 4087a9a20ba..026419fe879 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -837,6 +837,7 @@ nouveau_debugfs_channel_fini(struct nouveau_channel *chan) #endif /* nouveau_dma.c */ +extern void nouveau_dma_pre_init(struct nouveau_channel *); extern int nouveau_dma_init(struct nouveau_channel *); extern int nouveau_dma_wait(struct nouveau_channel *, int size); -- cgit v1.2.3 From fe5a64acbfab4f79ccd18972c3d4c1cae31f3b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Sun, 10 Jan 2010 17:09:14 +0000 Subject: drm/nv04: Fix set_operation software method. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_graph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index 98f3b40318d..e260986ea65 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -537,7 +537,7 @@ nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass, int mthd, uint32_t data) { struct drm_device *dev = chan->dev; - uint32_t instance = nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff; + uint32_t instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; int subc = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; uint32_t tmp; -- cgit v1.2.3 From 7a15cbd40108a670baae71cbd3cec62b65891fa6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Jan 2010 11:42:17 +1000 Subject: drm/radeon/kms: fix displayport->dvi connector DDC. It appears that attempting AUXCH DDC breaks the subsequent attempt to do DDC over the i2c lines, so use the sink type to determine if we should be doing AUXCH or i2c DDC. This fixes my DVI monitor plugged into DP->DVI convertor. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 0ec491ead2f..47ceae9cdc4 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -357,7 +357,8 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - if (dig->dp_i2c_bus) + if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || + dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter); } if (!radeon_connector->ddc_bus) -- cgit v1.2.3 From 6398d42454ce1671b3422c34fd0f600c9c76c8b1 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 13 Jan 2010 12:32:36 +0100 Subject: drm/radeon/kms: Do not unpin buffer in fb destruction It's not necessary to unpin buffer in fb destruction. pin/unpin need to be balanced and we don't pin in fb creation. We pin when an fb is associated to a crtc and unpin when the fb is disassociated from the crtc. Note: Maybe we should take reference on fb in set_base callback so fb doesn't disappear until it's unbind from ctrc. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 47ceae9cdc4..49f3c69cf24 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -668,7 +668,6 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) radeonfb_remove(dev, fb); if (radeon_fb->obj) { - radeon_gem_object_unpin(radeon_fb->obj); mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(radeon_fb->obj); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 30d2d9a54d48e4fefede0389ded1b6fc2d44a522 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 13 Jan 2010 10:29:27 +0100 Subject: drm/radeon/kms: Fix r600 blit cleanup path r600 blit cleanup path need to check if a bo was allocated before trying to free or unpin it. This patch add this check and avoid oops when the initialization on r6xx or r7xx hw fails. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 12 +++++++----- drivers/gpu/drm/radeon/r600_blit_kms.c | 14 ++++++++------ drivers/gpu/drm/radeon/rv770.c | 10 ++++++---- 3 files changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 9757962146f..3e02dd403d7 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1961,11 +1961,13 @@ int r600_suspend(struct radeon_device *rdev) r600_wb_disable(rdev); r600_pcie_gart_disable(rdev); /* unpin shaders bo */ - r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (unlikely(r != 0)) - return r; - radeon_bo_unpin(rdev->r600_blit.shader_obj); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); + if (rdev->r600_blit.shader_obj) { + r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); + if (!r) { + radeon_bo_unpin(rdev->r600_blit.shader_obj); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); + } + } return 0; } diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index 8787ea89dc6..2bedce477a9 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -512,14 +512,16 @@ void r600_blit_fini(struct radeon_device *rdev) { int r; + if (rdev->r600_blit.shader_obj == NULL) + return; + /* If we can't reserve the bo, unref should be enough to destroy + * it when it becomes idle. + */ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (unlikely(r != 0)) { - dev_err(rdev->dev, "(%d) can't finish r600 blit\n", r); - goto out_unref; + if (!r) { + radeon_bo_unpin(rdev->r600_blit.shader_obj); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); } - radeon_bo_unpin(rdev->r600_blit.shader_obj); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); -out_unref: radeon_bo_unref(&rdev->r600_blit.shader_obj); } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 16f7317fa1a..7f17ddf1f45 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -975,10 +975,12 @@ int rv770_suspend(struct radeon_device *rdev) r600_wb_disable(rdev); rv770_pcie_gart_disable(rdev); /* unpin shaders bo */ - r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (likely(r == 0)) { - radeon_bo_unpin(rdev->r600_blit.shader_obj); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); + if (rdev->r600_blit.shader_obj) { + r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); + if (likely(r == 0)) { + radeon_bo_unpin(rdev->r600_blit.shader_obj); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); + } } return 0; } -- cgit v1.2.3 From 0a3f316370da07fcdb11fde4f5a683d60713b7fd Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 13 Jan 2010 15:16:39 +0100 Subject: drm/radeon/kms: Disable AGP is aperture size < 32M radeon KMS need a GART of at least 32M to properly work. This patch check the AGP aperture size and disable if it's less than 32M. Note than unlike non KMS path we don't staticaly allocate AGP memory so we are not wasting memory not used by graphic processing. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_agp.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index 220f454ea9f..c9ad7f5cc1a 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -133,6 +133,13 @@ int radeon_agp_init(struct radeon_device *rdev) bool is_v3; int ret; + if (rdev->ddev->agp->agp_info.aper_size < 32) { + dev_warn(rdev->dev, "AGP aperture to small (%dM) " + "need at least 32M, disabling AGP\n", + rdev->ddev->agp->agp_info.aper_size); + return -EINVAL; + } + /* Acquire AGP. */ if (!rdev->ddev->agp->acquired) { ret = drm_agp_acquire(rdev->ddev); -- cgit v1.2.3 From 700a0cc088a42a2ed92c6f961534fdb38588af87 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 13 Jan 2010 15:16:38 +0100 Subject: drm/radeon/kms: Use radeon_agp_disable when disabling AGP Use same common function to disable agp so we replace the GART callback by the proper one when we do so. This fix oops if radeon_agp_init report failure. This patch also move radeon_agp_init out of *_mc_init for r600 & rv770 so that we can have a similar behavior than for previous hw, ie if agp_init fails it will fallback to GPU GART and disable AGP. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 4 +--- drivers/gpu/drm/radeon/r420.c | 4 +--- drivers/gpu/drm/radeon/r600.c | 9 +++++---- drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_device.c | 1 + drivers/gpu/drm/radeon/rv770.c | 9 +++++---- 6 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 8760d66e058..62b27bede65 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3399,9 +3399,7 @@ int r100_mc_init(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); if (r) { - printk(KERN_WARNING "[drm] Disabling AGP\n"); - rdev->flags &= ~RADEON_IS_AGP; - rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + radeon_agp_disable(rdev); } else { rdev->mc.gtt_location = rdev->mc.agp_base; } diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 053404e71a9..4526faaacca 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -50,9 +50,7 @@ int r420_mc_init(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); if (r) { - printk(KERN_WARNING "[drm] Disabling AGP\n"); - rdev->flags &= ~RADEON_IS_AGP; - rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + radeon_agp_disable(rdev); } else { rdev->mc.gtt_location = rdev->mc.agp_base; } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 3e02dd403d7..b3713f61964 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -624,7 +624,6 @@ int r600_mc_init(struct radeon_device *rdev) fixed20_12 a; u32 tmp; int chansize, numchan; - int r; /* Get VRAM informations */ rdev->mc.vram_is_ddr = true; @@ -667,9 +666,6 @@ int r600_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = rdev->mc.aper_size; if (rdev->flags & RADEON_IS_AGP) { - r = radeon_agp_init(rdev); - if (r) - return r; /* gtt_size is setup by radeon_agp_init */ rdev->mc.gtt_location = rdev->mc.agp_base; tmp = 0xFFFFFFFFUL - rdev->mc.agp_base - rdev->mc.gtt_size; @@ -2028,6 +2024,11 @@ int r600_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) + radeon_agp_disable(rdev); + } r = r600_mc_init(rdev); if (r) return r; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index eb5f99b9469..ab37dd0f2e7 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1017,6 +1017,8 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) /* Common functions */ +/* AGP */ +extern void radeon_agp_disable(struct radeon_device *rdev); extern int radeon_gart_table_vram_pin(struct radeon_device *rdev); extern int radeon_modeset_init(struct radeon_device *rdev); extern void radeon_modeset_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 0c51f8e4661..768b1509fa0 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -544,6 +544,7 @@ void radeon_agp_disable(struct radeon_device *rdev) rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush; rdev->asic->gart_set_page = &r100_pci_gart_set_page; } + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; } void radeon_check_arguments(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 7f17ddf1f45..eb065bbe1ee 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -779,7 +779,6 @@ int rv770_mc_init(struct radeon_device *rdev) fixed20_12 a; u32 tmp; int chansize, numchan; - int r; /* Get VRAM informations */ rdev->mc.vram_is_ddr = true; @@ -822,9 +821,6 @@ int rv770_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = rdev->mc.aper_size; if (rdev->flags & RADEON_IS_AGP) { - r = radeon_agp_init(rdev); - if (r) - return r; /* gtt_size is setup by radeon_agp_init */ rdev->mc.gtt_location = rdev->mc.agp_base; tmp = 0xFFFFFFFFUL - rdev->mc.agp_base - rdev->mc.gtt_size; @@ -1039,6 +1035,11 @@ int rv770_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) + radeon_agp_disable(rdev); + } r = rv770_mc_init(rdev); if (r) return r; -- cgit v1.2.3 From df1c93bae2b671e2aa50899a120af20afdbd504b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 13 Jan 2010 22:28:36 +0100 Subject: drm/vmwgfx: Don't promote updates from GMR-backed scanouts to fullscreen. That's unnecessary since partial screen updates from GMRs are fast. Also fix cliprect pointer dereferencing Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b1af76e371c..686692de209 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -553,9 +553,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, } *cmd; int i, increment = 1; - if (!num_clips || - !(dev_priv->fifo.capabilities & - SVGA_FIFO_CAP_SCREEN_OBJECT)) { + if (!num_clips) { num_clips = 1; clips = &norect; norect.x1 = norect.y1 = 0; @@ -574,10 +572,10 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, for (i = 0; i < num_clips; i++, clips += increment) { cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE); - cmd[i].body.x = cpu_to_le32(clips[i].x1); - cmd[i].body.y = cpu_to_le32(clips[i].y1); - cmd[i].body.width = cpu_to_le32(clips[i].x2 - clips[i].x1); - cmd[i].body.height = cpu_to_le32(clips[i].y2 - clips[i].y1); + cmd[i].body.x = cpu_to_le32(clips->x1); + cmd[i].body.y = cpu_to_le32(clips->y1); + cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1); + cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1); } vmw_fifo_commit(dev_priv, sizeof(*cmd) * num_clips); -- cgit v1.2.3 From 50ec3b7c35fda131e92abc6f9d93a230b7e009eb Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 13 Jan 2010 22:28:37 +0100 Subject: drm/vmwgfx: Fix an error path causing an oops. An error happening before the snooper.image member had been set up would cause a kfree of an arbitrary pointer. Set up the snooper.image member early. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 39 +++++++++++++++++--------------- 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index c012d5927f6..125c2f44f98 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -599,6 +599,27 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, if (unlikely(ret != 0)) goto out_err1; + + if (srf->flags & (1 << 9) && + srf->num_sizes == 1 && + srf->sizes[0].width == 64 && + srf->sizes[0].height == 64 && + srf->format == SVGA3D_A8R8G8B8) { + + srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL); + /* clear the image */ + if (srf->snooper.image) { + memset(srf->snooper.image, 0x00, 64 * 64 * 4); + } else { + DRM_ERROR("Failed to allocate cursor_image\n"); + ret = -ENOMEM; + goto out_err1; + } + } else { + srf->snooper.image = NULL; + } + srf->snooper.crtc = NULL; + user_srf->base.shareable = false; user_srf->base.tfile = NULL; @@ -622,24 +643,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, return ret; } - if (srf->flags & (1 << 9) && - srf->num_sizes == 1 && - srf->sizes[0].width == 64 && - srf->sizes[0].height == 64 && - srf->format == SVGA3D_A8R8G8B8) { - - srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL); - /* clear the image */ - if (srf->snooper.image) - memset(srf->snooper.image, 0x00, 64 * 64 * 4); - else - DRM_ERROR("Failed to allocate cursor_image\n"); - - } else { - srf->snooper.image = NULL; - } - srf->snooper.crtc = NULL; - rep->sid = user_srf->base.hash.key; if (rep->sid == SVGA3D_INVALID_ID) DRM_ERROR("Created bad Surface ID.\n"); -- cgit v1.2.3 From 7704befbd599e9c9524f640e14658ca8ed9d8717 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 13 Jan 2010 22:28:38 +0100 Subject: drm/vmwgfx: Make fence sequences continous across a VT switch. A vt switch in stealth mode would take down the FIFO, and re- initialize fence sequence numbers. This patch saves the current state of the fence sequence when the FIFO is disabled. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 1db1ef30be2..70e4f5f0c12 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -217,6 +217,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->dev = dev; dev_priv->vmw_chipset = chipset; + dev_priv->last_read_sequence = (uint32_t) -100; mutex_init(&dev_priv->hw_mutex); mutex_init(&dev_priv->cmdbuf_mutex); rwlock_init(&dev_priv->resource_lock); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 01feb48af33..f7d5f70b52d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -98,8 +98,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) (unsigned int) min, (unsigned int) fifo->capabilities); - dev_priv->fence_seq = (uint32_t) -100; - dev_priv->last_read_sequence = (uint32_t) -100; + dev_priv->fence_seq = dev_priv->last_read_sequence; iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE); return vmw_fifo_send_fence(dev_priv, &dummy); -- cgit v1.2.3 From effe1105bef07f42366c20eac41b80ff9fcf675e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 13 Jan 2010 22:28:39 +0100 Subject: drm/vmwgfx: Use bo_driver::move_notify to unbind GMRs. This was previously done explicitly for overlay- and fb buffers. Now it's done for any buffer leaving the SYSTEM memory region. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 10 +++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 8 -------- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 9 --------- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 23 ++++++++++++----------- 5 files changed, 22 insertions(+), 29 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index d6f2d2b882e..4be47d84077 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -172,6 +172,13 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp) return 0; } +static void vmw_move_notify(struct ttm_buffer_object *bo, + struct ttm_mem_reg *new_mem) +{ + if (new_mem->mem_type != TTM_PL_SYSTEM) + vmw_dmabuf_gmr_unbind(bo); +} + /** * FIXME: We're using the old vmware polling method to sync. * Do this with fences instead. @@ -225,5 +232,6 @@ struct ttm_bo_driver vmw_bo_driver = { .sync_obj_wait = vmw_sync_obj_wait, .sync_obj_flush = vmw_sync_obj_flush, .sync_obj_unref = vmw_sync_obj_unref, - .sync_obj_ref = vmw_sync_obj_ref + .sync_obj_ref = vmw_sync_obj_ref, + .move_notify = vmw_move_notify }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index e61bd85b697..4c9d6b2b995 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -353,6 +353,7 @@ extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, struct vmw_dma_buffer *bo); extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv, struct vmw_dma_buffer *bo); +extern void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo); extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 641dde76ada..4f4f6432be8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -649,14 +649,6 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, if (unlikely(ret != 0)) goto err_unlock; - if (vmw_bo->gmr_bound) { - vmw_gmr_unbind(vmw_priv, vmw_bo->gmr_id); - spin_lock(&bo->glob->lru_lock); - ida_remove(&vmw_priv->gmr_ida, vmw_bo->gmr_id); - spin_unlock(&bo->glob->lru_lock); - vmw_bo->gmr_bound = NULL; - } - ret = ttm_bo_validate(bo, &ne_placement, false, false); ttm_bo_unreserve(bo); err_unlock: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index bb6e6a096d2..5b6eabeb7f5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -104,7 +104,6 @@ static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, bool pin, bool interruptible) { struct ttm_buffer_object *bo = &buf->base; - struct ttm_bo_global *glob = bo->glob; struct ttm_placement *overlay_placement = &vmw_vram_placement; int ret; @@ -116,14 +115,6 @@ static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, if (unlikely(ret != 0)) goto err; - if (buf->gmr_bound) { - vmw_gmr_unbind(dev_priv, buf->gmr_id); - spin_lock(&glob->lru_lock); - ida_remove(&dev_priv->gmr_ida, buf->gmr_id); - spin_unlock(&glob->lru_lock); - buf->gmr_bound = NULL; - } - if (pin) overlay_placement = &vmw_vram_ne_placement; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 125c2f44f98..e0878077e8a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -757,20 +757,29 @@ static size_t vmw_dmabuf_acc_size(struct ttm_bo_global *glob, return bo_user_size + page_array_size; } -void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) +void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo) { struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); struct ttm_bo_global *glob = bo->glob; struct vmw_private *dev_priv = container_of(bo->bdev, struct vmw_private, bdev); - ttm_mem_global_free(glob->mem_glob, bo->acc_size); if (vmw_bo->gmr_bound) { vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id); spin_lock(&glob->lru_lock); ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id); spin_unlock(&glob->lru_lock); + vmw_bo->gmr_bound = false; } +} + +void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) +{ + struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); + struct ttm_bo_global *glob = bo->glob; + + vmw_dmabuf_gmr_unbind(bo); + ttm_mem_global_free(glob->mem_glob, bo->acc_size); kfree(vmw_bo); } @@ -816,18 +825,10 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv, static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo) { struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); - struct vmw_dma_buffer *vmw_bo = &vmw_user_bo->dma; struct ttm_bo_global *glob = bo->glob; - struct vmw_private *dev_priv = - container_of(bo->bdev, struct vmw_private, bdev); + vmw_dmabuf_gmr_unbind(bo); ttm_mem_global_free(glob->mem_glob, bo->acc_size); - if (vmw_bo->gmr_bound) { - vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id); - spin_lock(&glob->lru_lock); - ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id); - spin_unlock(&glob->lru_lock); - } kfree(vmw_user_bo); } -- cgit v1.2.3 From 3f09ea4ecdcbcea05541f83e557d6ce2e56626d8 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 13 Jan 2010 22:28:40 +0100 Subject: drm/ttm: Add a swap_notify callback. This is needed for a bugfix in the vmwgfx driver. Drivers may have GPU bindings on buffers that core TTM is not aware of, and TTM may view those buffers as ordinary system memory buffers. Add a notifier to such drivers when TTM is about to move the buffer contents out to swappable memory. The driver must then release any private GPU bindings on those buffers. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 2920f9a279e..e10a04e7c4e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1844,6 +1844,9 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) * anyone tries to access a ttm page. */ + if (bo->bdev->driver->swap_notify) + bo->bdev->driver->swap_notify(bo); + ret = ttm_tt_swapout(bo->ttm, bo->persistant_swap_storage); out: -- cgit v1.2.3 From 476d51dbdbaa2e61fa4899459c658f476eee3fd9 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 13 Jan 2010 22:28:41 +0100 Subject: drm/vmwgfx: Implement a swap_notify callback. Unbind GMR bindings on the buffer about to be swapped out. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 4be47d84077..37a81925b15 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -179,6 +179,11 @@ static void vmw_move_notify(struct ttm_buffer_object *bo, vmw_dmabuf_gmr_unbind(bo); } +static void vmw_swap_notify(struct ttm_buffer_object *bo) +{ + vmw_dmabuf_gmr_unbind(bo); +} + /** * FIXME: We're using the old vmware polling method to sync. * Do this with fences instead. @@ -233,5 +238,6 @@ struct ttm_bo_driver vmw_bo_driver = { .sync_obj_flush = vmw_sync_obj_flush, .sync_obj_unref = vmw_sync_obj_unref, .sync_obj_ref = vmw_sync_obj_ref, - .move_notify = vmw_move_notify + .move_notify = vmw_move_notify, + .swap_notify = vmw_swap_notify }; -- cgit v1.2.3 From e99e1e7893ac80fe769477cb1ddd4b482cef8902 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 13 Jan 2010 22:28:42 +0100 Subject: drm/ttm: Export symbols needed for vmwgfx suspend / resume operations. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 1 + drivers/gpu/drm/ttm/ttm_lock.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index e10a04e7c4e..7a64f07b120 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1867,3 +1867,4 @@ void ttm_bo_swapout_all(struct ttm_bo_device *bdev) while (ttm_bo_swapout(&bdev->glob->shrink) == 0) ; } +EXPORT_SYMBOL(ttm_bo_swapout_all); diff --git a/drivers/gpu/drm/ttm/ttm_lock.c b/drivers/gpu/drm/ttm/ttm_lock.c index f619ebcaa4e..3d172ef04ee 100644 --- a/drivers/gpu/drm/ttm/ttm_lock.c +++ b/drivers/gpu/drm/ttm/ttm_lock.c @@ -288,6 +288,7 @@ void ttm_suspend_unlock(struct ttm_lock *lock) wake_up_all(&lock->queue); spin_unlock(&lock->lock); } +EXPORT_SYMBOL(ttm_suspend_unlock); static bool __ttm_suspend_lock(struct ttm_lock *lock) { @@ -309,3 +310,4 @@ void ttm_suspend_lock(struct ttm_lock *lock) { wait_event(lock->queue, __ttm_suspend_lock(lock)); } +EXPORT_SYMBOL(ttm_suspend_lock); -- cgit v1.2.3 From d9f36a0051b7c0382107cb0342af1126a6eb627d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 13 Jan 2010 22:28:43 +0100 Subject: drm/vmwgfx: Implement basic pm operations. Currently we really only support S3, since the device doesn't support saving of the 3D state. On S3/S4, move all buffer objects to swappable memory and take down GMR bindings. We need to do that from a PM notifier since we can't do persistant memory allocations from the standard PM callbacks. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 62 ++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 ++ 2 files changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 70e4f5f0c12..dedd121d8fe 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -147,6 +147,8 @@ static char *vmw_devname = "vmwgfx"; static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static void vmw_master_init(struct vmw_master *); +static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, + void *ptr); static void vmw_print_capabilities(uint32_t capabilities) { @@ -352,6 +354,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) vmw_fb_init(dev_priv); } + dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; + register_pm_notifier(&dev_priv->pm_nb); + return 0; out_no_device: @@ -386,6 +391,8 @@ static int vmw_driver_unload(struct drm_device *dev) DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n"); + unregister_pm_notifier(&dev_priv->pm_nb); + if (!dev_priv->stealth) { vmw_fb_close(dev_priv); vmw_kms_close(dev_priv); @@ -651,6 +658,57 @@ static void vmw_remove(struct pci_dev *pdev) drm_put_dev(dev); } +static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, + void *ptr) +{ + struct vmw_private *dev_priv = + container_of(nb, struct vmw_private, pm_nb); + struct vmw_master *vmaster = dev_priv->active_master; + + switch (val) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + ttm_suspend_lock(&vmaster->lock); + + /** + * This empties VRAM and unbinds all GMR bindings. + * Buffer contents is moved to swappable memory. + */ + ttm_bo_swapout_all(&dev_priv->bdev); + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + ttm_suspend_unlock(&vmaster->lock); + break; + case PM_RESTORE_PREPARE: + break; + case PM_POST_RESTORE: + break; + default: + break; + } + return 0; +} + +/** + * These might not be needed with the virtual SVGA device. + */ + +int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + return 0; +} + +int vmw_pci_resume(struct pci_dev *pdev) +{ + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + return pci_enable_device(pdev); +} + static struct drm_driver driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_MODESET, @@ -690,7 +748,9 @@ static struct drm_driver driver = { .name = VMWGFX_DRIVER_NAME, .id_table = vmw_pci_id_list, .probe = vmw_probe, - .remove = vmw_remove + .remove = vmw_remove, + .suspend = vmw_pci_suspend, + .resume = vmw_pci_resume }, .name = VMWGFX_DRIVER_NAME, .desc = VMWGFX_DRIVER_DESC, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 4c9d6b2b995..7532b9b47ee 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -32,6 +32,7 @@ #include "drmP.h" #include "vmwgfx_drm.h" #include "drm_hashtab.h" +#include "linux/suspend.h" #include "ttm/ttm_bo_driver.h" #include "ttm/ttm_object.h" #include "ttm/ttm_lock.h" @@ -258,6 +259,7 @@ struct vmw_private { struct vmw_master *active_master; struct vmw_master fbdev_master; + struct notifier_block pm_nb; }; static inline struct vmw_private *vmw_priv(struct drm_device *dev) -- cgit v1.2.3 From 354fb52cb6138de0e6cf84a0f6a7f3467586e390 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 13 Jan 2010 22:28:45 +0100 Subject: drm/ttm: Make sure system buffer objects has offset == 0. This is a convention that the vmwgfx driver has come to rely on. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 7a64f07b120..da3702135ad 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -426,7 +426,8 @@ moved: bdev->man[bo->mem.mem_type].gpu_offset; bo->cur_placement = bo->mem.placement; spin_unlock(&bo->lock); - } + } else + bo->offset = 0; return 0; -- cgit v1.2.3 From 0a90dc51aa3162abb7cd64323ba2e6674e1c5ff4 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 11 Jan 2010 21:18:53 +0100 Subject: drm/nv50: wait for pgraph to idle before unloading the context This should fix the problem with gpu hangs people have had when closing channels. Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_graph.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index ca79f32be44..56a9753db23 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -282,6 +282,7 @@ nv50_graph_unload_context(struct drm_device *dev) return 0; inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE; + nouveau_wait_for_idle(dev); nv_wr32(dev, 0x400500, fifo & ~1); nv_wr32(dev, 0x400784, inst); nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20); -- cgit v1.2.3 From 9855e584d296a32bbcc1bb3d29b7e0ed078b03cc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 12 Jan 2010 13:02:19 +1000 Subject: drm/nouveau: trust init table registers are safe Apparently the original reason for checking this was there were known register accesses that caused hangs on some chipsets. This was more than likely because of incorrect parsing of previous opcodes, and I hardly think aborting a script half way through is going to be any better (in fact, we have had bug reports where this has been the cause of s/r failures among other things). This patch (which has been in Fedora 12 for a long time now) removes all checking for known register ranges, and just leaves the check to ensure the access is within the mapped aperture to avoid an oops. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 59 ++++++---------------------------- 1 file changed, 9 insertions(+), 50 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index ba143972769..9710e69898f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -310,63 +310,22 @@ valid_reg(struct nvbios *bios, uint32_t reg) struct drm_device *dev = bios->dev; /* C51 has misaligned regs on purpose. Marvellous */ - if (reg & 0x2 || (reg & 0x1 && dev_priv->VBIOS.pub.chip_version != 0x51)) { - NV_ERROR(dev, "========== misaligned reg 0x%08X ==========\n", - reg); - return 0; - } - /* - * Warn on C51 regs that have not been verified accessible in - * mmiotracing - */ + if (reg & 0x2 || + (reg & 0x1 && dev_priv->VBIOS.pub.chip_version != 0x51)) + NV_ERROR(dev, "======= misaligned reg 0x%08X =======\n", reg); + + /* warn on C51 regs that haven't been verified accessible in tracing */ if (reg & 0x1 && dev_priv->VBIOS.pub.chip_version == 0x51 && reg != 0x130d && reg != 0x1311 && reg != 0x60081d) NV_WARN(dev, "=== C51 misaligned reg 0x%08X not verified ===\n", reg); - /* Trust the init scripts on G80 */ - if (dev_priv->card_type >= NV_50) - return 1; - - #define WITHIN(x, y, z) ((x >= y) && (x < y + z)) - if (WITHIN(reg, NV_PMC_OFFSET, NV_PMC_SIZE)) - return 1; - if (WITHIN(reg, NV_PBUS_OFFSET, NV_PBUS_SIZE)) - return 1; - if (WITHIN(reg, NV_PFIFO_OFFSET, NV_PFIFO_SIZE)) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x30 && - (WITHIN(reg, 0x4000, 0x600) || reg == 0x00004600)) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x40 && - WITHIN(reg, 0xc000, 0x48)) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x17 && reg == 0x0000d204) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x40) { - if (reg == 0x00011014 || reg == 0x00020328) - return 1; - if (WITHIN(reg, 0x88000, NV_PBUS_SIZE)) /* new PBUS */ - return 1; + if (reg >= (8*1024*1024)) { + NV_ERROR(dev, "=== reg 0x%08x out of mapped bounds ===\n", reg); + return 0; } - if (WITHIN(reg, NV_PFB_OFFSET, NV_PFB_SIZE)) - return 1; - if (WITHIN(reg, NV_PEXTDEV_OFFSET, NV_PEXTDEV_SIZE)) - return 1; - if (WITHIN(reg, NV_PCRTC0_OFFSET, NV_PCRTC0_SIZE * 2)) - return 1; - if (WITHIN(reg, NV_PRAMDAC0_OFFSET, NV_PRAMDAC0_SIZE * 2)) - return 1; - if (dev_priv->VBIOS.pub.chip_version >= 0x17 && reg == 0x0070fff0) - return 1; - if (dev_priv->VBIOS.pub.chip_version == 0x51 && - WITHIN(reg, NV_PRAMIN_OFFSET, NV_PRAMIN_SIZE)) - return 1; - #undef WITHIN - NV_ERROR(dev, "========== unknown reg 0x%08X ==========\n", reg); - - return 0; + return 1; } static bool -- cgit v1.2.3 From e147eae80afe98b86a7921a40a709584e6603e34 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 12 Jan 2010 15:28:19 +1000 Subject: drm/nouveau: wait on fence after bo move if validating for another channel Not an ideal solution, but it'll do for the moment for correctness. We need to come up with a nicer way to manage inter-channel sync, the hw is unfortunately a little lacking in this area. Should fix some resume corruption, as well as corruption that may be seen while under memory pressure. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index e342a418d43..db0ed4c13f9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -469,6 +469,8 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, evict, no_wait, new_mem); + if (nvbo->channel && nvbo->channel != chan) + ret = nouveau_fence_wait(fence, NULL, false, false); nouveau_fence_unref((void *)&fence); return ret; } -- cgit v1.2.3 From 77cb5c75e89ccfeb993d9dec37f8edb3a855e9f4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 13 Jan 2010 11:22:33 +1000 Subject: drm/nouveau: remove PRIV0 check in nouveau_mem_close() We don't setup PRIV0 anymore, so this is unnecessary. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index fb9bdd6edf1..be4c7781d76 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -383,10 +383,7 @@ void nouveau_mem_close(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - if (dev_priv->ttm.bdev.man[TTM_PL_PRIV0].has_type) - ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_PRIV0); ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); - ttm_bo_device_release(&dev_priv->ttm.bdev); nouveau_ttm_global_release(dev_priv); -- cgit v1.2.3 From ed42f8240cfea13580fe91195e52c5247275e7df Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 14 Jan 2010 15:58:10 +1000 Subject: drm/nouveau: assume no nv04 board has a DCB table There's a report of a TNT2 where the DCB table pointer is *not* NULL (it contains a part of a VBIOS data string), and we assume this means a DCB table is present, causing all kinds of hilarity. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 9710e69898f..9dd2efa07f6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5523,11 +5523,13 @@ void merge_like_dcb_entries(struct drm_device *dev, struct parsed_dcb *dcb) dcb->entries = newentries; } -static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) +static int +parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) { + struct drm_nouveau_private *dev_priv = dev->dev_private; struct bios_parsed_dcb *bdcb = &bios->bdcb; struct parsed_dcb *dcb; - uint16_t dcbptr, i2ctabptr = 0; + uint16_t dcbptr = 0, i2ctabptr = 0; uint8_t *dcbtable; uint8_t headerlen = 0x4, entries = DCB_MAX_NUM_ENTRIES; bool configblock = true; @@ -5538,16 +5540,18 @@ static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool two dcb->entries = 0; /* get the offset from 0x36 */ - dcbptr = ROM16(bios->data[0x36]); + if (dev_priv->card_type > NV_04) { + dcbptr = ROM16(bios->data[0x36]); + if (dcbptr == 0x0000) + NV_WARN(dev, "No output data (DCB) found in BIOS\n"); + } + /* this situation likely means a really old card, pre DCB */ if (dcbptr == 0x0) { - NV_WARN(dev, "No output data (DCB) found in BIOS, " - "assuming a CRT output exists\n"); - /* this situation likely means a really old card, pre DCB */ + NV_INFO(dev, "Assuming a CRT output exists\n"); fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1); - if (nv04_tv_identify(dev, - bios->legacy.i2c_indices.tv) >= 0) + if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0) fabricate_tv_output(dcb, twoHeads); return 0; -- cgit v1.2.3 From b0d2de860bd621959bc826ffd42618fe1de37a61 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 14 Jan 2010 17:53:04 +1000 Subject: drm/nouveau: less magic DCB 1.5 parsing This in the very least matches the parsing of all the previously known entries, and hopefully (at least closer to) correct for any we haven't seen yet. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 79 +++++++++++++++++----------------- 1 file changed, 40 insertions(+), 39 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 9dd2efa07f6..ca2fcdf32b8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5393,52 +5393,49 @@ static bool parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb, uint32_t conn, uint32_t conf, struct dcb_entry *entry) { - if (conn != 0xf0003f00 && conn != 0xf2247f10 && conn != 0xf2204001 && - conn != 0xf2204301 && conn != 0xf2204311 && conn != 0xf2208001 && - conn != 0xf2244001 && conn != 0xf2244301 && conn != 0xf2244311 && - conn != 0xf4204011 && conn != 0xf4208011 && conn != 0xf4248011 && - conn != 0xf2045ff2 && conn != 0xf2045f14 && conn != 0xf207df14 && - conn != 0xf2205004 && conn != 0xf2209004) { - NV_ERROR(dev, "Unknown DCB 1.5 entry, please report\n"); - - /* cause output setting to fail for !TV, so message is seen */ - if ((conn & 0xf) != 0x1) - dcb->entries = 0; - - return false; - } - /* most of the below is a "best guess" atm */ - entry->type = conn & 0xf; - if (entry->type == 2) - /* another way of specifying straps based lvds... */ + switch (conn & 0x0000000f) { + case 0: + entry->type = OUTPUT_ANALOG; + break; + case 1: + entry->type = OUTPUT_TV; + break; + case 2: + case 3: entry->type = OUTPUT_LVDS; - if (entry->type == 4) { /* digital */ - if (conn & 0x10) - entry->type = OUTPUT_LVDS; - else + break; + case 4: + switch ((conn & 0x000000f0) >> 4) { + case 0: entry->type = OUTPUT_TMDS; + break; + case 1: + entry->type = OUTPUT_LVDS; + break; + default: + NV_ERROR(dev, "Unknown DCB subtype 4/%d\n", + (conn & 0x000000f0) >> 4); + return false; + } + break; + default: + NV_ERROR(dev, "Unknown DCB type %d\n", conn & 0x0000000f); + return false; } - /* what's in bits 5-13? could be some encoder maker thing, in tv case */ - entry->i2c_index = (conn >> 14) & 0xf; - /* raw heads field is in range 0-1, so move to 1-2 */ - entry->heads = ((conn >> 18) & 0x7) + 1; - entry->location = (conn >> 21) & 0xf; - /* unused: entry->bus = (conn >> 25) & 0x7; */ - /* set or to be same as heads -- hopefully safe enough */ - entry->or = entry->heads; + + entry->i2c_index = (conn & 0x0003c000) >> 14; + entry->heads = ((conn & 0x001c0000) >> 18) + 1; + entry->or = entry->heads; /* same as heads, hopefully safe enough */ + entry->location = (conn & 0x01e00000) >> 21; + entry->bus = (conn & 0x0e000000) >> 25; entry->duallink_possible = false; switch (entry->type) { case OUTPUT_ANALOG: entry->crtconf.maxfreq = (conf & 0xffff) * 10; break; - case OUTPUT_LVDS: - /* - * This is probably buried in conn's unknown bits. - * This will upset EDID-ful models, if they exist - */ - entry->lvdsconf.use_straps_for_mode = true; - entry->lvdsconf.use_power_scripts = true; + case OUTPUT_TV: + entry->tvconf.has_component_output = false; break; case OUTPUT_TMDS: /* @@ -5447,8 +5444,12 @@ parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb, */ fabricate_vga_output(dcb, entry->i2c_index, entry->heads); break; - case OUTPUT_TV: - entry->tvconf.has_component_output = false; + case OUTPUT_LVDS: + if ((conn & 0x00003f00) != 0x10) + entry->lvdsconf.use_straps_for_mode = true; + entry->lvdsconf.use_power_scripts = true; + break; + default: break; } -- cgit v1.2.3 From 716abaa8e52548e8863831cb32984655f46b5566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Tue, 12 Jan 2010 18:21:56 +0000 Subject: drm/nv50: Fix typo in PGRAPH initialisation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables streamout functionality. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_graph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 56a9753db23..20319e59d36 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -84,7 +84,7 @@ nv50_graph_init_regs__nv(struct drm_device *dev) nv_wr32(dev, 0x400804, 0xc0000000); nv_wr32(dev, 0x406800, 0xc0000000); nv_wr32(dev, 0x400c04, 0xc0000000); - nv_wr32(dev, 0x401804, 0xc0000000); + nv_wr32(dev, 0x401800, 0xc0000000); nv_wr32(dev, 0x405018, 0xc0000000); nv_wr32(dev, 0x402000, 0xc0000000); -- cgit v1.2.3 From b79d8a65d52d3d80204e1bad30ee57bb5a58ced1 Mon Sep 17 00:00:00 2001 From: Andrea Tacconi Date: Thu, 14 Jan 2010 14:52:37 +0100 Subject: drm/nouveau: add NV18 device id to call_lvds_manufacturer_script This fixes imac black screen (NV18 card) Signed-off-by: Andrea Tacconi Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index ca2fcdf32b8..03f1ddbaa2d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -3155,7 +3155,7 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entr } #ifdef __powerpc__ /* Powerbook specific quirks */ - if (script == LVDS_RESET && ((dev->pci_device & 0xffff) == 0x0179 || (dev->pci_device & 0xffff) == 0x0329)) + if (script == LVDS_RESET && ((dev->pci_device & 0xffff) == 0x0179 || (dev->pci_device & 0xffff) == 0x0189 || (dev->pci_device & 0xffff) == 0x0329)) nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); if ((dev->pci_device & 0xffff) == 0x0179 || (dev->pci_device & 0xffff) == 0x0189 || (dev->pci_device & 0xffff) == 0x0329) { if (script == LVDS_PANEL_ON) { -- cgit v1.2.3 From 3d9aefb8bd1be2b5e07acf0f938c21769f03cc64 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 14 Jan 2010 14:56:54 +0100 Subject: drm/nouveau: Break some long lines. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 03f1ddbaa2d..d7f8d8b4a4b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -3155,16 +3155,25 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entr } #ifdef __powerpc__ /* Powerbook specific quirks */ - if (script == LVDS_RESET && ((dev->pci_device & 0xffff) == 0x0179 || (dev->pci_device & 0xffff) == 0x0189 || (dev->pci_device & 0xffff) == 0x0329)) - nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); - if ((dev->pci_device & 0xffff) == 0x0179 || (dev->pci_device & 0xffff) == 0x0189 || (dev->pci_device & 0xffff) == 0x0329) { - if (script == LVDS_PANEL_ON) { - bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) | (1 << 31)); - bios_wr32(bios, NV_PCRTC_GPIO_EXT, bios_rd32(bios, NV_PCRTC_GPIO_EXT) | 1); - } - if (script == LVDS_PANEL_OFF) { - bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) & ~(1 << 31)); - bios_wr32(bios, NV_PCRTC_GPIO_EXT, bios_rd32(bios, NV_PCRTC_GPIO_EXT) & ~3); + if ((dev->pci_device & 0xffff) == 0x0179 || + (dev->pci_device & 0xffff) == 0x0189 || + (dev->pci_device & 0xffff) == 0x0329) { + if (script == LVDS_RESET) { + nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); + + } else if (script == LVDS_PANEL_ON) { + bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, + bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) + | (1 << 31)); + bios_wr32(bios, NV_PCRTC_GPIO_EXT, + bios_rd32(bios, NV_PCRTC_GPIO_EXT) | 1); + + } else if (script == LVDS_PANEL_OFF) { + bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, + bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) + & ~(1 << 31)); + bios_wr32(bios, NV_PCRTC_GPIO_EXT, + bios_rd32(bios, NV_PCRTC_GPIO_EXT) & ~3); } } #endif -- cgit v1.2.3 From c8ebe275790f2c5efc3ffec515c93b7a139829d3 Mon Sep 17 00:00:00 2001 From: Xavier Chantry Date: Mon, 11 Jan 2010 22:42:21 +0100 Subject: drm/nouveau: fix edid memleak in nouveau_connector This was spotted by kmemleak. Signed-off-by: Xavier Chantry Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 5a10deb8bdb..54c85305a0f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -83,14 +83,16 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder) static void nouveau_connector_destroy(struct drm_connector *drm_connector) { - struct nouveau_connector *connector = nouveau_connector(drm_connector); - struct drm_device *dev = connector->base.dev; + struct nouveau_connector *nv_connector = + nouveau_connector(drm_connector); + struct drm_device *dev = nv_connector->base.dev; NV_DEBUG_KMS(dev, "\n"); - if (!connector) + if (!nv_connector) return; + kfree(nv_connector->edid); drm_sysfs_connector_remove(drm_connector); drm_connector_cleanup(drm_connector); kfree(drm_connector); @@ -237,6 +239,9 @@ nouveau_connector_detect(struct drm_connector *connector) return connector_status_connected; } + kfree(nv_connector->edid); + nv_connector->edid = NULL; + i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); if (i2c) { nouveau_connector_ddc_prepare(connector, &flags); @@ -687,8 +692,12 @@ nouveau_connector_create_lvds(struct drm_device *dev, */ if (!nv_connector->edid && !nv_connector->native_mode && !dev_priv->VBIOS.pub.fp_no_ddc) { - nv_connector->edid = + struct edid *edid = (struct edid *)nouveau_bios_embedded_edid(dev); + if (edid) { + nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + *(nv_connector->edid) = *edid; + } } if (!nv_connector->edid) -- cgit v1.2.3 From 0ed3165e55fdedee6fc04b757907a2d5ccacdf18 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 14 Jan 2010 15:47:03 +0100 Subject: drm/nouveau: Fallback to analog load detection when the EDID block is invalid. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 54c85305a0f..3dc7e09da28 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -252,7 +252,7 @@ nouveau_connector_detect(struct drm_connector *connector) if (!nv_connector->edid) { NV_ERROR(dev, "DDC responded, but no EDID for %s\n", drm_get_connector_name(connector)); - return connector_status_disconnected; + goto detect_analog; } if (nv_encoder->dcb->type == OUTPUT_DP && @@ -286,6 +286,7 @@ nouveau_connector_detect(struct drm_connector *connector) return connector_status_connected; } +detect_analog: nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); if (!nv_encoder) nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); -- cgit v1.2.3 From b8780e2ad20feb8d086bc961a678e8fdb4fa296b Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 14 Jan 2010 15:54:23 +0100 Subject: drm/nouveau: Unset the EDID connector property when the EDID block goes away. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 3dc7e09da28..8da35281a0c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -239,8 +239,12 @@ nouveau_connector_detect(struct drm_connector *connector) return connector_status_connected; } - kfree(nv_connector->edid); - nv_connector->edid = NULL; + /* Cleanup the previous EDID block. */ + if (nv_connector->edid) { + drm_mode_connector_update_edid_property(connector, NULL); + kfree(nv_connector->edid); + nv_connector->edid = NULL; + } i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); if (i2c) { -- cgit v1.2.3 From ac8fb975e8c88d312a376b035494be17548d01c6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 15 Jan 2010 09:24:20 +1000 Subject: drm/nouveau: reserve VGA area for the moment This is to prevent things such as GART tables and other important GPU structures being allocated there before we take over fbcon ourselves. This is more of a workaround for the moment, a better solution will require some more invasive changes, but it'll be done at some point. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_mem.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 026419fe879..cc36866e2a9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -509,6 +509,8 @@ struct drm_nouveau_private { void __iomem *ramin; uint32_t ramin_size; + struct nouveau_bo *vga_ram; + struct workqueue_struct *wq; struct work_struct irq_work; diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index be4c7781d76..186f34b01f2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -383,6 +383,9 @@ void nouveau_mem_close(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + nouveau_bo_unpin(dev_priv->vga_ram); + nouveau_bo_ref(NULL, &dev_priv->vga_ram); + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); ttm_bo_device_release(&dev_priv->ttm.bdev); @@ -619,6 +622,15 @@ nouveau_mem_init(struct drm_device *dev) return ret; } + ret = nouveau_bo_new(dev, NULL, 256*1024, 0, TTM_PL_FLAG_VRAM, + 0, 0, true, true, &dev_priv->vga_ram); + if (ret == 0) + ret = nouveau_bo_pin(dev_priv->vga_ram, TTM_PL_FLAG_VRAM); + if (ret) { + NV_WARN(dev, "failed to reserve VGA memory\n"); + nouveau_bo_ref(NULL, &dev_priv->vga_ram); + } + /* GART */ #if !defined(__powerpc__) && !defined(__ia64__) if (drm_device_is_agp(dev) && dev->agp) { @@ -650,6 +662,7 @@ nouveau_mem_init(struct drm_device *dev) dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1), drm_get_resource_len(dev, 1), DRM_MTRR_WC); + return 0; } -- cgit v1.2.3 From 12f735b79f0ad63964dedabed3eee8a581bb66a5 Mon Sep 17 00:00:00 2001 From: Luca Barbieri Date: Sun, 10 Jan 2010 20:10:53 +0100 Subject: drm/nouveau: check pushbuffer bounds in ioctl Currently there is no check that the pushbuffer request bounds are inside the TTM BO. This allows to instruct the kernel to do relocations on user-selected addresses, since the relocation bounds checking relies on the request bounds. This can oops the kernel accidentally and is easily exploitable. This patch adds bound checking and alignment checking for ->offset and ->nr_dwords. It also makes some variables unsigned, which should have no effect, but prevents possible bounds checking problems. Signed-off-by: Luca Barbieri Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 2009db2426c..50483304408 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -466,13 +466,14 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size) static int nouveau_gem_pushbuf_reloc_apply(struct nouveau_channel *chan, int nr_bo, struct drm_nouveau_gem_pushbuf_bo *bo, - int nr_relocs, uint64_t ptr_relocs, - int nr_dwords, int first_dword, + unsigned nr_relocs, uint64_t ptr_relocs, + unsigned nr_dwords, unsigned first_dword, uint32_t *pushbuf, bool is_iomem) { struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; struct drm_device *dev = chan->dev; - int ret = 0, i; + int ret = 0; + unsigned i; reloc = u_memcpya(ptr_relocs, nr_relocs, sizeof(*reloc)); if (IS_ERR(reloc)) @@ -667,6 +668,18 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data, } pbbo = nouveau_gem_object(gem); + if ((req->offset & 3) || req->nr_dwords < 2 || + (unsigned long)req->offset > (unsigned long)pbbo->bo.mem.size || + (unsigned long)req->nr_dwords > + ((unsigned long)(pbbo->bo.mem.size - req->offset ) >> 2)) { + NV_ERROR(dev, "pb call misaligned or out of bounds: " + "%d + %d * 4 > %ld\n", + req->offset, req->nr_dwords, pbbo->bo.mem.size); + ret = -EINVAL; + drm_gem_object_unreference(gem); + goto out; + } + ret = ttm_bo_reserve(&pbbo->bo, false, false, true, chan->fence.sequence); if (ret) { -- cgit v1.2.3 From 79b7dcb2af7da728819cf060b94ce8c9ead36f7e Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 14 Jan 2010 19:02:20 +0100 Subject: drm: EDID accept separate sync video mode X is accepting such video mode, do the same. Pointed out by Joshua Roys on IRC. Fix https://bugzilla.redhat.com/show_bug.cgi?id=540024 [fix printf to use composite not integrated :- airlied] Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_edid.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index defcaf10846..f665b05592f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -633,8 +633,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, return NULL; } if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { - printk(KERN_WARNING "integrated sync not supported\n"); - return NULL; + printk(KERN_WARNING "composite sync not supported\n"); } /* it is incorrect if hsync/vsync width is zero */ -- cgit v1.2.3 From ba59953d281747b1f7518a60f0ba8ff671cd0d65 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 15 Jan 2010 12:08:57 +1000 Subject: drm/nouveau: fix a race condition in nouveau_dma_wait() Can be triggered easily on certain cards (NV46 and NV50 of mine) by running "dmesg", the DRM's channel will lockup. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dma.c | 76 ++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 29 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 7afbe8b40d5..50d9e67745a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -126,47 +126,52 @@ OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords) chan->dma.cur += nr_dwords; } -static inline bool -READ_GET(struct nouveau_channel *chan, uint32_t *get) +/* Fetch and adjust GPU GET pointer + * + * Returns: + * value >= 0, the adjusted GET pointer + * -EINVAL if GET pointer currently outside main push buffer + * -EBUSY if timeout exceeded + */ +static inline int +READ_GET(struct nouveau_channel *chan, uint32_t *prev_get, uint32_t *timeout) { uint32_t val; val = nvchan_rd32(chan, chan->user_get); - if (val < chan->pushbuf_base || - val > chan->pushbuf_base + (chan->dma.max << 2)) { - /* meaningless to dma_wait() except to know whether the - * GPU has stalled or not - */ - *get = val; - return false; + + /* reset counter as long as GET is still advancing, this is + * to avoid misdetecting a GPU lockup if the GPU happens to + * just be processing an operation that takes a long time + */ + if (val != *prev_get) { + *prev_get = val; + *timeout = 0; + } + + if ((++*timeout & 0xff) == 0) { + DRM_UDELAY(1); + if (*timeout > 100000) + return -EBUSY; } - *get = (val - chan->pushbuf_base) >> 2; - return true; + if (val < chan->pushbuf_base || + val > chan->pushbuf_base + (chan->dma.max << 2)) + return -EINVAL; + + return (val - chan->pushbuf_base) >> 2; } int nouveau_dma_wait(struct nouveau_channel *chan, int size) { - uint32_t get, prev_get = 0, cnt = 0; - bool get_valid; + uint32_t prev_get = 0, cnt = 0; + int get; while (chan->dma.free < size) { - /* reset counter as long as GET is still advancing, this is - * to avoid misdetecting a GPU lockup if the GPU happens to - * just be processing an operation that takes a long time - */ - get_valid = READ_GET(chan, &get); - if (get != prev_get) { - prev_get = get; - cnt = 0; - } - - if ((++cnt & 0xff) == 0) { - DRM_UDELAY(1); - if (cnt > 100000) - return -EBUSY; - } + get = READ_GET(chan, &prev_get, &cnt); + if (unlikely(get == -EBUSY)) + return -EBUSY; /* loop until we have a usable GET pointer. the value * we read from the GPU may be outside the main ring if @@ -177,7 +182,7 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size) * from the SKIPS area, so the code below doesn't have to deal * with some fun corner cases. */ - if (!get_valid || get < NOUVEAU_DMA_SKIPS) + if (unlikely(get == -EINVAL) || get < NOUVEAU_DMA_SKIPS) continue; if (get <= chan->dma.cur) { @@ -203,6 +208,19 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size) * after processing the currently pending commands. */ OUT_RING(chan, chan->pushbuf_base | 0x20000000); + + /* wait for GET to depart from the skips area. + * prevents writing GET==PUT and causing a race + * condition that causes us to think the GPU is + * idle when it's not. + */ + do { + get = READ_GET(chan, &prev_get, &cnt); + if (unlikely(get == -EBUSY)) + return -EBUSY; + if (unlikely(get == -EINVAL)) + continue; + } while (get <= NOUVEAU_DMA_SKIPS); WRITE_PUT(NOUVEAU_DMA_SKIPS); /* we're now submitting commands at the start of -- cgit v1.2.3 From 0d92971dd6973d865a873c24df2d7bfe06ec4486 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 15 Jan 2010 12:21:37 +1000 Subject: drm/nouveau: fix thinko in nv04_instmem.c Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_instmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c index a20c206625a..a3b9563a6f6 100644 --- a/drivers/gpu/drm/nouveau/nv04_instmem.c +++ b/drivers/gpu/drm/nouveau/nv04_instmem.c @@ -30,7 +30,7 @@ nv04_instmem_determine_amount(struct drm_device *dev) * of vram. For now, only reserve a small piece until we know * more about what each chipset requires. */ - switch (dev_priv->chipset & 0xf0) { + switch (dev_priv->chipset) { case 0x40: case 0x47: case 0x49: -- cgit v1.2.3 From d051bbb22e9d8e87e2a5b8efb176d1bfd0f7feee Mon Sep 17 00:00:00 2001 From: Luca Barbieri Date: Sat, 16 Jan 2010 15:27:51 +0100 Subject: drm/nouveau: Acknowledge DMA_VTX_PROTECTION PGRAPH interrupts Currently Nouveau is unable to dismiss DMA_VTX_PROTECTION errors, which results in an infinite loop in the interrupt handler. These errors are caused both by bugs in the Gallium driver and by user-specified index buffers with out of bounds indices. By mmio-tracing the nVidia drivers, I found out how this is done. On DMA_VTX_PROTECTION, The nVidia driver reads the register 0x402000, always getting the value 4, and then writes 4 back to 0x402000. This patch adds that logic by reading 0x402000 and writing the same value back. It's unclear what should happen if the value read is not 4, and the current approach might not be the correct one. To test this, modify mesa/progs/trivial/vbo-drawrange.c, defining ELTOBJ to 1 and replacing indices with huge out of bounds integers. Without this patch, the GPU and/or kernel should lock up. With this patch, it should misrender as expected but not lock up. The errors are still logged since they are useful for development. This has been tested on NV49 and may not work on other cards. To find out how things work on other cards, run the aforementioned test using the blob with mmiotrace and grep for a read of the PGRAPH source register. Signed-off-by: Luca Barbieri Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 919a619ca7f..3b9bad66162 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -483,6 +483,13 @@ nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource) if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { if (nouveau_pgraph_intr_swmthd(dev, &trap)) unhandled = 1; + } else if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { + uint32_t v = nv_rd32(dev, 0x402000); + nv_wr32(dev, 0x402000, v); + + /* dump the error anyway for now: it's useful for + Gallium development */ + unhandled = 1; } else { unhandled = 1; } -- cgit v1.2.3 From 71666475018a3024fb49499096d26a9350349e8b Mon Sep 17 00:00:00 2001 From: Luca Barbieri Date: Sat, 16 Jan 2010 15:30:15 +0100 Subject: drm/nouveau: Evict buffers in VRAM before freeing sgdma Currently, we take down the sgdma engine without evicting all buffers from VRAM. The TTM device release will try to evict anything in VRAM to GART memory, but this will fail since sgdma has already been taken down. This causes an infinite loop in kernel mode on module unload. It usually doesn't happen because there aren't any buffer on close. However, if the GPU is locked up, this condition is easily triggered. This patch fixes it in the simplest way possible by cleaning VRAM right before cleaning SGDMA memory. Signed-off-by: Luca Barbieri Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 1 - drivers/gpu/drm/nouveau/nouveau_state.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 186f34b01f2..8f3a12f614e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -386,7 +386,6 @@ void nouveau_mem_close(struct drm_device *dev) nouveau_bo_unpin(dev_priv->vga_ram); nouveau_bo_ref(NULL, &dev_priv->vga_ram); - ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); ttm_bo_device_release(&dev_priv->ttm.bdev); nouveau_ttm_global_release(dev_priv); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 09b9a46dfc0..f2d0187ba15 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -525,6 +525,7 @@ static void nouveau_card_takedown(struct drm_device *dev) engine->mc.takedown(dev); mutex_lock(&dev->struct_mutex); + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); mutex_unlock(&dev->struct_mutex); nouveau_sgdma_takedown(dev); -- cgit v1.2.3 From 134f248bea4bf5c3169b4950eb49c6651b09eb0e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 18 Jan 2010 08:33:04 +1000 Subject: drm/nv50: fix alignment of per-channel fifo cache GPU pointer to the structure is shifted right by 10 bits, so we need to align to 1024 bytes, not 256. Reported-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_fifo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index 39caf167587..32b244bcb48 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -272,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) return ret; ramfc = chan->ramfc->gpuobj; - ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 256, + ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 1024, 0, &chan->cache); if (ret) return ret; -- cgit v1.2.3 From 58d65b84dee524b0a4a8b747b8eb8bbf2fb16d9d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 18 Jan 2010 08:52:35 +1000 Subject: drm/nv50: prevent accidently turning off encoders we're actually using On most cards the DisplayPort connector is created with 2 encoders sharing a single SOR (for native DP, and for DVI-over-DP). The previous logic for turning off unused encoders didn't take into account that we could have multiple drm_encoders on a single hw encoder and ended up turning off encoders that were actually being used still. This patch fixes that issue. We probably want to look at something a bit better later on, and only expose one drm_encoder per hw encoder block. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_crtc.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 118d3285fd8..40b7360841f 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -432,6 +432,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc) struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_encoder *encoder; + uint32_t dac = 0, sor = 0; NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); @@ -439,9 +440,28 @@ nv50_crtc_prepare(struct drm_crtc *crtc) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - if (drm_helper_encoder_in_use(encoder)) + if (!drm_helper_encoder_in_use(encoder)) continue; + if (nv_encoder->dcb->type == OUTPUT_ANALOG || + nv_encoder->dcb->type == OUTPUT_TV) + dac |= (1 << nv_encoder->or); + else + sor |= (1 << nv_encoder->or); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + + if (nv_encoder->dcb->type == OUTPUT_ANALOG || + nv_encoder->dcb->type == OUTPUT_TV) { + if (dac & (1 << nv_encoder->or)) + continue; + } else { + if (sor & (1 << nv_encoder->or)) + continue; + } + nv_encoder->disconnect(nv_encoder); } -- cgit v1.2.3 From f3d1ccc14f37a07614c67a270f05a8d94ec3667c Mon Sep 17 00:00:00 2001 From: Andrew Randrianasulu Date: Wed, 20 Jan 2010 11:36:30 -0500 Subject: drm/radeon/kms/r200: fix bug in CS parser The checks for CUBE and 3D textures were inverted. fixes fdo bug 24159 agd5f: added comments for clarity. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r200.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c index 20942127c46..ff1e0cd608b 100644 --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -371,13 +371,16 @@ int r200_packet0_check(struct radeon_cs_parser *p, case 5: case 6: case 7: + /* 1D/2D */ track->textures[i].tex_coord_type = 0; break; case 1: - track->textures[i].tex_coord_type = 1; + /* CUBE */ + track->textures[i].tex_coord_type = 2; break; case 2: - track->textures[i].tex_coord_type = 2; + /* 3D */ + track->textures[i].tex_coord_type = 1; break; } break; -- cgit v1.2.3 From 828153e29206196552c2cc34461ad7e5b93e3f22 Mon Sep 17 00:00:00 2001 From: Andrew Randrianasulu Date: Wed, 20 Jan 2010 11:56:07 -0500 Subject: drm/radeon/kms/r200: fix bug in CS parser Add missing vertex shader regs for r200. fixed fdo bug 26061 agd5f: use official reg names Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/reg_srcs/r200 | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/reg_srcs/r200 b/drivers/gpu/drm/radeon/reg_srcs/r200 index 6021c8849a1..c29ac434ac9 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r200 +++ b/drivers/gpu/drm/radeon/reg_srcs/r200 @@ -91,6 +91,8 @@ r200 0x3294 0x22b8 SE_TCL_TEX_CYL_WRAP_CTL 0x22c0 SE_TCL_UCP_VERT_BLEND_CNTL 0x22c4 SE_TCL_POINT_SPRITE_CNTL +0x22d0 SE_PVS_CNTL +0x22d4 SE_PVS_CONST_CNTL 0x2648 RE_POINTSIZE 0x26c0 RE_TOP_LEFT 0x26c4 RE_MISC -- cgit v1.2.3 From cf57fc7aa2ac61d02a29550b99db6a01ccd7917c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 18 Jan 2010 20:20:07 -0500 Subject: drm/radeon/kms/r100: fix bug in CS parser The first dword of PACKET3_3D_DRAW_IMMD maps to SE_VTX_FMT so the vertex size is part of the draw packet. This patch fixes a possible case where you have a command buffer that does not contain SE_VTX_FMT register write, but does contain PACKET3_3D_DRAW_IMMD. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 62b27bede65..11c9a3fe681 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -1504,6 +1504,7 @@ static int r100_packet3_check(struct radeon_cs_parser *p, DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); return -EINVAL; } + track->vtx_size = r100_get_vtx_size(radeon_get_ib_value(p, idx + 0)); track->vap_vf_cntl = radeon_get_ib_value(p, idx + 1); track->immd_dwords = pkt->count - 1; r = r100_cs_track_check(p->rdev, track); -- cgit v1.2.3 From 07bec2df01cde5590a1700b992d12de3f46b12bc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 13 Jan 2010 19:09:12 -0500 Subject: drm/radeon/kms: fix hardcoded mmio size in register functions newer asics have large mmio apertures Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index ab37dd0f2e7..c23278240a4 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -847,7 +847,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev, static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) { - if (reg < 0x10000) + if (reg < rdev->rmmio_size) return readl(((void __iomem *)rdev->rmmio) + reg); else { writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); @@ -857,7 +857,7 @@ static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) { - if (reg < 0x10000) + if (reg < rdev->rmmio_size) writel(v, ((void __iomem *)rdev->rmmio) + reg); else { writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); -- cgit v1.2.3 From 9f53e7931610cbd1715fd2d2c0f9a853e17f02d8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Jan 2010 12:38:48 -0500 Subject: drm/radeon/kms/atom: fix some parser bugs - add support for inline src params - fix shift_left/shift_right and shl/shr ops shift_* ops use inline src params, shl/r use full params - fix mask op (uses inline params) Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 90 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 16 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 388140a7e65..9a3378184e1 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -385,6 +385,32 @@ static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr) return atom_get_src_int(ctx, attr, ptr, NULL, 1); } +static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr) +{ + uint32_t val = 0xCDCDCDCD; + + switch (align) { + case ATOM_SRC_DWORD: + val = U32(*ptr); + (*ptr) += 4; + break; + case ATOM_SRC_WORD0: + case ATOM_SRC_WORD8: + case ATOM_SRC_WORD16: + val = U16(*ptr); + (*ptr) += 2; + break; + case ATOM_SRC_BYTE0: + case ATOM_SRC_BYTE8: + case ATOM_SRC_BYTE16: + case ATOM_SRC_BYTE24: + val = U8(*ptr); + (*ptr)++; + break; + } + return val; +} + static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t *saved, int print) { @@ -677,9 +703,9 @@ static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); SDEBUG(" src1: "); - src1 = atom_get_src(ctx, attr, ptr); + src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); SDEBUG(" src2: "); - src2 = atom_get_src(ctx, attr, ptr); + src2 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); dst &= src1; dst |= src2; SDEBUG(" dst: "); @@ -809,6 +835,38 @@ static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg) SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block); } +static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++), shift; + uint32_t saved, dst; + int dptr = *ptr; + attr &= 0x38; + attr |= atom_def_dst[attr >> 3] << 6; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); + SDEBUG(" shift: %d\n", shift); + dst <<= shift; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++), shift; + uint32_t saved, dst; + int dptr = *ptr; + attr &= 0x38; + attr |= atom_def_dst[attr >> 3] << 6; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); + SDEBUG(" shift: %d\n", shift); + dst >>= shift; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) { uint8_t attr = U8((*ptr)++), shift; @@ -818,7 +876,7 @@ static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) attr |= atom_def_dst[attr >> 3] << 6; SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - shift = U8((*ptr)++); + shift = atom_get_src(ctx, attr, ptr); SDEBUG(" shift: %d\n", shift); dst <<= shift; SDEBUG(" dst: "); @@ -834,7 +892,7 @@ static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) attr |= atom_def_dst[attr >> 3] << 6; SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - shift = U8((*ptr)++); + shift = atom_get_src(ctx, attr, ptr); SDEBUG(" shift: %d\n", shift); dst >>= shift; SDEBUG(" dst: "); @@ -937,18 +995,18 @@ static struct { atom_op_or, ATOM_ARG_FB}, { atom_op_or, ATOM_ARG_PLL}, { atom_op_or, ATOM_ARG_MC}, { - atom_op_shl, ATOM_ARG_REG}, { - atom_op_shl, ATOM_ARG_PS}, { - atom_op_shl, ATOM_ARG_WS}, { - atom_op_shl, ATOM_ARG_FB}, { - atom_op_shl, ATOM_ARG_PLL}, { - atom_op_shl, ATOM_ARG_MC}, { - atom_op_shr, ATOM_ARG_REG}, { - atom_op_shr, ATOM_ARG_PS}, { - atom_op_shr, ATOM_ARG_WS}, { - atom_op_shr, ATOM_ARG_FB}, { - atom_op_shr, ATOM_ARG_PLL}, { - atom_op_shr, ATOM_ARG_MC}, { + atom_op_shift_left, ATOM_ARG_REG}, { + atom_op_shift_left, ATOM_ARG_PS}, { + atom_op_shift_left, ATOM_ARG_WS}, { + atom_op_shift_left, ATOM_ARG_FB}, { + atom_op_shift_left, ATOM_ARG_PLL}, { + atom_op_shift_left, ATOM_ARG_MC}, { + atom_op_shift_right, ATOM_ARG_REG}, { + atom_op_shift_right, ATOM_ARG_PS}, { + atom_op_shift_right, ATOM_ARG_WS}, { + atom_op_shift_right, ATOM_ARG_FB}, { + atom_op_shift_right, ATOM_ARG_PLL}, { + atom_op_shift_right, ATOM_ARG_MC}, { atom_op_mul, ATOM_ARG_REG}, { atom_op_mul, ATOM_ARG_PS}, { atom_op_mul, ATOM_ARG_WS}, { -- cgit v1.2.3 From e2f8e87089427d3a203538dc73058b90e82b11f6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Jan 2010 12:45:29 -0500 Subject: drm/radeon/kms/atom: upstream parser updates Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 8 +++++++- drivers/gpu/drm/radeon/atom.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 9a3378184e1..cf3126108a4 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -246,6 +246,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, case ATOM_WS_ATTRIBUTES: val = gctx->io_attr; break; + case ATOM_WS_REGPTR: + val = gctx->reg_block; + break; default: val = ctx->ws[idx]; } @@ -508,6 +511,9 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, case ATOM_WS_ATTRIBUTES: gctx->io_attr = val; break; + case ATOM_WS_REGPTR: + gctx->reg_block = val; + break; default: ctx->ws[idx] = val; } @@ -705,7 +711,7 @@ static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) SDEBUG(" src1: "); src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); SDEBUG(" src2: "); - src2 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); + src2 = atom_get_src(ctx, attr, ptr); dst &= src1; dst |= src2; SDEBUG(" dst: "); diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index 47fd943f6d1..bc73781423a 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -91,6 +91,7 @@ #define ATOM_WS_AND_MASK 0x45 #define ATOM_WS_FB_WINDOW 0x46 #define ATOM_WS_ATTRIBUTES 0x47 +#define ATOM_WS_REGPTR 0x48 #define ATOM_IIO_NOP 0 #define ATOM_IIO_START 1 -- cgit v1.2.3 From 54f088a9603dbee88809cb2ddfd8dc1ef8a74be5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Jan 2010 16:34:01 -0500 Subject: drm/radeon/kms: fix atombios_crtc_set_base Make it call the proper backend depending on the GPU family. Right now r4xx cards with atombios modesetting enabled were using the avivo crtc base code. This also allows us to add support for new asics more easily. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 260fcf59f00..a60610271af 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -575,8 +575,8 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } -int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) +static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; @@ -706,6 +706,18 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, return 0; } +int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + + if (ASIC_IS_AVIVO(rdev)) + return avivo_crtc_set_base(crtc, x, y, old_fb); + else + return radeon_crtc_set_base(crtc, x, y, old_fb); +} + int atombios_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -727,7 +739,7 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, else { if (radeon_crtc->crtc_id == 0) atombios_set_crtc_dtd_timing(crtc, adjusted_mode); - radeon_crtc_set_base(crtc, x, y, old_fb); + atombios_crtc_set_base(crtc, x, y, old_fb); radeon_legacy_atom_set_surface(crtc); } atombios_overscan_setup(crtc, mode, adjusted_mode); -- cgit v1.2.3 From 615e0cb67968c94fd9e53797985843a5b816dec4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 20 Jan 2010 16:22:53 -0500 Subject: drm/radeon/kms/r4xx: cleanup atom path most of radeon_legacy_atom_set_surface() is taken care of in atombios_set_base(), so remove the duplicate setup and move the remaining bits (DISP_MERGE setup and FP2 sync) to atombios_crtc.c where they are used. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 26 +++++++++++- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 63 ----------------------------- drivers/gpu/drm/radeon/radeon_mode.h | 1 - 3 files changed, 25 insertions(+), 65 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index a60610271af..e098bd0cbd2 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -718,6 +718,30 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, return radeon_crtc_set_base(crtc, x, y, old_fb); } +/* properly set additional regs when using atombios */ +static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + u32 disp_merge_cntl; + + switch (radeon_crtc->crtc_id) { + case 0: + disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); + break; + case 1: + disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; + WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); + WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); + WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); + break; + } +} + int atombios_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -740,7 +764,7 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, if (radeon_crtc->crtc_id == 0) atombios_set_crtc_dtd_timing(crtc, adjusted_mode); atombios_crtc_set_base(crtc, x, y, old_fb); - radeon_legacy_atom_set_surface(crtc); + radeon_legacy_atom_fixup(crtc); } atombios_overscan_setup(crtc, mode, adjusted_mode); atombios_scaler_setup(crtc); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index cc27485a07a..762e07b0895 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -339,69 +339,6 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } } -/* properly set crtc bpp when using atombios */ -void radeon_legacy_atom_set_surface(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - int format; - uint32_t crtc_gen_cntl; - uint32_t disp_merge_cntl; - uint32_t crtc_pitch; - - switch (crtc->fb->bits_per_pixel) { - case 8: - format = 2; - break; - case 15: /* 555 */ - format = 3; - break; - case 16: /* 565 */ - format = 4; - break; - case 24: /* RGB */ - format = 5; - break; - case 32: /* xRGB */ - format = 6; - break; - default: - return; - } - - crtc_pitch = ((((crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8)) * crtc->fb->bits_per_pixel) + - ((crtc->fb->bits_per_pixel * 8) - 1)) / - (crtc->fb->bits_per_pixel * 8)); - crtc_pitch |= crtc_pitch << 16; - - WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); - - switch (radeon_crtc->crtc_id) { - case 0: - disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); - disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; - WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); - - crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0xfffff0ff; - crtc_gen_cntl |= (format << 8); - crtc_gen_cntl |= RADEON_CRTC_EXT_DISP_EN; - WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); - break; - case 1: - disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); - disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; - WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); - - crtc_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0xfffff0ff; - crtc_gen_cntl |= (format << 8); - WREG32(RADEON_CRTC2_GEN_CNTL, crtc_gen_cntl); - WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); - WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); - break; - } -} - int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 91cb041cb40..eb19b3022b0 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -453,7 +453,6 @@ extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode); extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); -extern void radeon_legacy_atom_set_surface(struct drm_crtc *crtc); extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, -- cgit v1.2.3 From 0c45249f419d8b86abe0e51c6627ca4b085e8c23 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 15 Jan 2010 14:44:37 +0100 Subject: drm/radeon/kms: r600/r700 disable irq at suspend To avoid hw doing anythings after we disabled PCIE GART, fully disable IRQ at suspend. Also cleanup a bit the ih structure and process function. Signed-off-by: Jerome Glisse Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 30 ++++++++++++++---------------- drivers/gpu/drm/radeon/radeon.h | 4 ++-- drivers/gpu/drm/radeon/rv770.c | 1 + 3 files changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index b3713f61964..a6a23a9f9a5 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1954,6 +1954,7 @@ int r600_suspend(struct radeon_device *rdev) /* FIXME: we should wait for ring to be empty */ r600_cp_stop(rdev); rdev->cp.ready = false; + r600_irq_suspend(rdev); r600_wb_disable(rdev); r600_pcie_gart_disable(rdev); /* unpin shaders bo */ @@ -2200,14 +2201,14 @@ void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size) rb_bufsz = drm_order(ring_size / 4); ring_size = (1 << rb_bufsz) * 4; rdev->ih.ring_size = ring_size; - rdev->ih.align_mask = 4 - 1; + rdev->ih.ptr_mask = rdev->ih.ring_size - 1; + rdev->ih.rptr = 0; } -static int r600_ih_ring_alloc(struct radeon_device *rdev, unsigned ring_size) +static int r600_ih_ring_alloc(struct radeon_device *rdev) { int r; - rdev->ih.ring_size = ring_size; /* Allocate ring buffer */ if (rdev->ih.ring_obj == NULL) { r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size, @@ -2237,9 +2238,6 @@ static int r600_ih_ring_alloc(struct radeon_device *rdev, unsigned ring_size) return r; } } - rdev->ih.ptr_mask = (rdev->cp.ring_size / 4) - 1; - rdev->ih.rptr = 0; - return 0; } @@ -2389,7 +2387,7 @@ int r600_irq_init(struct radeon_device *rdev) u32 interrupt_cntl, ih_cntl, ih_rb_cntl; /* allocate ring */ - ret = r600_ih_ring_alloc(rdev, rdev->ih.ring_size); + ret = r600_ih_ring_alloc(rdev); if (ret) return ret; @@ -2452,10 +2450,15 @@ int r600_irq_init(struct radeon_device *rdev) return ret; } -void r600_irq_fini(struct radeon_device *rdev) +void r600_irq_suspend(struct radeon_device *rdev) { r600_disable_interrupts(rdev); r600_rlc_stop(rdev); +} + +void r600_irq_fini(struct radeon_device *rdev) +{ + r600_irq_suspend(rdev); r600_ih_ring_fini(rdev); } @@ -2648,9 +2651,7 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev) tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); } - wptr = wptr & WPTR_OFFSET_MASK; - - return wptr; + return (wptr & rdev->ih.ptr_mask); } /* r600 IV Ring @@ -2686,7 +2687,6 @@ int r600_irq_process(struct radeon_device *rdev) u32 wptr = r600_get_ih_wptr(rdev); u32 rptr = rdev->ih.rptr; u32 src_id, src_data; - u32 last_entry = rdev->ih.ring_size - 16; u32 ring_index, disp_int, disp_int_cont, disp_int_cont2; unsigned long flags; bool queue_hotplug = false; @@ -2820,10 +2820,8 @@ restart_ih: } /* wptr/rptr are in bytes! */ - if (rptr == last_entry) - rptr = 0; - else - rptr += 16; + rptr += 16; + rptr &= rdev->ih.ptr_mask; } /* make sure wptr hasn't changed while processing */ wptr = r600_get_ih_wptr(rdev); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index c23278240a4..09c655f3843 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -410,7 +410,6 @@ struct r600_ih { unsigned wptr_old; unsigned ring_size; uint64_t gpu_addr; - uint32_t align_mask; uint32_t ptr_mask; spinlock_t lock; bool enabled; @@ -1162,7 +1161,8 @@ extern int r600_irq_init(struct radeon_device *rdev); extern void r600_irq_fini(struct radeon_device *rdev); extern void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size); extern int r600_irq_set(struct radeon_device *rdev); - +extern void r600_irq_suspend(struct radeon_device *rdev); +/* r600 audio */ extern int r600_audio_init(struct radeon_device *rdev); extern int r600_audio_tmds_index(struct drm_encoder *encoder); extern void r600_audio_set_clock(struct drm_encoder *encoder, int clock); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index eb065bbe1ee..c8cf2bc2b91 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -968,6 +968,7 @@ int rv770_suspend(struct radeon_device *rdev) /* FIXME: we should wait for ring to be empty */ r700_cp_stop(rdev); rdev->cp.ready = false; + r600_irq_suspend(rdev); r600_wb_disable(rdev); rv770_pcie_gart_disable(rdev); /* unpin shaders bo */ -- cgit v1.2.3 From 79c2bbc505751bb5130ac753251fc9a0eb37bb12 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 15 Jan 2010 14:44:38 +0100 Subject: drm/radeon/kms: r600/r700 don't process IRQ if not initialized In some rare case the wptr returned from the hw wasn't 0 and leaded to trick r600_process_irq that their were irq to process. Add a check to bail out if irq hasn't been initialized this will avoid oops provoqued by the rare wptr != 0 on initialization. Signed-off-by: Jerome Glisse Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index a6a23a9f9a5..0f9a8c6788a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2473,8 +2473,12 @@ int r600_irq_set(struct radeon_device *rdev) return -EINVAL; } /* don't enable anything if the ih is disabled */ - if (!rdev->ih.enabled) + if (!rdev->ih.enabled) { + r600_disable_interrupts(rdev); + /* force the active interrupt state to all disabled */ + r600_disable_interrupt_state(rdev); return 0; + } if (ASIC_IS_DCE3(rdev)) { hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; @@ -2692,6 +2696,8 @@ int r600_irq_process(struct radeon_device *rdev) bool queue_hotplug = false; DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + if (!rdev->ih.enabled) + return IRQ_NONE; spin_lock_irqsave(&rdev->ih.lock, flags); -- cgit v1.2.3 From 7924e5eb8fe422d6b1ce3b3e2be749a480dfcdd9 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 15 Jan 2010 14:44:39 +0100 Subject: drm/radeon/kms: r600 handle irq vector ring overflow In some rare case i faced an irq overflow quickly followed by a GPU lockup (hard hang) this patch try to deal with irq vector ring overflow, so far haven't been able to reproduce it with the patch. Signed-off-by: Jerome Glisse Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 0f9a8c6788a..bb9115bdc3a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2648,9 +2648,13 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { - WARN_ON(1); - /* XXX deal with overflow */ - DRM_ERROR("IH RB overflow\n"); + /* When a ring buffer overflow happen start parsing interrupt + * from the last not overwritten vector (wptr + 16). Hopefully + * this should allow us to catchup. + */ + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", + wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); -- cgit v1.2.3 From 7e71c9e2e7704ebf044d4a964e02fbd2098a173f Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 17 Jan 2010 21:21:41 +0100 Subject: drm/radeon/kms: Forbid creation of framebuffer with no valid GEM object This will avoid oops if at later point the fb is use. Trying to create a framebuffer with no valid GEM object is bogus and should be forbidden as this patch does. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 49f3c69cf24..f899320f0a6 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -715,7 +715,11 @@ radeon_user_framebuffer_create(struct drm_device *dev, struct drm_gem_object *obj; obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); - + if (obj == NULL) { + dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, " + "can't create framebuffer\n", mode_cmd->handle); + return NULL; + } return radeon_framebuffer_create(dev, mode_cmd, obj); } -- cgit v1.2.3 From db96380ea26fcc31ab37189aedeabd12894b1431 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 17 Jan 2010 21:21:56 +0100 Subject: drm/radeon/kms: r600/r700 don't test ib if ib initialization fails If ib initialization failed don't try to test ib as it will result in an oops (accessing NULL ib buffer ptr). Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 13 +++++++------ drivers/gpu/drm/radeon/rv770.c | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index bb9115bdc3a..d0bd117a463 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2064,13 +2064,14 @@ int r600_init(struct radeon_device *rdev) if (rdev->accel_working) { r = radeon_ib_pool_init(rdev); if (r) { - DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r); - rdev->accel_working = false; - } - r = r600_ib_test(rdev); - if (r) { - DRM_ERROR("radeon: failed testing IB (%d).\n", r); + dev_err(rdev->dev, "IB initialization failed (%d).\n", r); rdev->accel_working = false; + } else { + r = r600_ib_test(rdev); + if (r) { + dev_err(rdev->dev, "IB test failed (%d).\n", r); + rdev->accel_working = false; + } } } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index c8cf2bc2b91..cf8f2b17d62 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1075,13 +1075,14 @@ int rv770_init(struct radeon_device *rdev) if (rdev->accel_working) { r = radeon_ib_pool_init(rdev); if (r) { - DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r); - rdev->accel_working = false; - } - r = r600_ib_test(rdev); - if (r) { - DRM_ERROR("radeon: failed testing IB (%d).\n", r); + dev_err(rdev->dev, "IB initialization failed (%d).\n", r); rdev->accel_working = false; + } else { + r = r600_ib_test(rdev); + if (r) { + dev_err(rdev->dev, "IB test failed (%d).\n", r); + rdev->accel_working = false; + } } } return 0; -- cgit v1.2.3 From c8c15ff1e90bfc4a2db1ba77a01b3b2783e723fc Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 18 Jan 2010 13:01:36 +0100 Subject: drm/radeon: r6xx/r7xx possible security issue, system ram access This patch workaround a possible security issue which can allow user to abuse drm on r6xx/r7xx hw to access any system ram memory. This patch doesn't break userspace, it detect "valid" old use of CB_COLOR[0-7]_FRAG & CB_COLOR[0-7]_TILE registers and overwritte the address these registers are pointing to with the one of the last color buffer. This workaround will work for old mesa & xf86-video-ati and any old user which did use similar register programming pattern as those (we expect that there is no others user of those ioctl except possibly a malicious one). This patch add a warning if it detects such usage, warning encourage people to update their mesa & xf86-video-ati. New userspace will submit proper relocation. Fix for xf86-video-ati / mesa (this kernel patch is enough to prevent abuse, fix for userspace are to set proper cs stream and avoid kernel warning) : http://cgit.freedesktop.org/xorg/driver/xf86-video-ati/commit/?id=95d63e408cc88b6934bec84a0b1ef94dfe8bee7b http://cgit.freedesktop.org/mesa/mesa/commit/?id=46dc6fd3ed5ef96cda53641a97bc68c3bc104a9f Abusing this register to perform system ram memory is not easy, here is outline on how it could be achieve. First attacker must have access to the drm device and be able to submit command stream throught cs ioctl. Then attacker must build a proper command stream for r6xx/r7xx hw which will abuse the FRAG or TILE buffer to overwrite the GPU GART which is in VRAM. To achieve so attacker as to setup CB_COLOR[0-7]_FRAG or CB_COLOR[0-7]_TILE to point to the GPU GART, then it has to find a way to write predictable value into those buffer (with little cleverness i believe this can be done but this is an hard task). Once attacker have such program it can overwritte GPU GART to program GPU gart to point anywhere in system memory. It then can reusse same method as he used to reprogram GART to overwritte the system ram through the GART mapping. In the process the attacker has to be carefull to not overwritte any sensitive area of the GART table, like ring or IB gart entry as it will more then likely lead to GPU lockup. Bottom line is that i think it's very hard to use this flaw to get system ram access but in theory one can achieve so. Side note: I am not aware of anyone ever using the GPU as an attack vector, nevertheless we take great care in the opensource driver to try to detect and forbid malicious use of GPU. I don't think the closed source driver are as cautious as we are. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_cs.c | 83 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/r600d.h | 25 ++++++++++++ drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_cs.c | 1 + 4 files changed, 110 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 44060b92d9e..9cc4ba8d03d 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -36,6 +36,10 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p, typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**); static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm; +struct r600_cs_track { + u32 cb_color0_base_last; +}; + /** * r600_cs_packet_parse() - parse cp packet and point ib index to next packet * @parser: parser structure holding parsing context. @@ -176,6 +180,28 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p, return 0; } +/** + * r600_cs_packet_next_is_pkt3_nop() - test if next packet is packet3 nop for reloc + * @parser: parser structure holding parsing context. + * + * Check next packet is relocation packet3, do bo validation and compute + * GPU offset using the provided start. + **/ +static inline int r600_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet p3reloc; + int r; + + r = r600_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return 0; + } + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + return 0; + } + return 1; +} + /** * r600_cs_packet_next_vline() - parse userspace VLINE packet * @parser: parser structure holding parsing context. @@ -337,6 +363,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt) { struct radeon_cs_reloc *reloc; + struct r600_cs_track *track; volatile u32 *ib; unsigned idx; unsigned i; @@ -344,6 +371,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p, int r; u32 idx_value; + track = (struct r600_cs_track *)p->track; ib = p->ib->ptr; idx = pkt->idx + 1; idx_value = radeon_get_ib_value(p, idx); @@ -503,9 +531,60 @@ static int r600_packet3_check(struct radeon_cs_parser *p, for (i = 0; i < pkt->count; i++) { reg = start_reg + (4 * i); switch (reg) { + /* This register were added late, there is userspace + * which does provide relocation for those but set + * 0 offset. In order to avoid breaking old userspace + * we detect this and set address to point to last + * CB_COLOR0_BASE, note that if userspace doesn't set + * CB_COLOR0_BASE before this register we will report + * error. Old userspace always set CB_COLOR0_BASE + * before any of this. + */ + case R_0280E0_CB_COLOR0_FRAG: + case R_0280E4_CB_COLOR1_FRAG: + case R_0280E8_CB_COLOR2_FRAG: + case R_0280EC_CB_COLOR3_FRAG: + case R_0280F0_CB_COLOR4_FRAG: + case R_0280F4_CB_COLOR5_FRAG: + case R_0280F8_CB_COLOR6_FRAG: + case R_0280FC_CB_COLOR7_FRAG: + case R_0280C0_CB_COLOR0_TILE: + case R_0280C4_CB_COLOR1_TILE: + case R_0280C8_CB_COLOR2_TILE: + case R_0280CC_CB_COLOR3_TILE: + case R_0280D0_CB_COLOR4_TILE: + case R_0280D4_CB_COLOR5_TILE: + case R_0280D8_CB_COLOR6_TILE: + case R_0280DC_CB_COLOR7_TILE: + if (!r600_cs_packet_next_is_pkt3_nop(p)) { + if (!track->cb_color0_base_last) { + dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg); + return -EINVAL; + } + ib[idx+1+i] = track->cb_color0_base_last; + printk_once(KERN_WARNING "You have old & broken userspace " + "please consider updating mesa & xf86-video-ati\n"); + } else { + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); + return -EINVAL; + } + ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + } + break; case DB_DEPTH_BASE: case DB_HTILE_DATA_BASE: case CB_COLOR0_BASE: + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color0_base_last = ib[idx+1+i]; + break; case CB_COLOR1_BASE: case CB_COLOR2_BASE: case CB_COLOR3_BASE: @@ -678,8 +757,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p, int r600_cs_parse(struct radeon_cs_parser *p) { struct radeon_cs_packet pkt; + struct r600_cs_track *track; int r; + track = kzalloc(sizeof(*track), GFP_KERNEL); + p->track = track; do { r = r600_cs_packet_parse(p, &pkt, p->idx); if (r) { @@ -757,6 +839,7 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp, /* initialize parser */ memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; + parser.dev = &dev->pdev->dev; parser.rdev = NULL; parser.family = family; parser.ib = &fake_ib; diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 05894edadab..30480881aed 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -882,4 +882,29 @@ #define S_000E60_SOFT_RESET_VMC(x) (((x) & 1) << 17) #define R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480 + +#define R_0280E0_CB_COLOR0_FRAG 0x0280E0 +#define S_0280E0_BASE_256B(x) (((x) & 0xFFFFFFFF) << 0) +#define G_0280E0_BASE_256B(x) (((x) >> 0) & 0xFFFFFFFF) +#define C_0280E0_BASE_256B 0x00000000 +#define R_0280E4_CB_COLOR1_FRAG 0x0280E4 +#define R_0280E8_CB_COLOR2_FRAG 0x0280E8 +#define R_0280EC_CB_COLOR3_FRAG 0x0280EC +#define R_0280F0_CB_COLOR4_FRAG 0x0280F0 +#define R_0280F4_CB_COLOR5_FRAG 0x0280F4 +#define R_0280F8_CB_COLOR6_FRAG 0x0280F8 +#define R_0280FC_CB_COLOR7_FRAG 0x0280FC +#define R_0280C0_CB_COLOR0_TILE 0x0280C0 +#define S_0280C0_BASE_256B(x) (((x) & 0xFFFFFFFF) << 0) +#define G_0280C0_BASE_256B(x) (((x) >> 0) & 0xFFFFFFFF) +#define C_0280C0_BASE_256B 0x00000000 +#define R_0280C4_CB_COLOR1_TILE 0x0280C4 +#define R_0280C8_CB_COLOR2_TILE 0x0280C8 +#define R_0280CC_CB_COLOR3_TILE 0x0280CC +#define R_0280D0_CB_COLOR4_TILE 0x0280D0 +#define R_0280D4_CB_COLOR5_TILE 0x0280D4 +#define R_0280D8_CB_COLOR6_TILE 0x0280D8 +#define R_0280DC_CB_COLOR7_TILE 0x0280DC + + #endif diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 09c655f3843..f7df1a7e441 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -464,6 +464,7 @@ struct radeon_cs_chunk { }; struct radeon_cs_parser { + struct device *dev; struct radeon_device *rdev; struct drm_file *filp; /* chunks */ diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 65590a0f1d9..1496cb8658e 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -231,6 +231,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; parser.rdev = rdev; + parser.dev = rdev->dev; r = radeon_cs_parser_init(&parser, data); if (r) { DRM_ERROR("Failed to initialize parser !\n"); -- cgit v1.2.3 From a348c84d953f61c776e53cde0a63a4e407a23c18 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 21 Jan 2010 16:50:30 -0500 Subject: drm/radeon/kms/atom: fix crtc lock ordering This makes crtc_prepare and crtc_commit match. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index e098bd0cbd2..7af5c1f7b6d 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -782,8 +782,8 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, static void atombios_crtc_prepare(struct drm_crtc *crtc) { - atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); atombios_lock_crtc(crtc, 1); + atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); } static void atombios_crtc_commit(struct drm_crtc *crtc) -- cgit v1.2.3 From fc10332b8ac5ca32d11f898027d84c007543bd80 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Jan 2010 17:16:10 -0500 Subject: drm/radeon/kms: clean up pll struct - add a new flag for fixed post div - pull the pll flags into the struct Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 35 ++++++++++++++--------------- drivers/gpu/drm/radeon/radeon_display.c | 35 ++++++++++++++++------------- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 14 ++++++------ drivers/gpu/drm/radeon/radeon_mode.h | 27 +++++++++++++++------- 4 files changed, 62 insertions(+), 49 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 7af5c1f7b6d..7a8cdf2813d 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -426,7 +426,11 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) uint32_t adjusted_clock; uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; struct radeon_pll *pll; - int pll_flags = 0; + + if (radeon_crtc->crtc_id == 0) + pll = &rdev->clock.p1pll; + else + pll = &rdev->clock.p2pll; memset(&args, 0, sizeof(args)); @@ -434,20 +438,20 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) if ((rdev->family == CHIP_RS600) || (rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) - pll_flags |= (RADEON_PLL_USE_FRAC_FB_DIV | - RADEON_PLL_PREFER_CLOSEST_LOWER); + pll->flags |= (RADEON_PLL_USE_FRAC_FB_DIV | + RADEON_PLL_PREFER_CLOSEST_LOWER); if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ - pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else - pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; } else { - pll_flags |= RADEON_PLL_LEGACY; + pll->flags |= RADEON_PLL_LEGACY; if (mode->clock > 200000) /* range limits??? */ - pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else - pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; } @@ -456,10 +460,10 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) if (!ASIC_IS_AVIVO(rdev)) { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) - pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) - pll_flags |= RADEON_PLL_USE_REF_DIV; + pll->flags |= RADEON_PLL_USE_REF_DIV; } radeon_encoder = to_radeon_encoder(encoder); break; @@ -494,23 +498,18 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) adjusted_clock = mode->clock; } - if (radeon_crtc->crtc_id == 0) - pll = &rdev->clock.p1pll; - else - pll = &rdev->clock.p2pll; - if (ASIC_IS_AVIVO(rdev)) { if (radeon_new_pll) radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div, pll_flags); + &ref_div, &post_div); else radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div, pll_flags); + &ref_div, &post_div); } else radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div, pll_flags); + &ref_div, &post_div); index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index f899320f0a6..6a92f994cc2 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -411,11 +411,12 @@ void radeon_compute_pll(struct radeon_pll *pll, uint32_t *fb_div_p, uint32_t *frac_fb_div_p, uint32_t *ref_div_p, - uint32_t *post_div_p, - int flags) + uint32_t *post_div_p) { uint32_t min_ref_div = pll->min_ref_div; uint32_t max_ref_div = pll->max_ref_div; + uint32_t min_post_div = pll->min_post_div; + uint32_t max_post_div = pll->max_post_div; uint32_t min_fractional_feed_div = 0; uint32_t max_fractional_feed_div = 0; uint32_t best_vco = pll->best_vco; @@ -431,7 +432,7 @@ void radeon_compute_pll(struct radeon_pll *pll, DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div); freq = freq * 1000; - if (flags & RADEON_PLL_USE_REF_DIV) + if (pll->flags & RADEON_PLL_USE_REF_DIV) min_ref_div = max_ref_div = pll->reference_div; else { while (min_ref_div < max_ref_div-1) { @@ -446,19 +447,22 @@ void radeon_compute_pll(struct radeon_pll *pll, } } - if (flags & RADEON_PLL_USE_FRAC_FB_DIV) { + if (pll->flags & RADEON_PLL_USE_POST_DIV) + min_post_div = max_post_div = pll->post_div; + + if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { min_fractional_feed_div = pll->min_frac_feedback_div; max_fractional_feed_div = pll->max_frac_feedback_div; } - for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) { + for (post_div = min_post_div; post_div <= max_post_div; ++post_div) { uint32_t ref_div; - if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) + if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) continue; /* legacy radeons only have a few post_divs */ - if (flags & RADEON_PLL_LEGACY) { + if (pll->flags & RADEON_PLL_LEGACY) { if ((post_div == 5) || (post_div == 7) || (post_div == 9) || @@ -505,7 +509,7 @@ void radeon_compute_pll(struct radeon_pll *pll, tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div; current_freq = radeon_div(tmp, ref_div * post_div); - if (flags & RADEON_PLL_PREFER_CLOSEST_LOWER) { + if (pll->flags & RADEON_PLL_PREFER_CLOSEST_LOWER) { error = freq - current_freq; error = error < 0 ? 0xffffffff : error; } else @@ -532,12 +536,12 @@ void radeon_compute_pll(struct radeon_pll *pll, best_freq = current_freq; best_error = error; best_vco_diff = vco_diff; - } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || - ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) || - ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) || - ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) || - ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) || - ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) { + } else if (((pll->flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || + ((pll->flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) || + ((pll->flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) || + ((pll->flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) || + ((pll->flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) || + ((pll->flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) { best_post_div = post_div; best_ref_div = ref_div; best_feedback_div = feedback_div; @@ -573,8 +577,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, uint32_t *fb_div_p, uint32_t *frac_fb_div_p, uint32_t *ref_div_p, - uint32_t *post_div_p, - int flags) + uint32_t *post_div_p) { fixed20_12 m, n, frac_n, p, f_vco, f_pclk, best_freq; fixed20_12 pll_out_max, pll_out_min; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 762e07b0895..b6d8081e124 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -692,7 +692,6 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) uint32_t post_divider = 0; uint32_t freq = 0; uint8_t pll_gain; - int pll_flags = RADEON_PLL_LEGACY; bool use_bios_divs = false; /* PLL registers */ uint32_t pll_ref_div = 0; @@ -726,10 +725,12 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) else pll = &rdev->clock.p1pll; + pll->flags = RADEON_PLL_LEGACY; + if (mode->clock > 200000) /* range limits??? */ - pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else - pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { @@ -741,7 +742,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) } if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) - pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { if (!rdev->is_atom_bios) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -756,7 +757,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) } } } - pll_flags |= RADEON_PLL_USE_REF_DIV; + pll->flags |= RADEON_PLL_USE_REF_DIV; } } } @@ -766,8 +767,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) if (!use_bios_divs) { radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &frac_fb_div, - &reference_div, &post_divider, - pll_flags); + &reference_div, &post_divider); for (post_div = &post_divs[0]; post_div->divider; ++post_div) { if (post_div->divider == post_divider) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index eb19b3022b0..96b851f92f4 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -125,16 +125,24 @@ struct radeon_tmds_pll { #define RADEON_PLL_PREFER_HIGH_POST_DIV (1 << 9) #define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10) #define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11) +#define RADEON_PLL_USE_POST_DIV (1 << 12) struct radeon_pll { - uint16_t reference_freq; - uint16_t reference_div; + /* reference frequency */ + uint32_t reference_freq; + + /* fixed dividers */ + uint32_t reference_div; + uint32_t post_div; + + /* pll in/out limits */ uint32_t pll_in_min; uint32_t pll_in_max; uint32_t pll_out_min; uint32_t pll_out_max; - uint16_t xclk; + uint32_t best_vco; + /* divider limits */ uint32_t min_ref_div; uint32_t max_ref_div; uint32_t min_post_div; @@ -143,7 +151,12 @@ struct radeon_pll { uint32_t max_feedback_div; uint32_t min_frac_feedback_div; uint32_t max_frac_feedback_div; - uint32_t best_vco; + + /* flags for the current clock */ + uint32_t flags; + + /* pll id */ + uint32_t id; }; struct radeon_i2c_chan { @@ -417,8 +430,7 @@ extern void radeon_compute_pll(struct radeon_pll *pll, uint32_t *fb_div_p, uint32_t *frac_fb_div_p, uint32_t *ref_div_p, - uint32_t *post_div_p, - int flags); + uint32_t *post_div_p); extern void radeon_compute_pll_avivo(struct radeon_pll *pll, uint64_t freq, @@ -426,8 +438,7 @@ extern void radeon_compute_pll_avivo(struct radeon_pll *pll, uint32_t *fb_div_p, uint32_t *frac_fb_div_p, uint32_t *ref_div_p, - uint32_t *post_div_p, - int flags); + uint32_t *post_div_p); extern void radeon_setup_encoder_clones(struct drm_device *dev); -- cgit v1.2.3 From 4eaeca33512b9774c25507b9a9bdcfe3791a5cc5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Jan 2010 17:32:27 -0500 Subject: drm/radeon/kms: clean up atombios pll code - split pll adjust into a separate function - use a union for SetPixelClock params Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 196 ++++++++++++++++++++------------- 1 file changed, 121 insertions(+), 75 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 7a8cdf2813d..e619aca5423 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -409,30 +409,22 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable) } } -void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +union adjust_pixel_clock { + ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; +}; + +static u32 atombios_adjust_pll(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct radeon_pll *pll) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder = NULL; struct radeon_encoder *radeon_encoder = NULL; - uint8_t frev, crev; - int index; - SET_PIXEL_CLOCK_PS_ALLOCATION args; - PIXEL_CLOCK_PARAMETERS *spc1_ptr; - PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr; - PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr; - uint32_t pll_clock = mode->clock; - uint32_t adjusted_clock; - uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; - struct radeon_pll *pll; + u32 adjusted_clock = mode->clock; - if (radeon_crtc->crtc_id == 0) - pll = &rdev->clock.p1pll; - else - pll = &rdev->clock.p2pll; - - memset(&args, 0, sizeof(args)); + /* reset the pll flags */ + pll->flags = 0; if (ASIC_IS_AVIVO(rdev)) { if ((rdev->family == CHIP_RS600) || @@ -457,15 +449,17 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { - if (!ASIC_IS_AVIVO(rdev)) { - if (encoder->encoder_type != - DRM_MODE_ENCODER_DAC) + radeon_encoder = to_radeon_encoder(encoder); + if (ASIC_IS_AVIVO(rdev)) { + /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) + adjusted_clock = mode->clock * 2; + } else { + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; - if (encoder->encoder_type == - DRM_MODE_ENCODER_LVDS) + if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) pll->flags |= RADEON_PLL_USE_REF_DIV; } - radeon_encoder = to_radeon_encoder(encoder); break; } } @@ -475,28 +469,88 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) * special hw requirements. */ if (ASIC_IS_DCE3(rdev)) { - ADJUST_DISPLAY_PLL_PS_ALLOCATION adjust_pll_args; - - if (!encoder) - return; + union adjust_pixel_clock args; + struct radeon_encoder_atom_dig *dig; + u8 frev, crev; + int index; - memset(&adjust_pll_args, 0, sizeof(adjust_pll_args)); - adjust_pll_args.usPixelClock = cpu_to_le16(mode->clock / 10); - adjust_pll_args.ucTransmitterID = radeon_encoder->encoder_id; - adjust_pll_args.ucEncodeMode = atombios_get_encoder_mode(encoder); + if (!radeon_encoder->enc_priv) + return adjusted_clock; + dig = radeon_encoder->enc_priv; index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); - atom_execute_table(rdev->mode_info.atom_context, - index, (uint32_t *)&adjust_pll_args); - adjusted_clock = le16_to_cpu(adjust_pll_args.usPixelClock) * 10; - } else { - /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ - if (ASIC_IS_AVIVO(rdev) && - (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)) - adjusted_clock = mode->clock * 2; - else - adjusted_clock = mode->clock; + atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, + &crev); + + memset(&args, 0, sizeof(args)); + + switch (frev) { + case 1: + switch (crev) { + case 1: + case 2: + args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v1.ucTransmitterID = radeon_encoder->encoder_id; + args.v1.ucEncodeMode = atombios_get_encoder_mode(encoder); + + atom_execute_table(rdev->mode_info.atom_context, + index, (uint32_t *)&args); + adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; + break; + default: + DRM_ERROR("Unknown table version %d %d\n", frev, crev); + return adjusted_clock; + } + break; + default: + DRM_ERROR("Unknown table version %d %d\n", frev, crev); + return adjusted_clock; + } } + return adjusted_clock; +} + +union set_pixel_clock { + SET_PIXEL_CLOCK_PS_ALLOCATION base; + PIXEL_CLOCK_PARAMETERS v1; + PIXEL_CLOCK_PARAMETERS_V2 v2; + PIXEL_CLOCK_PARAMETERS_V3 v3; +}; + +void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder = NULL; + struct radeon_encoder *radeon_encoder = NULL; + u8 frev, crev; + int index; + union set_pixel_clock args; + u32 pll_clock = mode->clock; + u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; + struct radeon_pll *pll; + u32 adjusted_clock; + + memset(&args, 0, sizeof(args)); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + radeon_encoder = to_radeon_encoder(encoder); + break; + } + } + + if (!radeon_encoder) + return; + + if (radeon_crtc->crtc_id == 0) + pll = &rdev->clock.p1pll; + else + pll = &rdev->clock.p2pll; + + /* adjust pixel clock as needed */ + adjusted_clock = atombios_adjust_pll(crtc, mode, pll); if (ASIC_IS_AVIVO(rdev)) { if (radeon_new_pll) @@ -519,45 +573,38 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) case 1: switch (crev) { case 1: - spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput; - spc1_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); - spc1_ptr->usRefDiv = cpu_to_le16(ref_div); - spc1_ptr->usFbDiv = cpu_to_le16(fb_div); - spc1_ptr->ucFracFbDiv = frac_fb_div; - spc1_ptr->ucPostDiv = post_div; - spc1_ptr->ucPpll = + args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v1.usRefDiv = cpu_to_le16(ref_div); + args.v1.usFbDiv = cpu_to_le16(fb_div); + args.v1.ucFracFbDiv = frac_fb_div; + args.v1.ucPostDiv = post_div; + args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; - spc1_ptr->ucCRTC = radeon_crtc->crtc_id; - spc1_ptr->ucRefDivSrc = 1; + args.v1.ucCRTC = radeon_crtc->crtc_id; + args.v1.ucRefDivSrc = 1; break; case 2: - spc2_ptr = - (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput; - spc2_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); - spc2_ptr->usRefDiv = cpu_to_le16(ref_div); - spc2_ptr->usFbDiv = cpu_to_le16(fb_div); - spc2_ptr->ucFracFbDiv = frac_fb_div; - spc2_ptr->ucPostDiv = post_div; - spc2_ptr->ucPpll = + args.v2.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v2.usRefDiv = cpu_to_le16(ref_div); + args.v2.usFbDiv = cpu_to_le16(fb_div); + args.v2.ucFracFbDiv = frac_fb_div; + args.v2.ucPostDiv = post_div; + args.v2.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; - spc2_ptr->ucCRTC = radeon_crtc->crtc_id; - spc2_ptr->ucRefDivSrc = 1; + args.v2.ucCRTC = radeon_crtc->crtc_id; + args.v2.ucRefDivSrc = 1; break; case 3: - if (!encoder) - return; - spc3_ptr = - (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput; - spc3_ptr->usPixelClock = cpu_to_le16(mode->clock / 10); - spc3_ptr->usRefDiv = cpu_to_le16(ref_div); - spc3_ptr->usFbDiv = cpu_to_le16(fb_div); - spc3_ptr->ucFracFbDiv = frac_fb_div; - spc3_ptr->ucPostDiv = post_div; - spc3_ptr->ucPpll = + args.v3.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v3.usRefDiv = cpu_to_le16(ref_div); + args.v3.usFbDiv = cpu_to_le16(fb_div); + args.v3.ucFracFbDiv = frac_fb_div; + args.v3.ucPostDiv = post_div; + args.v3.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; - spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2); - spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id; - spc3_ptr->ucEncoderMode = + args.v3.ucMiscInfo = (radeon_crtc->crtc_id << 2); + args.v3.ucTransmitterId = radeon_encoder->encoder_id; + args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder); break; default: @@ -570,7 +617,6 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) return; } - printk("executing set pll\n"); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } -- cgit v1.2.3 From 947bfc83043181e86e3e3134da158e479c9bcc51 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 21 Jan 2010 17:14:49 -0500 Subject: drm/radeon/kms/atom: atom parser fixes Only reset the reg block on the initial execute table call; nested calls require the reg block not be reset on each call. Also reset the fb window and io mode. This matches the upstream parser behavior. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index cf3126108a4..e3b44562d26 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -1122,8 +1122,6 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); - /* reset reg block */ - ctx->reg_block = 0; ectx.ctx = ctx; ectx.ps_shift = ps / 4; ectx.start = base; @@ -1160,6 +1158,12 @@ static void atom_execute_table_locked(struct atom_context *ctx, int index, uint3 void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) { mutex_lock(&ctx->mutex); + /* reset reg block */ + ctx->reg_block = 0; + /* reset fb window */ + ctx->fb_base = 0; + /* reset io mode */ + ctx->io_mode = ATOM_IO_MM; atom_execute_table_locked(ctx, index, params); mutex_unlock(&ctx->mutex); } -- cgit v1.2.3 From 38678d3557420a1c40f7ad5a04a46a7de7a305b9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 21 Jan 2010 19:28:18 -0500 Subject: drm/radeon/kms: fix legacy get_engine/memory clock Fix a bad shift in the post div. Should fix fdo bug 26145 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_clocks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c index 812f24dbc2a..73c4405bf42 100644 --- a/drivers/gpu/drm/radeon/radeon_clocks.c +++ b/drivers/gpu/drm/radeon/radeon_clocks.c @@ -56,7 +56,7 @@ uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev) else if (post_div == 3) sclk >>= 2; else if (post_div == 4) - sclk >>= 4; + sclk >>= 3; return sclk; } @@ -86,7 +86,7 @@ uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev) else if (post_div == 3) mclk >>= 2; else if (post_div == 4) - mclk >>= 4; + mclk >>= 3; return mclk; } -- cgit v1.2.3 From a1470890f29da73783e932078ed911f5871e3ad3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 18 Jan 2010 11:42:37 +1000 Subject: drm/nouveau: report LVDS as disconnected if lid closed Also adds a module option to ignore the status reported via ACPI, in case we hit systems with broken ACPI. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 7 +++++++ drivers/gpu/drm/nouveau/nouveau_drv.c | 4 ++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + 3 files changed, 12 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 8da35281a0c..7e6d673f3a2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -24,9 +24,12 @@ * */ +#include + #include "drmP.h" #include "drm_edid.h" #include "drm_crtc_helper.h" + #include "nouveau_reg.h" #include "nouveau_drv.h" #include "nouveau_encoder.h" @@ -235,6 +238,10 @@ nouveau_connector_detect(struct drm_connector *connector) if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); if (nv_encoder && nv_connector->native_mode) { +#ifdef CONFIG_ACPI + if (!nouveau_ignorelid && !acpi_lid_open()) + return connector_status_disconnected; +#endif nouveau_connector_set_encoder(connector, nv_encoder); return connector_status_connected; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 06eb993e088..343ab7f17cc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -71,6 +71,10 @@ MODULE_PARM_DESC(uscript_tmds, "TMDS output script table ID (>=GeForce 8)"); int nouveau_uscript_tmds = -1; module_param_named(uscript_tmds, nouveau_uscript_tmds, int, 0400); +MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status"); +int nouveau_ignorelid = 0; +module_param_named(ignorelid, nouveau_ignorelid, int, 0400); + MODULE_PARM_DESC(tv_norm, "Default TV norm.\n" "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n" "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n" diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index cc36866e2a9..6b9690418bc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -677,6 +677,7 @@ extern char *nouveau_tv_norm; extern int nouveau_reg_debug; extern char *nouveau_vbios; extern int nouveau_ctxfw; +extern int nouveau_ignorelid; /* nouveau_state.c */ extern void nouveau_preclose(struct drm_device *dev, struct drm_file *); -- cgit v1.2.3 From 0208843dd59330c30e0773c77d5362260aa340e0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 21 Jan 2010 15:03:23 +1000 Subject: drm/nouveau: fix failure path if userspace specifies no valid memtypes We need to add the buffer to the list even if we fail, otherwise the validate_fini() call won't unreserve + unreference the GEM object, making TTM very unhappy. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 50483304408..6ac804b0c9f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -321,6 +321,7 @@ retry: else { NV_ERROR(dev, "invalid valid domains: 0x%08x\n", b->valid_domains); + list_add_tail(&nvbo->entry, &op->both_list); validate_fini(op, NULL); return -EINVAL; } -- cgit v1.2.3 From 0107bae01add219e1a146f2b412d64a7f1946028 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 22 Jan 2010 09:10:05 +1000 Subject: drm/nv50: fail auxch transaction if reply count not what we expect Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 9e2926c4857..dd493722422 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -490,7 +490,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, if (!nv_wait(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) { NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n", nv_rd32(dev, NV50_AUXCH_CTRL(index))); - return -EBUSY; + ret = -EBUSY; + goto out; } udelay(400); @@ -501,6 +502,11 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, break; } + if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) { + ret = -EREMOTEIO; + goto out; + } + if (cmd & 1) { for (i = 0; i < 4; i++) { data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i)); -- cgit v1.2.3 From 162265367a96d381f07066581d65e52627b08618 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 22 Jan 2010 10:57:01 +1000 Subject: drm/nv50: prevent switching off SOR when in use for DVI-over-DP Another hack because of us exposing each encoder block's function as an encoder rather than exposing a single encoder that deals with them all. A proper fix will come, it's just rather invasive so this hack will do until then. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_sor.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index e395c16d30f..ecf1936b822 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -90,11 +90,24 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_encoder *enc; uint32_t val; int or = nv_encoder->or; NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode); + nv_encoder->last_dpms = mode; + list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nvenc = nouveau_encoder(enc); + + if (nvenc == nv_encoder || + nvenc->dcb->or != nv_encoder->dcb->or) + continue; + + if (nvenc->last_dpms == DRM_MODE_DPMS_ON) + return; + } + /* wait for it to be done */ if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or), NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) { -- cgit v1.2.3 From 1a961ce09fe39df9a1b796df98794fd32c76c413 Mon Sep 17 00:00:00 2001 From: Luca Barbieri Date: Wed, 20 Jan 2010 20:01:30 +0100 Subject: drm/ttm: Fix race condition in ttm_bo_delayed_delete (v3, final) Resending this with Thomas Hellstrom's signoff for merging into 2.6.33 ttm_bo_delayed_delete has a race condition, because after we do: kref_put(&nentry->list_kref, ttm_bo_release_list); we are not holding the list lock and not holding any reference to objects, and thus every bo in the list can be removed and freed at this point. However, we then use the next pointer we stored, which is not guaranteed to be valid. This was apparently the cause of some Nouveau oopses I experienced. This patch rewrites the function so that it keeps the reference to nentry until nentry itself is freed and we already got a reference to nentry->next. v2 updated by me according to Thomas Hellstrom's feedback. v3 proposed by Thomas Hellstrom. Commit comment updated by me. Both updates fixed minor efficiency/style issues only and all three versions should be correct. Signed-off-by: Luca Barbieri Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 54 +++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 31 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index da3702135ad..8036b6e189e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -524,52 +524,44 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all) static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all) { struct ttm_bo_global *glob = bdev->glob; - struct ttm_buffer_object *entry, *nentry; - struct list_head *list, *next; - int ret; + struct ttm_buffer_object *entry = NULL; + int ret = 0; spin_lock(&glob->lru_lock); - list_for_each_safe(list, next, &bdev->ddestroy) { - entry = list_entry(list, struct ttm_buffer_object, ddestroy); - nentry = NULL; + if (list_empty(&bdev->ddestroy)) + goto out_unlock; - /* - * Protect the next list entry from destruction while we - * unlock the lru_lock. - */ + entry = list_first_entry(&bdev->ddestroy, + struct ttm_buffer_object, ddestroy); + kref_get(&entry->list_kref); + + for (;;) { + struct ttm_buffer_object *nentry = NULL; - if (next != &bdev->ddestroy) { - nentry = list_entry(next, struct ttm_buffer_object, - ddestroy); + if (entry->ddestroy.next != &bdev->ddestroy) { + nentry = list_first_entry(&entry->ddestroy, + struct ttm_buffer_object, ddestroy); kref_get(&nentry->list_kref); } - kref_get(&entry->list_kref); spin_unlock(&glob->lru_lock); ret = ttm_bo_cleanup_refs(entry, remove_all); kref_put(&entry->list_kref, ttm_bo_release_list); + entry = nentry; + + if (ret || !entry) + goto out; spin_lock(&glob->lru_lock); - if (nentry) { - bool next_onlist = !list_empty(next); - spin_unlock(&glob->lru_lock); - kref_put(&nentry->list_kref, ttm_bo_release_list); - spin_lock(&glob->lru_lock); - /* - * Someone might have raced us and removed the - * next entry from the list. We don't bother restarting - * list traversal. - */ - - if (!next_onlist) - break; - } - if (ret) + if (list_empty(&entry->ddestroy)) break; } - ret = !list_empty(&bdev->ddestroy); - spin_unlock(&glob->lru_lock); +out_unlock: + spin_unlock(&glob->lru_lock); +out: + if (entry) + kref_put(&entry->list_kref, ttm_bo_release_list); return ret; } -- cgit v1.2.3 From 0eaddb28d3460f13102cd82cf58af875bfb1bd53 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sat, 16 Jan 2010 16:05:04 +0100 Subject: drm/ttm: Allow system memory as a busy placement. This is needed to fix a vmwgfx memory usage bug. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 8036b6e189e..1a3e909b7bb 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -943,6 +943,14 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, ttm_flag_masked(&cur_flags, placement->busy_placement[i], ~TTM_PL_MASK_MEMTYPE); + + if (mem_type == TTM_PL_SYSTEM) { + mem->mem_type = mem_type; + mem->placement = cur_flags; + mem->mm_node = NULL; + return 0; + } + ret = ttm_bo_mem_force_space(bo, mem_type, placement, mem, interruptible, no_wait); if (ret == 0 && mem->mm_node) { -- cgit v1.2.3 From 8ba5152a3acd5914cade42a1c8c9dc58ad8d1a89 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sat, 16 Jan 2010 16:05:05 +0100 Subject: drm/vmwgfx: Optimize memory footprint for DMA buffers. Use VRAM whenever there is free space for DMA buffers, but use system GMR memory if using VRAM would cause an eviction. This significantly reduces the guest system memory usage for VMs with a large amount of VRAM allocated. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 9 +++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 19 +++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 2 +- 4 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 37a81925b15..825ebe3d89d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -48,6 +48,15 @@ struct ttm_placement vmw_vram_placement = { .busy_placement = &vram_placement_flags }; +struct ttm_placement vmw_vram_sys_placement = { + .fpfn = 0, + .lpfn = 0, + .num_placement = 1, + .placement = &vram_placement_flags, + .num_busy_placement = 1, + .busy_placement = &sys_placement_flags +}; + struct ttm_placement vmw_vram_ne_placement = { .fpfn = 0, .lpfn = 0, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 7532b9b47ee..50529a7f06f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -404,6 +404,7 @@ extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma); extern struct ttm_placement vmw_vram_placement; extern struct ttm_placement vmw_vram_ne_placement; +extern struct ttm_placement vmw_vram_sys_placement; extern struct ttm_placement vmw_sys_placement; extern struct ttm_bo_driver vmw_bo_driver; extern int vmw_dma_quiescent(struct drm_device *dev); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 2e92da56740..d69caf92ffe 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -487,6 +487,21 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv, { int ret; + if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL) + return 0; + + /** + * Put BO in VRAM, only if there is space. + */ + + ret = ttm_bo_validate(bo, &vmw_vram_sys_placement, true, false); + if (unlikely(ret == -ERESTARTSYS)) + return ret; + + /** + * Otherwise, set it up as GMR. + */ + if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL) return 0; @@ -494,6 +509,10 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv, if (likely(ret == 0 || ret == -ERESTARTSYS)) return ret; + /** + * If that failed, try VRAM again, this time evicting + * previous contents. + */ ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index e0878077e8a..e01db120eff 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -872,7 +872,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, } ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, req->size, - &vmw_vram_placement, true, + &vmw_vram_sys_placement, true, &vmw_user_dmabuf_destroy); if (unlikely(ret != 0)) return ret; -- cgit v1.2.3 From d796d8446fe0ff4442c1a1d0b10c861f17ac8168 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 25 Jan 2010 13:08:08 +1000 Subject: drm/radeon/kms: make hibernate work on IGPs This is the least invasive fix without migrating the radeon driver to pm_ops from what I can see. We just always migrate VRAM objects on IGPs for now and we can fix it up later to migrate depending on STR vs STD. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 4e636de877b..d72a71bff21 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -220,7 +220,8 @@ int radeon_bo_unpin(struct radeon_bo *bo) int radeon_bo_evict_vram(struct radeon_device *rdev) { - if (rdev->flags & RADEON_IS_IGP) { + /* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */ + if (0 && (rdev->flags & RADEON_IS_IGP)) { if (rdev->mc.igp_sideport_enabled == false) /* Useless to evict on IGP chips */ return 0; -- cgit v1.2.3 From 5fd4df4d475a7fee96fff54f6341192f547984e0 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Mon, 18 Jan 2010 16:47:04 +0800 Subject: drm: fix regression in fb blank handling commit 731b5a15a3b1474a41c2ca29b4c32b0f21bc852e Author: James Simmons Date: Thu Oct 29 20:39:07 2009 +0000 drm/kms: properly handle fbdev blanking uses DRM_MODE_DPMS_ON for FB_BLANK_NORMAL, but DRM_MODE_DPMS_ON is actually for turning output on instead of blank. This makes fb blank broken on my T61, it put LVDS on but leave pipe disabled which made screen totally white or caused some 'burning' effect. [airlied: James objects to this but at this point in 2.6.33, I can't see a patch that will fix this properly like he wants coming in time and otherwise this is a regression - proper fix for 2.6.34 hopefully.] Cc: James Simmons Signed-off-by: Zhenyu Wang Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 1c2b7d44ec0..0f9e90552dc 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -389,7 +389,7 @@ int drm_fb_helper_blank(int blank, struct fb_info *info) break; /* Display: Off; HSync: On, VSync: On */ case FB_BLANK_NORMAL: - drm_fb_helper_off(info, DRM_MODE_DPMS_ON); + drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY); break; /* Display: Off; HSync: Off, VSync: On */ case FB_BLANK_HSYNC_SUSPEND: -- cgit v1.2.3 From f2ab3a13d2cbe19426c27c35a014c98212e914a5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 25 Jan 2010 16:13:12 +1000 Subject: drm/radeon/kms: drop unnecessary printks. These printks aren't required anymore. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index e619aca5423..af464e351fb 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -307,7 +307,6 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; - printk("executing set crtc dtd timing\n"); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } @@ -347,7 +346,6 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc, args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; - printk("executing set crtc timing\n"); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } -- cgit v1.2.3 From 7087e16286913b41ba9a5186360645b57b8508dd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 25 Jan 2010 16:13:55 +1000 Subject: drm/radeon/kms: preface warning printk with driver name This just adds a little more info to the warning for old -ati/mesa userspaces. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 9cc4ba8d03d..e4c45ec1650 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -562,7 +562,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p, return -EINVAL; } ib[idx+1+i] = track->cb_color0_base_last; - printk_once(KERN_WARNING "You have old & broken userspace " + printk_once(KERN_WARNING "radeon: You have old & broken userspace " "please consider updating mesa & xf86-video-ati\n"); } else { r = r600_cs_packet_next_reloc(p, &reloc); -- cgit v1.2.3 From eceb784cec4dc0fcc2993d9ee4a7c0d111ada80a Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Mon, 25 Jan 2010 10:35:16 +0800 Subject: drm/i915: disable hotplug detect before Ironlake CRT detect This tries to fix CRT detect loop hang seen on some Ironlake form factor, to clear up hotplug detect state before taking CRT detect to make sure next hotplug detect cycle is consistent. Cc: Stable Team Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_crt.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index ddefc871edf..79dd4026586 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -157,6 +157,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) adpa = I915_READ(PCH_ADPA); adpa &= ~ADPA_CRT_HOTPLUG_MASK; + /* disable HPD first */ + I915_WRITE(PCH_ADPA, adpa); + (void)I915_READ(PCH_ADPA); adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | ADPA_CRT_HOTPLUG_WARMUP_10MS | -- cgit v1.2.3 From 0ce907f89118aa8748f950700b6919b1d8d8a038 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 23 Jan 2010 20:26:35 +0000 Subject: drm/i915: Prevent use of uninitialized pointers along error path. X.org hang with [drm:i915_gem_do_execbuffer] *ERROR* in dmesg http://bugzilla.kernel.org/show_bug.cgi?id=15114 Matej found he was hitting an error path within i915_gem_do_execbuffer() that led to the attempt to dereference an uninitialised pointer during cleanup. This path used to be safe as we used to calloc the object lists, but this was changed in c8e0f93. Daniel Vetter had also spotted this error and proposed a similar patch. [ 6379.732892] [drm:i915_gem_do_execbuffer] *ERROR* Object ffff880098cd6540 appears more than once in object list [ 6379.740976] [drm:i915_gem_do_execbuffer] *ERROR* Object ffff880098cd6540 appears more than once in object list [ 6379.740995] BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0 [ 6379.740998] IP: [] i915_gem_do_execbuffer+0xba5/0x1260 [ 6379.741006] PGD babab067 PUD bb435067 PMD 0 [ 6379.741010] Oops: 0002 [#1] PREEMPT SMP [ 6379.741014] last sysfs file: /sys/devices/pci0000:00/0000:00:1c.2/0000:06:00.0/ieee80211/phy0/rfkill0/state [ 6379.741017] CPU 1 [ 6379.741021] Pid: 2186, comm: X Not tainted 2.6.33-rc4-00399-g24bc734 #142 M11D/ESPRIMO Mobile M9400 [ 6379.741023] RIP: 0010:[] [] i915_gem_do_execbuffer+0xba5/0x1260 [ 6379.741027] RSP: 0018:ffff8800b9047b78 EFLAGS: 00213206 [ 6379.741029] RAX: 0000000000000000 RBX: 000000000000004f RCX: ffff880098cac800 [ 6379.741032] RDX: ffff880098caca78 RSI: ffff8800b9047c98 RDI: ffff880098cd6540 [ 6379.741034] RBP: ffff8800b9047c78 R08: ffffffff814b96b5 R09: 0000000000000006 [ 6379.741036] R10: 0000000000000000 R11: 0000000000000003 R12: 000000000000004e [ 6379.741038] R13: 00000000fffffff7 R14: 0000000000000000 R15: 0000000000000001 [ 6379.741041] FS: 0000000000000000(0000) GS:ffff880001900000(0063) knlGS:00000000f72636c0 [ 6379.741043] CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 [ 6379.741041] FS: 0000000000000000(0000) GS:ffff880001900000(0063) knlGS:00000000f72636c0 [ 6379.741043] CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 [ 6379.741045] CR2: 00000000000000a0 CR3: 00000000b9000000 CR4: 00000000000006e0 [ 6379.741048] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 6379.741050] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 6379.741052] Process X (pid: 2186, threadinfo ffff8800b9046000, task ffff8800bb5d8000) [ 6379.741054] Stack: [ 6379.741055] ffffc90023f57000 ffffc90023f56fff ffffc90023f56fff ffffc90023f55000 [ 6379.741059] <0> ffff8800b9047c98 ffff8800bb43c840 ffff8800bf1de800 ffff8800bf1de820 [ 6379.741063] <0> ffff8800b9047bd8 ffff880098cac800 0000000000000000 0000000000000002 [ 6379.741068] Call Trace: [ 6379.741072] [] ? i915_gem_execbuffer+0x6b/0x370 [ 6379.741077] [] ? __vmalloc_node+0xa2/0xb0 [ 6379.741080] [] ? i915_gem_execbuffer+0x6b/0x370 [ 6379.741083] [] i915_gem_execbuffer+0x1b6/0x370 [ 6379.741086] [] drm_ioctl+0x1d5/0x460 [ 6379.741089] [] ? i915_gem_execbuffer+0x0/0x370 [ 6379.741093] [] i915_compat_ioctl+0x45/0x50 [ 6379.741097] [] compat_sys_ioctl+0xa9/0x1570 [ 6379.741102] [] ? vfs_read+0x13c/0x1a0 [ 6379.741106] [] sysenter_dispatch+0x7/0x2b [ 6379.741108] Code: 08 85 c0 74 52 31 db 0f 1f 80 00 00 00 00 48 63 c3 48 8b 8d 68 ff ff ff 48 8d 14 c1 48 8b 02 48 85 c0 74 25 48 8b 80 80 00 00 00 80 a0 00 00 00 00 00 00 00 48 8b 3a 48 85 ff 74 0c 48 c7 c6 [ 6379.741142] RIP [] i915_gem_do_execbuffer+0xba5/0x1260 [ 6379.741145] RSP [ 6379.741147] CR2: 00000000000000a0 [ 6379.741159] ---[ end trace 0598809afa4c31db ]--- Reported-by: Matej Laitl Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0c67924ca80..1ef7ec4f38f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3742,6 +3742,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (object_list[i] == NULL) { DRM_ERROR("Invalid object handle %d at index %d\n", exec_list[i].handle, i); + /* prevent error path from reading uninitialized data */ + args->buffer_count = i + 1; ret = -EBADF; goto err; } @@ -3750,6 +3752,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (obj_priv->in_execbuffer) { DRM_ERROR("Object %p appears more than once in object list\n", object_list[i]); + /* prevent error path from reading uninitialized data */ + args->buffer_count = i + 1; ret = -EBADF; goto err; } -- cgit v1.2.3 From c062df61966405b0be6743bfb0cf300dca2fa7c2 Mon Sep 17 00:00:00 2001 From: Li Peng Date: Sat, 23 Jan 2010 00:12:58 +0800 Subject: drm/i915: enable vblank interrupt on ironlake so far vblank interrupt on ironlake is disabled, this would cause bad gfx performance if userspace calls drm_wait_vblank. This patch enables vblank interrupt on ironlake and follows vblank get/put model. Signed-off-by: Li Peng Acked-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 30 +++++++++++++++++++----------- drivers/gpu/drm/i915/intel_display.c | 1 + 2 files changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 89a071a3e6f..e7472d82132 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -309,6 +309,12 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) if (de_iir & DE_GSE) ironlake_opregion_gse_intr(dev); + if (de_iir & DE_PIPEA_VBLANK) + drm_handle_vblank(dev, 0); + + if (de_iir & DE_PIPEB_VBLANK) + drm_handle_vblank(dev, 1); + /* check event from PCH */ if ((de_iir & DE_PCH_EVENT) && (pch_iir & SDE_HOTPLUG_MASK)) { @@ -844,11 +850,11 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) if (!(pipeconf & PIPEACONF_ENABLE)) return -EINVAL; - if (IS_IRONLAKE(dev)) - return 0; - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - if (IS_I965G(dev)) + if (IS_IRONLAKE(dev)) + ironlake_enable_display_irq(dev_priv, (pipe == 0) ? + DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); + else if (IS_I965G(dev)) i915_enable_pipestat(dev_priv, pipe, PIPE_START_VBLANK_INTERRUPT_ENABLE); else @@ -866,13 +872,14 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; - if (IS_IRONLAKE(dev)) - return; - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - i915_disable_pipestat(dev_priv, pipe, - PIPE_VBLANK_INTERRUPT_ENABLE | - PIPE_START_VBLANK_INTERRUPT_ENABLE); + if (IS_IRONLAKE(dev)) + ironlake_disable_display_irq(dev_priv, (pipe == 0) ? + DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); + else + i915_disable_pipestat(dev_priv, pipe, + PIPE_VBLANK_INTERRUPT_ENABLE | + PIPE_START_VBLANK_INTERRUPT_ENABLE); spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } @@ -1015,7 +1022,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ - u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT; + u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | + DE_PIPEA_VBLANK | DE_PIPEB_VBLANK; u32 render_mask = GT_USER_INTERRUPT; u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 45da78ef4a9..2cc489b6629 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1638,6 +1638,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_OFF: DRM_DEBUG_KMS("crtc %d dpms off\n", pipe); + drm_vblank_off(dev, pipe); /* Disable display plane */ temp = I915_READ(dspcntr_reg); if ((temp & DISPLAY_PLANE_ENABLE) != 0) { -- cgit v1.2.3 From 8a6c77d645d9111f7bc01f908464301f5c3e0a05 Mon Sep 17 00:00:00 2001 From: Li Peng Date: Thu, 21 Jan 2010 18:45:46 +0800 Subject: drm/i915: Fix the device info of Pineview Pineview doesn't has CXSR and need GTT-based hardware status page. It fixes a X boot hung issue on Pinview since commit cfdf1f Signed-off-by: Li Peng Acked-by: Zhao Yakui Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 46d88965852..ecac882e1d5 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -120,7 +120,7 @@ const static struct intel_device_info intel_gm45_info = { const static struct intel_device_info intel_pineview_info = { .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, - .has_pipe_cxsr = 1, + .need_gfx_hws = 1, .has_hotplug = 1, }; -- cgit v1.2.3 From de3f440f8c9922afe8770dd16c84f1c87d779b59 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 14 Jan 2010 13:18:02 -0800 Subject: drm/i915: handle non-flip pending case when unpinning the scanout buffer The first page flip queued will replace the current front buffer, which should have a 0 pending flip count. So at finish time we need to handle that case (i.e. if the flip count is 0 *or* dec_and_test is 0 we need to wake the waiters). Also fix up an error path in the queue function and add some debug output (only enabled with driver debugging). Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2cc489b6629..5f14dfbf715 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3985,6 +3985,12 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) spin_lock_irqsave(&dev->event_lock, flags); work = intel_crtc->unpin_work; if (work == NULL || !work->pending) { + if (work && !work->pending) { + obj_priv = work->obj->driver_private; + DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n", + obj_priv, + atomic_read(&obj_priv->pending_flip)); + } spin_unlock_irqrestore(&dev->event_lock, flags); return; } @@ -4006,7 +4012,10 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev->event_lock, flags); obj_priv = work->obj->driver_private; - if (atomic_dec_and_test(&obj_priv->pending_flip)) + + /* Initial scanout buffer will have a 0 pending flip count */ + if ((atomic_read(&obj_priv->pending_flip) == 0) || + atomic_dec_and_test(&obj_priv->pending_flip)) DRM_WAKEUP(&dev_priv->pending_flip_queue); schedule_work(&work->work); } @@ -4019,8 +4028,11 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane) unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); - if (intel_crtc->unpin_work) + if (intel_crtc->unpin_work) { intel_crtc->unpin_work->pending = 1; + } else { + DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n"); + } spin_unlock_irqrestore(&dev->event_lock, flags); } @@ -4054,6 +4066,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, /* We borrow the event spin lock for protecting unpin_work */ spin_lock_irqsave(&dev->event_lock, flags); if (intel_crtc->unpin_work) { + DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); spin_unlock_irqrestore(&dev->event_lock, flags); kfree(work); mutex_unlock(&dev->struct_mutex); @@ -4067,7 +4080,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, ret = intel_pin_and_fence_fb_obj(dev, obj); if (ret != 0) { + DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n", + obj->driver_private); kfree(work); + intel_crtc->unpin_work = NULL; mutex_unlock(&dev->struct_mutex); return ret; } -- cgit v1.2.3 From 4bdadb9785696439c6e2b3efe34aa76df1149c83 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Jan 2010 13:36:32 +0000 Subject: drm/i915: Selectively enable self-reclaim Having missed the ENOMEM return via i915_gem_fault(), there are probably other paths that I also missed. By not enabling NORETRY by default these paths can run the shrinker and take memory from the system (but not from our own inactive lists because our shrinker can not run whilst we hold the struct mutex) and this may allow the system to survive a little longer whilst our drivers consume all available memory. References: OOM killer unexpectedly called with kernel 2.6.32 http://bugzilla.kernel.org/show_bug.cgi?id=14933 v2: Pass gfp into page mapping. v3: Use new read_cache_page_gfp() instead of open-coding. Signed-off-by: Chris Wilson Cc: KOSAKI Motohiro Cc: Hugh Dickins Cc: Jesse Barnes Cc: Eric Anholt Cc: stable@kernel.org Signed-off-by: Linus Torvalds --- drivers/gpu/drm/drm_gem.c | 13 --------- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 54 ++++++++++++------------------------- 4 files changed, 19 insertions(+), 52 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index e9dbb481c46..8bf3770f294 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -142,19 +142,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) if (IS_ERR(obj->filp)) goto free; - /* Basically we want to disable the OOM killer and handle ENOMEM - * ourselves by sacrificing pages from cached buffers. - * XXX shmem_file_[gs]et_gfp_mask() - */ - mapping_set_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping, - GFP_HIGHUSER | - __GFP_COLD | - __GFP_FS | - __GFP_RECLAIMABLE | - __GFP_NORETRY | - __GFP_NOWARN | - __GFP_NOMEMALLOC); - kref_init(&obj->refcount); kref_init(&obj->handlecount); obj->size = size; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9c9998c4dce..a894ade0309 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -290,7 +290,7 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { obj = obj_priv->obj; if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) { - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret) { DRM_ERROR("Failed to get pages: %d\n", ret); spin_unlock(&dev_priv->mm.active_list_lock); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2c1669488b5..aaf934d96f2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -872,7 +872,7 @@ int i915_gem_attach_phys_object(struct drm_device *dev, void i915_gem_detach_phys_object(struct drm_device *dev, struct drm_gem_object *obj); void i915_gem_free_all_phys_object(struct drm_device *dev); -int i915_gem_object_get_pages(struct drm_gem_object *obj); +int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); void i915_gem_object_put_pages(struct drm_gem_object *obj); void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); void i915_gem_object_flush_write_domain(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0c67924ca80..dda787aafcc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -277,7 +277,7 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret != 0) goto fail_unlock; @@ -321,40 +321,24 @@ fail_unlock: return ret; } -static inline gfp_t -i915_gem_object_get_page_gfp_mask (struct drm_gem_object *obj) -{ - return mapping_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping); -} - -static inline void -i915_gem_object_set_page_gfp_mask (struct drm_gem_object *obj, gfp_t gfp) -{ - mapping_set_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping, gfp); -} - static int i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj) { int ret; - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, __GFP_NORETRY | __GFP_NOWARN); /* If we've insufficient memory to map in the pages, attempt * to make some space by throwing out some old buffers. */ if (ret == -ENOMEM) { struct drm_device *dev = obj->dev; - gfp_t gfp; ret = i915_gem_evict_something(dev, obj->size); if (ret) return ret; - gfp = i915_gem_object_get_page_gfp_mask(obj); - i915_gem_object_set_page_gfp_mask(obj, gfp & ~__GFP_NORETRY); - ret = i915_gem_object_get_pages(obj); - i915_gem_object_set_page_gfp_mask (obj, gfp); + ret = i915_gem_object_get_pages(obj, 0); } return ret; @@ -790,7 +774,7 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret != 0) goto fail_unlock; @@ -2230,7 +2214,8 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) } int -i915_gem_object_get_pages(struct drm_gem_object *obj) +i915_gem_object_get_pages(struct drm_gem_object *obj, + gfp_t gfpmask) { struct drm_i915_gem_object *obj_priv = obj->driver_private; int page_count, i; @@ -2256,7 +2241,10 @@ i915_gem_object_get_pages(struct drm_gem_object *obj) inode = obj->filp->f_path.dentry->d_inode; mapping = inode->i_mapping; for (i = 0; i < page_count; i++) { - page = read_mapping_page(mapping, i, NULL); + page = read_cache_page_gfp(mapping, i, + mapping_gfp_mask (mapping) | + __GFP_COLD | + gfpmask); if (IS_ERR(page)) { ret = PTR_ERR(page); i915_gem_object_put_pages(obj); @@ -2579,7 +2567,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = obj->driver_private; struct drm_mm_node *free_space; - bool retry_alloc = false; + gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; int ret; if (obj_priv->madv != I915_MADV_WILLNEED) { @@ -2623,15 +2611,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) DRM_INFO("Binding object of size %zd at 0x%08x\n", obj->size, obj_priv->gtt_offset); #endif - if (retry_alloc) { - i915_gem_object_set_page_gfp_mask (obj, - i915_gem_object_get_page_gfp_mask (obj) & ~__GFP_NORETRY); - } - ret = i915_gem_object_get_pages(obj); - if (retry_alloc) { - i915_gem_object_set_page_gfp_mask (obj, - i915_gem_object_get_page_gfp_mask (obj) | __GFP_NORETRY); - } + ret = i915_gem_object_get_pages(obj, gfpmask); if (ret) { drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; @@ -2641,9 +2621,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) ret = i915_gem_evict_something(dev, obj->size); if (ret) { /* now try to shrink everyone else */ - if (! retry_alloc) { - retry_alloc = true; - goto search_free; + if (gfpmask) { + gfpmask = 0; + goto search_free; } return ret; @@ -4946,7 +4926,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev, if (!obj_priv->phys_obj) return; - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret) goto out; @@ -5004,7 +4984,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1]; obj_priv->phys_obj->cur_obj = obj; - ret = i915_gem_object_get_pages(obj); + ret = i915_gem_object_get_pages(obj, 0); if (ret) { DRM_ERROR("failed to get page list\n"); goto out; -- cgit v1.2.3 From 643ced9b0b4810b5725910667604f1a373f30f2f Mon Sep 17 00:00:00 2001 From: Li Peng Date: Thu, 28 Jan 2010 01:05:09 +0800 Subject: drm/i915: don't trigger ironlake vblank interrupt at irq install Zhenyu noticed that the ironlake vblank enabling patch has one issue that it will trigger vblank starting from irq postinstall, this isn't necessary. This patch addresses this issue by only adding the vblank into DEIER but mask them in DEIMR, so that it won't trigger vblank interrupt at irq install. Signed-off-by: Li Peng Acked-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e7472d82132..fcd87ad75fe 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1022,14 +1022,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ - u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | - DE_PIPEA_VBLANK | DE_PIPEB_VBLANK; + u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT; u32 render_mask = GT_USER_INTERRUPT; u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; dev_priv->irq_mask_reg = ~display_mask; - dev_priv->de_irq_enable_reg = display_mask; + dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK; /* should always can generate irq */ I915_WRITE(DEIIR, I915_READ(DEIIR)); -- cgit v1.2.3 From 2dd873838805a6e84c1afdfbf13e8709bfb5c70f Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Wed, 27 Jan 2010 16:32:46 +0800 Subject: drm/i915: Add support for SDVO composite TV Signed-off-by: Zhao Yakui Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index eaacfd0920d..82678d30ab0 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2345,6 +2345,14 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags) connector->connector_type = DRM_MODE_CONNECTOR_VGA; intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT); + } else if (flags & SDVO_OUTPUT_CVBS0) { + + sdvo_priv->controlled_output = SDVO_OUTPUT_CVBS0; + encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; + connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; + sdvo_priv->is_tv = true; + intel_output->needs_tv_clock = true; + intel_output->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; } else if (flags & SDVO_OUTPUT_LVDS0) { sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; -- cgit v1.2.3 From f034b12dbb5749b11e9390e15e93ffa87ece8038 Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Thu, 21 Jan 2010 15:20:18 +0800 Subject: drm/i915: Fix the incorrect DMI string for Samsung SX20S laptop Signed-off-by: Zhao Yakui Reported-by: Philipp Kohlbecher Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_lvds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index aa74e59bec6..75a9772061c 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -611,7 +611,7 @@ static const struct dmi_system_id bad_lid_status[] = { { .ident = "Samsung SX20S", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Phoenix Technologies LTD"), + DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), DMI_MATCH(DMI_BOARD_NAME, "SX20S"), }, }, -- cgit v1.2.3 From 013d5aa2bbb2ceacba7a0dad7f2a0eb20133323f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 29 Jan 2010 11:18:31 -0800 Subject: drm/i915: page flip support for Ironlake This patch adds support for page flipping on Ironlake, which uses different interrupt bits for triggering flip submit IRQs. Signed-off-by: Jesse Barnes [anholt: hand-resolved for rebasing off of render power saving patch] Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index fcd87ad75fe..50ddf4a95c5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -309,11 +309,21 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) if (de_iir & DE_GSE) ironlake_opregion_gse_intr(dev); - if (de_iir & DE_PIPEA_VBLANK) + if (de_iir & DE_PLANEA_FLIP_DONE) + intel_prepare_page_flip(dev, 0); + + if (de_iir & DE_PLANEB_FLIP_DONE) + intel_prepare_page_flip(dev, 1); + + if (de_iir & DE_PIPEA_VBLANK) { drm_handle_vblank(dev, 0); + intel_finish_page_flip(dev, 0); + } - if (de_iir & DE_PIPEB_VBLANK) + if (de_iir & DE_PIPEB_VBLANK) { drm_handle_vblank(dev, 1); + intel_finish_page_flip(dev, 1); + } /* check event from PCH */ if ((de_iir & DE_PCH_EVENT) && @@ -1022,7 +1032,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ - u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT; + u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | + DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; u32 render_mask = GT_USER_INTERRUPT; u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; -- cgit v1.2.3 From 97b94ccb9aa1b82ed7a9a045d0ae5b32c99b84a0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 29 Jan 2010 15:31:47 +1000 Subject: drm/radeon/kms: fix incorrect logic in DP vs eDP connector checking. This makes displayport work again here. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 3eb0ca5b3d7..9c023d25aad 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -468,7 +468,7 @@ void radeon_dp_set_link_config(struct drm_connector *connector, struct radeon_connector *radeon_connector; struct radeon_connector_atom_dig *dig_connector; - if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) || + if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) && (connector->connector_type != DRM_MODE_CONNECTOR_eDP)) return; @@ -583,7 +583,7 @@ void dp_link_train(struct drm_encoder *encoder, u8 train_set[4]; int i; - if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) || + if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) && (connector->connector_type != DRM_MODE_CONNECTOR_eDP)) return; -- cgit v1.2.3 From 43c33ed87d0f1b900a6a3014db556ecc7f4a989b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 29 Jan 2010 15:55:30 +1000 Subject: drm/radeon/kms: use active device to pick connector for encoder On the W500 we have UNIPHY routed to both DVI and DP, this seems to always pick the DVI connector which means link training fails. Switch to using active device to pick the connector, this seems like it should be safe from a code review, and it fixes things a bit more here. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 82eb551970b..10746c9c805 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -202,7 +202,7 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { radeon_connector = to_radeon_connector(connector); - if (radeon_encoder->devices & radeon_connector->devices) + if (radeon_encoder->active_device & radeon_connector->devices) return connector; } return NULL; -- cgit v1.2.3 From f28cf33945cc112f8ee835512b7440905dc29ad2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Jan 2010 17:15:25 +1000 Subject: drm/kms/radeon: pick digitial encoders smarter. (v3) booting a Lenovo W500 with LVDS + DP outputs showed up a TODO we had on our list, to pick a correct digital encoder block. The LVTMA encoder requires the second digital encoder, all others can use any encoder at all. This fixes the digital encoder selection logic to enable LVDS/DP combos to work okay. V2: fix silly addition of connector dig_block and cleanup the other places in the code that pick the encoder. V3: rename to dig_encoder and clean up further - also fix the picking algorithm. tested on Lenovo W500 + desktop 3650 cards. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 23 ++--- drivers/gpu/drm/radeon/radeon_encoders.c | 163 +++++++++++++++++-------------- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- 3 files changed, 99 insertions(+), 89 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 9c023d25aad..71060114d5d 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -596,21 +596,14 @@ void dp_link_train(struct drm_encoder *encoder, return; dig_connector = radeon_connector->con_priv; - if (ASIC_IS_DCE32(rdev)) { - if (dig->dig_block) - enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER; - else - enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER; - if (dig_connector->linkb) - enc_id |= ATOM_DP_CONFIG_LINK_B; - else - enc_id |= ATOM_DP_CONFIG_LINK_A; - } else { - if (dig_connector->linkb) - enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER | ATOM_DP_CONFIG_LINK_B; - else - enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER | ATOM_DP_CONFIG_LINK_A; - } + if (dig->dig_encoder) + enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER; + else + enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER; + if (dig_connector->linkb) + enc_id |= ATOM_DP_CONFIG_LINK_B; + else + enc_id |= ATOM_DP_CONFIG_LINK_A; memset(link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); if (dig_connector->dp_clock == 270000) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 10746c9c805..3c91724457c 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -156,6 +156,26 @@ radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t return ret; } +static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + return true; + default: + return false; + } +} void radeon_link_encoder_connector(struct drm_device *dev) { @@ -676,31 +696,11 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) memset(&args, 0, sizeof(args)); - if (ASIC_IS_DCE32(rdev)) { - if (dig->dig_block) - index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); - else - index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); - num = dig->dig_block + 1; - } else { - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - /* XXX doesn't really matter which dig encoder we pick as long as it's - * not already in use - */ - if (dig_connector->linkb) - index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); - else - index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); - num = 1; - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - /* Only dig2 encoder can drive LVTMA */ - index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); - num = 2; - break; - } - } + if (dig->dig_encoder) + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + num = dig->dig_encoder + 1; atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); @@ -822,7 +822,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); } if (ASIC_IS_DCE32(rdev)) { - if (dig->dig_block) + if (dig->dig_encoder == 1) args.v2.acConfig.ucEncoderSel = 1; if (dig_connector->linkb) args.v2.acConfig.ucLinkSel = 1; @@ -849,17 +849,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v2.acConfig.fCoherentMode = 1; } } else { + args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; + if (dig->dig_encoder) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; + switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - /* XXX doesn't really matter which dig encoder we pick as long as it's - * not already in use - */ - if (dig_connector->linkb) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; - else - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; if (rdev->flags & RADEON_IS_IGP) { if (radeon_encoder->pixel_clock > 165000) { if (dig_connector->igp_lane_info & 0x3) @@ -878,10 +877,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } } break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - /* Only dig2 encoder can drive LVTMA */ - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; - break; } if (radeon_encoder->pixel_clock > 165000) @@ -1046,6 +1041,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) union crtc_sourc_param args; int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; memset(&args, 0, sizeof(args)); @@ -1109,40 +1105,16 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (ASIC_IS_DCE32(rdev)) { - if (radeon_crtc->crtc_id) - args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; - else - args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; - } else { - struct drm_connector *connector; - struct radeon_connector *radeon_connector; - struct radeon_connector_atom_dig *dig_connector; - - connector = radeon_get_connector_for_encoder(encoder); - if (!connector) - return; - radeon_connector = to_radeon_connector(connector); - if (!radeon_connector->con_priv) - return; - dig_connector = radeon_connector->con_priv; - - /* XXX doesn't really matter which dig encoder we pick as long as it's - * not already in use - */ - if (dig_connector->linkb) - args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; - else - args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; - } + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + dig = radeon_encoder->enc_priv; + if (dig->dig_encoder) + args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - /* Only dig2 encoder can drive LVTMA */ - args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; - break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; @@ -1202,6 +1174,47 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder, } } +static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *test_encoder; + struct radeon_encoder_atom_dig *dig; + uint32_t dig_enc_in_use = 0; + /* on DCE32 and encoder can driver any block so just crtc id */ + if (ASIC_IS_DCE32(rdev)) { + return radeon_crtc->crtc_id; + } + + /* on DCE3 - LVTMA can only be driven by DIGB */ + list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { + struct radeon_encoder *radeon_test_encoder; + + if (encoder == test_encoder) + continue; + + if (!radeon_encoder_is_digital(test_encoder)) + continue; + + radeon_test_encoder = to_radeon_encoder(test_encoder); + dig = radeon_test_encoder->enc_priv; + + if (dig->dig_encoder >= 0) + dig_enc_in_use |= (1 << dig->dig_encoder); + } + + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { + if (dig_enc_in_use & 0x2) + DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); + return 1; + } + if (!(dig_enc_in_use & 1)) + return 0; + return 1; +} + static void radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, @@ -1214,12 +1227,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, if (radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { - if (radeon_encoder->enc_priv) { - struct radeon_encoder_atom_dig *dig; - - dig = radeon_encoder->enc_priv; - dig->dig_block = radeon_crtc->crtc_id; - } + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + if (dig) + dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); } radeon_encoder->pixel_clock = adjusted_mode->clock; @@ -1379,7 +1389,13 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder) static void radeon_atom_encoder_disable(struct drm_encoder *encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig; radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + + if (radeon_encoder_is_digital(encoder)) { + dig = radeon_encoder->enc_priv; + dig->dig_encoder = -1; + } radeon_encoder->active_device = 0; } @@ -1436,6 +1452,7 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) /* coherent mode by default */ dig->coherent_mode = true; + dig->dig_encoder = -1; return dig; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 96b851f92f4..e81b2aeb6a8 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -299,7 +299,7 @@ struct radeon_atom_ss { struct radeon_encoder_atom_dig { /* atom dig */ bool coherent_mode; - int dig_block; + int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */ /* atom lvds */ uint32_t lvds_misc; uint16_t panel_pwr_delay; -- cgit v1.2.3 From db78e27de7e29a6db6be7caf607cf803d84094aa Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 12 Jan 2010 18:49:43 +0100 Subject: drm/ttm: Avoid conflicting reserve_memtype during ttm_tt_set_page_caching. Fixes errors like: > reserve_ram_pages_type failed 0x15b7a000-0x15b7b000, track 0x8, req 0x10 when a BO is moved between WC and UC areas. Reported-by: Xavier Chantry Signed-off-by: Francisco Jerez Acked-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_tt.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 9c2b1cc5dba..e2123af7775 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -198,17 +198,26 @@ EXPORT_SYMBOL(ttm_tt_populate); static inline int ttm_tt_set_page_caching(struct page *p, enum ttm_caching_state c_state) { + int ret = 0; + if (PageHighMem(p)) return 0; - switch (c_state) { - case tt_cached: - return set_pages_wb(p, 1); - case tt_wc: - return set_memory_wc((unsigned long) page_address(p), 1); - default: - return set_pages_uc(p, 1); + if (get_page_memtype(p) != -1) { + /* p isn't in the default caching state, set it to + * writeback first to free its current memtype. */ + + ret = set_pages_wb(p, 1); + if (ret) + return ret; } + + if (c_state == tt_wc) + ret = set_memory_wc((unsigned long) page_address(p), 1); + else if (c_state == tt_uncached) + ret = set_pages_uc(p, 1); + + return ret; } #else /* CONFIG_X86 */ static inline int ttm_tt_set_page_caching(struct page *p, -- cgit v1.2.3 From cdb6e375c3c84558ed2c13c5461b22e8f7b7980e Mon Sep 17 00:00:00 2001 From: John Kacur Date: Sun, 31 Jan 2010 20:38:02 +0100 Subject: =?UTF-8?q?drm/kms/radeon/agp:=20Fix=20warning,=20format=20?= =?UTF-8?q?=E2=80=98%d=E2=80=99=20expects=20type=20=E2=80=98int=E2=80=99,?= =?UTF-8?q?=20but=20argument=204=20has=20type=20=E2=80=98size=5Ft=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix warning by using %zu instead of %d for size_t - Fix spelling mistake, "to" should be "too". Signed-off-by: John Kacur Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_agp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index c9ad7f5cc1a..f58c5f46243 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -134,7 +134,7 @@ int radeon_agp_init(struct radeon_device *rdev) int ret; if (rdev->ddev->agp->agp_info.aper_size < 32) { - dev_warn(rdev->dev, "AGP aperture to small (%dM) " + dev_warn(rdev->dev, "AGP aperture too small (%zuM) " "need at least 32M, disabling AGP\n", rdev->ddev->agp->agp_info.aper_size); return -EINVAL; -- cgit v1.2.3 From 2dea2e29b9fad48c759aa406b5ea426bff4339af Mon Sep 17 00:00:00 2001 From: John Kacur Date: Sun, 31 Jan 2010 20:38:03 +0100 Subject: drm/kms/radeon/agp: Move the check of the aper_size after drm_acp_acquire and drm_agp_info First call drm_agp_acquire to check if agp has been acquired. Second call drm_agp_info to fill in the info data struct, including aper_size. Finally do the check to see if the aper_size makes sense. Signed-off-by: John Kacur Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_agp.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index f58c5f46243..b634d984766 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -133,13 +133,6 @@ int radeon_agp_init(struct radeon_device *rdev) bool is_v3; int ret; - if (rdev->ddev->agp->agp_info.aper_size < 32) { - dev_warn(rdev->dev, "AGP aperture too small (%zuM) " - "need at least 32M, disabling AGP\n", - rdev->ddev->agp->agp_info.aper_size); - return -EINVAL; - } - /* Acquire AGP. */ if (!rdev->ddev->agp->acquired) { ret = drm_agp_acquire(rdev->ddev); @@ -154,6 +147,14 @@ int radeon_agp_init(struct radeon_device *rdev) DRM_ERROR("Unable to get AGP info: %d\n", ret); return ret; } + + if (rdev->ddev->agp->agp_info.aper_size < 32) { + dev_warn(rdev->dev, "AGP aperture too small (%zuM) " + "need at least 32M, disabling AGP\n", + rdev->ddev->agp->agp_info.aper_size); + return -EINVAL; + } + mode.mode = info.mode; agp_status = (RREG32(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode; is_v3 = !!(agp_status & RADEON_AGPv3_MODE); -- cgit v1.2.3 From 4b866288be6ffaefaad9cec212cb09e3258a68ee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 1 Feb 2010 11:22:10 +1000 Subject: drm/radeon/kms: release agp on error. if we get an error, release the AGP if we've acquired it already. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_agp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index b634d984766..c0681a5556d 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -144,11 +144,13 @@ int radeon_agp_init(struct radeon_device *rdev) ret = drm_agp_info(rdev->ddev, &info); if (ret) { + drm_agp_release(rdev->ddev); DRM_ERROR("Unable to get AGP info: %d\n", ret); return ret; } if (rdev->ddev->agp->agp_info.aper_size < 32) { + drm_agp_release(rdev->ddev); dev_warn(rdev->dev, "AGP aperture too small (%zuM) " "need at least 32M, disabling AGP\n", rdev->ddev->agp->agp_info.aper_size); @@ -229,6 +231,7 @@ int radeon_agp_init(struct radeon_device *rdev) ret = drm_agp_enable(rdev->ddev, mode); if (ret) { DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); + drm_agp_release(rdev->ddev); return ret; } -- cgit v1.2.3 From dd5fde6041d7ea30fcfedcc159a4cec8b01f73b2 Mon Sep 17 00:00:00 2001 From: Richard Kennedy Date: Tue, 26 Jan 2010 17:10:48 +0000 Subject: drm/ttm: remove padding from ttm_ref_object on 64bit builds Re-order structure ttm_ref_object to remove 8 bytes of alignment padding on 64 bit builds, so shrinking its size from 72 to 64 bytes allowing it to fit into a smaller slab. Signed-off-by: Richard Kennedy Acked-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c index 1099abac824..75e9d6f86ba 100644 --- a/drivers/gpu/drm/ttm/ttm_object.c +++ b/drivers/gpu/drm/ttm/ttm_object.c @@ -109,8 +109,8 @@ struct ttm_ref_object { struct drm_hash_item hash; struct list_head head; struct kref kref; - struct ttm_base_object *obj; enum ttm_ref_type ref_type; + struct ttm_base_object *obj; struct ttm_object_file *tfile; }; -- cgit v1.2.3 From 110b20c3ddcfa98cc932aef3af2d59b4e0841f08 Mon Sep 17 00:00:00 2001 From: Austin Yuan Date: Thu, 21 Jan 2010 13:45:40 +0800 Subject: drm/ttm: remove unnecessary save_flags and ttm_flag_masked in ttm_bo_util.c Signed-off-by: Austin Yuan Acked-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo_util.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index ceae52f45c3..3f72fe1ddf8 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -53,7 +53,6 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, { struct ttm_tt *ttm = bo->ttm; struct ttm_mem_reg *old_mem = &bo->mem; - uint32_t save_flags = old_mem->placement; int ret; if (old_mem->mem_type != TTM_PL_SYSTEM) { @@ -62,7 +61,6 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, ttm_flag_masked(&old_mem->placement, TTM_PL_FLAG_SYSTEM, TTM_PL_MASK_MEM); old_mem->mem_type = TTM_PL_SYSTEM; - save_flags = old_mem->placement; } ret = ttm_tt_set_placement_caching(ttm, new_mem->placement); @@ -77,7 +75,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, *old_mem = *new_mem; new_mem->mm_node = NULL; - ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE); + return 0; } EXPORT_SYMBOL(ttm_bo_move_ttm); @@ -219,7 +217,6 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, void *old_iomap; void *new_iomap; int ret; - uint32_t save_flags = old_mem->placement; unsigned long i; unsigned long page; unsigned long add = 0; @@ -270,7 +267,6 @@ out2: *old_mem = *new_mem; new_mem->mm_node = NULL; - ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE); if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && (ttm != NULL)) { ttm_tt_unbind(ttm); @@ -537,7 +533,6 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; struct ttm_mem_reg *old_mem = &bo->mem; int ret; - uint32_t save_flags = old_mem->placement; struct ttm_buffer_object *ghost_obj; void *tmp_obj = NULL; @@ -598,7 +593,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, *old_mem = *new_mem; new_mem->mm_node = NULL; - ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE); + return 0; } EXPORT_SYMBOL(ttm_bo_move_accel_cleanup); -- cgit v1.2.3 From 8e19a951774a16cf2626292ae06fd2b62630e67e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 30 Jan 2010 03:38:06 +0000 Subject: drm/vmwgfx: Correctly detect 3D Signed-off-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 ++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 19 +++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 2 +- 4 files changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index dedd121d8fe..f47ff2c0546 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -357,6 +357,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; register_pm_notifier(&dev_priv->pm_nb); + DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? "Have 3D\n" : "No 3D\n"); + return 0; out_no_device: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 50529a7f06f..59acc51993f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -389,6 +389,7 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence); extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason); extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma); +extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv); /** * TTM glue - vmwgfx_ttm_glue.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index f7d5f70b52d..4157547cc6e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -29,6 +29,25 @@ #include "drmP.h" #include "ttm/ttm_placement.h" +bool vmw_fifo_have_3d(struct vmw_private *dev_priv) +{ + __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + uint32_t fifo_min, hwversion; + + fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN); + if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) + return false; + + hwversion = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION); + if (hwversion == 0) + return false; + + if (hwversion < SVGA3D_HWVERSION_WS65_B1) + return false; + + return true; +} + int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 5fa6a4ed238..778851f9f1d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -43,7 +43,7 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, param->value = vmw_overlay_num_free_overlays(dev_priv); break; case DRM_VMW_PARAM_3D: - param->value = dev_priv->capabilities & SVGA_CAP_3D ? 1 : 0; + param->value = vmw_fifo_have_3d(dev_priv) ? 1 : 0; break; case DRM_VMW_PARAM_FIFO_OFFSET: param->value = dev_priv->mmio_start; -- cgit v1.2.3 From c188660f6dbb0df9febe1b841a16c66c28353c15 Mon Sep 17 00:00:00 2001 From: Peter Hanzel Date: Sat, 30 Jan 2010 03:38:07 +0000 Subject: drm/vmwgfx: Request SVGA version 2 and bail if not found This fixes the driver not loading on older versions of VMware. Signed-off-by: Peter Hanzel Signed-off-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index f47ff2c0546..a6e8f687fa6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -209,6 +209,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) { struct vmw_private *dev_priv; int ret; + uint32_t svga_id; dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (unlikely(dev_priv == NULL)) { @@ -239,6 +240,16 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->mmio_start = pci_resource_start(dev->pdev, 2); mutex_lock(&dev_priv->hw_mutex); + + vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); + svga_id = vmw_read(dev_priv, SVGA_REG_ID); + if (svga_id != SVGA_ID_2) { + ret = -ENOSYS; + DRM_ERROR("Unsuported SVGA ID 0x%x\n", svga_id); + mutex_unlock(&dev_priv->hw_mutex); + goto out_err0; + } + dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); if (dev_priv->capabilities & SVGA_CAP_GMR) { -- cgit v1.2.3 From 5ffdb658f605cbc420944e7c7eeec9fbb8a73772 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 30 Jan 2010 03:38:08 +0000 Subject: drm/vmwgfx: Don't send bad flags to the host Signed-off-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 ++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 10 ++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 16 +++++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 59acc51993f..135be9688c9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -96,6 +96,8 @@ struct vmw_surface { struct drm_vmw_size *sizes; uint32_t num_sizes; + bool scanout; + /* TODO so far just a extra pointer */ struct vmw_cursor_snooper snooper; }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 686692de209..eeba6d1d06e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -707,6 +707,9 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, if (ret) goto try_dmabuf; + if (!surface->scanout) + goto err_not_scanout; + ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, mode_cmd->width, mode_cmd->height); @@ -740,6 +743,13 @@ try_dmabuf: } return &vfb->base; + +err_not_scanout: + DRM_ERROR("surface not marked as scanout\n"); + /* vmw_user_surface_lookup takes one ref */ + vmw_surface_unreference(&surface); + + return NULL; } static int vmw_kms_fb_changed(struct drm_device *dev) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index e01db120eff..c7efbd47ab8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -35,6 +35,11 @@ #define VMW_RES_SURFACE ttm_driver_type1 #define VMW_RES_STREAM ttm_driver_type2 +/* XXX: This isn't a real hardware flag, but just a hack for kernel to + * know about primary surfaces. Find a better way to accomplish this. + */ +#define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9) + struct vmw_user_context { struct ttm_base_object base; struct vmw_resource res; @@ -599,8 +604,17 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, if (unlikely(ret != 0)) goto out_err1; + if (srf->flags & SVGA3D_SURFACE_HINT_SCANOUT) { + /* we should not send this flag down to hardware since + * its not a official one + */ + srf->flags &= ~SVGA3D_SURFACE_HINT_SCANOUT; + srf->scanout = true; + } else { + srf->scanout = false; + } - if (srf->flags & (1 << 9) && + if (srf->scanout && srf->num_sizes == 1 && srf->sizes[0].width == 64 && srf->sizes[0].height == 64 && -- cgit v1.2.3 From ff82f052d2a187dd0fa0e431ba70eb457c71a40e Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 22 Jan 2010 15:19:00 +0100 Subject: drm/radeon/kms: Bailout of blit if error happen & protect with mutex V3 If an error happen in r600_blit_prepare_copy report it rather than WARNING and keeping execution. For instance if ib allocation failed we did just warn about but then latter tried to access NULL ib ptr causing oops. This patch also protect r600_copy_blit with a mutex as otherwise one process might overwrite blit temporary data with new one possibly leading to GPU lockup. Should partialy or totaly fix: https://bugzilla.redhat.com/show_bug.cgi?id=553279 V2 failing blit initialization is not fatal, fallback to memcpy when this happen V3 init blit before startup as we pin in startup, remove duplicate code (this one was actualy tested unlike V2) Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 54 +++++++++++++++++----------------- drivers/gpu/drm/radeon/r600_blit_kms.c | 7 +++-- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/rv770.c | 31 ++++++++++--------- 4 files changed, 48 insertions(+), 45 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d0bd117a463..b833b4b9716 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1788,23 +1788,24 @@ void r600_fence_ring_emit(struct radeon_device *rdev, radeon_ring_write(rdev, RB_INT_STAT); } -int r600_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_pages, - struct radeon_fence *fence) -{ - /* FIXME: implement */ - return 0; -} - int r600_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_pages, struct radeon_fence *fence) { - r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE); + int r; + + mutex_lock(&rdev->r600_blit.mutex); + rdev->r600_blit.vb_ib = NULL; + r = r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE); + if (r) { + if (rdev->r600_blit.vb_ib) + radeon_ib_free(rdev, &rdev->r600_blit.vb_ib); + mutex_unlock(&rdev->r600_blit.mutex); + return r; + } r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE); r600_blit_done_copy(rdev, fence); + mutex_unlock(&rdev->r600_blit.mutex); return 0; } @@ -1860,26 +1861,19 @@ int r600_startup(struct radeon_device *rdev) return r; } r600_gpu_init(rdev); - - if (!rdev->r600_blit.shader_obj) { - r = r600_blit_init(rdev); + /* pin copy shader into vram */ + if (rdev->r600_blit.shader_obj) { + r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); + if (unlikely(r != 0)) + return r; + r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM, + &rdev->r600_blit.shader_gpu_addr); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); if (r) { - DRM_ERROR("radeon: failed blitter (%d).\n", r); + dev_err(rdev->dev, "(%d) pin blit object failed\n", r); return r; } } - - r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (unlikely(r != 0)) - return r; - r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM, - &rdev->r600_blit.shader_gpu_addr); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); - if (r) { - dev_err(rdev->dev, "(%d) pin blit object failed\n", r); - return r; - } - /* Enable IRQ */ r = r600_irq_init(rdev); if (r) { @@ -2051,6 +2045,12 @@ int r600_init(struct radeon_device *rdev) r = r600_pcie_gart_init(rdev); if (r) return r; + r = r600_blit_init(rdev); + if (r) { + r600_blit_fini(rdev); + rdev->asic->copy = NULL; + dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); + } rdev->accel_working = true; r = r600_startup(rdev); diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index 2bedce477a9..af1c3ca8a4c 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -449,6 +449,7 @@ int r600_blit_init(struct radeon_device *rdev) u32 packet2s[16]; int num_packet2s = 0; + mutex_init(&rdev->r600_blit.mutex); rdev->r600_blit.state_offset = 0; if (rdev->family >= CHIP_RV770) @@ -557,7 +558,8 @@ int r600_blit_prepare_copy(struct radeon_device *rdev, int size_bytes) int dwords_per_loop = 76, num_loops; r = r600_vb_ib_get(rdev); - WARN_ON(r); + if (r) + return r; /* set_render_target emits 2 extra dwords on rv6xx */ if (rdev->family > CHIP_R600 && rdev->family < CHIP_RV770) @@ -583,7 +585,8 @@ int r600_blit_prepare_copy(struct radeon_device *rdev, int size_bytes) ring_size += 5; /* done copy */ ring_size += 7; /* fence emit for done copy */ r = radeon_ring_lock(rdev, ring_size); - WARN_ON(r); + if (r) + return r; set_default_state(rdev); /* 14 */ set_shaders(rdev); /* 26 */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index f7df1a7e441..2d5f2bfa720 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -416,6 +416,7 @@ struct r600_ih { }; struct r600_blit { + struct mutex mutex; struct radeon_bo *shader_obj; u64 shader_gpu_addr; u32 vs_offset, ps_offset; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index cf8f2b17d62..2d465768ac7 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -887,26 +887,19 @@ static int rv770_startup(struct radeon_device *rdev) return r; } rv770_gpu_init(rdev); - - if (!rdev->r600_blit.shader_obj) { - r = r600_blit_init(rdev); + /* pin copy shader into vram */ + if (rdev->r600_blit.shader_obj) { + r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); + if (unlikely(r != 0)) + return r; + r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM, + &rdev->r600_blit.shader_gpu_addr); + radeon_bo_unreserve(rdev->r600_blit.shader_obj); if (r) { - DRM_ERROR("radeon: failed blitter (%d).\n", r); + DRM_ERROR("failed to pin blit object %d\n", r); return r; } } - - r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); - if (unlikely(r != 0)) - return r; - r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM, - &rdev->r600_blit.shader_gpu_addr); - radeon_bo_unreserve(rdev->r600_blit.shader_obj); - if (r) { - DRM_ERROR("failed to pin blit object %d\n", r); - return r; - } - /* Enable IRQ */ r = r600_irq_init(rdev); if (r) { @@ -1062,6 +1055,12 @@ int rv770_init(struct radeon_device *rdev) r = r600_pcie_gart_init(rdev); if (r) return r; + r = r600_blit_init(rdev); + if (r) { + r600_blit_fini(rdev); + rdev->asic->copy = NULL; + dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); + } rdev->accel_working = true; r = rv770_startup(rdev); -- cgit v1.2.3 From f71d0187987e691516cd10c2702f002c0e2f0edc Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 1 Feb 2010 11:35:47 +1000 Subject: drm/radeon/kms: move radeon KMS on/off switch out of staging. We are happy enough that the KMS driver is stable enough for enough people for the kms enable/disable to leave staging. Distros can now contemplate turning this on. Signed-off-by: Dave Airlie --- drivers/gpu/drm/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 96eddd17e05..305c5900396 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -66,6 +66,8 @@ config DRM_RADEON If M is selected, the module will be called radeon. +source "drivers/gpu/drm/radeon/Kconfig" + config DRM_I810 tristate "Intel I810" depends on DRM && AGP && AGP_INTEL -- cgit v1.2.3 From 17aafccab4352b422aa01fa6ebf82daff693a5b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 22 Jan 2010 09:20:00 +0100 Subject: drm/radeon/kms: Fix oops after radeon_cs_parser_init() failure. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If radeon_cs_parser_init() fails, radeon_cs_ioctl() calls radeon_cs_parser_fini() with the non-zero error value. The latter dereferenced parser->ib which hasn't been initialized yet -> boom. Add a test for parser->ib being non-NULL before dereferencing it. Signed-off-by: Michel Dänzer Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 1496cb8658e..1190148cf5e 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -189,7 +189,7 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error) { unsigned i; - if (error) { + if (error && parser->ib) { radeon_bo_list_unvalidate(&parser->validated, parser->ib->fence); } else { -- cgit v1.2.3 From 33c5fd121eabbccc9103daf6cda36941eb3c349f Mon Sep 17 00:00:00 2001 From: David John Date: Wed, 27 Jan 2010 15:19:08 +0530 Subject: drm/i915: Disable SR when more than one pipe is enabled Self Refresh should be disabled on dual plane configs. Otherwise, as the SR watermark is not calculated for such configs, switching to non VGA mode causes FIFO underrun and display flicker. This fixes Korg Bug #14897. Signed-off-by: David John Signed-off-by: Jesse Barnes Cc: stable@kernel.org Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5f14dfbf715..12775df1bbf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2520,6 +2520,10 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock, sr_entries = roundup(sr_entries / cacheline_size, 1); DRM_DEBUG("self-refresh entries: %d\n", sr_entries); I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); + } else { + /* Turn off self refresh if both pipes are enabled */ + I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) + & ~FW_BLC_SELF_EN); } DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n", @@ -2563,6 +2567,10 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, srwm = 1; srwm &= 0x3f; I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); + } else { + /* Turn off self refresh if both pipes are enabled */ + I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) + & ~FW_BLC_SELF_EN); } DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n", @@ -2631,6 +2639,10 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, if (srwm < 0) srwm = 1; I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f)); + } else { + /* Turn off self refresh if both pipes are enabled */ + I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) + & ~FW_BLC_SELF_EN); } DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", -- cgit v1.2.3 From 67026e03244d76b8f1fa725b079d4182fe8910aa Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Tue, 2 Feb 2010 20:09:04 +0100 Subject: drm/i915: slow acpi_lid_open() causes flickering - V2 acpi_lid_open() could take up to 10ms on my computer. Some component is calling the drm GETCONNECTOR ioctl many times in a row. This results in flickering (for example, when starting a video). Fix it by assuming an always connected lid status. Signed-off-by: Thomas Meyer Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_lvds.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 75a9772061c..b1d0acbae4e 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -622,6 +622,13 @@ static const struct dmi_system_id bad_lid_status[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire one"), }, }, + { + .ident = "Aspire 1810T", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1810T"), + }, + }, { .ident = "PC-81005", .matches = { @@ -643,7 +650,7 @@ static enum drm_connector_status intel_lvds_detect(struct drm_connector *connect { enum drm_connector_status status = connector_status_connected; - if (!acpi_lid_open() && !dmi_check_system(bad_lid_status)) + if (!dmi_check_system(bad_lid_status) && !acpi_lid_open()) status = connector_status_disconnected; return status; -- cgit v1.2.3 From 93533c291a0af78ca57115fc44d2e6c4c9517cd2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 31 Jan 2010 10:40:48 +0000 Subject: drm/i915: Fix leak of relocs along do_execbuffer error path Following a gpu hang, we would leak the relocation buffer. So simply earrange the error path to always free the relocation buffer. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1ef7ec4f38f..be0fd1a6332 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3584,6 +3584,9 @@ i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object2 *exec_list, uint32_t reloc_count = 0, i; int ret = 0; + if (relocs == NULL) + return 0; + for (i = 0; i < buffer_count; i++) { struct drm_i915_gem_relocation_entry __user *user_relocs; int unwritten; @@ -3673,7 +3676,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_gem_object *batch_obj; struct drm_i915_gem_object *obj_priv; struct drm_clip_rect *cliprects = NULL; - struct drm_i915_gem_relocation_entry *relocs; + struct drm_i915_gem_relocation_entry *relocs = NULL; int ret = 0, ret2, i, pinned = 0; uint64_t exec_offset; uint32_t seqno, flush_domains, reloc_index; @@ -3950,6 +3953,7 @@ err: mutex_unlock(&dev->struct_mutex); +pre_mutex_err: /* Copy the updated relocations out regardless of current error * state. Failure to update the relocs would mean that the next * time userland calls execbuf, it would do so with presumed offset @@ -3964,7 +3968,6 @@ err: ret = ret2; } -pre_mutex_err: drm_free_large(object_list); kfree(cliprects); -- cgit v1.2.3 From c38c7b64a2747a211c3a6e8e5919ee25ccd474e7 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 4 Feb 2010 17:27:27 +0100 Subject: drm/radeon/kms: move blit initialization after we disabled VGA VGA might be overwritting VRAM and corrupt our blit shader leading to corruption, it likely won't happen if you load fbcon right after radeon. Thanks to Shawn Starr and Andre Maasikas for tracking down this issue. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 12 ++++++------ drivers/gpu/drm/radeon/rv770.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index b833b4b9716..8c94040cb7f 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1861,6 +1861,12 @@ int r600_startup(struct radeon_device *rdev) return r; } r600_gpu_init(rdev); + r = r600_blit_init(rdev); + if (r) { + r600_blit_fini(rdev); + rdev->asic->copy = NULL; + dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); + } /* pin copy shader into vram */ if (rdev->r600_blit.shader_obj) { r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); @@ -2045,12 +2051,6 @@ int r600_init(struct radeon_device *rdev) r = r600_pcie_gart_init(rdev); if (r) return r; - r = r600_blit_init(rdev); - if (r) { - r600_blit_fini(rdev); - rdev->asic->copy = NULL; - dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); - } rdev->accel_working = true; r = r600_startup(rdev); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 2d465768ac7..06b037eebef 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -887,6 +887,12 @@ static int rv770_startup(struct radeon_device *rdev) return r; } rv770_gpu_init(rdev); + r = r600_blit_init(rdev); + if (r) { + r600_blit_fini(rdev); + rdev->asic->copy = NULL; + dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); + } /* pin copy shader into vram */ if (rdev->r600_blit.shader_obj) { r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); @@ -1055,12 +1061,6 @@ int rv770_init(struct radeon_device *rdev) r = r600_pcie_gart_init(rdev); if (r) return r; - r = r600_blit_init(rdev); - if (r) { - r600_blit_fini(rdev); - rdev->asic->copy = NULL; - dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); - } rdev->accel_working = true; r = rv770_startup(rdev); -- cgit v1.2.3 From 062b389c8704e539e234cfd67c7e034a514f50bf Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 4 Feb 2010 20:36:39 +0100 Subject: drm/radeon/kms: fix regression rendering issue on R6XX/R7XX It seems that some R6XX/R7XX silently ignore HDP flush when programmed through ring, this patch addback an ioctl callback to allow R6XX/R7XX hw to perform such flush through MMIO in order to fix a regression. For more details see: http://bugzilla.kernel.org/show_bug.cgi?id=15186 Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 15 +++++++++++++++ drivers/gpu/drm/radeon/radeon.h | 7 +++++++ drivers/gpu/drm/radeon/radeon_asic.h | 11 +++++++++++ drivers/gpu/drm/radeon/radeon_gem.c | 3 +++ 4 files changed, 36 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 8c94040cb7f..45d565bae71 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2900,3 +2900,18 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev) return 0; #endif } + +/** + * r600_ioctl_wait_idle - flush host path cache on wait idle ioctl + * rdev: radeon device structure + * bo: buffer object struct which userspace is waiting for idle + * + * Some R6XX/R7XX doesn't seems to take into account HDP flush performed + * through ring buffer, this leads to corruption in rendering, see + * http://bugzilla.kernel.org/show_bug.cgi?id=15186 to avoid this we + * directly perform HDP flush by writing register through MMIO. + */ +void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) +{ + WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); +} diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 2d5f2bfa720..37150fc406b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -661,6 +661,13 @@ struct radeon_asic { void (*hpd_fini)(struct radeon_device *rdev); bool (*hpd_sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd); void (*hpd_set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd); + /* ioctl hw specific callback. Some hw might want to perform special + * operation on specific ioctl. For instance on wait idle some hw + * might want to perform and HDP flush through MMIO as it seems that + * some R6XX/R7XX hw doesn't take HDP flush into account if programmed + * through ring. + */ + void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); }; /* diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index f2fbd2e4e9d..05ee1aeac3f 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -117,6 +117,7 @@ static struct radeon_asic r100_asic = { .hpd_fini = &r100_hpd_fini, .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -176,6 +177,7 @@ static struct radeon_asic r300_asic = { .hpd_fini = &r100_hpd_fini, .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; /* @@ -219,6 +221,7 @@ static struct radeon_asic r420_asic = { .hpd_fini = &r100_hpd_fini, .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -267,6 +270,7 @@ static struct radeon_asic rs400_asic = { .hpd_fini = &r100_hpd_fini, .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -323,6 +327,7 @@ static struct radeon_asic rs600_asic = { .hpd_fini = &rs600_hpd_fini, .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -370,6 +375,7 @@ static struct radeon_asic rs690_asic = { .hpd_fini = &rs600_hpd_fini, .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -421,6 +427,7 @@ static struct radeon_asic rv515_asic = { .hpd_fini = &rs600_hpd_fini, .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; @@ -463,6 +470,7 @@ static struct radeon_asic r520_asic = { .hpd_fini = &rs600_hpd_fini, .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, + .ioctl_wait_idle = NULL, }; /* @@ -504,6 +512,7 @@ void r600_hpd_fini(struct radeon_device *rdev); bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); +extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); static struct radeon_asic r600_asic = { .init = &r600_init, @@ -538,6 +547,7 @@ static struct radeon_asic r600_asic = { .hpd_fini = &r600_hpd_fini, .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, + .ioctl_wait_idle = r600_ioctl_wait_idle, }; /* @@ -582,6 +592,7 @@ static struct radeon_asic rv770_asic = { .hpd_fini = &r600_hpd_fini, .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, + .ioctl_wait_idle = r600_ioctl_wait_idle, }; #endif diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 0e1325e1853..db8e9a355a0 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -308,6 +308,9 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, } robj = gobj->driver_private; r = radeon_bo_wait(robj, NULL, false); + /* callback hw specific functions if any */ + if (robj->rdev->asic->ioctl_wait_idle) + robj->rdev->asic->ioctl_wait_idle(robj->rdev, robj); mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(gobj); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 9e5b2af75abc67c13005c706cf95bbbb78f7fddc Mon Sep 17 00:00:00 2001 From: Pauli Nieminen Date: Thu, 4 Feb 2010 19:20:53 +0200 Subject: drm/r100/kms: Emit cache flush to the end of command buffer. (v2) Cache flush is required in case CPU is accessing rendered data. This fixes glean/readPixSanity test case and random rendering errors in sauerbraten and warzone2100. v2 Fix comment ordering in r100_fence_ring_emit and remove extra defines added in first version. Signed-off-by: Pauli Nieminen Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 11c9a3fe681..626e79023e3 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -354,11 +354,17 @@ u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc) return RREG32(RADEON_CRTC2_CRNT_FRAME); } +/* Who ever call radeon_fence_emit should call ring_lock and ask + * for enough space (today caller are ib schedule and buffer move) */ void r100_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence) { - /* Who ever call radeon_fence_emit should call ring_lock and ask - * for enough space (today caller are ib schedule and buffer move) */ + /* We have to make sure that caches are flushed before + * CPU might read something from VRAM. */ + radeon_ring_write(rdev, PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, RADEON_RB3D_DC_FLUSH_ALL); + radeon_ring_write(rdev, PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, RADEON_RB3D_ZC_FLUSH_ALL); /* Wait until IDLE & CLEAN */ radeon_ring_write(rdev, PACKET0(0x1720, 0)); radeon_ring_write(rdev, (1 << 16) | (1 << 17)); -- cgit v1.2.3 From d7748bacbbee80b2cc4b690a74d5db2cd84acd7b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 2 Feb 2010 14:40:33 -0800 Subject: ati_pcigart: fix printk format warning Fix ati_pcigart printk format warning: drivers/gpu/drm/ati_pcigart.c:115: warning: format '%Lx' expects type 'long long unsigned int', but argument 3 has type 'dma_addr_t' Signed-off-by: Randy Dunlap Cc: Zhenyu Wang Cc: Dave Airlie Signed-off-by: Andrew Morton Signed-off-by: Dave Airlie --- drivers/gpu/drm/ati_pcigart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c index a1fce68e3bb..17be051b7aa 100644 --- a/drivers/gpu/drm/ati_pcigart.c +++ b/drivers/gpu/drm/ati_pcigart.c @@ -113,7 +113,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga if (pci_set_dma_mask(dev->pdev, gart_info->table_mask)) { DRM_ERROR("fail to set dma mask to 0x%Lx\n", - gart_info->table_mask); + (unsigned long long)gart_info->table_mask); ret = 1; goto done; } -- cgit v1.2.3 From 94cf6434a1bc5958d5da3be62f1272792dada2bf Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 2 Feb 2010 14:40:29 -0800 Subject: drivers/gpu/drm/radeon/radeon_combios.c: fix warning drivers/gpu/drm/radeon/radeon_combios.c: In function 'radeon_combios_get_lvds_info': drivers/gpu/drm/radeon/radeon_combios.c:893: warning: comparison is always false due to limited range of data type Cc: Dave Airlie Signed-off-by: Andrew Morton Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 579c8920e08..e7b19440102 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -971,8 +971,7 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder lvds->native_mode.vdisplay); lvds->panel_vcc_delay = RBIOS16(lcd_info + 0x2c); - if (lvds->panel_vcc_delay > 2000 || lvds->panel_vcc_delay < 0) - lvds->panel_vcc_delay = 2000; + lvds->panel_vcc_delay = min_t(u16, lvds->panel_vcc_delay, 2000); lvds->panel_pwr_delay = RBIOS8(lcd_info + 0x24); lvds->panel_digon_delay = RBIOS16(lcd_info + 0x38) & 0xf; -- cgit v1.2.3 From 655efd3dc92cd0d37292157178d33deb0430aeaa Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 2 Feb 2010 11:51:45 +0100 Subject: drm/radeon/kms: don't call suspend path before cleaning up GPU In suspend path we unmap the GART table while in cleaning up path we will unbind buffer and thus try to write to unmapped GART leading to oops. In order to avoid this we don't call the suspend path in cleanup path. Cleanup path is clever enough to desactive GPU like the suspend path is doing, thus this was redondant. Tested on: RV370, R420, RV515, RV570, RV610, RV770 (all PCIE) Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 4 +--- drivers/gpu/drm/radeon/r300.c | 5 ++--- drivers/gpu/drm/radeon/r420.c | 3 +-- drivers/gpu/drm/radeon/r520.c | 3 +-- drivers/gpu/drm/radeon/r600.c | 21 +++++++++++++-------- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/rs400.c | 2 -- drivers/gpu/drm/radeon/rs600.c | 2 -- drivers/gpu/drm/radeon/rs690.c | 2 -- drivers/gpu/drm/radeon/rv515.c | 4 +--- drivers/gpu/drm/radeon/rv770.c | 12 ++++++------ 11 files changed, 26 insertions(+), 33 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 626e79023e3..c0d4650cdb7 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3375,7 +3375,6 @@ int r100_suspend(struct radeon_device *rdev) void r100_fini(struct radeon_device *rdev) { - r100_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -3487,13 +3486,12 @@ int r100_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - r100_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); if (rdev->flags & RADEON_IS_PCI) r100_pci_gart_fini(rdev); - radeon_irq_kms_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 0051d11b907..e699e6d053d 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -1327,7 +1327,6 @@ int r300_suspend(struct radeon_device *rdev) void r300_fini(struct radeon_device *rdev) { - r300_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -1418,15 +1417,15 @@ int r300_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - r300_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); if (rdev->flags & RADEON_IS_PCIE) rv370_pcie_gart_fini(rdev); if (rdev->flags & RADEON_IS_PCI) r100_pci_gart_fini(rdev); - radeon_irq_kms_fini(rdev); + radeon_agp_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 4526faaacca..d9373246c97 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -389,16 +389,15 @@ int r420_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - r420_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); if (rdev->flags & RADEON_IS_PCIE) rv370_pcie_gart_fini(rdev); if (rdev->flags & RADEON_IS_PCI) r100_pci_gart_fini(rdev); radeon_agp_fini(rdev); - radeon_irq_kms_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 9a189072f2b..ddf5731eba0 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -294,13 +294,12 @@ int r520_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rv515_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); rv370_pcie_gart_fini(rdev); radeon_agp_fini(rdev); - radeon_irq_kms_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 45d565bae71..9661a469f3b 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1654,6 +1654,12 @@ void r600_ring_init(struct radeon_device *rdev, unsigned ring_size) rdev->cp.align_mask = 16 - 1; } +void r600_cp_fini(struct radeon_device *rdev) +{ + r600_cp_stop(rdev); + radeon_ring_fini(rdev); +} + /* * GPU scratch registers helpers function. @@ -2055,9 +2061,11 @@ int r600_init(struct radeon_device *rdev) rdev->accel_working = true; r = r600_startup(rdev); if (r) { - r600_suspend(rdev); + dev_err(rdev->dev, "disabling GPU acceleration\n"); + r600_cp_fini(rdev); r600_wb_fini(rdev); - radeon_ring_fini(rdev); + r600_irq_fini(rdev); + radeon_irq_kms_fini(rdev); r600_pcie_gart_fini(rdev); rdev->accel_working = false; } @@ -2083,20 +2091,17 @@ int r600_init(struct radeon_device *rdev) void r600_fini(struct radeon_device *rdev) { - /* Suspend operations */ - r600_suspend(rdev); - r600_audio_fini(rdev); r600_blit_fini(rdev); + r600_cp_fini(rdev); + r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); - radeon_ring_fini(rdev); - r600_wb_fini(rdev); r600_pcie_gart_fini(rdev); + radeon_agp_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_clocks_fini(rdev); - radeon_agp_fini(rdev); radeon_bo_fini(rdev); radeon_atombios_fini(rdev); kfree(rdev->bios); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 37150fc406b..f57480ba135 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1150,6 +1150,7 @@ extern bool r600_card_posted(struct radeon_device *rdev); extern void r600_cp_stop(struct radeon_device *rdev); extern void r600_ring_init(struct radeon_device *rdev, unsigned ring_size); extern int r600_cp_resume(struct radeon_device *rdev); +extern void r600_cp_fini(struct radeon_device *rdev); extern int r600_count_pipe_bits(uint32_t val); extern int r600_gart_clear_page(struct radeon_device *rdev, int i); extern int r600_mc_wait_for_idle(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 9f5418983e2..eeeb0d6d7a4 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -448,7 +448,6 @@ int rs400_suspend(struct radeon_device *rdev) void rs400_fini(struct radeon_device *rdev) { - rs400_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -527,7 +526,6 @@ int rs400_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rs400_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index d5255751e7b..c3818562a13 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -610,7 +610,6 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { - rs600_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -689,7 +688,6 @@ int rs600_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rs600_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index cd31da91377..06e2771aee5 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -676,7 +676,6 @@ int rs690_suspend(struct radeon_device *rdev) void rs690_fini(struct radeon_device *rdev) { - rs690_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -756,7 +755,6 @@ int rs690_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rs690_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 62756717b04..0e1e6b8632b 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -537,7 +537,6 @@ void rv515_set_safe_registers(struct radeon_device *rdev) void rv515_fini(struct radeon_device *rdev) { - rv515_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -615,13 +614,12 @@ int rv515_init(struct radeon_device *rdev) if (r) { /* Somethings want wront with the accel init stop accel */ dev_err(rdev->dev, "Disabling GPU acceleration\n"); - rv515_suspend(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); + radeon_irq_kms_fini(rdev); rv370_pcie_gart_fini(rdev); radeon_agp_fini(rdev); - radeon_irq_kms_fini(rdev); rdev->accel_working = false; } return 0; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 06b037eebef..c9320e72798 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1065,9 +1065,11 @@ int rv770_init(struct radeon_device *rdev) rdev->accel_working = true; r = rv770_startup(rdev); if (r) { - rv770_suspend(rdev); + dev_err(rdev->dev, "disabling GPU acceleration\n"); + r600_cp_fini(rdev); r600_wb_fini(rdev); - radeon_ring_fini(rdev); + r600_irq_fini(rdev); + radeon_irq_kms_fini(rdev); rv770_pcie_gart_fini(rdev); rdev->accel_working = false; } @@ -1089,13 +1091,11 @@ int rv770_init(struct radeon_device *rdev) void rv770_fini(struct radeon_device *rdev) { - rv770_suspend(rdev); - r600_blit_fini(rdev); + r600_cp_fini(rdev); + r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); - radeon_ring_fini(rdev); - r600_wb_fini(rdev); rv770_pcie_gart_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); -- cgit v1.2.3 From 23fff28a9b0529869bffef8aab0d3f350dd3b5a4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2010 11:57:42 +1000 Subject: drm/radeon/kms: disable HDMI audio for now on rv710/rv730 Support isn't correct yet and we are getting green tinges on the displays. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index 99e2c3891a7..b1c1d343345 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -35,7 +35,7 @@ */ static int r600_audio_chipset_supported(struct radeon_device *rdev) { - return rdev->family >= CHIP_R600 + return (rdev->family >= CHIP_R600 && rdev->family < CHIP_RV710) || rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740; -- cgit v1.2.3 From 624ab4f87e99f10ea3b45e76039c477fd4d7a7e6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 27 Jan 2010 16:07:15 +1000 Subject: drm/radeon/kms: make initial state of load detect property correct. this was incorrect on my rs480. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 55266416fa4..2d8e5a70f28 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1343,7 +1343,7 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_connector->dac_load_detect = false; drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.load_detect_property, - 1); + radeon_connector->dac_load_detect); drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.tv_std_property, radeon_combios_get_tv_info(rdev)); -- cgit v1.2.3 From a17538f93c16f0e15e35dc31eedad87e2d9c5c26 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2010 13:41:54 +1000 Subject: drm/radeon/kms: rs400/480 MC setup is different than r300. Boot testing on my rs480 laptop found the MC idle never happened on startup, a quick check with AMD found the idle bit is in a different place on the rs4xx than r300. Implement a new rs400 mc idle function to fix this. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rs400.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index eeeb0d6d7a4..287fcebfb4e 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -223,15 +223,31 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) return 0; } +int rs400_mc_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32(0x0150); + if (tmp & (1 << 2)) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + void rs400_gpu_init(struct radeon_device *rdev) { /* FIXME: HDP same place on rs400 ? */ r100_hdp_reset(rdev); /* FIXME: is this correct ? */ r420_pipes_init(rdev); - if (r300_mc_wait_for_idle(rdev)) { - printk(KERN_WARNING "Failed to wait MC idle while " - "programming pipes. Bad things might happen.\n"); + if (rs400_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "rs400: Failed to wait MC idle while " + "programming pipes. Bad things might happen. %08x\n", RREG32(0x150)); } } @@ -370,8 +386,8 @@ void rs400_mc_program(struct radeon_device *rdev) r100_mc_stop(rdev, &save); /* Wait for mc idle */ - if (r300_mc_wait_for_idle(rdev)) - dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n"); + if (rs400_mc_wait_for_idle(rdev)) + dev_warn(rdev->dev, "rs400: Wait MC idle timeout before updating MC.\n"); WREG32(R_000148_MC_FB_LOCATION, S_000148_MC_FB_START(rdev->mc.vram_start >> 16) | S_000148_MC_FB_TOP(rdev->mc.vram_end >> 16)); -- cgit v1.2.3 From 5ff55717674470b96562f931f778c878080755b7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2010 13:57:03 +1000 Subject: drm/radeon/kms: fix r300 vram width calculations This was incorrect according to the docs and the UMS driver does it like this. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r300.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index e699e6d053d..43b55a030b4 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -506,11 +506,14 @@ void r300_vram_info(struct radeon_device *rdev) /* DDR for all card after R300 & IGP */ rdev->mc.vram_is_ddr = true; + tmp = RREG32(RADEON_MEM_CNTL); - if (tmp & R300_MEM_NUM_CHANNELS_MASK) { - rdev->mc.vram_width = 128; - } else { - rdev->mc.vram_width = 64; + tmp &= R300_MEM_NUM_CHANNELS_MASK; + switch (tmp) { + case 0: rdev->mc.vram_width = 64; break; + case 1: rdev->mc.vram_width = 128; break; + case 2: rdev->mc.vram_width = 256; break; + default: rdev->mc.vram_width = 128; break; } r100_vram_init_sizes(rdev); -- cgit v1.2.3 From 38fd2c6ff526e6a59edfa8e08f6f0724646784c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 28 Jan 2010 18:16:30 +0100 Subject: drm/radeon/kms: suspend and resume audio stuff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes FDO bug #26214 Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 8 ++++++++ drivers/gpu/drm/radeon/r600_audio.c | 3 +-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 9661a469f3b..29faebc105d 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1950,6 +1950,13 @@ int r600_resume(struct radeon_device *rdev) DRM_ERROR("radeon: failled testing IB (%d).\n", r); return r; } + + r = r600_audio_init(rdev); + if (r) { + DRM_ERROR("radeon: audio resume failed\n"); + return r; + } + return r; } @@ -1957,6 +1964,7 @@ int r600_suspend(struct radeon_device *rdev) { int r; + r600_audio_fini(rdev); /* FIXME: we should wait for ring to be empty */ r600_cp_stop(rdev); rdev->cp.ready = false; diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index b1c1d343345..0dcb6904c4f 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -261,7 +261,6 @@ void r600_audio_fini(struct radeon_device *rdev) if (!r600_audio_chipset_supported(rdev)) return; - WREG32_P(R600_AUDIO_ENABLE, 0x0, ~0x81000000); - del_timer(&rdev->audio_timer); + WREG32_P(R600_AUDIO_ENABLE, 0x0, ~0x81000000); } -- cgit v1.2.3 From 1ca137cdcd4e11af03dbe073d48a470b833a456d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2010 19:02:24 +1000 Subject: drm/radeon/kms: change Kconfig text to reflect the new option. Ingo pointed out that we really don't give the user enough warning to make a decision here. So revise the Kconfig text with a better warning. Acked-by: Ingo Molnar Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Kconfig | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig index 5982321be4d..1c02d23f6fc 100644 --- a/drivers/gpu/drm/radeon/Kconfig +++ b/drivers/gpu/drm/radeon/Kconfig @@ -1,10 +1,14 @@ config DRM_RADEON_KMS - bool "Enable modesetting on radeon by default" + bool "Enable modesetting on radeon by default - NEW DRIVER" depends on DRM_RADEON help - Choose this option if you want kernel modesetting enabled by default, - and you have a new enough userspace to support this. Running old - userspaces with this enabled will cause pain. + Choose this option if you want kernel modesetting enabled by default. + + This is a completely new driver. It's only part of the existing drm + for compatibility reasons. It requires an entirely different graphics + stack above it and works very differently from the old drm stack. + i.e. don't enable this unless you know what you are doing it may + cause issues or bugs compared to the previous userspace driver stack. When kernel modesetting is enabled the IOCTL of radeon/drm driver are considered as invalid and an error message is printed -- cgit v1.2.3 From 4b9d2a2112163a757943c78ea98587fc9e828641 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 8 Feb 2010 13:16:55 +1000 Subject: drm/radeon/kms: don't crash if no DDC bus on VGA/DVI connector. This is strange - like really really strange, twilight zone of strange. VGA ports have DDC buses, but sometimes for some reasons the BIOS says we don't and we oops - AMD mentioned bios bugs so we'll have to add quirks. reported on irc by nirbheek and https://bugzilla.redhat.com/show_bug.cgi?id=554323 Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 20 ++++++++++++-------- drivers/gpu/drm/radeon/radeon_display.c | 11 ++++++++++- 2 files changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 2d8e5a70f28..23818854001 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -580,16 +580,18 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; struct drm_encoder_helper_funcs *encoder_funcs; - bool dret; + bool dret = false; enum drm_connector_status ret = connector_status_disconnected; encoder = radeon_best_single_encoder(connector); if (!encoder) ret = connector_status_disconnected; - radeon_i2c_do_lock(radeon_connector->ddc_bus, 1); - dret = radeon_ddc_probe(radeon_connector); - radeon_i2c_do_lock(radeon_connector->ddc_bus, 0); + if (radeon_connector->ddc_bus) { + radeon_i2c_do_lock(radeon_connector->ddc_bus, 1); + dret = radeon_ddc_probe(radeon_connector); + radeon_i2c_do_lock(radeon_connector->ddc_bus, 0); + } if (dret) { if (radeon_connector->edid) { kfree(radeon_connector->edid); @@ -740,11 +742,13 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect struct drm_mode_object *obj; int i; enum drm_connector_status ret = connector_status_disconnected; - bool dret; + bool dret = false; - radeon_i2c_do_lock(radeon_connector->ddc_bus, 1); - dret = radeon_ddc_probe(radeon_connector); - radeon_i2c_do_lock(radeon_connector->ddc_bus, 0); + if (radeon_connector->ddc_bus) { + radeon_i2c_do_lock(radeon_connector->ddc_bus, 1); + dret = radeon_ddc_probe(radeon_connector); + radeon_i2c_do_lock(radeon_connector->ddc_bus, 0); + } if (dret) { if (radeon_connector->edid) { kfree(radeon_connector->edid); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 6a92f994cc2..7e17a362b54 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -278,7 +278,7 @@ static void radeon_print_display_setup(struct drm_device *dev) DRM_INFO(" %s\n", connector_names[connector->connector_type]); if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) DRM_INFO(" %s\n", hpd_names[radeon_connector->hpd.hpd]); - if (radeon_connector->ddc_bus) + if (radeon_connector->ddc_bus) { DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", radeon_connector->ddc_bus->rec.mask_clk_reg, radeon_connector->ddc_bus->rec.mask_data_reg, @@ -288,6 +288,15 @@ static void radeon_print_display_setup(struct drm_device *dev) radeon_connector->ddc_bus->rec.en_data_reg, radeon_connector->ddc_bus->rec.y_clk_reg, radeon_connector->ddc_bus->rec.y_data_reg); + } else { + if (connector->connector_type == DRM_MODE_CONNECTOR_VGA || + connector->connector_type == DRM_MODE_CONNECTOR_DVII || + connector->connector_type == DRM_MODE_CONNECTOR_DVID || + connector->connector_type == DRM_MODE_CONNECTOR_DVIA || + connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) + DRM_INFO(" DDC: no ddc bus - possible BIOS bug - please report to xorg-driver-ati@lists.x.org\n"); + } DRM_INFO(" Encoders:\n"); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); -- cgit v1.2.3 From efa8450f6c93c9d4c99adfea2f52f1d02d878d5b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 9 Feb 2010 09:06:00 +1000 Subject: drm/radeon/kms: add quirk for VGA without DDC on rv730 XFX card. Reported on irc by nirbheek. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index fa82ca74324..2dcda611587 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -287,6 +287,15 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, *connector_type = DRM_MODE_CONNECTOR_DVID; } + /* XFX Pine Group device rv730 reports no VGA DDC lines + * even though they are wired up to record 0x93 + */ + if ((dev->pdev->device == 0x9498) && + (dev->pdev->subsystem_vendor == 0x1682) && + (dev->pdev->subsystem_device == 0x2452)) { + struct radeon_device *rdev = dev->dev_private; + *i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93); + } return true; } -- cgit v1.2.3 From f927b8907cb25943d6275d4ea036c065b8fd3f33 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 27 Jan 2010 14:29:05 +1000 Subject: drm/nouveau: fix non-vram notifier blocks Due to a thinko, these were previously forced to VRAM even if we allocated them in GART. This commit fixes that bug, but keeps the previous behaviour of using VRAM by default until it's been tested properly across more chipsets. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.c | 2 +- drivers/gpu/drm/nouveau/nouveau_notifier.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 343ab7f17cc..fc692e5553a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -56,7 +56,7 @@ int nouveau_vram_pushbuf; module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM"); -int nouveau_vram_notify; +int nouveau_vram_notify = 1; module_param_named(vram_notify, nouveau_vram_notify, int, 0400); MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)"); diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 6c66a34b634..d99dc087f9b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -34,15 +34,20 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct nouveau_bo *ntfy = NULL; + uint32_t flags; int ret; - ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, nouveau_vram_notify ? - TTM_PL_FLAG_VRAM : TTM_PL_FLAG_TT, + if (nouveau_vram_notify) + flags = TTM_PL_FLAG_VRAM; + else + flags = TTM_PL_FLAG_TT; + + ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0x0000, false, true, &ntfy); if (ret) return ret; - ret = nouveau_bo_pin(ntfy, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(ntfy, flags); if (ret) goto out_err; @@ -128,6 +133,8 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, target = NV_DMA_TARGET_PCI; } else { target = NV_DMA_TARGET_AGP; + if (dev_priv->card_type >= NV_50) + offset += dev_priv->vm_gart_base; } } else { NV_ERROR(dev, "Bad DMA target, mem_type %d!\n", -- cgit v1.2.3 From a32ed69d7bb3cd259d813d71281d62993b9a70fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Tue, 26 Jan 2010 14:00:42 +0000 Subject: drm/nouveau: Add module options to disable acceleration. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit noaccel=1 disables all acceleration and doesn't even attempt initialising PGRAPH+PFIFO, nofbaccel=1 only makes fbcon unaccelerated. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.c | 8 ++++++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_fbcon.c | 10 +++++++--- drivers/gpu/drm/nouveau/nouveau_state.c | 32 ++++++++++++++++++++------------ 4 files changed, 37 insertions(+), 15 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index fc692e5553a..da3b93b8450 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -75,6 +75,14 @@ MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status"); int nouveau_ignorelid = 0; module_param_named(ignorelid, nouveau_ignorelid, int, 0400); +MODULE_PARM_DESC(noagp, "Disable all acceleration"); +int nouveau_noaccel = 0; +module_param_named(noaccel, nouveau_noaccel, int, 0400); + +MODULE_PARM_DESC(noagp, "Disable fbcon acceleration"); +int nouveau_nofbaccel = 0; +module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); + MODULE_PARM_DESC(tv_norm, "Default TV norm.\n" "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n" "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n" diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 6b9690418bc..5445cefdd03 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -678,6 +678,8 @@ extern int nouveau_reg_debug; extern char *nouveau_vbios; extern int nouveau_ctxfw; extern int nouveau_ignorelid; +extern int nouveau_nofbaccel; +extern int nouveau_noaccel; /* nouveau_state.c */ extern void nouveau_preclose(struct drm_device *dev, struct drm_file *); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 0b05c869e0e..eddadaccc28 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -267,8 +267,12 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, dev_priv->fbdev_info = info; strcpy(info->fix.id, "nouveaufb"); - info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | - FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT; + if (nouveau_nofbaccel) + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_DISABLED; + else + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT; info->fbops = &nouveau_fbcon_ops; info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset - dev_priv->vm_vram_base; @@ -316,7 +320,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, par->nouveau_fb = nouveau_fb; par->dev = dev; - if (dev_priv->channel) { + if (dev_priv->channel && !nouveau_nofbaccel) { switch (dev_priv->card_type) { case NV_50: nv50_fbcon_accel_init(info); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index f2d0187ba15..241e24d60eb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -427,15 +427,19 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out_timer; - /* PGRAPH */ - ret = engine->graph.init(dev); - if (ret) - goto out_fb; + if (nouveau_noaccel) + engine->graph.accel_blocked = true; + else { + /* PGRAPH */ + ret = engine->graph.init(dev); + if (ret) + goto out_fb; - /* PFIFO */ - ret = engine->fifo.init(dev); - if (ret) - goto out_graph; + /* PFIFO */ + ret = engine->fifo.init(dev); + if (ret) + goto out_graph; + } /* this call irq_preinstall, register irq handler and * call irq_postinstall @@ -479,9 +483,11 @@ nouveau_card_init(struct drm_device *dev) out_irq: drm_irq_uninstall(dev); out_fifo: - engine->fifo.takedown(dev); + if (!nouveau_noaccel) + engine->fifo.takedown(dev); out_graph: - engine->graph.takedown(dev); + if (!nouveau_noaccel) + engine->graph.takedown(dev); out_fb: engine->fb.takedown(dev); out_timer: @@ -518,8 +524,10 @@ static void nouveau_card_takedown(struct drm_device *dev) dev_priv->channel = NULL; } - engine->fifo.takedown(dev); - engine->graph.takedown(dev); + if (!nouveau_noaccel) { + engine->fifo.takedown(dev); + engine->graph.takedown(dev); + } engine->fb.takedown(dev); engine->timer.takedown(dev); engine->mc.takedown(dev); -- cgit v1.2.3 From 69c9700b544e496dc3ccf472a4f3a76dcf4abaf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Tue, 26 Jan 2010 18:39:20 +0000 Subject: drm/nouveau: Add getparam to get available PGRAPH units. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On nv50, this will be needed by applications using CUDA to know how much stack/local memory to allocate. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_reg.h | 1 + drivers/gpu/drm/nouveau/nouveau_state.c | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index 251f1b3b38b..aa9b310e41b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -99,6 +99,7 @@ * the card will hang early on in the X init process. */ # define NV_PMC_ENABLE_UNK13 (1<<13) +#define NV40_PMC_GRAPH_UNITS 0x00001540 #define NV40_PMC_BACKLIGHT 0x000015f0 # define NV40_PMC_BACKLIGHT_MASK 0x001f0000 #define NV40_PMC_1700 0x00001700 diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 241e24d60eb..fcd7610817a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -825,6 +825,15 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, case NOUVEAU_GETPARAM_VM_VRAM_BASE: getparam->value = dev_priv->vm_vram_base; break; + case NOUVEAU_GETPARAM_GRAPH_UNITS: + /* NV40 and NV50 versions are quite different, but register + * address is the same. User is supposed to know the card + * family anyway... */ + if (dev_priv->chipset >= 0x40) { + getparam->value = nv_rd32(dev, NV40_PMC_GRAPH_UNITS); + break; + } + /* FALLTHRU */ default: NV_ERROR(dev, "unknown parameter %lld\n", getparam->param); return -EINVAL; -- cgit v1.2.3 From 139295b671ff4ccd904f2fa58e9dbc0fe99cc7fe Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 30 Jan 2010 18:28:00 +0100 Subject: drm/nouveau: Fixup semaphores on pre-nv50 cards. Apparently, they generate a PFIFO interrupt each time one of the semaphore methods is executed if its ctxdma wasn't manually marked as valid. This patch makes it flip the valid bit in response to the DMA_SEMAPHORE method (which triggers the IRQ even for a valid ctxdma). Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 3b9bad66162..baa9b3e0b66 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -211,6 +211,20 @@ nouveau_fifo_irq_handler(struct drm_device *dev) get + 4); } + if (status & NV_PFIFO_INTR_SEMAPHORE) { + uint32_t sem; + + status &= ~NV_PFIFO_INTR_SEMAPHORE; + nv_wr32(dev, NV03_PFIFO_INTR_0, + NV_PFIFO_INTR_SEMAPHORE); + + sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE); + nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); + + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); + } + if (status) { NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", status, chid); -- cgit v1.2.3 From f0fbe3eb5f65fe5948219f4ceac68f8a665b1fc6 Mon Sep 17 00:00:00 2001 From: Luca Barbieri Date: Sat, 30 Jan 2010 23:21:38 +0100 Subject: drm/nouveau: call ttm_bo_wait with the bo lock held to prevent hang nouveau_gem_ioctl_cpu_prep calls ttm_bo_wait without the bo lock held. ttm_bo_wait unlocks that lock, and so must be called with it held. Currently this bug causes libdrm nouveau_bo_busy() to hang the machine. Signed-off-by: Luca Barbieri Acked-by: Maarten Maathuis Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 6ac804b0c9f..70cc30803e3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -925,7 +925,9 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, } if (req->flags & NOUVEAU_GEM_CPU_PREP_NOBLOCK) { + spin_lock(&nvbo->bo.lock); ret = ttm_bo_wait(&nvbo->bo, false, false, no_wait); + spin_unlock(&nvbo->bo.lock); } else { ret = ttm_bo_synccpu_write_grab(&nvbo->bo, no_wait); if (ret == 0) -- cgit v1.2.3 From 7dad9ef6d9255b4d2d0a26305a785a55f3ba55e3 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 2 Feb 2010 14:40:30 -0800 Subject: drivers/gpu/drm/nouveau/nouveau_grctx.c: correct NULL test Test the just-allocated value for NULL rather than some other value. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x,y; statement S; @@ x = \(kmalloc\|kcalloc\|kzalloc\)(...); ( if ((x) == NULL) S | if ( - y + x == NULL) S ) // Signed-off-by: Julia Lawall Cc: David Airlie Cc: Ben Skeggs Signed-off-by: Andrew Morton Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_grctx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c index 419f4c2b3b8..c7ebec69674 100644 --- a/drivers/gpu/drm/nouveau/nouveau_grctx.c +++ b/drivers/gpu/drm/nouveau/nouveau_grctx.c @@ -97,8 +97,8 @@ nouveau_grctx_prog_load(struct drm_device *dev) } pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL); - if (!pgraph->ctxprog) { - NV_ERROR(dev, "OOM copying ctxprog\n"); + if (!pgraph->ctxvals) { + NV_ERROR(dev, "OOM copying ctxvals\n"); release_firmware(fw); nouveau_grctx_fini(dev); return -ENOMEM; -- cgit v1.2.3 From 126b5440565a1fa0cb49fd30041525d5a9a848f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Wed, 27 Jan 2010 14:03:18 +0000 Subject: drm/nouveau: Fix fbcon on mixed pre-NV50 + NV50 multicard. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used single shared fbops struct and patched it at fb init time with pointers to the right variant. On mixed multicard, this meant that it was either sending NV50-style commands to all cards, or NV04-style commands to all cards. Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 30 ++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_fbcon.h | 6 ++++++ drivers/gpu/drm/nouveau/nv04_fbcon.c | 9 +++------ drivers/gpu/drm/nouveau/nv50_fbcon.c | 9 +++------ 4 files changed, 42 insertions(+), 12 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index eddadaccc28..ea879a2efef 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -107,6 +107,34 @@ static struct fb_ops nouveau_fbcon_ops = { .fb_setcmap = drm_fb_helper_setcmap, }; +static struct fb_ops nv04_fbcon_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_setcolreg = drm_fb_helper_setcolreg, + .fb_fillrect = nv04_fbcon_fillrect, + .fb_copyarea = nv04_fbcon_copyarea, + .fb_imageblit = nv04_fbcon_imageblit, + .fb_sync = nouveau_fbcon_sync, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_blank = drm_fb_helper_blank, + .fb_setcmap = drm_fb_helper_setcmap, +}; + +static struct fb_ops nv50_fbcon_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_setcolreg = drm_fb_helper_setcolreg, + .fb_fillrect = nv50_fbcon_fillrect, + .fb_copyarea = nv50_fbcon_copyarea, + .fb_imageblit = nv50_fbcon_imageblit, + .fb_sync = nouveau_fbcon_sync, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_blank = drm_fb_helper_blank, + .fb_setcmap = drm_fb_helper_setcmap, +}; + static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) { @@ -324,9 +352,11 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, switch (dev_priv->card_type) { case NV_50: nv50_fbcon_accel_init(info); + info->fbops = &nv50_fbcon_ops; break; default: nv04_fbcon_accel_init(info); + info->fbops = &nv04_fbcon_ops; break; }; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 462e0b87b4b..f9c34e1a8c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -40,7 +40,13 @@ int nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb); void nouveau_fbcon_restore(void); void nouveau_fbcon_zfill(struct drm_device *dev); +void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); +void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv04_fbcon_accel_init(struct fb_info *info); +void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); +void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv50_fbcon_accel_init(struct fb_info *info); void nouveau_fbcon_gpu_lockup(struct fb_info *info); diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index d910873c136..fd01caabd5c 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -27,7 +27,7 @@ #include "nouveau_dma.h" #include "nouveau_fbcon.h" -static void +void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { struct nouveau_fbcon_par *par = info->par; @@ -54,7 +54,7 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) FIRE_RING(chan); } -static void +void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbcon_par *par = info->par; @@ -88,7 +88,7 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) FIRE_RING(chan); } -static void +void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbcon_par *par = info->par; @@ -307,9 +307,6 @@ nv04_fbcon_accel_init(struct fb_info *info) FIRE_RING(chan); - info->fbops->fb_fillrect = nv04_fbcon_fillrect; - info->fbops->fb_copyarea = nv04_fbcon_copyarea; - info->fbops->fb_imageblit = nv04_fbcon_imageblit; return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index e4f279ee61c..0f57cdf7ccb 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -3,7 +3,7 @@ #include "nouveau_dma.h" #include "nouveau_fbcon.h" -static void +void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbcon_par *par = info->par; @@ -46,7 +46,7 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) FIRE_RING(chan); } -static void +void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { struct nouveau_fbcon_par *par = info->par; @@ -81,7 +81,7 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) FIRE_RING(chan); } -static void +void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbcon_par *par = info->par; @@ -262,9 +262,6 @@ nv50_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base); - info->fbops->fb_fillrect = nv50_fbcon_fillrect; - info->fbops->fb_copyarea = nv50_fbcon_copyarea; - info->fbops->fb_imageblit = nv50_fbcon_imageblit; return 0; } -- cgit v1.2.3 From 9967b9481d2387af4dbe5ceda7a209466ba004a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Mon, 8 Feb 2010 00:20:17 +0000 Subject: drm/nouveau: Add proper vgaarb support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcin Kościelnicki Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index fcd7610817a..a4851af5b05 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -310,6 +310,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) static unsigned int nouveau_vga_set_decode(void *priv, bool state) { + struct drm_device *dev = priv; + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->chipset >= 0x40) + nv_wr32(dev, 0x88054, state); + else + nv_wr32(dev, 0x1854, state); + if (state) return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; -- cgit v1.2.3 From e235c1f3e132a243a1f81b3d95c99ee199b4d3f3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 22 Jan 2010 13:17:28 +1000 Subject: drm/nv40: make INIT_COMPUTE_MEM a NOP, just like nv50 It appears we aren't required to do memory sizing ourselves on nv40 either. NV40 init tables read a strap from PEXTDEV_BOOT_0 into a CRTC register, and then later use that value to select a memory configuration (written to PFB_CFG0, just like INIT_COMPUTE_MEM on earlier cards) with INIT_IO_RESTRICT_PROG. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index d7f8d8b4a4b..fb4793e65ff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1865,7 +1865,7 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) struct drm_nouveau_private *dev_priv = bios->dev->dev_private; - if (dev_priv->card_type >= NV_50) + if (dev_priv->card_type >= NV_40) return 1; /* -- cgit v1.2.3 From 1ee7698fc3ec3d7949fa55e5154c8f5de8f1c3d9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 9 Feb 2010 10:08:34 +1000 Subject: drm/nouveau: make dp auxch xfer len check for reads only Writes don't return a count, and adding the check broke native DP. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index dd493722422..f954ad93e81 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -502,12 +502,12 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, break; } - if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) { - ret = -EREMOTEIO; - goto out; - } - if (cmd & 1) { + if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) { + ret = -EREMOTEIO; + goto out; + } + for (i = 0; i < 4; i++) { data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i)); NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]); -- cgit v1.2.3 From 39c9bfb453b748ce220ceefacbe2a5c19fabf67b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 9 Feb 2010 10:22:29 +1000 Subject: drm/nv50: prevent multiple init tables being parsed at the same time With DVI and DP plugged, the DVI clock change interrupts being run can cause DP link training to fail. This adds a spinlock around init table parsing to prevent this. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 17 +++++++++-------- drivers/gpu/drm/nouveau/nouveau_bios.h | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index fb4793e65ff..2cd0fad17da 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -3765,7 +3765,6 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, */ struct drm_nouveau_private *dev_priv = dev->dev_private; - struct init_exec iexec = {true, false}; struct nvbios *bios = &dev_priv->VBIOS; uint8_t *table = &bios->data[bios->display.script_table_ptr]; uint8_t *otable = NULL; @@ -3845,8 +3844,6 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } } - bios->display.output = dcbent; - if (pxclk == 0) { script = ROM16(otable[6]); if (!script) { @@ -3855,7 +3852,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing output script 0\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk == -1) { script = ROM16(otable[8]); @@ -3865,7 +3862,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing output script 1\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk == -2) { if (table[4] >= 12) @@ -3878,7 +3875,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing output script 2\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk > 0) { script = ROM16(otable[table[4] + i*6 + 2]); @@ -3890,7 +3887,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing clock script 0\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk < 0) { script = ROM16(otable[table[4] + i*6 + 4]); @@ -3902,7 +3899,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_TRACE(dev, "0x%04X: parsing clock script 1\n", script); - parse_init_table(bios, script, &iexec); + nouveau_bios_run_init_table(dev, script, dcbent); } return 0; @@ -5864,10 +5861,13 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvbios *bios = &dev_priv->VBIOS; struct init_exec iexec = { true, false }; + unsigned long flags; + spin_lock_irqsave(&bios->lock, flags); bios->display.output = dcbent; parse_init_table(bios, table, &iexec); bios->display.output = NULL; + spin_unlock_irqrestore(&bios->lock, flags); } static bool NVInitVBIOS(struct drm_device *dev) @@ -5876,6 +5876,7 @@ static bool NVInitVBIOS(struct drm_device *dev) struct nvbios *bios = &dev_priv->VBIOS; memset(bios, 0, sizeof(struct nvbios)); + spin_lock_init(&bios->lock); bios->dev = dev; if (!NVShadowVBIOS(dev, bios->data)) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 058e98c76d8..68446fd4146 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -205,6 +205,8 @@ struct nvbios { struct drm_device *dev; struct nouveau_bios_info pub; + spinlock_t lock; + uint8_t data[NV_PROM_SIZE]; unsigned int length; bool execute; -- cgit v1.2.3 From 5025b43120b629bdf11087a3c652dc9cbe172191 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 9 Feb 2010 12:30:35 +1000 Subject: drm/nv50: disregard dac outputs in nv50_sor_dpms() Fixes DVI+VGA on my 9400, and likely a lot of other configurations that got broken by the previos DVI-over-DP fix. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_sor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index ecf1936b822..c2fff543b06 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -101,6 +101,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) struct nouveau_encoder *nvenc = nouveau_encoder(enc); if (nvenc == nv_encoder || + nvenc->disconnect != nv50_sor_disconnect || nvenc->dcb->or != nv_encoder->dcb->or) continue; -- cgit v1.2.3 From eb1dba0ebaa5b7642b323fac148f9947522a48a8 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 27 Dec 2009 12:22:07 +0100 Subject: drm/nv50: align size of buffer object to the right boundaries. - In the current situation the padding that is added is dangerous to write to, userspace could potentially overwrite parts of another bo. - Depth and stencil buffers are supposed to be large enough in general so the waste of memory should be acceptable. - Alternatives are hiding the padding from users or splitting vram into 2 zones. Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index db0ed4c13f9..028719fddf7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -65,8 +65,10 @@ nouveau_bo_fixup_align(struct drm_device *dev, /* * Some of the tile_flags have a periodic structure of N*4096 bytes, - * align to to that as well as the page size. Overallocate memory to - * avoid corruption of other buffer objects. + * align to to that as well as the page size. Align the size to the + * appropriate boundaries. This does imply that sizes are rounded up + * 3-7 pages, so be aware of this and do not waste memory by allocating + * many small buffers. */ if (dev_priv->card_type == NV_50) { uint32_t block_size = nouveau_mem_fb_amount(dev) >> 15; @@ -77,22 +79,20 @@ nouveau_bo_fixup_align(struct drm_device *dev, case 0x2800: case 0x4800: case 0x7a00: - *size = roundup(*size, block_size); if (is_power_of_2(block_size)) { - *size += 3 * block_size; for (i = 1; i < 10; i++) { *align = 12 * i * block_size; if (!(*align % 65536)) break; } } else { - *size += 6 * block_size; for (i = 1; i < 10; i++) { *align = 8 * i * block_size; if (!(*align % 65536)) break; } } + *size = roundup(*size, *align); break; default: break; -- cgit v1.2.3 From a51a3bf50d41708388f51ce63d965c0e77726eab Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 1 Feb 2010 18:32:09 +0100 Subject: drm/nv50: avoid unloading pgraph context when ctxprog is running - We need to disable pgraph fifo access before checking the current channel, otherwise we could still hit a running ctxprog. - The writes to 0x400500 are already handled by pgraph->fifo_access and are therefore redundant, moreover pgraph fifo access should not be reenabled before current context is set as invalid. So remove them altogether. Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 7 +++---- drivers/gpu/drm/nouveau/nv50_graph.c | 10 +++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 343d718a966..2281f99da7f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -278,12 +278,11 @@ nouveau_channel_free(struct nouveau_channel *chan) /* Ensure the channel is no longer active on the GPU */ pfifo->reassign(dev, false); - if (pgraph->channel(dev) == chan) { - pgraph->fifo_access(dev, false); + pgraph->fifo_access(dev, false); + if (pgraph->channel(dev) == chan) pgraph->unload_context(dev); - pgraph->fifo_access(dev, true); - } pgraph->destroy_context(chan); + pgraph->fifo_access(dev, true); if (pfifo->channel_id(dev) == chan->id) { pfifo->disable(dev); diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 20319e59d36..6d504801b51 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -165,6 +165,12 @@ nv50_graph_channel(struct drm_device *dev) uint32_t inst; int i; + /* Be sure we're not in the middle of a context switch or bad things + * will happen, such as unloading the wrong pgraph context. + */ + if (!nv_wait(0x400300, 0x00000001, 0x00000000)) + NV_ERROR(dev, "Ctxprog is still running\n"); + inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR); if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED)) return NULL; @@ -275,7 +281,7 @@ nv50_graph_load_context(struct nouveau_channel *chan) int nv50_graph_unload_context(struct drm_device *dev) { - uint32_t inst, fifo = nv_rd32(dev, 0x400500); + uint32_t inst; inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR); if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED)) @@ -283,12 +289,10 @@ nv50_graph_unload_context(struct drm_device *dev) inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE; nouveau_wait_for_idle(dev); - nv_wr32(dev, 0x400500, fifo & ~1); nv_wr32(dev, 0x400784, inst); nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20); nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01); nouveau_wait_for_idle(dev); - nv_wr32(dev, 0x400500, fifo); nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst); return 0; -- cgit v1.2.3 From a87ff62a80a6a65fc664cd410061910b8c52b896 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 1 Feb 2010 18:47:52 +0100 Subject: drm/nv50: delete ramfc object after disabling fifo, not before ramfc is zero'ed upon destruction, so it's safer to do things in the right order. Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_fifo.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index 32b244bcb48..204a79ff10f 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -317,17 +317,20 @@ void nv50_fifo_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; + struct nouveau_gpuobj_ref *ramfc = chan->ramfc; NV_DEBUG(dev, "ch%d\n", chan->id); - nouveau_gpuobj_ref_del(dev, &chan->ramfc); - nouveau_gpuobj_ref_del(dev, &chan->cache); - + /* This will ensure the channel is seen as disabled. */ + chan->ramfc = NULL; nv50_fifo_channel_disable(dev, chan->id, false); /* Dummy channel, also used on ch 127 */ if (chan->id == 0) nv50_fifo_channel_disable(dev, 127, false); + + nouveau_gpuobj_ref_del(dev, &ramfc); + nouveau_gpuobj_ref_del(dev, &chan->cache); } int -- cgit v1.2.3 From b1d37aa0aa43c5bf857364093ab2191acd37f2ec Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Wed, 20 Jan 2010 19:54:34 +0100 Subject: drm/nv50: make the pgraph irq handler loop like the pre-nv50 version Unset the bit that indicates that a ctxprog can continue at the end. Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 141 +++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 64 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index baa9b3e0b66..447f9f69d6b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -580,86 +580,99 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) static void nv50_pgraph_irq_handler(struct drm_device *dev) { - uint32_t status, nsource; + uint32_t status; - status = nv_rd32(dev, NV03_PGRAPH_INTR); - nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); + while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) { + uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); - if (status & 0x00000001) { - nouveau_pgraph_intr_notify(dev, nsource); - status &= ~0x00000001; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001); - } + if (status & 0x00000001) { + nouveau_pgraph_intr_notify(dev, nsource); + status &= ~0x00000001; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001); + } - if (status & 0x00000010) { - nouveau_pgraph_intr_error(dev, nsource | - NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD); + if (status & 0x00000010) { + nouveau_pgraph_intr_error(dev, nsource | + NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD); - status &= ~0x00000010; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010); - } + status &= ~0x00000010; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010); + } - if (status & 0x00001000) { - nv_wr32(dev, 0x400500, 0x00000000); - nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); - nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev, - NV40_PGRAPH_INTR_EN) & ~NV_PGRAPH_INTR_CONTEXT_SWITCH); - nv_wr32(dev, 0x400500, 0x00010001); + if (status & 0x00001000) { + nv_wr32(dev, 0x400500, 0x00000000); + nv_wr32(dev, NV03_PGRAPH_INTR, + NV_PGRAPH_INTR_CONTEXT_SWITCH); + nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev, + NV40_PGRAPH_INTR_EN) & + ~NV_PGRAPH_INTR_CONTEXT_SWITCH); + nv_wr32(dev, 0x400500, 0x00010001); - nv50_graph_context_switch(dev); + nv50_graph_context_switch(dev); - status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - } + status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + } - if (status & 0x00100000) { - nouveau_pgraph_intr_error(dev, nsource | - NV03_PGRAPH_NSOURCE_DATA_ERROR); + if (status & 0x00100000) { + nouveau_pgraph_intr_error(dev, nsource | + NV03_PGRAPH_NSOURCE_DATA_ERROR); - status &= ~0x00100000; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000); - } + status &= ~0x00100000; + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000); + } - if (status & 0x00200000) { - int r; - - nouveau_pgraph_intr_error(dev, nsource | - NV03_PGRAPH_NSOURCE_PROTECTION_ERROR); - - NV_ERROR(dev, "magic set 1:\n"); - for (r = 0x408900; r <= 0x408910; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r)); - nv_wr32(dev, 0x408900, nv_rd32(dev, 0x408904) | 0xc0000000); - for (r = 0x408e08; r <= 0x408e24; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r)); - nv_wr32(dev, 0x408e08, nv_rd32(dev, 0x408e08) | 0xc0000000); - - NV_ERROR(dev, "magic set 2:\n"); - for (r = 0x409900; r <= 0x409910; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r)); - nv_wr32(dev, 0x409900, nv_rd32(dev, 0x409904) | 0xc0000000); - for (r = 0x409e08; r <= 0x409e24; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r)); - nv_wr32(dev, 0x409e08, nv_rd32(dev, 0x409e08) | 0xc0000000); - - status &= ~0x00200000; - nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource); - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000); - } + if (status & 0x00200000) { + int r; + + nouveau_pgraph_intr_error(dev, nsource | + NV03_PGRAPH_NSOURCE_PROTECTION_ERROR); + + NV_ERROR(dev, "magic set 1:\n"); + for (r = 0x408900; r <= 0x408910; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + nv_wr32(dev, 0x408900, + nv_rd32(dev, 0x408904) | 0xc0000000); + for (r = 0x408e08; r <= 0x408e24; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + nv_wr32(dev, 0x408e08, + nv_rd32(dev, 0x408e08) | 0xc0000000); + + NV_ERROR(dev, "magic set 2:\n"); + for (r = 0x409900; r <= 0x409910; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + nv_wr32(dev, 0x409900, + nv_rd32(dev, 0x409904) | 0xc0000000); + for (r = 0x409e08; r <= 0x409e24; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + nv_wr32(dev, 0x409e08, + nv_rd32(dev, 0x409e08) | 0xc0000000); + + status &= ~0x00200000; + nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource); + nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000); + } - if (status) { - NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status); - nv_wr32(dev, NV03_PGRAPH_INTR, status); - } + if (status) { + NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", + status); + nv_wr32(dev, NV03_PGRAPH_INTR, status); + } - { - const int isb = (1 << 16) | (1 << 0); + { + const int isb = (1 << 16) | (1 << 0); - if ((nv_rd32(dev, 0x400500) & isb) != isb) - nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | isb); - nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); + if ((nv_rd32(dev, 0x400500) & isb) != isb) + nv_wr32(dev, 0x400500, + nv_rd32(dev, 0x400500) | isb); + } } nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); + nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); } static void -- cgit v1.2.3 From b91ad0ec52770dcb622b94fc1f57e076686f427a Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 5 Feb 2010 09:14:17 +0800 Subject: drm/i915: Rework DPLL calculation parameters for Ironlake Got Ironlake DPLL parameter table, which reflects the hardware optimized values. So this one trys to list DPLL parameters for different output types, should potential fix clock issue seen on new Arrandale CPUs. This fixes DPLL setting failure on one 1920x1080 dual channel LVDS for Ironlake. Test has also been made on LVDS panels with smaller size and CRT/HDMI/DP ports for different monitors on their all supported modes. Update: - Change name of double LVDS to dual LVDS. - Fix SSC 120M reference clock to use the right range. Cc: CSJ Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 217 +++++++++++++++++++++++++++-------- 1 file changed, 167 insertions(+), 50 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 12775df1bbf..7e9c835f9ae 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -240,33 +240,86 @@ struct intel_limit { #define IRONLAKE_DOT_MAX 350000 #define IRONLAKE_VCO_MIN 1760000 #define IRONLAKE_VCO_MAX 3510000 -#define IRONLAKE_N_MIN 1 -#define IRONLAKE_N_MAX 6 -#define IRONLAKE_M_MIN 79 -#define IRONLAKE_M_MAX 127 #define IRONLAKE_M1_MIN 12 #define IRONLAKE_M1_MAX 22 #define IRONLAKE_M2_MIN 5 #define IRONLAKE_M2_MAX 9 -#define IRONLAKE_P_SDVO_DAC_MIN 5 -#define IRONLAKE_P_SDVO_DAC_MAX 80 -#define IRONLAKE_P_LVDS_MIN 28 -#define IRONLAKE_P_LVDS_MAX 112 -#define IRONLAKE_P1_MIN 1 -#define IRONLAKE_P1_MAX 8 -#define IRONLAKE_P2_SDVO_DAC_SLOW 10 -#define IRONLAKE_P2_SDVO_DAC_FAST 5 -#define IRONLAKE_P2_LVDS_SLOW 14 /* single channel */ -#define IRONLAKE_P2_LVDS_FAST 7 /* double channel */ #define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */ -#define IRONLAKE_P_DISPLAY_PORT_MIN 10 -#define IRONLAKE_P_DISPLAY_PORT_MAX 20 -#define IRONLAKE_P2_DISPLAY_PORT_FAST 10 -#define IRONLAKE_P2_DISPLAY_PORT_SLOW 10 -#define IRONLAKE_P2_DISPLAY_PORT_LIMIT 0 -#define IRONLAKE_P1_DISPLAY_PORT_MIN 1 -#define IRONLAKE_P1_DISPLAY_PORT_MAX 2 +/* We have parameter ranges for different type of outputs. */ + +/* DAC & HDMI Refclk 120Mhz */ +#define IRONLAKE_DAC_N_MIN 1 +#define IRONLAKE_DAC_N_MAX 5 +#define IRONLAKE_DAC_M_MIN 79 +#define IRONLAKE_DAC_M_MAX 127 +#define IRONLAKE_DAC_P_MIN 5 +#define IRONLAKE_DAC_P_MAX 80 +#define IRONLAKE_DAC_P1_MIN 1 +#define IRONLAKE_DAC_P1_MAX 8 +#define IRONLAKE_DAC_P2_SLOW 10 +#define IRONLAKE_DAC_P2_FAST 5 + +/* LVDS single-channel 120Mhz refclk */ +#define IRONLAKE_LVDS_S_N_MIN 1 +#define IRONLAKE_LVDS_S_N_MAX 3 +#define IRONLAKE_LVDS_S_M_MIN 79 +#define IRONLAKE_LVDS_S_M_MAX 118 +#define IRONLAKE_LVDS_S_P_MIN 28 +#define IRONLAKE_LVDS_S_P_MAX 112 +#define IRONLAKE_LVDS_S_P1_MIN 2 +#define IRONLAKE_LVDS_S_P1_MAX 8 +#define IRONLAKE_LVDS_S_P2_SLOW 14 +#define IRONLAKE_LVDS_S_P2_FAST 14 + +/* LVDS dual-channel 120Mhz refclk */ +#define IRONLAKE_LVDS_D_N_MIN 1 +#define IRONLAKE_LVDS_D_N_MAX 3 +#define IRONLAKE_LVDS_D_M_MIN 79 +#define IRONLAKE_LVDS_D_M_MAX 127 +#define IRONLAKE_LVDS_D_P_MIN 14 +#define IRONLAKE_LVDS_D_P_MAX 56 +#define IRONLAKE_LVDS_D_P1_MIN 2 +#define IRONLAKE_LVDS_D_P1_MAX 8 +#define IRONLAKE_LVDS_D_P2_SLOW 7 +#define IRONLAKE_LVDS_D_P2_FAST 7 + +/* LVDS single-channel 100Mhz refclk */ +#define IRONLAKE_LVDS_S_SSC_N_MIN 1 +#define IRONLAKE_LVDS_S_SSC_N_MAX 2 +#define IRONLAKE_LVDS_S_SSC_M_MIN 79 +#define IRONLAKE_LVDS_S_SSC_M_MAX 126 +#define IRONLAKE_LVDS_S_SSC_P_MIN 28 +#define IRONLAKE_LVDS_S_SSC_P_MAX 112 +#define IRONLAKE_LVDS_S_SSC_P1_MIN 2 +#define IRONLAKE_LVDS_S_SSC_P1_MAX 8 +#define IRONLAKE_LVDS_S_SSC_P2_SLOW 14 +#define IRONLAKE_LVDS_S_SSC_P2_FAST 14 + +/* LVDS dual-channel 100Mhz refclk */ +#define IRONLAKE_LVDS_D_SSC_N_MIN 1 +#define IRONLAKE_LVDS_D_SSC_N_MAX 3 +#define IRONLAKE_LVDS_D_SSC_M_MIN 79 +#define IRONLAKE_LVDS_D_SSC_M_MAX 126 +#define IRONLAKE_LVDS_D_SSC_P_MIN 14 +#define IRONLAKE_LVDS_D_SSC_P_MAX 42 +#define IRONLAKE_LVDS_D_SSC_P1_MIN 2 +#define IRONLAKE_LVDS_D_SSC_P1_MAX 6 +#define IRONLAKE_LVDS_D_SSC_P2_SLOW 7 +#define IRONLAKE_LVDS_D_SSC_P2_FAST 7 + +/* DisplayPort */ +#define IRONLAKE_DP_N_MIN 1 +#define IRONLAKE_DP_N_MAX 2 +#define IRONLAKE_DP_M_MIN 81 +#define IRONLAKE_DP_M_MAX 90 +#define IRONLAKE_DP_P_MIN 10 +#define IRONLAKE_DP_P_MAX 20 +#define IRONLAKE_DP_P2_FAST 10 +#define IRONLAKE_DP_P2_SLOW 10 +#define IRONLAKE_DP_P2_LIMIT 0 +#define IRONLAKE_DP_P1_MIN 1 +#define IRONLAKE_DP_P1_MAX 2 static bool intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, @@ -474,33 +527,78 @@ static const intel_limit_t intel_limits_pineview_lvds = { .find_pll = intel_find_best_PLL, }; -static const intel_limit_t intel_limits_ironlake_sdvo = { +static const intel_limit_t intel_limits_ironlake_dac = { .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, - .n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX }, - .m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX }, + .n = { .min = IRONLAKE_DAC_N_MIN, .max = IRONLAKE_DAC_N_MAX }, + .m = { .min = IRONLAKE_DAC_M_MIN, .max = IRONLAKE_DAC_M_MAX }, .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_P_SDVO_DAC_MIN, .max = IRONLAKE_P_SDVO_DAC_MAX }, - .p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX }, + .p = { .min = IRONLAKE_DAC_P_MIN, .max = IRONLAKE_DAC_P_MAX }, + .p1 = { .min = IRONLAKE_DAC_P1_MIN, .max = IRONLAKE_DAC_P1_MAX }, .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, - .p2_slow = IRONLAKE_P2_SDVO_DAC_SLOW, - .p2_fast = IRONLAKE_P2_SDVO_DAC_FAST }, + .p2_slow = IRONLAKE_DAC_P2_SLOW, + .p2_fast = IRONLAKE_DAC_P2_FAST }, .find_pll = intel_g4x_find_best_PLL, }; -static const intel_limit_t intel_limits_ironlake_lvds = { +static const intel_limit_t intel_limits_ironlake_single_lvds = { .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, - .n = { .min = IRONLAKE_N_MIN, .max = IRONLAKE_N_MAX }, - .m = { .min = IRONLAKE_M_MIN, .max = IRONLAKE_M_MAX }, + .n = { .min = IRONLAKE_LVDS_S_N_MIN, .max = IRONLAKE_LVDS_S_N_MAX }, + .m = { .min = IRONLAKE_LVDS_S_M_MIN, .max = IRONLAKE_LVDS_S_M_MAX }, .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_P_LVDS_MIN, .max = IRONLAKE_P_LVDS_MAX }, - .p1 = { .min = IRONLAKE_P1_MIN, .max = IRONLAKE_P1_MAX }, + .p = { .min = IRONLAKE_LVDS_S_P_MIN, .max = IRONLAKE_LVDS_S_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_S_P1_MIN, .max = IRONLAKE_LVDS_S_P1_MAX }, .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, - .p2_slow = IRONLAKE_P2_LVDS_SLOW, - .p2_fast = IRONLAKE_P2_LVDS_FAST }, + .p2_slow = IRONLAKE_LVDS_S_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_S_P2_FAST }, + .find_pll = intel_g4x_find_best_PLL, +}; + +static const intel_limit_t intel_limits_ironlake_dual_lvds = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_LVDS_D_N_MIN, .max = IRONLAKE_LVDS_D_N_MAX }, + .m = { .min = IRONLAKE_LVDS_D_M_MIN, .max = IRONLAKE_LVDS_D_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_LVDS_D_P_MIN, .max = IRONLAKE_LVDS_D_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_D_P1_MIN, .max = IRONLAKE_LVDS_D_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_LVDS_D_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_D_P2_FAST }, + .find_pll = intel_g4x_find_best_PLL, +}; + +static const intel_limit_t intel_limits_ironlake_single_lvds_100m = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX }, + .m = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST }, + .find_pll = intel_g4x_find_best_PLL, +}; + +static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { + .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, + .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, + .n = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX }, + .m = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX }, + .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, + .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, + .p = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX }, + .p1 = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX }, + .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, + .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW, + .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST }, .find_pll = intel_g4x_find_best_PLL, }; @@ -509,34 +607,53 @@ static const intel_limit_t intel_limits_ironlake_display_port = { .max = IRONLAKE_DOT_MAX }, .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX}, - .n = { .min = IRONLAKE_N_MIN, - .max = IRONLAKE_N_MAX }, - .m = { .min = IRONLAKE_M_MIN, - .max = IRONLAKE_M_MAX }, + .n = { .min = IRONLAKE_DP_N_MIN, + .max = IRONLAKE_DP_N_MAX }, + .m = { .min = IRONLAKE_DP_M_MIN, + .max = IRONLAKE_DP_M_MAX }, .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_P_DISPLAY_PORT_MIN, - .max = IRONLAKE_P_DISPLAY_PORT_MAX }, - .p1 = { .min = IRONLAKE_P1_DISPLAY_PORT_MIN, - .max = IRONLAKE_P1_DISPLAY_PORT_MAX}, - .p2 = { .dot_limit = IRONLAKE_P2_DISPLAY_PORT_LIMIT, - .p2_slow = IRONLAKE_P2_DISPLAY_PORT_SLOW, - .p2_fast = IRONLAKE_P2_DISPLAY_PORT_FAST }, + .p = { .min = IRONLAKE_DP_P_MIN, + .max = IRONLAKE_DP_P_MAX }, + .p1 = { .min = IRONLAKE_DP_P1_MIN, + .max = IRONLAKE_DP_P1_MAX}, + .p2 = { .dot_limit = IRONLAKE_DP_P2_LIMIT, + .p2_slow = IRONLAKE_DP_P2_SLOW, + .p2_fast = IRONLAKE_DP_P2_FAST }, .find_pll = intel_find_pll_ironlake_dp, }; static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; const intel_limit_t *limit; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - limit = &intel_limits_ironlake_lvds; - else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || + int refclk = 120; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (dev_priv->lvds_use_ssc && dev_priv->lvds_ssc_freq == 100) + refclk = 100; + + if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) { + /* LVDS dual channel */ + if (refclk == 100) + limit = &intel_limits_ironlake_dual_lvds_100m; + else + limit = &intel_limits_ironlake_dual_lvds; + } else { + if (refclk == 100) + limit = &intel_limits_ironlake_single_lvds_100m; + else + limit = &intel_limits_ironlake_single_lvds; + } + } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || HAS_eDP) limit = &intel_limits_ironlake_display_port; else - limit = &intel_limits_ironlake_sdvo; + limit = &intel_limits_ironlake_dac; return limit; } -- cgit v1.2.3 From 99fcb766a3a50466fe31d743260a3400c1aee855 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 7 Feb 2010 16:20:18 +0100 Subject: drm/i915: Update write_domains on active list after flush. Before changing the status of a buffer with a pending write we will await upon a new flush for that buffer. So we can take advantage of any flushes posted whilst the buffer is active and pending processing by the GPU, by clearing its write_domain and updating its last_rendering_seqno -- thus saving a potential flush in deep queues and improves flushing behaviour upon eviction for both GTT space and fences. In order to reduce the time spent searching the active list for matching write_domains, we move those to a separate list whose elements are the buffers belong to the active/flushing list with pending writes. Orignal patch by Chris Wilson , forward-ported by me. In addition to better performance, this also fixes a real bug. Before this changes, i915_gem_evict_everything didn't work as advertised. When the gpu was actually busy and processing request, the flush and subsequent wait would not move active and dirty buffers to the inactive list, but just to the flushing list. Which triggered the BUG_ON at the end of this function. With the more tight dirty buffer tracking, all currently busy and dirty buffers get moved to the inactive list by one i915_gem_flush operation. I've left the BUG_ON I've used to prove this in there. References: Bug 25911 - 2.10.0 causes kernel oops and system hangs http://bugs.freedesktop.org/show_bug.cgi?id=25911 Bug 26101 - [i915] xf86-video-intel 2.10.0 (and git) triggers kernel oops within seconds after login http://bugs.freedesktop.org/show_bug.cgi?id=26101 Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson Tested-by: Adam Lantos Cc: stable@kernel.org Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 11 +++++++++++ drivers/gpu/drm/i915/i915_gem.c | 23 +++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index aaf934d96f2..b99b6a841d9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -492,6 +492,15 @@ typedef struct drm_i915_private { */ struct list_head flushing_list; + /** + * List of objects currently pending a GPU write flush. + * + * All elements on this list will belong to either the + * active_list or flushing_list, last_rendering_seqno can + * be used to differentiate between the two elements. + */ + struct list_head gpu_write_list; + /** * LRU list of objects which are not in the ringbuffer and * are ready to unbind, but are still in the GTT. @@ -592,6 +601,8 @@ struct drm_i915_gem_object { /** This object's place on the active/flushing/inactive lists */ struct list_head list; + /** This object's place on GPU write list */ + struct list_head gpu_write_list; /** This object's place on the fenced object LRU */ struct list_head fence_list; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b4c8c023068..11daa618385 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1552,6 +1552,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) else list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + BUG_ON(!list_empty(&obj_priv->gpu_write_list)); + obj_priv->last_rendering_seqno = 0; if (obj_priv->active) { obj_priv->active = 0; @@ -1622,7 +1624,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, struct drm_i915_gem_object *obj_priv, *next; list_for_each_entry_safe(obj_priv, next, - &dev_priv->mm.flushing_list, list) { + &dev_priv->mm.gpu_write_list, + gpu_write_list) { struct drm_gem_object *obj = obj_priv->obj; if ((obj->write_domain & flush_domains) == @@ -1630,6 +1633,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, uint32_t old_write_domain = obj->write_domain; obj->write_domain = 0; + list_del_init(&obj_priv->gpu_write_list); i915_gem_object_move_to_active(obj, seqno); trace_i915_gem_object_change_domain(obj, @@ -2084,8 +2088,8 @@ static int i915_gem_evict_everything(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t seqno; int ret; + uint32_t seqno; bool lists_empty; spin_lock(&dev_priv->mm.active_list_lock); @@ -2107,6 +2111,8 @@ i915_gem_evict_everything(struct drm_device *dev) if (ret) return ret; + BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); + ret = i915_gem_evict_from_inactive_list(dev); if (ret) return ret; @@ -2701,7 +2707,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) old_write_domain = obj->write_domain; i915_gem_flush(dev, 0, obj->write_domain); seqno = i915_add_request(dev, NULL, obj->write_domain); - obj->write_domain = 0; + BUG_ON(obj->write_domain); i915_gem_object_move_to_active(obj, seqno); trace_i915_gem_object_change_domain(obj, @@ -3850,16 +3856,23 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_flush(dev, dev->invalidate_domains, dev->flush_domains); - if (dev->flush_domains) + if (dev->flush_domains & I915_GEM_GPU_DOMAINS) (void)i915_add_request(dev, file_priv, dev->flush_domains); } for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; + struct drm_i915_gem_object *obj_priv = obj->driver_private; uint32_t old_write_domain = obj->write_domain; obj->write_domain = obj->pending_write_domain; + if (obj->write_domain) + list_move_tail(&obj_priv->gpu_write_list, + &dev_priv->mm.gpu_write_list); + else + list_del_init(&obj_priv->gpu_write_list); + trace_i915_gem_object_change_domain(obj, obj->read_domains, old_write_domain); @@ -4370,6 +4383,7 @@ int i915_gem_init_object(struct drm_gem_object *obj) obj_priv->obj = obj; obj_priv->fence_reg = I915_FENCE_REG_NONE; INIT_LIST_HEAD(&obj_priv->list); + INIT_LIST_HEAD(&obj_priv->gpu_write_list); INIT_LIST_HEAD(&obj_priv->fence_list); obj_priv->madv = I915_MADV_WILLNEED; @@ -4821,6 +4835,7 @@ i915_gem_load(struct drm_device *dev) spin_lock_init(&dev_priv->mm.active_list_lock); INIT_LIST_HEAD(&dev_priv->mm.active_list); INIT_LIST_HEAD(&dev_priv->mm.flushing_list); + INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); INIT_LIST_HEAD(&dev_priv->mm.request_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); -- cgit v1.2.3 From fd2e8ea597222b8f38ae8948776a61ea7958232e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 9 Feb 2010 14:14:36 +0000 Subject: drm/i915: Increase fb alignment to 64k An untiled framebuffer must be aligned to 64k. This is normally handled by intel_pin_and_fence_fb_obj(), but the intelfb_create() likes to be different and do the pinning itself. However, it aligns the buffer object incorrectly for pre-i965 chipsets causing a PGTBL_ERR when it is installed onto the output. Fixes: KMS error message while initializing modesetting - render error detected: EIR: 0x10 [i915] http://bugs.freedesktop.org/show_bug.cgi?id=22936 Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 371d753e362..aaabbcbe590 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -148,7 +148,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(fbo, PAGE_SIZE); + ret = i915_gem_object_pin(fbo, 64*1024); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; -- cgit v1.2.3 From ee25df2bc379728c45d81e04cf87984db1425edf Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 6 Feb 2010 10:41:53 -0800 Subject: drm/i915: handle FBC and self-refresh better On 945, we need to avoid entering self-refresh if the compressor is busy, or we may cause display FIFO underruns leading to ugly flicker. Fixes fdo bug #24314, kernel bug #15043. Tested-by: Alexander Lam Signed-off-by: Jesse Barnes Tested-by: Julien Cristau (fd.o #25371) Cc: stable@kernel.org Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 847006c5218..ab1bd2d3d3b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -338,6 +338,7 @@ #define FBC_CTL_PERIODIC (1<<30) #define FBC_CTL_INTERVAL_SHIFT (16) #define FBC_CTL_UNCOMPRESSIBLE (1<<14) +#define FBC_C3_IDLE (1<<13) #define FBC_CTL_STRIDE_SHIFT (5) #define FBC_CTL_FENCENO (1<<0) #define FBC_COMMAND 0x0320c diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e9c835f9ae..a4d382c8bf5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1031,6 +1031,8 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) /* enable it... */ fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; + if (IS_I945GM(dev)) + fbc_ctl |= FBC_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; if (obj_priv->tiling_mode != I915_TILING_NONE) -- cgit v1.2.3 From b1b87f6b65a770a69f3632cf7c1f9182547c1249 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 26 Jan 2010 14:40:05 -0800 Subject: drm/i915: untangle page flip completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a new page flip is requested, we need to both queue an unpin for the current framebuffer, and also increment the flip pending count on the newly submitted buffer. At flip finish time, we need to unpin the old fb and decrement the flip pending count on the new buffer. The old code was conflating the two, and led to hangs when new direct rendered apps were started, replacing the existing frame buffer. This patch splits out the buffers and prevents the hangs. Signed-off-by: Jesse Barnes Reviewed-by: Chris Wilson Reviewed-by: Kristian Høgsberg Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a4d382c8bf5..dc6ffe82d2c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4081,7 +4081,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) struct intel_unpin_work { struct work_struct work; struct drm_device *dev; - struct drm_gem_object *obj; + struct drm_gem_object *old_fb_obj; + struct drm_gem_object *pending_flip_obj; struct drm_pending_vblank_event *event; int pending; }; @@ -4092,8 +4093,8 @@ static void intel_unpin_work_fn(struct work_struct *__work) container_of(__work, struct intel_unpin_work, work); mutex_lock(&work->dev->struct_mutex); - i915_gem_object_unpin(work->obj); - drm_gem_object_unreference(work->obj); + i915_gem_object_unpin(work->old_fb_obj); + drm_gem_object_unreference(work->old_fb_obj); mutex_unlock(&work->dev->struct_mutex); kfree(work); } @@ -4117,7 +4118,7 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) work = intel_crtc->unpin_work; if (work == NULL || !work->pending) { if (work && !work->pending) { - obj_priv = work->obj->driver_private; + obj_priv = work->pending_flip_obj->driver_private; DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n", obj_priv, atomic_read(&obj_priv->pending_flip)); @@ -4142,7 +4143,7 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev->event_lock, flags); - obj_priv = work->obj->driver_private; + obj_priv = work->pending_flip_obj->driver_private; /* Initial scanout buffer will have a 0 pending flip count */ if ((atomic_read(&obj_priv->pending_flip) == 0) || @@ -4191,7 +4192,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->event = event; work->dev = crtc->dev; intel_fb = to_intel_framebuffer(crtc->fb); - work->obj = intel_fb->obj; + work->old_fb_obj = intel_fb->obj; INIT_WORK(&work->work, intel_unpin_work_fn); /* We borrow the event spin lock for protecting unpin_work */ @@ -4220,13 +4221,14 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, } /* Reference the old fb object for the scheduled work. */ - drm_gem_object_reference(work->obj); + drm_gem_object_reference(work->old_fb_obj); crtc->fb = fb; i915_gem_object_flush_write_domain(obj); drm_vblank_get(dev, intel_crtc->pipe); obj_priv = obj->driver_private; atomic_inc(&obj_priv->pending_flip); + work->pending_flip_obj = obj; BEGIN_LP_RING(4); OUT_RING(MI_DISPLAY_FLIP | -- cgit v1.2.3 From f072d2e77128c5b332ce217764cf170b660b99dc Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Tue, 9 Feb 2010 09:46:19 +0800 Subject: drm/i915: fix flip done interrupt on Ironlake On Ironlake plane flip interrupt means flip done event already, the behavior is not like old chips, and perform like other usual interrupt. So only need to handle flip done event when receiving that interrupt. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 50ddf4a95c5..a17d6bdfe63 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -309,21 +309,21 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) if (de_iir & DE_GSE) ironlake_opregion_gse_intr(dev); - if (de_iir & DE_PLANEA_FLIP_DONE) + if (de_iir & DE_PLANEA_FLIP_DONE) { intel_prepare_page_flip(dev, 0); + intel_finish_page_flip(dev, 0); + } - if (de_iir & DE_PLANEB_FLIP_DONE) + if (de_iir & DE_PLANEB_FLIP_DONE) { intel_prepare_page_flip(dev, 1); + intel_finish_page_flip(dev, 1); + } - if (de_iir & DE_PIPEA_VBLANK) { + if (de_iir & DE_PIPEA_VBLANK) drm_handle_vblank(dev, 0); - intel_finish_page_flip(dev, 0); - } - if (de_iir & DE_PIPEB_VBLANK) { + if (de_iir & DE_PIPEB_VBLANK) drm_handle_vblank(dev, 1); - intel_finish_page_flip(dev, 1); - } /* check event from PCH */ if ((de_iir & DE_PCH_EVENT) && -- cgit v1.2.3 From aacef09b59e99d9e919ede74d107d5d7f3721432 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Tue, 9 Feb 2010 09:46:20 +0800 Subject: drm/i915: fix pipe source image setting in flip command The MI_DISPLAY_FLIP command needs to be set the same pipe source image like in pipe source register, e.g source image size minus one. This fixes screen corrupt issue on Ironlake. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dc6ffe82d2c..c161ace7132 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4180,7 +4180,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; unsigned long flags; - int ret; + int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC; + int ret, pipesrc; RING_LOCALS; work = kzalloc(sizeof *work, GFP_KERNEL); @@ -4236,7 +4237,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, OUT_RING(fb->pitch); if (IS_I965G(dev)) { OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode); - OUT_RING((fb->width << 16) | fb->height); + pipesrc = I915_READ(pipesrc_reg); + OUT_RING(pipesrc & 0x0fff0fff); } else { OUT_RING(obj_priv->gtt_offset); OUT_RING(MI_NOOP); -- cgit v1.2.3 From a40e8d3139e9eb54bf1d29f91639a6c5e05f652e Mon Sep 17 00:00:00 2001 From: Owain Ainsworth Date: Tue, 9 Feb 2010 14:25:55 +0000 Subject: drm/i915: Correctly return -ENOMEM on allocation failure in cmdbuf ioctls. Signed-off-by: Owain G. Ainsworth Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_dma.c | 4 +++- drivers/gpu/drm/i915/i915_gem.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e660ac07f3b..2307f98349f 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -735,8 +735,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, if (cmdbuf->num_cliprects) { cliprects = kcalloc(cmdbuf->num_cliprects, sizeof(struct drm_clip_rect), GFP_KERNEL); - if (cliprects == NULL) + if (cliprects == NULL) { + ret = -ENOMEM; goto fail_batch_free; + } ret = copy_from_user(cliprects, cmdbuf->cliprects, cmdbuf->num_cliprects * diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 11daa618385..ec8a0d7ffa3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3688,8 +3688,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (args->num_cliprects != 0) { cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects), GFP_KERNEL); - if (cliprects == NULL) + if (cliprects == NULL) { + ret = -ENOMEM; goto pre_mutex_err; + } ret = copy_from_user(cliprects, (struct drm_clip_rect __user *) -- cgit v1.2.3 From dd19e44b28b12f7ea59ebb54d8ea18054da7f9d1 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sat, 30 Jan 2010 15:41:00 +0100 Subject: drm/nouveau: move dereferences after null checks Reported-by: Dan Carpenter Signed-off-by: Marcin Slusarz Signed-off-by: Maarten Maathuis Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 7 ++++--- drivers/gpu/drm/nouveau/nouveau_object.c | 3 ++- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 7 ++++--- drivers/gpu/drm/nouveau/nv50_crtc.c | 11 +++++++---- 4 files changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 7e6d673f3a2..d2f63353ea9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -88,13 +88,14 @@ nouveau_connector_destroy(struct drm_connector *drm_connector) { struct nouveau_connector *nv_connector = nouveau_connector(drm_connector); - struct drm_device *dev = nv_connector->base.dev; - - NV_DEBUG_KMS(dev, "\n"); + struct drm_device *dev; if (!nv_connector) return; + dev = nv_connector->base.dev; + NV_DEBUG_KMS(dev, "\n"); + kfree(nv_connector->edid); drm_sysfs_connector_remove(drm_connector); drm_connector_cleanup(drm_connector); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 6c2cf81716d..e7c100ba63a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -885,11 +885,12 @@ int nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, struct nouveau_gpuobj **gpuobj_ret) { - struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct drm_nouveau_private *dev_priv; struct nouveau_gpuobj *gpuobj; if (!chan || !gpuobj_ret || *gpuobj_ret != NULL) return -EINVAL; + dev_priv = chan->dev->dev_private; gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); if (!gpuobj) diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 4c7f1e403e8..ed1590577b6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -54,11 +54,12 @@ static void nouveau_sgdma_clear(struct ttm_backend *be) { struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; - struct drm_device *dev = nvbe->dev; - - NV_DEBUG(nvbe->dev, "\n"); + struct drm_device *dev; if (nvbe && nvbe->pages) { + dev = nvbe->dev; + NV_DEBUG(dev, "\n"); + if (nvbe->bound) be->func->unbind(be); diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 40b7360841f..d1a651e3400 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -298,14 +298,17 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk) static void nv50_crtc_destroy(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - - NV_DEBUG_KMS(dev, "\n"); + struct drm_device *dev; + struct nouveau_crtc *nv_crtc; if (!crtc) return; + dev = crtc->dev; + nv_crtc = nouveau_crtc(crtc); + + NV_DEBUG_KMS(dev, "\n"); + drm_crtc_cleanup(&nv_crtc->base); nv50_cursor_fini(nv_crtc); -- cgit v1.2.3 From 13876c6e5fec94e9ea51b73ac025583dd7655345 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 10 Feb 2010 20:50:34 +1000 Subject: nouveau: fix state detection with switchable graphics Signed-off-by: Matthew Garrett Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 1cf488247a1..48227e74475 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -90,21 +90,21 @@ int nouveau_hybrid_setup(struct drm_device *dev) { int result; - if (nouveau_dsm(dev, NOUVEAU_DSM_ACTIVE, NOUVEAU_DSM_ACTIVE_QUERY, + if (nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STATE, &result)) return -ENODEV; NV_INFO(dev, "_DSM hardware status gave 0x%x\n", result); - if (result & 0x1) { /* Stamina mode - disable the external GPU */ + if (result) { /* Ensure that the external GPU is enabled */ + nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL); + nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED, + NULL); + } else { /* Stamina mode - disable the external GPU */ nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_STAMINA, NULL); nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STAMINA, NULL); - } else { /* Ensure that the external GPU is enabled */ - nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL); - nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED, - NULL); } return 0; -- cgit v1.2.3 From 6719fc663c6cd30da5dd02d08aaefb031a7a98fd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 9 Feb 2010 12:31:08 +1000 Subject: drm/radeon/kms: fix screen clearing before fbcon. This memset_io was added to debug something way back and got left behind, memset the fb to black so the borders don't be all white. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 66055b3d866..23aa393634f 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -248,7 +248,7 @@ int radeonfb_create(struct drm_device *dev, if (ret) goto out_unref; - memset_io(fbptr, 0xff, aligned_size); + memset_io(fbptr, 0x0, aligned_size); strcpy(info->fix.id, "radeondrmfb"); -- cgit v1.2.3 From 84b79f8d2882b0a84330c04839ed4d3cefd2ff77 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 7 Feb 2010 21:48:24 +0100 Subject: drm/i915: Fix crash while aborting hibernation Commit cbda12d77ea590082edb6d30bd342a67ebc459e0 (drm/i915: implement new pm ops for i915) introduced the problem that if s2disk hibernation is aborted, the system will crash, because i915_pm_freeze() does nothing, while it should at least reverse some operations carried out by i915_suspend(). Fix this issue by splitting the i915 suspend into a freeze part a suspend part, where the latter is not executed before creating a hibernation image, and the i915 resume into a "low-level" resume part and a thaw part, where the former is not executed after the image has been created. Signed-off-by: Rafael J. Wysocki Tested-by: Alan Jenkins Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.c | 168 ++++++++++++++++++++++++---------------- 1 file changed, 101 insertions(+), 67 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ecac882e1d5..79beffcf593 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -174,78 +174,100 @@ const static struct pci_device_id pciidlist[] = { MODULE_DEVICE_TABLE(pci, pciidlist); #endif -static int i915_suspend(struct drm_device *dev, pm_message_t state) +static int i915_drm_freeze(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!dev || !dev_priv) { - DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv); - DRM_ERROR("DRM not initialized, aborting suspend.\n"); - return -ENODEV; - } - - if (state.event == PM_EVENT_PRETHAW) - return 0; - pci_save_state(dev->pdev); /* If KMS is active, we do the leavevt stuff here */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { - if (i915_gem_idle(dev)) + int error = i915_gem_idle(dev); + if (error) { dev_err(&dev->pdev->dev, - "GEM idle failed, resume may fail\n"); + "GEM idle failed, resume might fail\n"); + return error; + } drm_irq_uninstall(dev); } i915_save_state(dev); + return 0; +} + +static void i915_drm_suspend(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + intel_opregion_free(dev, 1); + /* Modeset on resume, not lid events */ + dev_priv->modeset_on_lid = 0; +} + +static int i915_suspend(struct drm_device *dev, pm_message_t state) +{ + int error; + + if (!dev || !dev->dev_private) { + DRM_ERROR("dev: %p\n", dev); + DRM_ERROR("DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } + + if (state.event == PM_EVENT_PRETHAW) + return 0; + + error = i915_drm_freeze(dev); + if (error) + return error; + + i915_drm_suspend(dev); + if (state.event == PM_EVENT_SUSPEND) { /* Shut down the device */ pci_disable_device(dev->pdev); pci_set_power_state(dev->pdev, PCI_D3hot); } - /* Modeset on resume, not lid events */ - dev_priv->modeset_on_lid = 0; - return 0; } -static int i915_resume(struct drm_device *dev) +static int i915_drm_thaw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int ret = 0; - - if (pci_enable_device(dev->pdev)) - return -1; - pci_set_master(dev->pdev); - - i915_restore_state(dev); - - intel_opregion_init(dev, 1); + int error = 0; /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { mutex_lock(&dev->struct_mutex); dev_priv->mm.suspended = 0; - ret = i915_gem_init_ringbuffer(dev); - if (ret != 0) - ret = -1; + error = i915_gem_init_ringbuffer(dev); mutex_unlock(&dev->struct_mutex); drm_irq_install(dev); - } - if (drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Resume the modeset for every activated CRTC */ drm_helper_resume_force_mode(dev); } dev_priv->modeset_on_lid = 0; - return ret; + return error; +} + +static int i915_resume(struct drm_device *dev) +{ + if (pci_enable_device(dev->pdev)) + return -EIO; + + pci_set_master(dev->pdev); + + i915_restore_state(dev); + + intel_opregion_init(dev, 1); + + return i915_drm_thaw(dev); } /** @@ -386,57 +408,69 @@ i915_pci_remove(struct pci_dev *pdev) drm_put_dev(dev); } -static int -i915_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int i915_pm_suspend(struct device *dev) { - struct drm_device *dev = pci_get_drvdata(pdev); + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + int error; - return i915_suspend(dev, state); -} + if (!drm_dev || !drm_dev->dev_private) { + dev_err(dev, "DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } -static int -i915_pci_resume(struct pci_dev *pdev) -{ - struct drm_device *dev = pci_get_drvdata(pdev); + error = i915_drm_freeze(drm_dev); + if (error) + return error; - return i915_resume(dev); -} + i915_drm_suspend(drm_dev); -static int -i915_pm_suspend(struct device *dev) -{ - return i915_pci_suspend(to_pci_dev(dev), PMSG_SUSPEND); -} + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); -static int -i915_pm_resume(struct device *dev) -{ - return i915_pci_resume(to_pci_dev(dev)); + return 0; } -static int -i915_pm_freeze(struct device *dev) +static int i915_pm_resume(struct device *dev) { - return i915_pci_suspend(to_pci_dev(dev), PMSG_FREEZE); + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return i915_resume(drm_dev); } -static int -i915_pm_thaw(struct device *dev) +static int i915_pm_freeze(struct device *dev) { - /* thaw during hibernate, do nothing! */ - return 0; + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + if (!drm_dev || !drm_dev->dev_private) { + dev_err(dev, "DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } + + return i915_drm_freeze(drm_dev); } -static int -i915_pm_poweroff(struct device *dev) +static int i915_pm_thaw(struct device *dev) { - return i915_pci_suspend(to_pci_dev(dev), PMSG_HIBERNATE); + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return i915_drm_thaw(drm_dev); } -static int -i915_pm_restore(struct device *dev) +static int i915_pm_poweroff(struct device *dev) { - return i915_pci_resume(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + int error; + + error = i915_drm_freeze(drm_dev); + if (!error) + i915_drm_suspend(drm_dev); + + return error; } const struct dev_pm_ops i915_pm_ops = { @@ -445,7 +479,7 @@ const struct dev_pm_ops i915_pm_ops = { .freeze = i915_pm_freeze, .thaw = i915_pm_thaw, .poweroff = i915_pm_poweroff, - .restore = i915_pm_restore, + .restore = i915_pm_resume, }; static struct vm_operations_struct i915_gem_vm_ops = { -- cgit v1.2.3 From 75dfca80a610e4e87d3b9ccfb3f520692808697d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 10 Feb 2010 15:09:44 -0800 Subject: drm/i915: hold ref on flip object until it completes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will prevent things from falling over if the user frees the flip buffer before we complete the flip, since we'll hold an internal reference. Reported-by: Kristian Høgsberg Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c161ace7132..b27202d23eb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4094,6 +4094,7 @@ static void intel_unpin_work_fn(struct work_struct *__work) mutex_lock(&work->dev->struct_mutex); i915_gem_object_unpin(work->old_fb_obj); + drm_gem_object_unreference(work->pending_flip_obj); drm_gem_object_unreference(work->old_fb_obj); mutex_unlock(&work->dev->struct_mutex); kfree(work); @@ -4221,8 +4222,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, return ret; } - /* Reference the old fb object for the scheduled work. */ + /* Reference the objects for the scheduled work. */ drm_gem_object_reference(work->old_fb_obj); + drm_gem_object_reference(obj); crtc->fb = fb; i915_gem_object_flush_write_domain(obj); -- cgit v1.2.3 From f77cef3db357aeea22d82a2aa4f0ef8fbae41d47 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 9 Feb 2010 19:41:55 +0000 Subject: drm/vmwgfx: Update the user-space interface. When time-based throttling is implemented, we need to bump minor. When the old way of detecting scanout is removed, we need to bump major. In the meantime, this change should not break existing user-space. Signed-off-by: Thomas Hellstrom Signed-off-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 6 ++++++ drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 5 +++-- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 135be9688c9..0eaf68273ea 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -39,10 +39,10 @@ #include "ttm/ttm_execbuf_util.h" #include "ttm/ttm_module.h" -#define VMWGFX_DRIVER_DATE "20090724" +#define VMWGFX_DRIVER_DATE "20100118" #define VMWGFX_DRIVER_MAJOR 0 -#define VMWGFX_DRIVER_MINOR 1 -#define VMWGFX_DRIVER_PATCHLEVEL 2 +#define VMWGFX_DRIVER_MINOR 9 +#define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 778851f9f1d..1c7a316454d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -48,6 +48,12 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_FIFO_OFFSET: param->value = dev_priv->mmio_start; break; + case DRM_VMW_PARAM_HW_CAPS: + param->value = dev_priv->capabilities; + break; + case DRM_VMW_PARAM_FIFO_CAPS: + param->value = dev_priv->fifo.capabilities; + break; default: DRM_ERROR("Illegal vmwgfx get param request: %d\n", param->param); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index c7efbd47ab8..933e90d8286 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -610,9 +610,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, */ srf->flags &= ~SVGA3D_SURFACE_HINT_SCANOUT; srf->scanout = true; - } else { + } else if (req->scanout) + srf->scanout = true; + else srf->scanout = false; - } if (srf->scanout && srf->num_sizes == 1 && -- cgit v1.2.3 From 3bef35721018d2bac08d0d03979606b65347211e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 9 Feb 2010 19:41:57 +0000 Subject: drm/vmwgfx: Report propper framebuffer_{max|min}_{width|height} Signed-off-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index eeba6d1d06e..31f9afed0a6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -769,10 +769,10 @@ int vmw_kms_init(struct vmw_private *dev_priv) drm_mode_config_init(dev); dev->mode_config.funcs = &vmw_kms_funcs; - dev->mode_config.min_width = 640; - dev->mode_config.min_height = 480; - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; + dev->mode_config.min_width = 1; + dev->mode_config.min_height = 1; + dev->mode_config.max_width = dev_priv->fb_max_width; + dev->mode_config.max_height = dev_priv->fb_max_height; ret = vmw_kms_init_legacy_display_system(dev_priv); -- cgit v1.2.3 From a87897edbae2d60db7bcb6bb0a75e82013d68305 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 9 Feb 2010 21:29:47 +0000 Subject: drm/vmwgfx: Drop scanout flag compat and add execbuf ioctl parameter members. Bumps major. Even if this bumps the version to 1 it does not mean the driver is out of staging. From what we know this is the last backwards incompatible change to the driver. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 17 +---------------- 2 files changed, 4 insertions(+), 19 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 0eaf68273ea..3e4e670d321 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -39,9 +39,9 @@ #include "ttm/ttm_execbuf_util.h" #include "ttm/ttm_module.h" -#define VMWGFX_DRIVER_DATE "20100118" -#define VMWGFX_DRIVER_MAJOR 0 -#define VMWGFX_DRIVER_MINOR 9 +#define VMWGFX_DRIVER_DATE "20100209" +#define VMWGFX_DRIVER_MAJOR 1 +#define VMWGFX_DRIVER_MINOR 0 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 933e90d8286..f8fbbc67a40 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -35,11 +35,6 @@ #define VMW_RES_SURFACE ttm_driver_type1 #define VMW_RES_STREAM ttm_driver_type2 -/* XXX: This isn't a real hardware flag, but just a hack for kernel to - * know about primary surfaces. Find a better way to accomplish this. - */ -#define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9) - struct vmw_user_context { struct ttm_base_object base; struct vmw_resource res; @@ -579,6 +574,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, srf->flags = req->flags; srf->format = req->format; + srf->scanout = req->scanout; memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels)); srf->num_sizes = 0; for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) @@ -604,17 +600,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, if (unlikely(ret != 0)) goto out_err1; - if (srf->flags & SVGA3D_SURFACE_HINT_SCANOUT) { - /* we should not send this flag down to hardware since - * its not a official one - */ - srf->flags &= ~SVGA3D_SURFACE_HINT_SCANOUT; - srf->scanout = true; - } else if (req->scanout) - srf->scanout = true; - else - srf->scanout = false; - if (srf->scanout && srf->num_sizes == 1 && srf->sizes[0].width == 64 && -- cgit v1.2.3 From 85b9e4878f3b16993fba871c0c68d0948ec9c7c6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 8 Feb 2010 09:57:25 +0000 Subject: drm/vmwgfx: Fix a circular locking dependency bug. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 17 +++++++++-------- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 13 +++---------- 3 files changed, 14 insertions(+), 19 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 3e4e670d321..356dc935ec1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -113,6 +113,7 @@ struct vmw_fifo_state { unsigned long static_buffer_size; bool using_bounce_buffer; uint32_t capabilities; + struct mutex fifo_mutex; struct rw_semaphore rwsem; }; @@ -213,7 +214,7 @@ struct vmw_private { * Fencing and IRQs. */ - uint32_t fence_seq; + atomic_t fence_seq; wait_queue_head_t fence_queue; wait_queue_head_t fifo_queue; atomic_t fence_queue_waiters; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 4157547cc6e..39d43a01d84 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -74,6 +74,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) fifo->reserved_size = 0; fifo->using_bounce_buffer = false; + mutex_init(&fifo->fifo_mutex); init_rwsem(&fifo->rwsem); /* @@ -117,7 +118,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) (unsigned int) min, (unsigned int) fifo->capabilities); - dev_priv->fence_seq = dev_priv->last_read_sequence; + atomic_set(&dev_priv->fence_seq, dev_priv->last_read_sequence); iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE); return vmw_fifo_send_fence(dev_priv, &dummy); @@ -283,7 +284,7 @@ void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) uint32_t reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE; int ret; - down_write(&fifo_state->rwsem); + mutex_lock(&fifo_state->fifo_mutex); max = ioread32(fifo_mem + SVGA_FIFO_MAX); min = ioread32(fifo_mem + SVGA_FIFO_MIN); next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD); @@ -351,7 +352,7 @@ void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) } out_err: fifo_state->reserved_size = 0; - up_write(&fifo_state->rwsem); + mutex_unlock(&fifo_state->fifo_mutex); return NULL; } @@ -426,6 +427,7 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) } + down_write(&fifo_state->rwsem); if (fifo_state->using_bounce_buffer || reserveable) { next_cmd += bytes; if (next_cmd >= max) @@ -437,8 +439,9 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) if (reserveable) iowrite32(0, fifo_mem + SVGA_FIFO_RESERVED); mb(); - vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); up_write(&fifo_state->rwsem); + vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); + mutex_unlock(&fifo_state->fifo_mutex); } int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) @@ -451,9 +454,7 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) fm = vmw_fifo_reserve(dev_priv, bytes); if (unlikely(fm == NULL)) { - down_write(&fifo_state->rwsem); - *sequence = dev_priv->fence_seq; - up_write(&fifo_state->rwsem); + *sequence = atomic_read(&dev_priv->fence_seq); ret = -ENOMEM; (void)vmw_fallback_wait(dev_priv, false, true, *sequence, false, 3*HZ); @@ -461,7 +462,7 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) } do { - *sequence = dev_priv->fence_seq++; + *sequence = atomic_add_return(1, &dev_priv->fence_seq); } while (*sequence == 0); if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE)) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index d40086fc864..4d7cb539386 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -84,20 +84,13 @@ bool vmw_fence_signaled(struct vmw_private *dev_priv, vmw_fifo_idle(dev_priv, sequence)) return true; - /** - * Below is to signal stale fences that have wrapped. - * First, block fence submission. - */ - - down_read(&fifo_state->rwsem); - /** * Then check if the sequence is higher than what we've actually * emitted. Then the fence is stale and signaled. */ - ret = ((dev_priv->fence_seq - sequence) > VMW_FENCE_WRAP); - up_read(&fifo_state->rwsem); + ret = ((atomic_read(&dev_priv->fence_seq) - sequence) + > VMW_FENCE_WRAP); return ret; } @@ -127,7 +120,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, if (fifo_idle) down_read(&fifo_state->rwsem); - signal_seq = dev_priv->fence_seq; + signal_seq = atomic_read(&dev_priv->fence_seq); ret = 0; for (;;) { -- cgit v1.2.3 From c60a284cc41f9989391706e113d30b4f27dbe3e0 Mon Sep 17 00:00:00 2001 From: Pauli Nieminen Date: Thu, 11 Feb 2010 00:10:33 +0200 Subject: drm/radeon: Skip dma copy test in benchmark if card doesn't have dma engine. radeon_copy_dma is only available for r200 or newer cards. Call to radeon_copy_dma would result to NULL pointer dereference if benchmarking asic without dma engine. Signed-off-by: Pauli Nieminen Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_benchmark.c | 55 ++++++++++++++++++------------- 1 file changed, 33 insertions(+), 22 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 4ddfd4b5bc5..7932dc4d6b9 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -65,31 +65,42 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, if (r) { goto out_cleanup; } - start_jiffies = jiffies; - for (i = 0; i < n; i++) { - r = radeon_fence_create(rdev, &fence); - if (r) { - goto out_cleanup; + + /* r100 doesn't have dma engine so skip the test */ + if (rdev->asic->copy_dma) { + + start_jiffies = jiffies; + for (i = 0; i < n; i++) { + r = radeon_fence_create(rdev, &fence); + if (r) { + goto out_cleanup; + } + + r = radeon_copy_dma(rdev, saddr, daddr, + size / RADEON_GPU_PAGE_SIZE, fence); + + if (r) { + goto out_cleanup; + } + r = radeon_fence_wait(fence, false); + if (r) { + goto out_cleanup; + } + radeon_fence_unref(&fence); } - r = radeon_copy_dma(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, fence); - if (r) { - goto out_cleanup; + end_jiffies = jiffies; + time = end_jiffies - start_jiffies; + time = jiffies_to_msecs(time); + if (time > 0) { + i = ((n * size) >> 10) / time; + printk(KERN_INFO "radeon: dma %u bo moves of %ukb from" + " %d to %d in %lums (%ukb/ms %ukb/s %uM/s)\n", + n, size >> 10, + sdomain, ddomain, time, + i, i * 1000, (i * 1000) / 1024); } - r = radeon_fence_wait(fence, false); - if (r) { - goto out_cleanup; - } - radeon_fence_unref(&fence); - } - end_jiffies = jiffies; - time = end_jiffies - start_jiffies; - time = jiffies_to_msecs(time); - if (time > 0) { - i = ((n * size) >> 10) / time; - printk(KERN_INFO "radeon: dma %u bo moves of %ukb from %d to %d" - " in %lums (%ukb/ms %ukb/s %uM/s)\n", n, size >> 10, - sdomain, ddomain, time, i, i * 1000, (i * 1000) / 1024); } + start_jiffies = jiffies; for (i = 0; i < n; i++) { r = radeon_fence_create(rdev, &fence); -- cgit v1.2.3 From 648ac05c4f8a8aea908c7dff81ceffe003e28561 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 10 Feb 2010 16:52:45 +1000 Subject: drm/radeon/kms: retry auxch on 0x20 timeout value. ATOM appears to return 0x20 which seems to mean some sort of timeout. retry the transaction up to 10 times before failing, this makes DP->VGA convertor we bought work at least a bit more predictably. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 71060114d5d..b32eeea5bb8 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -332,11 +332,13 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); unsigned char *base; + int retry_count = 0; memset(&args, 0, sizeof(args)); base = (unsigned char *)rdev->mode_info.atom_context->scratch; +retry: memcpy(base, req_bytes, num_bytes); args.lpAuxRequest = 0; @@ -347,10 +349,12 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - if (args.ucReplyStatus) { - DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x\n", + if (args.ucReplyStatus && !args.ucDataOutLen) { + if (args.ucReplyStatus == 0x20 && retry_count < 10) + goto retry; + DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n", req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], - chan->rec.i2c_id, args.ucReplyStatus); + chan->rec.i2c_id, args.ucReplyStatus, retry_count); return false; } -- cgit v1.2.3 From 77c1ff3982c6b36961725dd19e872a1c07df7f3b Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Thu, 11 Feb 2010 14:04:48 +1000 Subject: vgaarb: fix incorrect dereference of userspace pointer. This patch corrects a userspace pointer dereference in the VGA arbiter in 2.6.32.1. copy_from_user() is used at line 822 to copy the contents of buf into kbuf, but a call to strncmp() on line 964 uses buf rather than kbuf. This problem led to a GPF in strncmp() when X was started on my x86_32 systems. X triggered the behavior with a write of "target PCI:0000:01:00.0" to /dev/vga_arbiter. The patch has been tested against 2.6.32.1 and observed to correct the GPF observed when starting X or manually writing the string "target PCI:0000:01:00.0" to /dev/vga_arbiter. Signed-off-by: Andy Getzendanner Cc: Jesse Barnes Cc: Signed-off-by: Andrew Morton Signed-off-by: Dave Airlie --- drivers/gpu/vga/vgaarb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 1ac0c93603c..24b56dc5459 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -961,7 +961,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, remaining -= 7; pr_devel("client 0x%p called 'target'\n", priv); /* if target is default */ - if (!strncmp(buf, "default", 7)) + if (!strncmp(kbuf, "default", 7)) pdev = pci_dev_get(vga_default_device()); else { if (!vga_pci_str_to_vars(curr_pos, remaining, -- cgit v1.2.3 From 775c67090c98780b44c4f95d5c05565df715b8bd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2010 00:17:59 +0100 Subject: drm: Fix a bug in the range manager. When searching for free space in a range, the function could return a node extending outside of the given range. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_mm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index cdec3297712..2ac074c8f5d 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -405,7 +405,8 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, wasted += alignment - tmp; } - if (entry->size >= size + wasted) { + if (entry->size >= size + wasted && + (entry->start + wasted + size) <= end) { if (!best_match) return entry; if (entry->size < best_size) { -- cgit v1.2.3 From e22238ea37a870f70e34668a4992bde0c92bba8d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 12 Feb 2010 00:18:00 +0100 Subject: drm/ttm: Fix a bug occuring when validating a buffer object in a range. If the buffer object was already in the requested memory type, but outside of the requested range it was never moved into the requested range. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 1a3e909b7bb..c7320ce4567 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1020,6 +1020,12 @@ static int ttm_bo_mem_compat(struct ttm_placement *placement, struct ttm_mem_reg *mem) { int i; + struct drm_mm_node *node = mem->mm_node; + + if (node && placement->lpfn != 0 && + (node->start < placement->fpfn || + node->start + node->size > placement->lpfn)) + return -1; for (i = 0; i < placement->num_placement; i++) { if ((placement->placement[i] & mem->placement & -- cgit v1.2.3 From ce36f00d599e0f988c2a1b7b276d9184ee9c5d82 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Sat, 13 Feb 2010 20:20:19 -0500 Subject: drm/radeon/kms/atom: use get_unaligned_le32() for ctx->ps Noticed on a DEC Alpha. Start up into console mode caused 15 unaligned accesses, and starting X caused another 48. Signed-off-by: Matt Turner CC: Jerome Glisse CC: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index e3b44562d26..2a3df5599ab 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -24,6 +24,7 @@ #include #include +#include #define ATOM_DEBUG @@ -212,7 +213,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, case ATOM_ARG_PS: idx = U8(*ptr); (*ptr)++; - val = le32_to_cpu(ctx->ps[idx]); + /* get_unaligned_le32 avoids unaligned accesses from atombios + * tables, noticed on a DEC Alpha. */ + val = get_unaligned_le32((u32 *)&ctx->ps[idx]); if (print) DEBUG("PS[0x%02X,0x%04X]", idx, val); break; -- cgit v1.2.3 From e803e8b2628f3e9a42f45c5b7bb1f9821b08352c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 15 Feb 2010 15:24:48 +1000 Subject: drm/radeon/kms: make sure retry count increases. In testing I've never seen it go past 1 retry anyways but better safe than sorry. Reported by Droste on irc. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index b32eeea5bb8..99915a682d5 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -350,7 +350,7 @@ retry: atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); if (args.ucReplyStatus && !args.ucDataOutLen) { - if (args.ucReplyStatus == 0x20 && retry_count < 10) + if (args.ucReplyStatus == 0x20 && retry_count++ < 10) goto retry; DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n", req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], -- cgit v1.2.3