Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/nouveau: Remove file nouveau_fbcon.c

Commit 4a16dd9d18a0 ("drm/nouveau/kms: switch to drm fbdev helpers")
converted nouveau to generic fbdev emulation. The driver's internal
implementation later got accidentally restored during a merge commit.
Remove the file from the driver. No functional changes.

v2:
* point Fixes tag to merge commit (Alex)

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Fixes: 4e291f2f5853 ("Merge tag 'drm-misc-next-2022-11-10-1' of git://anongit.freedesktop.org/drm/drm-misc into drm-next")
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: Karol Herbst <kherbst@redhat.com>
Cc: Lyude Paul <lyude@redhat.com>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Javier Martinez Canillas <javierm@redhat.com>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Dave Airlie <airlied@redhat.com>
Cc: dri-devel@lists.freedesktop.org
Cc: nouveau@lists.freedesktop.org
Link: https://patchwork.freedesktop.org/patch/msgid/20230110123526.28770-1-tzimmermann@suse.de

-613
-613
drivers/gpu/drm/nouveau/nouveau_fbcon.c
··· 1 - /* 2 - * Copyright © 2007 David Airlie 3 - * 4 - * Permission is hereby granted, free of charge, to any person obtaining a 5 - * copy of this software and associated documentation files (the "Software"), 6 - * to deal in the Software without restriction, including without limitation 7 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 - * and/or sell copies of the Software, and to permit persons to whom the 9 - * Software is furnished to do so, subject to the following conditions: 10 - * 11 - * The above copyright notice and this permission notice (including the next 12 - * paragraph) shall be included in all copies or substantial portions of the 13 - * Software. 14 - * 15 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 - * DEALINGS IN THE SOFTWARE. 22 - * 23 - * Authors: 24 - * David Airlie 25 - */ 26 - 27 - #include <linux/module.h> 28 - #include <linux/kernel.h> 29 - #include <linux/errno.h> 30 - #include <linux/string.h> 31 - #include <linux/mm.h> 32 - #include <linux/tty.h> 33 - #include <linux/sysrq.h> 34 - #include <linux/delay.h> 35 - #include <linux/init.h> 36 - #include <linux/screen_info.h> 37 - #include <linux/vga_switcheroo.h> 38 - #include <linux/console.h> 39 - 40 - #include <drm/drm_crtc.h> 41 - #include <drm/drm_crtc_helper.h> 42 - #include <drm/drm_probe_helper.h> 43 - #include <drm/drm_fb_helper.h> 44 - #include <drm/drm_fourcc.h> 45 - #include <drm/drm_atomic.h> 46 - 47 - #include "nouveau_drv.h" 48 - #include "nouveau_gem.h" 49 - #include "nouveau_bo.h" 50 - #include "nouveau_fbcon.h" 51 - #include "nouveau_chan.h" 52 - #include "nouveau_vmm.h" 53 - 54 - #include "nouveau_crtc.h" 55 - 56 - MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration"); 57 - int nouveau_nofbaccel = 0; 58 - module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); 59 - 60 - MODULE_PARM_DESC(fbcon_bpp, "fbcon bits-per-pixel (default: auto)"); 61 - static int nouveau_fbcon_bpp; 62 - module_param_named(fbcon_bpp, nouveau_fbcon_bpp, int, 0400); 63 - 64 - static void 65 - nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 66 - { 67 - struct nouveau_fbdev *fbcon = info->par; 68 - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); 69 - struct nvif_device *device = &drm->client.device; 70 - int ret; 71 - 72 - if (info->state != FBINFO_STATE_RUNNING) 73 - return; 74 - 75 - ret = -ENODEV; 76 - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && 77 - mutex_trylock(&drm->client.mutex)) { 78 - if (device->info.family < NV_DEVICE_INFO_V0_TESLA) 79 - ret = nv04_fbcon_fillrect(info, rect); 80 - else 81 - if (device->info.family < NV_DEVICE_INFO_V0_FERMI) 82 - ret = nv50_fbcon_fillrect(info, rect); 83 - else 84 - ret = nvc0_fbcon_fillrect(info, rect); 85 - mutex_unlock(&drm->client.mutex); 86 - } 87 - 88 - if (ret == 0) 89 - return; 90 - 91 - if (ret != -ENODEV) 92 - nouveau_fbcon_gpu_lockup(info); 93 - drm_fb_helper_cfb_fillrect(info, rect); 94 - } 95 - 96 - static void 97 - nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) 98 - { 99 - struct nouveau_fbdev *fbcon = info->par; 100 - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); 101 - struct nvif_device *device = &drm->client.device; 102 - int ret; 103 - 104 - if (info->state != FBINFO_STATE_RUNNING) 105 - return; 106 - 107 - ret = -ENODEV; 108 - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && 109 - mutex_trylock(&drm->client.mutex)) { 110 - if (device->info.family < NV_DEVICE_INFO_V0_TESLA) 111 - ret = nv04_fbcon_copyarea(info, image); 112 - else 113 - if (device->info.family < NV_DEVICE_INFO_V0_FERMI) 114 - ret = nv50_fbcon_copyarea(info, image); 115 - else 116 - ret = nvc0_fbcon_copyarea(info, image); 117 - mutex_unlock(&drm->client.mutex); 118 - } 119 - 120 - if (ret == 0) 121 - return; 122 - 123 - if (ret != -ENODEV) 124 - nouveau_fbcon_gpu_lockup(info); 125 - drm_fb_helper_cfb_copyarea(info, image); 126 - } 127 - 128 - static void 129 - nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) 130 - { 131 - struct nouveau_fbdev *fbcon = info->par; 132 - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); 133 - struct nvif_device *device = &drm->client.device; 134 - int ret; 135 - 136 - if (info->state != FBINFO_STATE_RUNNING) 137 - return; 138 - 139 - ret = -ENODEV; 140 - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && 141 - mutex_trylock(&drm->client.mutex)) { 142 - if (device->info.family < NV_DEVICE_INFO_V0_TESLA) 143 - ret = nv04_fbcon_imageblit(info, image); 144 - else 145 - if (device->info.family < NV_DEVICE_INFO_V0_FERMI) 146 - ret = nv50_fbcon_imageblit(info, image); 147 - else 148 - ret = nvc0_fbcon_imageblit(info, image); 149 - mutex_unlock(&drm->client.mutex); 150 - } 151 - 152 - if (ret == 0) 153 - return; 154 - 155 - if (ret != -ENODEV) 156 - nouveau_fbcon_gpu_lockup(info); 157 - drm_fb_helper_cfb_imageblit(info, image); 158 - } 159 - 160 - static int 161 - nouveau_fbcon_sync(struct fb_info *info) 162 - { 163 - struct nouveau_fbdev *fbcon = info->par; 164 - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); 165 - struct nouveau_channel *chan = drm->channel; 166 - int ret; 167 - 168 - if (!chan || !chan->accel_done || in_interrupt() || 169 - info->state != FBINFO_STATE_RUNNING || 170 - info->flags & FBINFO_HWACCEL_DISABLED) 171 - return 0; 172 - 173 - if (!mutex_trylock(&drm->client.mutex)) 174 - return 0; 175 - 176 - ret = nouveau_channel_idle(chan); 177 - mutex_unlock(&drm->client.mutex); 178 - if (ret) { 179 - nouveau_fbcon_gpu_lockup(info); 180 - return 0; 181 - } 182 - 183 - chan->accel_done = false; 184 - return 0; 185 - } 186 - 187 - static int 188 - nouveau_fbcon_open(struct fb_info *info, int user) 189 - { 190 - struct nouveau_fbdev *fbcon = info->par; 191 - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); 192 - int ret = pm_runtime_get_sync(drm->dev->dev); 193 - if (ret < 0 && ret != -EACCES) { 194 - pm_runtime_put(drm->dev->dev); 195 - return ret; 196 - } 197 - return 0; 198 - } 199 - 200 - static int 201 - nouveau_fbcon_release(struct fb_info *info, int user) 202 - { 203 - struct nouveau_fbdev *fbcon = info->par; 204 - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); 205 - pm_runtime_put(drm->dev->dev); 206 - return 0; 207 - } 208 - 209 - static const struct fb_ops nouveau_fbcon_ops = { 210 - .owner = THIS_MODULE, 211 - DRM_FB_HELPER_DEFAULT_OPS, 212 - .fb_open = nouveau_fbcon_open, 213 - .fb_release = nouveau_fbcon_release, 214 - .fb_fillrect = nouveau_fbcon_fillrect, 215 - .fb_copyarea = nouveau_fbcon_copyarea, 216 - .fb_imageblit = nouveau_fbcon_imageblit, 217 - .fb_sync = nouveau_fbcon_sync, 218 - }; 219 - 220 - static const struct fb_ops nouveau_fbcon_sw_ops = { 221 - .owner = THIS_MODULE, 222 - DRM_FB_HELPER_DEFAULT_OPS, 223 - .fb_open = nouveau_fbcon_open, 224 - .fb_release = nouveau_fbcon_release, 225 - .fb_fillrect = drm_fb_helper_cfb_fillrect, 226 - .fb_copyarea = drm_fb_helper_cfb_copyarea, 227 - .fb_imageblit = drm_fb_helper_cfb_imageblit, 228 - }; 229 - 230 - void 231 - nouveau_fbcon_accel_save_disable(struct drm_device *dev) 232 - { 233 - struct nouveau_drm *drm = nouveau_drm(dev); 234 - if (drm->fbcon && drm->fbcon->helper.info) { 235 - drm->fbcon->saved_flags = drm->fbcon->helper.info->flags; 236 - drm->fbcon->helper.info->flags |= FBINFO_HWACCEL_DISABLED; 237 - } 238 - } 239 - 240 - void 241 - nouveau_fbcon_accel_restore(struct drm_device *dev) 242 - { 243 - struct nouveau_drm *drm = nouveau_drm(dev); 244 - if (drm->fbcon && drm->fbcon->helper.info) 245 - drm->fbcon->helper.info->flags = drm->fbcon->saved_flags; 246 - } 247 - 248 - static void 249 - nouveau_fbcon_accel_fini(struct drm_device *dev) 250 - { 251 - struct nouveau_drm *drm = nouveau_drm(dev); 252 - struct nouveau_fbdev *fbcon = drm->fbcon; 253 - if (fbcon && drm->channel) { 254 - console_lock(); 255 - if (fbcon->helper.info) 256 - fbcon->helper.info->flags |= FBINFO_HWACCEL_DISABLED; 257 - console_unlock(); 258 - nouveau_channel_idle(drm->channel); 259 - nvif_object_dtor(&fbcon->twod); 260 - nvif_object_dtor(&fbcon->blit); 261 - nvif_object_dtor(&fbcon->gdi); 262 - nvif_object_dtor(&fbcon->patt); 263 - nvif_object_dtor(&fbcon->rop); 264 - nvif_object_dtor(&fbcon->clip); 265 - nvif_object_dtor(&fbcon->surf2d); 266 - } 267 - } 268 - 269 - static void 270 - nouveau_fbcon_accel_init(struct drm_device *dev) 271 - { 272 - struct nouveau_drm *drm = nouveau_drm(dev); 273 - struct nouveau_fbdev *fbcon = drm->fbcon; 274 - struct fb_info *info = fbcon->helper.info; 275 - int ret; 276 - 277 - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) 278 - ret = nv04_fbcon_accel_init(info); 279 - else 280 - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI) 281 - ret = nv50_fbcon_accel_init(info); 282 - else 283 - ret = nvc0_fbcon_accel_init(info); 284 - 285 - if (ret == 0) 286 - info->fbops = &nouveau_fbcon_ops; 287 - } 288 - 289 - static void 290 - nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon) 291 - { 292 - struct fb_info *info = fbcon->helper.info; 293 - struct fb_fillrect rect; 294 - 295 - /* Clear the entire fbcon. The drm will program every connector 296 - * with it's preferred mode. If the sizes differ, one display will 297 - * quite likely have garbage around the console. 298 - */ 299 - rect.dx = rect.dy = 0; 300 - rect.width = info->var.xres_virtual; 301 - rect.height = info->var.yres_virtual; 302 - rect.color = 0; 303 - rect.rop = ROP_COPY; 304 - info->fbops->fb_fillrect(info, &rect); 305 - } 306 - 307 - static int 308 - nouveau_fbcon_create(struct drm_fb_helper *helper, 309 - struct drm_fb_helper_surface_size *sizes) 310 - { 311 - struct nouveau_fbdev *fbcon = 312 - container_of(helper, struct nouveau_fbdev, helper); 313 - struct drm_device *dev = fbcon->helper.dev; 314 - struct nouveau_drm *drm = nouveau_drm(dev); 315 - struct nvif_device *device = &drm->client.device; 316 - struct fb_info *info; 317 - struct drm_framebuffer *fb; 318 - struct nouveau_channel *chan; 319 - struct nouveau_bo *nvbo; 320 - struct drm_mode_fb_cmd2 mode_cmd = {}; 321 - int ret; 322 - 323 - mode_cmd.width = sizes->surface_width; 324 - mode_cmd.height = sizes->surface_height; 325 - 326 - mode_cmd.pitches[0] = mode_cmd.width * (sizes->surface_bpp >> 3); 327 - mode_cmd.pitches[0] = roundup(mode_cmd.pitches[0], 256); 328 - 329 - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 330 - sizes->surface_depth); 331 - 332 - ret = nouveau_gem_new(&drm->client, mode_cmd.pitches[0] * 333 - mode_cmd.height, 0, NOUVEAU_GEM_DOMAIN_VRAM, 334 - 0, 0x0000, &nvbo); 335 - if (ret) { 336 - NV_ERROR(drm, "failed to allocate framebuffer\n"); 337 - goto out; 338 - } 339 - 340 - ret = nouveau_framebuffer_new(dev, &mode_cmd, &nvbo->bo.base, &fb); 341 - if (ret) 342 - goto out_unref; 343 - 344 - ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false); 345 - if (ret) { 346 - NV_ERROR(drm, "failed to pin fb: %d\n", ret); 347 - goto out_unref; 348 - } 349 - 350 - ret = nouveau_bo_map(nvbo); 351 - if (ret) { 352 - NV_ERROR(drm, "failed to map fb: %d\n", ret); 353 - goto out_unpin; 354 - } 355 - 356 - chan = nouveau_nofbaccel ? NULL : drm->channel; 357 - if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 358 - ret = nouveau_vma_new(nvbo, chan->vmm, &fbcon->vma); 359 - if (ret) { 360 - NV_ERROR(drm, "failed to map fb into chan: %d\n", ret); 361 - chan = NULL; 362 - } 363 - } 364 - 365 - info = drm_fb_helper_alloc_info(helper); 366 - if (IS_ERR(info)) { 367 - ret = PTR_ERR(info); 368 - goto out_unlock; 369 - } 370 - 371 - /* setup helper */ 372 - fbcon->helper.fb = fb; 373 - 374 - if (!chan) 375 - info->flags = FBINFO_HWACCEL_DISABLED; 376 - else 377 - info->flags = FBINFO_HWACCEL_COPYAREA | 378 - FBINFO_HWACCEL_FILLRECT | 379 - FBINFO_HWACCEL_IMAGEBLIT; 380 - info->fbops = &nouveau_fbcon_sw_ops; 381 - info->fix.smem_start = nvbo->bo.resource->bus.offset; 382 - info->fix.smem_len = nvbo->bo.base.size; 383 - 384 - info->screen_base = nvbo_kmap_obj_iovirtual(nvbo); 385 - info->screen_size = nvbo->bo.base.size; 386 - 387 - drm_fb_helper_fill_info(info, &fbcon->helper, sizes); 388 - 389 - /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ 390 - 391 - if (chan) 392 - nouveau_fbcon_accel_init(dev); 393 - nouveau_fbcon_zfill(dev, fbcon); 394 - 395 - /* To allow resizeing without swapping buffers */ 396 - NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n", 397 - fb->width, fb->height, nvbo->offset, nvbo); 398 - 399 - if (dev_is_pci(dev->dev)) 400 - vga_switcheroo_client_fb_set(to_pci_dev(dev->dev), info); 401 - 402 - return 0; 403 - 404 - out_unlock: 405 - if (chan) 406 - nouveau_vma_del(&fbcon->vma); 407 - nouveau_bo_unmap(nvbo); 408 - out_unpin: 409 - nouveau_bo_unpin(nvbo); 410 - out_unref: 411 - nouveau_bo_ref(NULL, &nvbo); 412 - out: 413 - return ret; 414 - } 415 - 416 - static int 417 - nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) 418 - { 419 - struct drm_framebuffer *fb = fbcon->helper.fb; 420 - struct nouveau_bo *nvbo; 421 - 422 - drm_fb_helper_unregister_info(&fbcon->helper); 423 - drm_fb_helper_fini(&fbcon->helper); 424 - 425 - if (fb && fb->obj[0]) { 426 - nvbo = nouveau_gem_object(fb->obj[0]); 427 - nouveau_vma_del(&fbcon->vma); 428 - nouveau_bo_unmap(nvbo); 429 - nouveau_bo_unpin(nvbo); 430 - drm_framebuffer_put(fb); 431 - } 432 - 433 - return 0; 434 - } 435 - 436 - void nouveau_fbcon_gpu_lockup(struct fb_info *info) 437 - { 438 - struct nouveau_fbdev *fbcon = info->par; 439 - struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); 440 - 441 - NV_ERROR(drm, "GPU lockup - switching to software fbcon\n"); 442 - info->flags |= FBINFO_HWACCEL_DISABLED; 443 - } 444 - 445 - static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { 446 - .fb_probe = nouveau_fbcon_create, 447 - }; 448 - 449 - static void 450 - nouveau_fbcon_set_suspend_work(struct work_struct *work) 451 - { 452 - struct nouveau_drm *drm = container_of(work, typeof(*drm), fbcon_work); 453 - int state = READ_ONCE(drm->fbcon_new_state); 454 - 455 - if (state == FBINFO_STATE_RUNNING) 456 - pm_runtime_get_sync(drm->dev->dev); 457 - 458 - console_lock(); 459 - if (state == FBINFO_STATE_RUNNING) 460 - nouveau_fbcon_accel_restore(drm->dev); 461 - drm_fb_helper_set_suspend(&drm->fbcon->helper, state); 462 - if (state != FBINFO_STATE_RUNNING) 463 - nouveau_fbcon_accel_save_disable(drm->dev); 464 - console_unlock(); 465 - 466 - if (state == FBINFO_STATE_RUNNING) { 467 - nouveau_fbcon_hotplug_resume(drm->fbcon); 468 - pm_runtime_mark_last_busy(drm->dev->dev); 469 - pm_runtime_put_autosuspend(drm->dev->dev); 470 - } 471 - } 472 - 473 - void 474 - nouveau_fbcon_set_suspend(struct drm_device *dev, int state) 475 - { 476 - struct nouveau_drm *drm = nouveau_drm(dev); 477 - 478 - if (!drm->fbcon) 479 - return; 480 - 481 - drm->fbcon_new_state = state; 482 - /* Since runtime resume can happen as a result of a sysfs operation, 483 - * it's possible we already have the console locked. So handle fbcon 484 - * init/deinit from a seperate work thread 485 - */ 486 - schedule_work(&drm->fbcon_work); 487 - } 488 - 489 - void 490 - nouveau_fbcon_output_poll_changed(struct drm_device *dev) 491 - { 492 - struct nouveau_drm *drm = nouveau_drm(dev); 493 - struct nouveau_fbdev *fbcon = drm->fbcon; 494 - int ret; 495 - 496 - if (!fbcon) 497 - return; 498 - 499 - mutex_lock(&fbcon->hotplug_lock); 500 - 501 - ret = pm_runtime_get(dev->dev); 502 - if (ret == 1 || ret == -EACCES) { 503 - drm_fb_helper_hotplug_event(&fbcon->helper); 504 - 505 - pm_runtime_mark_last_busy(dev->dev); 506 - pm_runtime_put_autosuspend(dev->dev); 507 - } else if (ret == 0) { 508 - /* If the GPU was already in the process of suspending before 509 - * this event happened, then we can't block here as we'll 510 - * deadlock the runtime pmops since they wait for us to 511 - * finish. So, just defer this event for when we runtime 512 - * resume again. It will be handled by fbcon_work. 513 - */ 514 - NV_DEBUG(drm, "fbcon HPD event deferred until runtime resume\n"); 515 - fbcon->hotplug_waiting = true; 516 - pm_runtime_put_noidle(drm->dev->dev); 517 - } else { 518 - DRM_WARN("fbcon HPD event lost due to RPM failure: %d\n", 519 - ret); 520 - } 521 - 522 - mutex_unlock(&fbcon->hotplug_lock); 523 - } 524 - 525 - void 526 - nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon) 527 - { 528 - struct nouveau_drm *drm; 529 - 530 - if (!fbcon) 531 - return; 532 - drm = nouveau_drm(fbcon->helper.dev); 533 - 534 - mutex_lock(&fbcon->hotplug_lock); 535 - if (fbcon->hotplug_waiting) { 536 - fbcon->hotplug_waiting = false; 537 - 538 - NV_DEBUG(drm, "Handling deferred fbcon HPD events\n"); 539 - drm_fb_helper_hotplug_event(&fbcon->helper); 540 - } 541 - mutex_unlock(&fbcon->hotplug_lock); 542 - } 543 - 544 - int 545 - nouveau_fbcon_init(struct drm_device *dev) 546 - { 547 - struct nouveau_drm *drm = nouveau_drm(dev); 548 - struct nouveau_fbdev *fbcon; 549 - int preferred_bpp = nouveau_fbcon_bpp; 550 - int ret; 551 - 552 - if (!dev->mode_config.num_crtc || 553 - (to_pci_dev(dev->dev)->class >> 8) != PCI_CLASS_DISPLAY_VGA) 554 - return 0; 555 - 556 - fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); 557 - if (!fbcon) 558 - return -ENOMEM; 559 - 560 - drm->fbcon = fbcon; 561 - INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work); 562 - mutex_init(&fbcon->hotplug_lock); 563 - 564 - drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs); 565 - 566 - ret = drm_fb_helper_init(dev, &fbcon->helper); 567 - if (ret) 568 - goto free; 569 - 570 - if (preferred_bpp != 8 && preferred_bpp != 16 && preferred_bpp != 32) { 571 - if (drm->client.device.info.ram_size <= 32 * 1024 * 1024) 572 - preferred_bpp = 8; 573 - else 574 - if (drm->client.device.info.ram_size <= 64 * 1024 * 1024) 575 - preferred_bpp = 16; 576 - else 577 - preferred_bpp = 32; 578 - } 579 - 580 - /* disable all the possible outputs/crtcs before entering KMS mode */ 581 - if (!drm_drv_uses_atomic_modeset(dev)) 582 - drm_helper_disable_unused_functions(dev); 583 - 584 - ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); 585 - if (ret) 586 - goto fini; 587 - 588 - if (fbcon->helper.info) 589 - fbcon->helper.info->pixmap.buf_align = 4; 590 - return 0; 591 - 592 - fini: 593 - drm_fb_helper_fini(&fbcon->helper); 594 - free: 595 - kfree(fbcon); 596 - drm->fbcon = NULL; 597 - return ret; 598 - } 599 - 600 - void 601 - nouveau_fbcon_fini(struct drm_device *dev) 602 - { 603 - struct nouveau_drm *drm = nouveau_drm(dev); 604 - 605 - if (!drm->fbcon) 606 - return; 607 - 608 - drm_kms_helper_poll_fini(dev); 609 - nouveau_fbcon_accel_fini(dev); 610 - nouveau_fbcon_destroy(dev, drm->fbcon); 611 - kfree(drm->fbcon); 612 - drm->fbcon = NULL; 613 - }