From 785b93ef8c309730c2de84ce9c229e40e2d01480 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 28 Aug 2009 15:46:53 +1000 Subject: drm/kms: move driver specific fb common code to helper functions (v2) Initially I always meant this code to be shared, but things ran away from me before I got to it. This refactors the i915 and radeon kms fbdev interaction layers out into generic helpers + driver specific pieces. It moves all the panic/sysrq enhancements to the core file, and stores a linked list of kernel fbs. This could possibly be improved to only store the fb which has fbcon on it for panics etc. radeon retains some specific codes used for a big endian workaround. changes: fix oops in v1 fix freeing path for crtc_info Reviewed-by: Jesse Barnes Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_fb.c | 670 +++++-------------------------------- 1 file changed, 92 insertions(+), 578 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_fb.c') diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index ec383edf5f38..ebb58959f418 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -28,15 +28,7 @@ */ #include -#include -#include -#include -#include -#include -#include -#include #include -#include #include "drmP.h" #include "drm.h" @@ -45,375 +37,86 @@ #include "radeon_drm.h" #include "radeon.h" +#include "drm_fb_helper.h" + struct radeon_fb_device { - struct radeon_device *rdev; - struct drm_display_mode *mode; + struct drm_fb_helper helper; struct radeon_framebuffer *rfb; - int crtc_count; - /* crtc currently bound to this */ - uint32_t crtc_ids[2]; + struct radeon_device *rdev; }; -static int radeonfb_setcolreg(unsigned regno, - unsigned red, - unsigned green, - unsigned blue, - unsigned transp, - struct fb_info *info) -{ - struct radeon_fb_device *rfbdev = info->par; - struct drm_device *dev = rfbdev->rdev->ddev; - struct drm_crtc *crtc; - int i; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct drm_mode_set *modeset = &radeon_crtc->mode_set; - struct drm_framebuffer *fb = modeset->fb; - - for (i = 0; i < rfbdev->crtc_count; i++) { - if (crtc->base.id == rfbdev->crtc_ids[i]) { - break; - } - } - if (i == rfbdev->crtc_count) { - continue; - } - if (regno > 255) { - return 1; - } - if (fb->depth == 8) { - radeon_crtc_fb_gamma_set(crtc, red, green, blue, regno); - return 0; - } - - if (regno < 16) { - switch (fb->depth) { - case 15: - fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 16: - fb->pseudo_palette[regno] = (red & 0xf800) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - case 24: - case 32: - fb->pseudo_palette[regno] = - (((red >> 8) & 0xff) << info->var.red.offset) | - (((green >> 8) & 0xff) << info->var.green.offset) | - (((blue >> 8) & 0xff) << info->var.blue.offset); - break; - } - } - } - return 0; -} - -static int radeonfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) +static int radeon_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) { - struct radeon_fb_device *rfbdev = info->par; - struct radeon_framebuffer *rfb = rfbdev->rfb; - struct drm_framebuffer *fb = &rfb->base; - int depth; - - if (var->pixclock == -1 || !var->pixclock) { - 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"); - return -EINVAL; - } - - switch (var->bits_per_pixel) { - case 16: - depth = (var->green.length == 6) ? 16 : 15; - break; - case 32: - depth = (var->transp.length > 0) ? 32 : 24; - break; - default: - depth = var->bits_per_pixel; - break; - } - - switch (depth) { - case 8: - var->red.offset = 0; - var->green.offset = 0; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 0; - var->transp.offset = 0; - break; -#ifdef __LITTLE_ENDIAN - case 15: - var->red.offset = 10; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 5; - var->blue.length = 5; - var->transp.length = 1; - var->transp.offset = 15; - break; - case 16: - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - var->transp.length = 0; - var->transp.offset = 0; - break; - case 24: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 0; - var->transp.offset = 0; - break; - case 32: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 8; - var->transp.offset = 24; - break; -#else - case 24: - var->red.offset = 8; - var->green.offset = 16; - var->blue.offset = 24; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 0; - var->transp.offset = 0; - break; - case 32: - var->red.offset = 8; - var->green.offset = 16; - var->blue.offset = 24; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 8; - var->transp.offset = 0; - break; -#endif - default: - return -EINVAL; - } - return 0; -} - -/* this will let fbcon do the mode init */ -static int radeonfb_set_par(struct fb_info *info) -{ - struct radeon_fb_device *rfbdev = info->par; - struct drm_device *dev = rfbdev->rdev->ddev; - struct fb_var_screeninfo *var = &info->var; - struct drm_crtc *crtc; int ret; - int i; - - if (var->pixclock != -1) { - DRM_ERROR("PIXEL CLCOK SET\n"); - return -EINVAL; - } - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - - for (i = 0; i < rfbdev->crtc_count; i++) { - if (crtc->base.id == rfbdev->crtc_ids[i]) { - break; - } - } - if (i == rfbdev->crtc_count) { - continue; - } - if (crtc->fb == radeon_crtc->mode_set.fb) { - mutex_lock(&dev->mode_config.mutex); - ret = crtc->funcs->set_config(&radeon_crtc->mode_set); - mutex_unlock(&dev->mode_config.mutex); - if (ret) { - return ret; - } - } - } - return 0; -} - -static int radeonfb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - struct radeon_fb_device *rfbdev = info->par; - struct drm_device *dev = rfbdev->rdev->ddev; - struct drm_mode_set *modeset; - struct drm_crtc *crtc; - struct radeon_crtc *radeon_crtc; - int ret = 0; - int i; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - for (i = 0; i < rfbdev->crtc_count; i++) { - if (crtc->base.id == rfbdev->crtc_ids[i]) { - break; - } - } - - if (i == rfbdev->crtc_count) { - continue; - } - - radeon_crtc = to_radeon_crtc(crtc); - modeset = &radeon_crtc->mode_set; - - modeset->x = var->xoffset; - modeset->y = var->yoffset; - - if (modeset->num_connectors) { - mutex_lock(&dev->mode_config.mutex); - ret = crtc->funcs->set_config(modeset); - mutex_unlock(&dev->mode_config.mutex); - if (!ret) { - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - } + ret = drm_fb_helper_check_var(var, info); + if (ret) + return ret; + + /* big endian override for radeon endian workaround */ +#ifdef __BIG_ENDIAN + { + int depth; + switch (var->bits_per_pixel) { + case 16: + depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + depth = var->bits_per_pixel; + break; } - } - return ret; -} - -static void radeonfb_on(struct fb_info *info) -{ - struct radeon_fb_device *rfbdev = info->par; - struct drm_device *dev = rfbdev->rdev->ddev; - struct drm_crtc *crtc; - struct drm_encoder *encoder; - int i; - - /* - * For each CRTC in this fb, find all associated encoders - * and turn them off, then turn off the CRTC. - */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - - for (i = 0; i < rfbdev->crtc_count; i++) { - if (crtc->base.id == rfbdev->crtc_ids[i]) { - break; - } - } - - mutex_lock(&dev->mode_config.mutex); - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); - - /* Found a CRTC on this fb, now find encoders */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - struct drm_encoder_helper_funcs *encoder_funcs; - - encoder_funcs = encoder->helper_private; - mutex_lock(&dev->mode_config.mutex); - encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); - } - } - } -} - -static void radeonfb_off(struct fb_info *info, int dpms_mode) -{ - struct radeon_fb_device *rfbdev = info->par; - struct drm_device *dev = rfbdev->rdev->ddev; - struct drm_crtc *crtc; - struct drm_encoder *encoder; - int i; - - /* - * For each CRTC in this fb, find all associated encoders - * and turn them off, then turn off the CRTC. - */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - - for (i = 0; i < rfbdev->crtc_count; i++) { - if (crtc->base.id == rfbdev->crtc_ids[i]) { - break; - } - } - - /* Found a CRTC on this fb, now find encoders */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - struct drm_encoder_helper_funcs *encoder_funcs; - - encoder_funcs = encoder->helper_private; - mutex_lock(&dev->mode_config.mutex); - encoder_funcs->dpms(encoder, dpms_mode); - mutex_unlock(&dev->mode_config.mutex); - } - } - if (dpms_mode == DRM_MODE_DPMS_OFF) { - mutex_lock(&dev->mode_config.mutex); - crtc_funcs->dpms(crtc, dpms_mode); - mutex_unlock(&dev->mode_config.mutex); + switch (depth) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 24: + var->red.offset = 8; + var->green.offset = 16; + var->blue.offset = 24; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 32: + var->red.offset = 8; + var->green.offset = 16; + var->blue.offset = 24; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + var->transp.offset = 0; + break; + default: + return -EINVAL; } } -} - -int radeonfb_blank(int blank, struct fb_info *info) -{ - switch (blank) { - case FB_BLANK_UNBLANK: - radeonfb_on(info); - break; - case FB_BLANK_NORMAL: - radeonfb_off(info, DRM_MODE_DPMS_STANDBY); - break; - case FB_BLANK_HSYNC_SUSPEND: - radeonfb_off(info, DRM_MODE_DPMS_STANDBY); - break; - case FB_BLANK_VSYNC_SUSPEND: - radeonfb_off(info, DRM_MODE_DPMS_SUSPEND); - break; - case FB_BLANK_POWERDOWN: - radeonfb_off(info, DRM_MODE_DPMS_OFF); - break; - } +#endif return 0; } static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, - .fb_check_var = radeonfb_check_var, - .fb_set_par = radeonfb_set_par, - .fb_setcolreg = radeonfb_setcolreg, + .fb_check_var = radeon_fb_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_setcolreg = drm_fb_helper_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_pan_display = radeonfb_pan_display, - .fb_blank = radeonfb_blank, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_blank = drm_fb_helper_blank, }; /** @@ -456,21 +159,6 @@ int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(radeonfb_resize); -static struct drm_mode_set panic_mode; - -int radeonfb_panic(struct notifier_block *n, unsigned long ununsed, - void *panic_str) -{ - DRM_ERROR("panic occurred, switching back to text console\n"); - drm_crtc_helper_set_config(&panic_mode); - return 0; -} -EXPORT_SYMBOL(radeonfb_panic); - -static struct notifier_block paniced = { - .notifier_call = radeonfb_panic, -}; - static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled) { int aligned = width; @@ -495,11 +183,16 @@ static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bo return aligned; } -int radeonfb_create(struct radeon_device *rdev, +static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { + .gamma_set = radeon_crtc_fb_gamma_set, +}; + +int radeonfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, uint32_t surface_width, uint32_t surface_height, - struct radeon_framebuffer **rfb_p) + struct drm_framebuffer **fb_p) { + struct radeon_device *rdev = dev->dev_private; struct fb_info *info; struct radeon_fb_device *rfbdev; struct drm_framebuffer *fb = NULL; @@ -554,8 +247,8 @@ int radeonfb_create(struct radeon_device *rdev, list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list); + *fb_p = fb; rfb = to_radeon_framebuffer(fb); - *rfb_p = rfb; rdev->fbdev_rfb = rfb; rdev->fbdev_robj = robj; @@ -564,7 +257,14 @@ int radeonfb_create(struct radeon_device *rdev, ret = -ENOMEM; goto out_unref; } + rfbdev = info->par; + rfbdev->helper.funcs = &radeon_fb_helper_funcs; + rfbdev->helper.dev = dev; + ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, 2, + RADEONFB_CONN_LIMIT); + if (ret) + goto out_unref; if (fb_tiled) radeon_object_check_tiling(robj, 0, 0); @@ -577,33 +277,19 @@ int radeonfb_create(struct radeon_device *rdev, memset_io(fbptr, 0, aligned_size); strcpy(info->fix.id, "radeondrmfb"); - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = FB_VISUAL_TRUECOLOR; - info->fix.type_aux = 0; - info->fix.xpanstep = 1; /* doing it in hw */ - info->fix.ypanstep = 1; /* doing it in hw */ - info->fix.ywrapstep = 0; - info->fix.accel = FB_ACCEL_NONE; - info->fix.type_aux = 0; + + drm_fb_helper_fill_fix(info, fb->pitch); + info->flags = FBINFO_DEFAULT; info->fbops = &radeonfb_ops; - info->fix.line_length = fb->pitch; + tmp = fb_gpuaddr - rdev->mc.vram_location; info->fix.smem_start = rdev->mc.aper_base + tmp; info->fix.smem_len = size; info->screen_base = fbptr; info->screen_size = size; - info->pseudo_palette = fb->pseudo_palette; - info->var.xres_virtual = fb->width; - info->var.yres_virtual = fb->height; - info->var.bits_per_pixel = fb->bits_per_pixel; - info->var.xoffset = 0; - info->var.yoffset = 0; - info->var.activate = FB_ACTIVATE_NOW; - info->var.height = -1; - info->var.width = -1; - info->var.xres = fb_width; - info->var.yres = fb_height; + + drm_fb_helper_fill_var(info, fb, fb_width, fb_height); /* setup aperture base/size for vesafb takeover */ info->aperture_base = rdev->ddev->mode_config.fb_base; @@ -626,6 +312,9 @@ int radeonfb_create(struct radeon_device *rdev, DRM_INFO("fb depth is %d\n", fb->depth); DRM_INFO(" pitch is %d\n", fb->pitch); +#ifdef __BIG_ENDIAN + /* fill var sets defaults for this stuff - override + on big endian */ switch (fb->depth) { case 8: info->var.red.offset = 0; @@ -637,47 +326,6 @@ int radeonfb_create(struct radeon_device *rdev, info->var.transp.offset = 0; info->var.transp.length = 0; break; -#ifdef __LITTLE_ENDIAN - case 15: - info->var.red.offset = 10; - info->var.green.offset = 5; - info->var.blue.offset = 0; - info->var.red.length = 5; - info->var.green.length = 5; - info->var.blue.length = 5; - info->var.transp.offset = 15; - info->var.transp.length = 1; - break; - case 16: - info->var.red.offset = 11; - info->var.green.offset = 5; - info->var.blue.offset = 0; - info->var.red.length = 5; - info->var.green.length = 6; - info->var.blue.length = 5; - info->var.transp.offset = 0; - break; - case 24: - info->var.red.offset = 16; - info->var.green.offset = 8; - info->var.blue.offset = 0; - info->var.red.length = 8; - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - break; - case 32: - info->var.red.offset = 16; - info->var.green.offset = 8; - info->var.blue.offset = 0; - info->var.red.length = 8; - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 24; - info->var.transp.length = 8; - break; -#else case 24: info->var.red.offset = 8; info->var.green.offset = 16; @@ -699,9 +347,9 @@ int radeonfb_create(struct radeon_device *rdev, info->var.transp.length = 8; break; default: -#endif break; } +#endif fb->fbdev = info; rfbdev->rfb = rfb; @@ -726,145 +374,10 @@ out: return ret; } -static int radeonfb_single_fb_probe(struct radeon_device *rdev) -{ - struct drm_crtc *crtc; - struct drm_connector *connector; - unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; - unsigned int surface_width = 0, surface_height = 0; - int new_fb = 0; - int crtc_count = 0; - int ret, i, conn_count = 0; - struct radeon_framebuffer *rfb; - struct fb_info *info; - struct radeon_fb_device *rfbdev; - struct drm_mode_set *modeset = NULL; - - /* first up get a count of crtcs now in use and new min/maxes width/heights */ - list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) { - if (drm_helper_crtc_in_use(crtc)) { - if (crtc->desired_mode) { - if (crtc->desired_mode->hdisplay < fb_width) - fb_width = crtc->desired_mode->hdisplay; - - if (crtc->desired_mode->vdisplay < fb_height) - fb_height = crtc->desired_mode->vdisplay; - - if (crtc->desired_mode->hdisplay > surface_width) - surface_width = crtc->desired_mode->hdisplay; - - if (crtc->desired_mode->vdisplay > surface_height) - surface_height = crtc->desired_mode->vdisplay; - } - crtc_count++; - } - } - - if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { - /* hmm everyone went away - assume VGA cable just fell out - and will come back later. */ - return 0; - } - - /* do we have an fb already? */ - if (list_empty(&rdev->ddev->mode_config.fb_kernel_list)) { - /* create an fb if we don't have one */ - ret = radeonfb_create(rdev, fb_width, fb_height, surface_width, surface_height, &rfb); - if (ret) { - return -EINVAL; - } - new_fb = 1; - } else { - struct drm_framebuffer *fb; - fb = list_first_entry(&rdev->ddev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); - rfb = to_radeon_framebuffer(fb); - - /* if someone hotplugs something bigger than we have already allocated, we are pwned. - As really we can't resize an fbdev that is in the wild currently due to fbdev - not really being designed for the lower layers moving stuff around under it. - - so in the grand style of things - punt. */ - if ((fb->width < surface_width) || (fb->height < surface_height)) { - DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); - return -EINVAL; - } - } - - info = rfb->base.fbdev; - rdev->fbdev_info = info; - rfbdev = info->par; - - crtc_count = 0; - /* okay we need to setup new connector sets in the crtcs */ - list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - modeset = &radeon_crtc->mode_set; - modeset->fb = &rfb->base; - conn_count = 0; - list_for_each_entry(connector, &rdev->ddev->mode_config.connector_list, head) { - if (connector->encoder) - if (connector->encoder->crtc == modeset->crtc) { - modeset->connectors[conn_count] = connector; - conn_count++; - if (conn_count > RADEONFB_CONN_LIMIT) - BUG(); - } - } - - for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++) - modeset->connectors[i] = NULL; - - - rfbdev->crtc_ids[crtc_count++] = crtc->base.id; - - modeset->num_connectors = conn_count; - if (modeset->crtc->desired_mode) { - if (modeset->mode) { - drm_mode_destroy(rdev->ddev, modeset->mode); - } - modeset->mode = drm_mode_duplicate(rdev->ddev, - modeset->crtc->desired_mode); - } - } - rfbdev->crtc_count = crtc_count; - - if (new_fb) { - info->var.pixclock = -1; - if (register_framebuffer(info) < 0) - return -EINVAL; - } else { - radeonfb_set_par(info); - } - printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, - info->fix.id); - - /* Switch back to kernel console on panic */ - panic_mode = *modeset; - atomic_notifier_chain_register(&panic_notifier_list, &paniced); - printk(KERN_INFO "registered panic notifier\n"); - - return 0; -} - int radeonfb_probe(struct drm_device *dev) { int ret; - - /* something has changed in the lower levels of hell - deal with it - here */ - - /* two modes : a) 1 fb to rule all crtcs. - b) one fb per crtc. - two actions 1) new connected device - 2) device removed. - case a/1 : if the fb surface isn't big enough - resize the surface fb. - if the fb size isn't big enough - resize fb into surface. - if everything big enough configure the new crtc/etc. - case a/2 : undo the configuration - possibly resize down the fb to fit the new configuration. - case b/1 : see if it is on a new crtc - setup a new fb and add it. - case b/2 : teardown the new fb. - */ - ret = radeonfb_single_fb_probe(dev->dev_private); + ret = drm_fb_helper_single_fb_probe(dev, &radeonfb_create); return ret; } EXPORT_SYMBOL(radeonfb_probe); @@ -880,16 +393,17 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) } info = fb->fbdev; if (info) { + struct radeon_fb_device *rfbdev = info->par; robj = rfb->obj->driver_private; unregister_framebuffer(info); radeon_object_kunmap(robj); radeon_object_unpin(robj); + drm_fb_helper_free(&rfbdev->helper); framebuffer_release(info); } printk(KERN_INFO "unregistered panic notifier\n"); - atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); - memset(&panic_mode, 0, sizeof(struct drm_mode_set)); + return 0; } EXPORT_SYMBOL(radeonfb_remove); -- cgit v1.2.3