From 76a44f14d6339e5bc0c936ef4a360f6c152511bd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 11:59:28 +1000 Subject: drm/modesetting: overhaul the fb create/delete. Move TTM code into the driver --- linux-core/drmP.h | 1 - linux-core/drm_crtc.c | 68 +++++++++----------------------------------- linux-core/drm_crtc.h | 15 +++++++--- linux-core/drm_crtc_helper.c | 14 +++++++++ linux-core/drm_crtc_helper.h | 4 +++ linux-core/i915_drv.c | 1 - linux-core/intel_display.c | 47 +++++++++++++++++++++++++++++- linux-core/intel_drv.h | 11 +++++++ linux-core/intel_fb.c | 58 +++++++++++++++++++++---------------- 9 files changed, 133 insertions(+), 86 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 11c01386..6e627cd9 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -744,7 +744,6 @@ struct drm_driver { /* FB routines, if present */ int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); - int (*fb_remove)(struct drm_device *dev, struct drm_framebuffer *fb); int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); /* Master routines */ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 784c2f74..7f843925 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -208,25 +208,21 @@ struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev, * RETURNS: * Pointer to new framebuffer or NULL on error. */ -struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev) +struct drm_framebuffer *drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, + const struct drm_framebuffer_funcs *funcs) { - struct drm_framebuffer *fb; - - fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); - if (!fb) - return NULL; - drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); fb->dev = dev; + fb->funcs = funcs; dev->mode_config.num_fb++; list_add(&fb->head, &dev->mode_config.fb_list); return fb; } -EXPORT_SYMBOL(drm_framebuffer_create); +EXPORT_SYMBOL(drm_framebuffer_init); /** - * drm_framebuffer_destroy - remove a framebuffer object + * drm_framebuffer_cleanup - remove a framebuffer object * @fb: framebuffer to remove * * LOCKING: @@ -235,7 +231,7 @@ EXPORT_SYMBOL(drm_framebuffer_create); * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes * it, setting it to NULL. */ -void drm_framebuffer_destroy(struct drm_framebuffer *fb) +void drm_framebuffer_cleanup(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; struct drm_crtc *crtc; @@ -249,10 +245,8 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) drm_mode_object_put(dev, &fb->base); list_del(&fb->head); dev->mode_config.num_fb--; - - kfree(fb); } -EXPORT_SYMBOL(drm_framebuffer_destroy); +EXPORT_SYMBOL(drm_framebuffer_cleanup); /** * drm_crtc_init - Initialise a new CRTC object @@ -705,11 +699,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) } list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { - /* there should only be bo of kernel type left */ - if (fb->bo->type != drm_bo_type_kernel) - drm_framebuffer_destroy(fb); - else - dev->driver->fb_remove(dev, fb); + fb->funcs->destroy(fb); } list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { @@ -1393,7 +1383,6 @@ int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *r = data; struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; - struct drm_buffer_object *bo; int ret = 0; if ((config->min_width > r->width) || (r->width > config->max_width)) { @@ -1406,33 +1395,18 @@ int drm_mode_addfb(struct drm_device *dev, } mutex_lock(&dev->mode_config.mutex); - /* TODO check limits are okay */ - ret = drm_get_buffer_object(dev, &bo, r->handle); - if (ret || !bo) { - DRM_ERROR("BO handle not valid\n"); - ret = -EINVAL; - goto out; - } /* TODO check buffer is sufficently large */ /* TODO setup destructor callback */ - fb = drm_framebuffer_create(dev); + fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); if (!fb) { DRM_ERROR("could not create framebuffer\n"); ret = -EINVAL; goto out; } - fb->width = r->width; - fb->height = r->height; - fb->pitch = r->pitch; - fb->bits_per_pixel = r->bpp; - fb->depth = r->depth; - fb->bo = bo; - r->buffer_id = fb->base.id; - list_add(&fb->filp_head, &file_priv->fbs); out: @@ -1490,11 +1464,8 @@ int drm_mode_rmfb(struct drm_device *dev, /* TODO release all crtc connected to the framebuffer */ /* TODO unhock the destructor from the buffer object */ - if (fb->bo->type == drm_bo_type_kernel) - DRM_ERROR("the bo type should not be of kernel type\n"); - list_del(&fb->filp_head); - drm_framebuffer_destroy(fb); + fb->funcs->destroy(fb); out: mutex_unlock(&dev->mode_config.mutex); @@ -1539,7 +1510,7 @@ int drm_mode_getfb(struct drm_device *dev, r->width = fb->width; r->depth = fb->depth; r->bpp = fb->bits_per_pixel; - r->handle = fb->bo->base.hash.key; + r->handle = fb->mm_handle; r->pitch = fb->pitch; out: @@ -1570,10 +1541,7 @@ void drm_fb_release(struct file *filp) mutex_lock(&dev->mode_config.mutex); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { list_del(&fb->filp_head); - if (fb->bo->type == drm_bo_type_kernel) - DRM_ERROR("the bo type should not be of kernel_type, the kernel will probably explode, why Dave\n"); - - drm_framebuffer_destroy(fb); + fb->funcs->destroy(fb); } mutex_unlock(&dev->mode_config.mutex); } @@ -2118,17 +2086,12 @@ int drm_mode_replacefb(struct drm_device *dev, struct drm_mode_fb_cmd *r = data; struct drm_mode_object *obj; struct drm_framebuffer *fb; - struct drm_buffer_object *bo; int found = 0; struct drm_framebuffer *fbl = NULL; int ret = 0; + /* right replace the current bo attached to this fb with a new bo */ mutex_lock(&dev->mode_config.mutex); - ret = drm_get_buffer_object(dev, &bo, r->handle); - if (ret || !bo) { - ret = -EINVAL; - goto out; - } obj = drm_mode_object_find(dev, r->buffer_id, DRM_MODE_OBJECT_FB); if (!obj) { ret = -EINVAL; @@ -2146,15 +2109,12 @@ int drm_mode_replacefb(struct drm_device *dev, goto out; } - if (fb->bo->type == drm_bo_type_kernel) - DRM_ERROR("the bo should not be a kernel bo\n"); - fb->width = r->width; fb->height = r->height; fb->pitch = r->pitch; fb->bits_per_pixel = r->bpp; fb->depth = r->depth; - fb->bo = bo; + fb->mm_handle = r->handle; if (dev->mode_config.funcs->resize_fb) dev->mode_config.funcs->resize_fb(dev, fb); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 01cf9af7..5c2d0b3c 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -15,6 +15,7 @@ struct drm_device; struct drm_mode_set; +struct drm_framebuffer; #define DRM_MODE_OBJECT_CRTC 0xcccccccc @@ -250,10 +251,15 @@ struct drm_display_info { char *raw_edid; /* if any */ }; +struct drm_framebuffer_funcs { + void (*destroy)(struct drm_framebuffer *framebuffer); +}; + struct drm_framebuffer { struct drm_device *dev; struct list_head head; struct drm_mode_object base; + const struct drm_framebuffer_funcs *funcs; unsigned int pitch; unsigned int width; unsigned int height; @@ -261,11 +267,10 @@ struct drm_framebuffer { unsigned int depth; int bits_per_pixel; int flags; - struct drm_buffer_object *bo; void *fbdev; u32 pseudo_palette[17]; - struct drm_bo_kmap_obj kmap; struct list_head filp_head; + uint32_t mm_handle; }; struct drm_property_blob { @@ -517,6 +522,7 @@ struct drm_mode_set */ struct drm_mode_config_funcs { bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb); + struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); }; struct drm_mode_group { @@ -645,8 +651,9 @@ extern int drm_connector_property_get_value(struct drm_connector *connector, extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); -extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev); -extern void drm_framebuffer_destroy(struct drm_framebuffer *fb); +extern struct drm_framebuffer *drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, + const struct drm_framebuffer_funcs *funcs); +extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index fcb1243c..f35c0a49 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -749,3 +749,17 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c } EXPORT_SYMBOL(drm_helper_hotplug_stage_two); + +int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, + struct drm_mode_fb_cmd *mode_cmd) +{ + fb->width = mode_cmd->width; + fb->height = mode_cmd->height; + fb->pitch = mode_cmd->pitch; + fb->bits_per_pixel = mode_cmd->bpp; + fb->depth = mode_cmd->depth; + fb->mm_handle = mode_cmd->handle; + + return 0; +} +EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 3a3a4d4f..460fd0d0 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -72,6 +72,10 @@ extern int drm_crtc_helper_set_config(struct drm_mode_set *set); extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); + +extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, + struct drm_mode_fb_cmd *mode_cmd); + static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) { crtc->helper_private = (void *)funcs; diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 51262d79..2aac4926 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -589,7 +589,6 @@ static struct drm_driver driver = { .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, .fb_probe = intelfb_probe, - .fb_remove = intelfb_remove, .fb_resize = intelfb_resize, .master_create = i915_master_create, .master_destroy = i915_master_destroy, diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 8a8f4edb..529cae14 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -368,6 +368,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; int pipe = intel_crtc->pipe; unsigned long Start, Offset; int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); @@ -382,7 +383,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) return; } - Start = crtc->fb->bo->offset; + intel_fb = to_intel_framebuffer(crtc->fb); + + Start = intel_fb->bo->offset; Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); I915_WRITE(dspstride, crtc->fb->pitch); @@ -1459,8 +1462,50 @@ static void intel_setup_outputs(struct drm_device *dev) } } +static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) +{ + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_device *dev = fb->dev; + if (fb->fbdev) + intelfb_remove(dev, fb); + + drm_framebuffer_cleanup(fb); + + kfree(intel_fb); +} + +static const struct drm_framebuffer_funcs intel_fb_funcs = { + .destroy = intel_user_framebuffer_destroy, +}; + +struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_mode_fb_cmd *mode_cmd) +{ + struct intel_framebuffer *intel_fb; + + intel_fb = kmalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) + return NULL; + + drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); + drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); + + if (file_priv) { + mutex_lock(&dev->struct_mutex); + intel_fb->bo = drm_lookup_buffer_object(file_priv, intel_fb->base.mm_handle, 0); + mutex_unlock(&dev->struct_mutex); + if (!intel_fb->bo) { + kfree(intel_fb); + return NULL; + } + } + return &intel_fb->base; +} + static const struct drm_mode_config_funcs intel_mode_funcs = { .resize_fb = NULL, + .fb_create = intel_user_framebuffer_create, }; void intel_modeset_init(struct drm_device *dev) diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 210ed990..46f0fbec 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -46,6 +46,12 @@ struct intel_i2c_chan { u8 slave_addr; }; +struct intel_framebuffer { + struct drm_framebuffer base; + struct drm_buffer_object *bo; + struct drm_bo_kmap_obj kmap; +}; + struct intel_output { struct drm_connector base; @@ -69,6 +75,7 @@ struct intel_crtc { #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_output(x) container_of(x, struct intel_output, base) #define enc_to_intel_output(x) container_of(x, struct intel_output, enc) +#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, const char *name); @@ -106,4 +113,8 @@ extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); + +extern struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_mode_fb_cmd *mode_cmd); #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index d490880a..1107cbfb 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -573,7 +573,10 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn struct intelfb_par *par; struct device *device = &dev->pdev->dev; struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; struct drm_display_mode *mode = crtc->desired_mode; + struct drm_mode_fb_cmd mode_cmd; + struct drm_buffer_object *fbo = NULL; int ret; @@ -585,22 +588,14 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn if (!connector) return -EINVAL; - fb = drm_framebuffer_create(dev); - if (!fb) { - framebuffer_release(info); - DRM_ERROR("failed to allocate fb.\n"); - return -EINVAL; - } - crtc->fb = fb; - - /* To allow resizeing without swapping buffers */ - fb->width = 2048;/* crtc->desired_mode->hdisplay; */ - fb->height = 2048;/* crtc->desired_mode->vdisplay; */ + mode_cmd.width = 2048;/* crtc->desired_mode->hdisplay; */ + mode_cmd.height = 2048;/* crtc->desired_mode->vdisplay; */ + + mode_cmd.bpp = 32; + mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); + mode_cmd.depth = 24; - fb->bits_per_pixel = 32; - fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); - fb->depth = 24; - ret = drm_buffer_object_create(dev, fb->pitch * fb->height, + ret = drm_buffer_object_create(dev, mode_cmd.pitch * mode_cmd.height, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | @@ -611,14 +606,27 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn &fbo); if (ret || !fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); - drm_framebuffer_destroy(fb); framebuffer_release(info); return -EINVAL; } + - fb->bo = fbo; - printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, - fb->height, fbo->offset, fbo); + fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); + if (!fb) { + framebuffer_release(info); + drm_bo_usage_deref_unlocked(&fbo); + DRM_ERROR("failed to allocate fb.\n"); + return -EINVAL; + } + + intel_fb = to_intel_framebuffer(fb); + + intel_fb->bo = fbo; + crtc->fb = fb; + + /* To allow resizeing without swapping buffers */ + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, + intel_fb->base.height, intel_fb->bo->offset, fbo); fb->fbdev = info; @@ -653,16 +661,16 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn } info->fix.line_length = fb->pitch; - info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base; + info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base; info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; - ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap); + ret = drm_bo_kmap(intel_fb->bo, 0, intel_fb->bo->num_pages, &intel_fb->kmap); if (ret) DRM_ERROR("error mapping fb: %d\n", ret); - info->screen_base = fb->kmap.virtual; + info->screen_base = intel_fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; info->var.xres_virtual = fb->width; @@ -771,6 +779,7 @@ EXPORT_SYMBOL(intelfb_probe); int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) { struct fb_info *info; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); if (!fb) return -EINVAL; @@ -779,9 +788,8 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) if (info) { unregister_framebuffer(info); - drm_bo_kunmap(&fb->kmap); - drm_bo_usage_deref_unlocked(&fb->bo); - drm_framebuffer_destroy(fb); + drm_bo_kunmap(&intel_fb->kmap); + drm_bo_usage_deref_unlocked(&intel_fb->bo); framebuffer_release(info); } return 0; -- cgit v1.2.3