--- zzzz-none-000/linux-3.10.107/drivers/gpu/drm/nouveau/nouveau_fbcon.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/gpu/drm/nouveau/nouveau_fbcon.c 2021-02-04 17:41:59.000000000 +0000 @@ -51,13 +51,8 @@ #include "nouveau_crtc.h" -#include -#include - -#include - MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration"); -static int nouveau_nofbaccel = 0; +int nouveau_nofbaccel = 0; module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); static void @@ -65,7 +60,7 @@ { struct nouveau_fbdev *fbcon = info->par; struct nouveau_drm *drm = nouveau_drm(fbcon->dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int ret; if (info->state != FBINFO_STATE_RUNNING) @@ -74,10 +69,10 @@ ret = -ENODEV; if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && mutex_trylock(&drm->client.mutex)) { - if (device->card_type < NV_50) + if (device->info.family < NV_DEVICE_INFO_V0_TESLA) ret = nv04_fbcon_fillrect(info, rect); else - if (device->card_type < NV_C0) + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) ret = nv50_fbcon_fillrect(info, rect); else ret = nvc0_fbcon_fillrect(info, rect); @@ -89,7 +84,7 @@ if (ret != -ENODEV) nouveau_fbcon_gpu_lockup(info); - cfb_fillrect(info, rect); + drm_fb_helper_cfb_fillrect(info, rect); } static void @@ -97,7 +92,7 @@ { struct nouveau_fbdev *fbcon = info->par; struct nouveau_drm *drm = nouveau_drm(fbcon->dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int ret; if (info->state != FBINFO_STATE_RUNNING) @@ -106,10 +101,10 @@ ret = -ENODEV; if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && mutex_trylock(&drm->client.mutex)) { - if (device->card_type < NV_50) + if (device->info.family < NV_DEVICE_INFO_V0_TESLA) ret = nv04_fbcon_copyarea(info, image); else - if (device->card_type < NV_C0) + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) ret = nv50_fbcon_copyarea(info, image); else ret = nvc0_fbcon_copyarea(info, image); @@ -121,7 +116,7 @@ if (ret != -ENODEV) nouveau_fbcon_gpu_lockup(info); - cfb_copyarea(info, image); + drm_fb_helper_cfb_copyarea(info, image); } static void @@ -129,7 +124,7 @@ { struct nouveau_fbdev *fbcon = info->par; struct nouveau_drm *drm = nouveau_drm(fbcon->dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int ret; if (info->state != FBINFO_STATE_RUNNING) @@ -138,10 +133,10 @@ ret = -ENODEV; if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && mutex_trylock(&drm->client.mutex)) { - if (device->card_type < NV_50) + if (device->info.family < NV_DEVICE_INFO_V0_TESLA) ret = nv04_fbcon_imageblit(info, image); else - if (device->card_type < NV_C0) + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) ret = nv50_fbcon_imageblit(info, image); else ret = nvc0_fbcon_imageblit(info, image); @@ -153,7 +148,7 @@ if (ret != -ENODEV) nouveau_fbcon_gpu_lockup(info); - cfb_imageblit(info, image); + drm_fb_helper_cfb_imageblit(info, image); } static int @@ -183,8 +178,30 @@ return 0; } +static int +nouveau_fbcon_open(struct fb_info *info, int user) +{ + struct nouveau_fbdev *fbcon = info->par; + struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + int ret = pm_runtime_get_sync(drm->dev->dev); + if (ret < 0 && ret != -EACCES) + return ret; + return 0; +} + +static int +nouveau_fbcon_release(struct fb_info *info, int user) +{ + struct nouveau_fbdev *fbcon = info->par; + struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + pm_runtime_put(drm->dev->dev); + return 0; +} + static struct fb_ops nouveau_fbcon_ops = { .owner = THIS_MODULE, + .fb_open = nouveau_fbcon_open, + .fb_release = nouveau_fbcon_release, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_fillrect = nouveau_fbcon_fillrect, @@ -200,11 +217,13 @@ static struct fb_ops nouveau_fbcon_sw_ops = { .owner = THIS_MODULE, + .fb_open = nouveau_fbcon_open, + .fb_release = nouveau_fbcon_release, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -212,6 +231,65 @@ .fb_debug_leave = drm_fb_helper_debug_leave, }; +void +nouveau_fbcon_accel_save_disable(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + if (drm->fbcon) { + drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags; + drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; + } +} + +void +nouveau_fbcon_accel_restore(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + if (drm->fbcon) { + drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags; + } +} + +static void +nouveau_fbcon_accel_fini(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_fbdev *fbcon = drm->fbcon; + if (fbcon && drm->channel) { + console_lock(); + fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; + console_unlock(); + nouveau_channel_idle(drm->channel); + nvif_object_fini(&fbcon->twod); + nvif_object_fini(&fbcon->blit); + nvif_object_fini(&fbcon->gdi); + nvif_object_fini(&fbcon->patt); + nvif_object_fini(&fbcon->rop); + nvif_object_fini(&fbcon->clip); + nvif_object_fini(&fbcon->surf2d); + } +} + +static void +nouveau_fbcon_accel_init(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_fbdev *fbcon = drm->fbcon; + struct fb_info *info = fbcon->helper.fbdev; + int ret; + + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) + ret = nv04_fbcon_accel_init(info); + else + if (drm->device.info.family < NV_DEVICE_INFO_V0_FERMI) + ret = nv50_fbcon_accel_init(info); + else + ret = nvc0_fbcon_accel_init(info); + + if (ret == 0) + info->fbops = &nouveau_fbcon_ops; +} + static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) { @@ -254,17 +332,17 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { - struct nouveau_fbdev *fbcon = (struct nouveau_fbdev *)helper; + struct nouveau_fbdev *fbcon = + container_of(helper, struct nouveau_fbdev, helper); struct drm_device *dev = fbcon->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct fb_info *info; struct drm_framebuffer *fb; struct nouveau_framebuffer *nouveau_fb; struct nouveau_channel *chan; struct nouveau_bo *nvbo; struct drm_mode_fb_cmd2 mode_cmd; - struct pci_dev *pdev = dev->pdev; int size, ret; mode_cmd.width = sizes->surface_width; @@ -286,24 +364,21 @@ goto out; } - ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, false); if (ret) { NV_ERROR(drm, "failed to pin fb: %d\n", ret); - nouveau_bo_ref(NULL, &nvbo); - goto out; + goto out_unref; } ret = nouveau_bo_map(nvbo); if (ret) { NV_ERROR(drm, "failed to map fb: %d\n", ret); - nouveau_bo_unpin(nvbo); - nouveau_bo_ref(NULL, &nvbo); - goto out; + goto out_unpin; } chan = nouveau_nofbaccel ? NULL : drm->channel; - if (chan && device->card_type >= NV_50) { - ret = nouveau_bo_vma_add(nvbo, nv_client(chan->cli)->vm, + if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + ret = nouveau_bo_vma_add(nvbo, drm->client.vm, &fbcon->nouveau_fb.vma); if (ret) { NV_ERROR(drm, "failed to map fb into chan: %d\n", ret); @@ -313,17 +388,12 @@ mutex_lock(&dev->struct_mutex); - info = framebuffer_alloc(0, &pdev->dev); - if (!info) { - ret = -ENOMEM; - goto out_unref; - } - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out_unref; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); + goto out_unlock; } + info->skip_vt_switch = 1; info->par = fbcon; @@ -334,10 +404,9 @@ /* setup helper */ fbcon->helper.fb = fb; - fbcon->helper.fbdev = info; strcpy(info->fix.id, "nouveaufb"); - if (nouveau_nofbaccel) + if (!chan) info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_DISABLED; else info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | @@ -359,32 +428,27 @@ mutex_unlock(&dev->struct_mutex); - if (chan) { - ret = -ENODEV; - if (device->card_type < NV_50) - ret = nv04_fbcon_accel_init(info); - else - if (device->card_type < NV_C0) - ret = nv50_fbcon_accel_init(info); - else - ret = nvc0_fbcon_accel_init(info); - - if (ret == 0) - info->fbops = &nouveau_fbcon_ops; - } - + if (chan) + nouveau_fbcon_accel_init(dev); nouveau_fbcon_zfill(dev, fbcon); /* To allow resizeing without swapping buffers */ - NV_INFO(drm, "allocated %dx%d fb: 0x%lx, bo %p\n", + NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n", nouveau_fb->base.width, nouveau_fb->base.height, nvbo->bo.offset, nvbo); vga_switcheroo_client_fb_set(dev->pdev, info); return 0; -out_unref: +out_unlock: mutex_unlock(&dev->struct_mutex); + if (chan) + nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma); + nouveau_bo_unmap(nvbo); +out_unpin: + nouveau_bo_unpin(nvbo); +out_unref: + nouveau_bo_ref(NULL, &nvbo); out: return ret; } @@ -393,27 +457,23 @@ nouveau_fbcon_output_poll_changed(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - drm_fb_helper_hotplug_event(&drm->fbcon->helper); + if (drm->fbcon) + drm_fb_helper_hotplug_event(&drm->fbcon->helper); } static int nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) { struct nouveau_framebuffer *nouveau_fb = &fbcon->nouveau_fb; - struct fb_info *info; - if (fbcon->helper.fbdev) { - info = fbcon->helper.fbdev; - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&fbcon->helper); + drm_fb_helper_release_fbi(&fbcon->helper); if (nouveau_fb->nvbo) { nouveau_bo_unmap(nouveau_fb->nvbo); nouveau_bo_vma_del(nouveau_fb->nvbo, &nouveau_fb->vma); - drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); + nouveau_bo_unpin(nouveau_fb->nvbo); + drm_gem_object_unreference_unlocked(&nouveau_fb->nvbo->gem); nouveau_fb->nvbo = NULL; } drm_fb_helper_fini(&fbcon->helper); @@ -431,23 +491,37 @@ info->flags |= FBINFO_HWACCEL_DISABLED; } -static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { +static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { .gamma_set = nouveau_fbcon_gamma_set, .gamma_get = nouveau_fbcon_gamma_get, .fb_probe = nouveau_fbcon_create, }; +void +nouveau_fbcon_set_suspend(struct drm_device *dev, int state) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + if (drm->fbcon) { + console_lock(); + if (state == FBINFO_STATE_RUNNING) + nouveau_fbcon_accel_restore(dev); + drm_fb_helper_set_suspend(&drm->fbcon->helper, state); + if (state != FBINFO_STATE_RUNNING) + nouveau_fbcon_accel_save_disable(dev); + console_unlock(); + } +} int nouveau_fbcon_init(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fb *pfb = nouveau_fb(drm->device); struct nouveau_fbdev *fbcon; int preferred_bpp; int ret; - if (!dev->mode_config.num_crtc) + if (!dev->mode_config.num_crtc || + (dev->pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) return 0; fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); @@ -456,21 +530,22 @@ fbcon->dev = dev; drm->fbcon = fbcon; - fbcon->helper.funcs = &nouveau_fbcon_helper_funcs; + + drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs); ret = drm_fb_helper_init(dev, &fbcon->helper, dev->mode_config.num_crtc, 4); - if (ret) { - kfree(fbcon); - return ret; - } + if (ret) + goto free; - drm_fb_helper_single_add_all_connectors(&fbcon->helper); + ret = drm_fb_helper_single_add_all_connectors(&fbcon->helper); + if (ret) + goto fini; - if (pfb->ram.size <= 32 * 1024 * 1024) + if (drm->device.info.ram_size <= 32 * 1024 * 1024) preferred_bpp = 8; else - if (pfb->ram.size <= 64 * 1024 * 1024) + if (drm->device.info.ram_size <= 64 * 1024 * 1024) preferred_bpp = 16; else preferred_bpp = 32; @@ -478,8 +553,19 @@ /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(dev); - drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); + ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); + if (ret) + goto fini; + + if (fbcon->helper.fbdev) + fbcon->helper.fbdev->pixmap.buf_align = 4; return 0; + +fini: + drm_fb_helper_fini(&fbcon->helper); +free: + kfree(fbcon); + return ret; } void @@ -490,39 +576,8 @@ if (!drm->fbcon) return; + nouveau_fbcon_accel_fini(dev); nouveau_fbcon_destroy(dev, drm->fbcon); kfree(drm->fbcon); drm->fbcon = NULL; } - -void nouveau_fbcon_save_disable_accel(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags; - drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; -} - -void nouveau_fbcon_restore_accel(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags; -} - -void nouveau_fbcon_set_suspend(struct drm_device *dev, int state) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - console_lock(); - if (state == 0) - nouveau_fbcon_save_disable_accel(dev); - fb_set_suspend(drm->fbcon->helper.fbdev, state); - if (state == 1) - nouveau_fbcon_restore_accel(dev); - console_unlock(); -} - -void nouveau_fbcon_zfill_all(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - nouveau_fbcon_zfill(dev, drm->fbcon); -}