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

video/aperture: Provide a VGA helper for gma500 and internal use

The hardware for gma500 is different from the rest, as it uses stolen
framebuffer memory that is not available via PCI BAR. The regular PCI
removal helper cannot detect the framebuffer, while the non-PCI helper
misses possible conflicting VGA devices (i.e., a framebuffer or text
console).

Gma500 therefore calls both helpers to catch all cases. It's confusing
as it implies that there's something about the PCI device that requires
ownership management. The relationship between the PCI device and the
VGA devices is non-obvious. At worst, readers might assume that calling
two functions for clearing aperture ownership is a bug in the driver.

Hence, move the PCI removal helper's code for VGA functionality into
a separate function and call this function from gma500. Documents the
purpose of each call to aperture helpers. The change contains comments
and example code form the discussion at [1].

v5:
* fix grammar in gma500 comment (Javier)

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.kernel.org/project/dri-devel/patch/20230404201842.567344-1-daniel.vetter@ffwll.ch/ # 1
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230406132109.32050-10-tzimmermann@suse.de

+81 -32
+34 -14
drivers/gpu/drm/gma500/psb_drv.c
··· 7 7 * 8 8 **************************************************************************/ 9 9 10 + #include <linux/aperture.h> 10 11 #include <linux/cpu.h> 11 12 #include <linux/module.h> 12 13 #include <linux/notifier.h> ··· 20 19 #include <acpi/video.h> 21 20 22 21 #include <drm/drm.h> 23 - #include <drm/drm_aperture.h> 24 22 #include <drm/drm_drv.h> 25 23 #include <drm/drm_file.h> 26 24 #include <drm/drm_ioctl.h> ··· 414 414 return ret; 415 415 } 416 416 417 + /* 418 + * Hardware for gma500 is a hybrid device, which both acts as a PCI 419 + * device (for legacy vga functionality) but also more like an 420 + * integrated display on a SoC where the framebuffer simply 421 + * resides in main memory and not in a special PCI bar (that 422 + * internally redirects to a stolen range of main memory) like all 423 + * other integrated PCI display devices implement it. 424 + * 425 + * To catch all cases we need to remove conflicting firmware devices 426 + * for the stolen system memory and for the VGA functionality. As we 427 + * currently cannot easily find the framebuffer's location in stolen 428 + * memory, we remove all framebuffers here. 429 + * 430 + * TODO: Refactor psb_driver_load() to map vdc_reg earlier. Then 431 + * we might be able to read the framebuffer range from the 432 + * device. 433 + */ 434 + static int gma_remove_conflicting_framebuffers(struct pci_dev *pdev, 435 + const struct drm_driver *req_driver) 436 + { 437 + resource_size_t base = 0; 438 + resource_size_t size = U32_MAX; /* 4 GiB HW limit */ 439 + const char *name = req_driver->name; 440 + int ret; 441 + 442 + ret = aperture_remove_conflicting_devices(base, size, name); 443 + if (ret) 444 + return ret; 445 + 446 + return __aperture_remove_legacy_vga_devices(pdev); 447 + } 448 + 417 449 static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 418 450 { 419 451 struct drm_psb_private *dev_priv; 420 452 struct drm_device *dev; 421 453 int ret; 422 454 423 - /* 424 - * We cannot yet easily find the framebuffer's location in memory. So 425 - * remove all framebuffers here. Note that we still want the pci special 426 - * handling to kick out vgacon. 427 - * 428 - * TODO: Refactor psb_driver_load() to map vdc_reg earlier. Then we 429 - * might be able to read the framebuffer range from the device. 430 - */ 431 - ret = drm_aperture_remove_framebuffers(&driver); 432 - if (ret) 433 - return ret; 434 - 435 - ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver); 455 + ret = gma_remove_conflicting_framebuffers(pdev, &driver); 436 456 if (ret) 437 457 return ret; 438 458
+40 -18
drivers/video/aperture.c
··· 302 302 EXPORT_SYMBOL(aperture_remove_conflicting_devices); 303 303 304 304 /** 305 + * __aperture_remove_legacy_vga_devices - remove legacy VGA devices of a PCI devices 306 + * @pdev: PCI device 307 + * 308 + * This function removes VGA devices provided by @pdev, such as a VGA 309 + * framebuffer or a console. This is useful if you have a VGA-compatible 310 + * PCI graphics device with framebuffers in non-BAR locations. Drivers 311 + * should acquire ownership of those memory areas and afterwards call 312 + * this helper to release remaining VGA devices. 313 + * 314 + * If your hardware has its framebuffers accessible via PCI BARS, use 315 + * aperture_remove_conflicting_pci_devices() instead. The function will 316 + * release any VGA devices automatically. 317 + * 318 + * WARNING: Apparently we must remove graphics drivers before calling 319 + * this helper. Otherwise the vga fbdev driver falls over if 320 + * we have vgacon configured. 321 + * 322 + * Returns: 323 + * 0 on success, or a negative errno code otherwise 324 + */ 325 + int __aperture_remove_legacy_vga_devices(struct pci_dev *pdev) 326 + { 327 + /* VGA framebuffer */ 328 + aperture_detach_devices(VGA_FB_PHYS_BASE, VGA_FB_PHYS_SIZE); 329 + 330 + /* VGA textmode console */ 331 + return vga_remove_vgacon(pdev); 332 + } 333 + EXPORT_SYMBOL(__aperture_remove_legacy_vga_devices); 334 + 335 + /** 305 336 * aperture_remove_conflicting_pci_devices - remove existing framebuffers for PCI devices 306 337 * @pdev: PCI device 307 338 * @name: a descriptive name of the requesting driver ··· 348 317 { 349 318 bool primary = false; 350 319 resource_size_t base, size; 351 - int bar, ret; 320 + int bar, ret = 0; 352 321 353 322 if (pdev == vga_default_device()) 354 323 primary = true; ··· 365 334 aperture_detach_devices(base, size); 366 335 } 367 336 368 - if (primary) { 369 - /* 370 - * If this is the primary adapter, there could be a VGA device 371 - * that consumes the VGA framebuffer I/O range. Remove this 372 - * device as well. 373 - */ 374 - aperture_detach_devices(VGA_FB_PHYS_BASE, VGA_FB_PHYS_SIZE); 337 + /* 338 + * If this is the primary adapter, there could be a VGA device 339 + * that consumes the VGA framebuffer I/O range. Remove this 340 + * device as well. 341 + */ 342 + if (primary) 343 + ret = __aperture_remove_legacy_vga_devices(pdev); 375 344 376 - /* 377 - * WARNING: Apparently we must kick fbdev drivers before vgacon, 378 - * otherwise the vga fbdev driver falls over. 379 - */ 380 - ret = vga_remove_vgacon(pdev); 381 - if (ret) 382 - return ret; 383 - } 384 - 385 - return 0; 345 + return ret; 386 346 387 347 } 388 348 EXPORT_SYMBOL(aperture_remove_conflicting_pci_devices);
+7
include/linux/aperture.h
··· 16 16 int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size, 17 17 const char *name); 18 18 19 + int __aperture_remove_legacy_vga_devices(struct pci_dev *pdev); 20 + 19 21 int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *name); 20 22 #else 21 23 static inline int devm_aperture_acquire_for_platform_device(struct platform_device *pdev, ··· 29 27 30 28 static inline int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size, 31 29 const char *name) 30 + { 31 + return 0; 32 + } 33 + 34 + static inline int __aperture_remove_legacy_vga_devices(struct pci_dev *pdev) 32 35 { 33 36 return 0; 34 37 }