From 480d548cb05f99de436143c5b30fcb852cf377c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 13 Mar 2023 16:50:40 +0100 Subject: [PATCH 01/10] drm/i915: Initialize intel_graphics_stolen_res synchronously on FreeBSD [Why] We may need that memory early enough that the async initialization may not be ready yet. [How] We stop using a SYSINIT() function and perform the initialization from `i915_init()` instead. --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 6 ------ drivers/gpu/drm/i915/i915_module.c | 11 +++++++++++ drivers/gpu/drm/i915/intel_freebsd.c | 12 ------------ 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index e682f867699..ab46acbc088 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -410,12 +410,6 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem) return 0; } -#ifdef __FreeBSD__ - DRM_INFO("Got stolen memory base 0x%x, size 0x%x\n", - intel_graphics_stolen_res.start, - resource_size(&intel_graphics_stolen_res)); -#endif - if (resource_size(&mem->region) == 0) return 0; diff --git a/drivers/gpu/drm/i915/i915_module.c b/drivers/gpu/drm/i915/i915_module.c index eb4313d9255..eaa9ce4cb3f 100644 --- a/drivers/gpu/drm/i915/i915_module.c +++ b/drivers/gpu/drm/i915/i915_module.c @@ -80,6 +80,17 @@ static int __init i915_init(void) { int err, i; +#ifdef __FreeBSD__ +#if defined(__amd64__) + intel_graphics_stolen_res = (struct linux_resource) + DEFINE_RES_MEM(intel_graphics_stolen_base, + intel_graphics_stolen_size); + DRM_INFO("Got Intel graphics stolen memory base 0x%x, size 0x%x\n", + intel_graphics_stolen_res.start, + resource_size(&intel_graphics_stolen_res)); +#endif +#endif + for (i = 0; i < ARRAY_SIZE(init_funcs); i++) { err = init_funcs[i].init(); if (err < 0) { diff --git a/drivers/gpu/drm/i915/intel_freebsd.c b/drivers/gpu/drm/i915/intel_freebsd.c index 94836150c13..1e2056ca580 100644 --- a/drivers/gpu/drm/i915/intel_freebsd.c +++ b/drivers/gpu/drm/i915/intel_freebsd.c @@ -158,15 +158,3 @@ linux_intel_gtt_insert_sg_entries(struct sg_table *st, unsigned int pg_start, intel_gtt_read_pte(pg_start + i - 1); } - -#if defined(__amd64__) -static void -intel_freebsd_init(void *arg __unused) -{ - /* Defined in $SYSDIR/x86/pci/pci_early_quirks.c */ - intel_graphics_stolen_res = (struct linux_resource) - DEFINE_RES_MEM(intel_graphics_stolen_base, - intel_graphics_stolen_size); -} -SYSINIT(intel_freebsd, SI_SUB_DRIVERS, SI_ORDER_ANY, intel_freebsd_init, NULL); -#endif From d136f1599ca702f3d915b4739cd14f50151f74ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 24 Aug 2023 09:49:50 +0200 Subject: [PATCH 02/10] vt(4) integration: Move fictitious range (un)register out of (un)register_framebuffer() [Why] To correctly register the VRAM memory fictitious region, we relied on the fact that the region address and size was defined in `fb_info->apertures->ranges[0]`. The values were set by the driver when they initialized their framebuffer. Really, this was a by-product of the framebuffer initialization and the region must be registered regardless of that. Likewise for the accompagnying call to `vt_freeze_main_vd()`. Starting with Linux 5.17, the `amdgpu` doesn't fill the `fb_info->apertures->ranges[0]` values anymore anyway. It starts to use the generic framebuffer code which doesn't use them. Therefore, we need to have a FreeBSD-specific setup of that memory region outside of the framebuffer initialization/vt(4) integration code. [How] A new pair of functions is introduced in `drm_os_freebsd.c` to register and unregister the memory region, as well as calling `vt_(un)freeze_main_vd()` accordingly. The drivers need to call explicitly the new functions. We can't rely on a side effect of the framebuffer initialization code. As a bonus, the calls to vt_(un)freeze_main_vd()` are now symetrical everywhere. Before this change, drivers called `vt_unfreeze_main_vd()` at different places. --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 30 +++++++++++++++--- drivers/gpu/drm/drm_os_freebsd.c | 36 ++++++++++++++++++++++ drivers/gpu/drm/drm_os_freebsd.h | 6 ++++ drivers/gpu/drm/i915/display/intel_fbdev.c | 25 +++++++++++++++ drivers/gpu/drm/i915/i915_pci.c | 1 - drivers/gpu/drm/linux_fb.c | 22 +------------ drivers/gpu/drm/radeon/radeon_fb.c | 25 +++++++++++++++ linuxkpi/gplv2/include/linux/fb.h | 2 -- 8 files changed, 119 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 7037ba180a9..fac9761bc6c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3692,6 +3692,26 @@ int amdgpu_device_init(struct amdgpu_device *adev, goto release_ras_con; } +#ifdef __FreeBSD__ + /* + * After amdgpu_device_ip_init(), gmc.aper_base and gmc.aper_size are + * set, and mode_config.fb_base was initialized from gmc.aper_base. + * Therefore, we can register the fictitious memory range. + * + * This was handled in register_framebuffer() in the past, based on the + * values of info->apertures->ranges[0]. However, the `amdgpu` driver + * stopped setting them when it got rid of its specific framebuffer + * initialization to use the generic drm_fb_helper code. + * + * We can't do this in register_framebuffer() anymore because the + * values passed to register_fictitious_range() below are unavailable + * from a generic structure set by both drivers. + */ + register_fictitious_range( + adev_to_drm(adev)->mode_config.fb_base, + adev->gmc.aper_size); +#endif + amdgpu_fence_driver_hw_init(adev); dev_info(adev->dev, @@ -3876,6 +3896,12 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) amdgpu_fbdev_fini(adev); +#ifdef __FreeBSD__ + unregister_fictitious_range( + adev_to_drm(adev)->mode_config.fb_base, + adev->gmc.aper_size); +#endif + amdgpu_device_ip_fini_early(adev); amdgpu_irq_fini_hw(adev); @@ -3919,10 +3945,6 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev) amdgpu_discovery_fini(adev); kfree(adev->pci_state); - -#ifdef __FreeBSD__ - vt_unfreeze_main_vd(); -#endif } /** diff --git a/drivers/gpu/drm/drm_os_freebsd.c b/drivers/gpu/drm/drm_os_freebsd.c index e05555a2baa..e72743436ea 100644 --- a/drivers/gpu/drm/drm_os_freebsd.c +++ b/drivers/gpu/drm/drm_os_freebsd.c @@ -18,6 +18,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include #include #undef fb_info @@ -79,6 +81,40 @@ sysctl_pci_id(SYSCTL_HANDLER_ARGS) return (sysctl_handle_string(oidp, buf, sizeof(buf), req)); } +int +register_fictitious_range(vm_paddr_t base, size_t size) +{ + int ret; + struct apertures_struct *ap; + + MPASS(base != 0); + MPASS(size != 0); + + ap = alloc_apertures(1); + ap->ranges[0].base = base; + ap->ranges[0].size = size; + vt_freeze_main_vd(ap); + kfree(ap); + + ret = vm_phys_fictitious_reg_range(base, base + size, +#ifdef VM_MEMATTR_WRITE_COMBINING + VM_MEMATTR_WRITE_COMBINING +#else + VM_MEMATTR_UNCACHEABLE +#endif + ); + MPASS(ret == 0); + + return (ret); +} + +void +unregister_fictitious_range(vm_paddr_t base, size_t size) +{ + vm_phys_fictitious_unreg_range(base, base + size); + vt_unfreeze_main_vd(); +} + /* Framebuffer related code */ /* Call restore out of vt(9) locks. */ diff --git a/drivers/gpu/drm/drm_os_freebsd.h b/drivers/gpu/drm/drm_os_freebsd.h index 29f499d9f10..cd05e65f370 100644 --- a/drivers/gpu/drm/drm_os_freebsd.h +++ b/drivers/gpu/drm/drm_os_freebsd.h @@ -40,6 +40,12 @@ struct drm_minor; int drm_dev_alias(struct device *dev, struct drm_minor *minor, const char *minor_str); void cancel_reset_debug_log(void); +void vt_freeze_main_vd(struct apertures_struct *a); +void vt_unfreeze_main_vd(void); + +int register_fictitious_range(vm_paddr_t start, vm_paddr_t end); +void unregister_fictitious_range(vm_paddr_t start, vm_paddr_t end); + void vt_restore_fbdev_mode(void *arg, int pending); int vt_kms_postswitch(void *arg); diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index acc7de27d8a..d661f6ab0f3 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -269,6 +269,25 @@ static int intelfb_create(struct drm_fb_helper *helper, info->fix.smem_len = vma->node.size; } +#ifdef __FreeBSD__ + /* + * After the if() above, we can register the fictitious memory range + * based on the info->apertures->ranges[0] values. + * + * This was handled in register_framebuffer() in the past, also based + * on the values of info->apertures->ranges[0]. However, the `amdgpu` + * driver stopped setting them when it got rid of its specific + * framebuffer initialization to use the generic drm_fb_helper code. + * + * We can't do this in register_framebuffer() anymore because the + * values passed to register_fictitious_range() below are unavailable + * from a generic structure set by both drivers. + */ + register_fictitious_range( + info->apertures->ranges[0].base, + info->apertures->ranges[0].size); +#endif + vaddr = i915_vma_pin_iomap(vma); if (IS_ERR(vaddr)) { drm_err(&dev_priv->drm, @@ -318,6 +337,12 @@ static void intel_fbdev_destroy(struct intel_fbdev *ifbdev) * trying to rectify all the possible error paths leading here. */ +#ifdef __FreeBSD__ + unregister_fictitious_range( + ifbdev->helper.fbdev->apertures->ranges[0].base, + ifbdev->helper.fbdev->apertures->ranges[0].size); +#endif + drm_fb_helper_fini(&ifbdev->helper); if (ifbdev->vma) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 7d888460d67..8394eac8fb6 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1256,6 +1256,5 @@ void i915_pci_unregister_driver(void) pci_unregister_driver(&i915_pci_driver); #elif defined(__FreeBSD__) linux_pci_unregister_drm_driver(&i915_pci_driver); - vt_unfreeze_main_vd(); #endif } diff --git a/drivers/gpu/drm/linux_fb.c b/drivers/gpu/drm/linux_fb.c index 55756766296..fdec1b9c958 100644 --- a/drivers/gpu/drm/linux_fb.c +++ b/drivers/gpu/drm/linux_fb.c @@ -38,10 +38,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include - #include #include @@ -58,7 +54,7 @@ extern struct vt_device *main_vd; static int __unregister_framebuffer(struct linux_fb_info *fb_info); -static void +void vt_freeze_main_vd(struct apertures_struct *a) { struct fb_info *fb; @@ -196,19 +192,6 @@ __register_framebuffer(struct linux_fb_info *fb_info) { int i, err; - vt_freeze_main_vd(fb_info->apertures); - - MPASS(fb_info->apertures->ranges[0].base); - MPASS(fb_info->apertures->ranges[0].size); - vm_phys_fictitious_reg_range(fb_info->apertures->ranges[0].base, - fb_info->apertures->ranges[0].base + - fb_info->apertures->ranges[0].size, -#ifdef VM_MEMATTR_WRITE_COMBINING - VM_MEMATTR_WRITE_COMBINING); -#else - VM_MEMATTR_UNCACHEABLE); -#endif - fb_info->fbio.fb_type = FBTYPE_PCIMISC; fb_info->fbio.fb_height = fb_info->var.yres; fb_info->fbio.fb_width = fb_info->var.xres; @@ -264,9 +247,6 @@ __unregister_framebuffer(struct linux_fb_info *fb_info) { int ret = 0; - vm_phys_fictitious_unreg_range(fb_info->apertures->ranges[0].base, - fb_info->apertures->ranges[0].base + - fb_info->apertures->ranges[0].size); if (fb_info->fbio.fb_fbd_dev) { mtx_lock(&Giant); device_delete_child(fb_info->fb_bsddev, fb_info->fbio.fb_fbd_dev); diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index a650c926adb..9b892109b38 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -284,6 +284,25 @@ static int radeonfb_create(struct drm_fb_helper *helper, info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; info->apertures->ranges[0].size = rdev->mc.aper_size; +#ifdef __FreeBSD__ + /* + * We can register the fictitious memory range based on the + * info->apertures->ranges[0] values. + * + * This was handled in register_framebuffer() in the past, also based + * on the values of info->apertures->ranges[0]. However, the `amdgpu` + * driver stopped setting them when it got rid of its specific + * framebuffer initialization to use the generic drm_fb_helper code. + * + * We can't do this in register_framebuffer() anymore because the + * values passed to register_fictitious_range() below are unavailable + * from a generic structure set by both drivers. + */ + register_fictitious_range( + info->apertures->ranges[0].base, + info->apertures->ranges[0].size); +#endif + /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ if (info->screen_base == NULL) { @@ -314,6 +333,12 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb { struct drm_framebuffer *fb = &rfbdev->fb; +#ifdef __FreeBSD__ + unregister_fictitious_range( + rfbdev->helper.fbdev->apertures->ranges[0].base, + rfbdev->helper.fbdev->apertures->ranges[0].size); +#endif + drm_fb_helper_unregister_fbi(&rfbdev->helper); if (fb->obj[0]) { diff --git a/linuxkpi/gplv2/include/linux/fb.h b/linuxkpi/gplv2/include/linux/fb.h index 87acdf4431f..1f60b8cd1ff 100644 --- a/linuxkpi/gplv2/include/linux/fb.h +++ b/linuxkpi/gplv2/include/linux/fb.h @@ -104,6 +104,4 @@ is_firmware_framebuffer(struct apertures_struct *a __unused) int linux_fb_get_options(const char *name, char **option); #define fb_get_options linux_fb_get_options -void vt_unfreeze_main_vd(void); - #endif /* __LINUX_FB_H_ */ From c556f9040b0617a8b27d0e4e5587c310861e706d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 16 Mar 2023 21:49:41 +0100 Subject: [PATCH 03/10] vt(4) integration: Uncomment everything in `drm_fb_helper.c` ... except the code related specifically to sysrq and framebuffer deferred I/O. [Why] In Linux 5.17, the amdgpu driver relies entirely on `drm_fb_helper` to handle its framebuffer. Indeed, the framebuffer-specific code is removed. Also in Linux 5.17, something changed in the i915 driver. I don't know exactly what, but the memory region passed to vt(4) and `vt_fb` isn't the one displayed on the screen. Therefore, all writes made by `vt_fb` leads to no changes on the screen and the computer looks frozen (that's not the case). However, when I vt-switch to another tty, the screen is refreshed to show the content of the tty active *before* the switch. Switching tty is the only time `vt_fb` calls into DRM. There is enough evidence that the i915 driver now assumes that the framebuffer is accessed like `drm_fb_helper` does it, i.e. like a Linux fbdev device. Unfortunately, our vt(4) integration is way way simpler than than Linux' fbdev. The goal of this commit and following ones is to change that vt(4) integration layer to behave like fbdev. [How] The first step is uncomment everything in `drm_fb_helper` to make sure that the API itself is ok. `drm_fb_helper` depends on lower-level functions, especially `fb_sys_{read,write}` and `fb_cfb_{read,write}` which are responsible for all reads and writes to the allocated memory region for the framebuffer. In this commit, they are simple stubs. They will be implemented in a future commit. As mentionned at the top, two areas are left commentted out: * sysrq, a Linux specific mechanism to interact with the kernel at a very low level. There is something close in FreeBSD, but we don't need to worry about it in `drm_fb_helper. * framebuffer deferred I/O, a framebuffer feature to flush the memory region asynchronously. We can't really implement that on FreeBSD and I believe we don't need to. --- drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c | 4 - drivers/gpu/drm/drm_fb_helper.c | 62 ++------ drivers/gpu/drm/i915/display/intel_fbdev.c | 4 - drivers/gpu/drm/linux_fb.c | 44 ++++++ drivers/gpu/drm/radeon/radeon_fb.c | 4 - include/drm/drm_fb_helper.h | 9 -- linuxkpi/bsd/include/uapi/linux/fb.h | 175 ++++++++++++++++++++- linuxkpi/gplv2/include/linux/fb.h | 113 +++++++++++-- 8 files changed, 333 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index a4add004828..cd0acbea75d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -46,7 +46,6 @@ the helper contains a pointer to amdgpu framebuffer baseclass. */ -#ifdef __linux__ static int amdgpufb_open(struct fb_info *info, int user) { @@ -69,18 +68,15 @@ amdgpufb_release(struct fb_info *info, int user) pm_runtime_put_autosuspend(fb_helper->dev->dev); return 0; } -#endif /* __linux__ */ static const struct fb_ops amdgpufb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, -#ifdef __linux__ .fb_open = amdgpufb_open, .fb_release = amdgpufb_release, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, -#endif }; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3a9ed6e97ef..c2c5bcf0fe3 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -332,7 +332,6 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) mutex_unlock(&fb_helper->lock); } -#ifdef __linux__ /** * drm_fb_helper_blank - implementation for &fb_ops.fb_blank * @blank: desired blanking state @@ -368,7 +367,6 @@ int drm_fb_helper_blank(int blank, struct fb_info *info) return 0; } EXPORT_SYMBOL(drm_fb_helper_blank); -#endif static void drm_fb_helper_resume_worker(struct work_struct *work) { @@ -590,9 +588,7 @@ struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper) } fb_helper->fbdev = info; -#ifdef __linux__ info->skip_vt_switch = true; -#endif return info; @@ -735,6 +731,7 @@ void drm_fb_helper_deferred_io(struct fb_info *info, } } EXPORT_SYMBOL(drm_fb_helper_deferred_io); +#endif /* defined(__linux__) */ /** * drm_fb_helper_sys_read - wrapper around fb_sys_read @@ -863,7 +860,6 @@ void drm_fb_helper_cfb_imageblit(struct fb_info *info, drm_fb_helper_damage(info, image->dx, image->dy, image->width, image->height); } EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); -#endif /* __linux__ */ /** * drm_fb_helper_set_suspend - wrapper around fb_set_suspend @@ -927,7 +923,6 @@ void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, } EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked); -#ifdef __linux__ static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info) { u32 *palette = (u32 *)info->pseudo_palette; @@ -1168,7 +1163,6 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) return ret; } EXPORT_SYMBOL(drm_fb_helper_setcmap); -#endif /* __linux__ */ /** * drm_fb_helper_ioctl - legacy ioctl implementation @@ -1237,7 +1231,6 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, } EXPORT_SYMBOL(drm_fb_helper_ioctl); -#ifdef __linux__ static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1, const struct fb_var_screeninfo *var_2) { @@ -1330,12 +1323,10 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, if (in_dbg_master()) return -EINVAL; -#ifdef __linux__ if (var->pixclock != 0) { drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n"); var->pixclock = 0; } -#endif if ((drm_format_info_block_width(fb->format, 0) > 1) || (drm_format_info_block_height(fb->format, 0) > 1)) @@ -1387,7 +1378,6 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, return 0; } EXPORT_SYMBOL(drm_fb_helper_check_var); -#endif /* __linux__ */ /** * drm_fb_helper_set_par - implementation for &fb_ops.fb_set_par @@ -1406,7 +1396,6 @@ int drm_fb_helper_set_par(struct fb_info *info) if (oops_in_progress) return -EBUSY; -#ifdef __linux__ if (var->pixclock != 0) { drm_err(fb_helper->dev, "PIXEL CLOCK SET\n"); return -EINVAL; @@ -1428,18 +1417,18 @@ int drm_fb_helper_set_par(struct fb_info *info) * commit function, which ensures that we never steal the display from * an active drm master. */ +#ifdef __linux__ force = var->activate & FB_ACTIVATE_KD_TEXT; - - __drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper, force); #elif defined(__FreeBSD__) - drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); + force = false; #endif + __drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper, force); + return 0; } EXPORT_SYMBOL(drm_fb_helper_set_par); -#ifdef __linux__ static void pan_set(struct drm_fb_helper *fb_helper, int x, int y) { struct drm_mode_set *mode_set; @@ -1451,12 +1440,10 @@ static void pan_set(struct drm_fb_helper *fb_helper, int x, int y) } mutex_unlock(&fb_helper->client.modeset_mutex); } -#endif static int pan_display_atomic(struct fb_var_screeninfo *var, struct fb_info *info) { -#ifdef __linux__ struct drm_fb_helper *fb_helper = info->par; int ret; @@ -1470,15 +1457,11 @@ static int pan_display_atomic(struct fb_var_screeninfo *var, pan_set(fb_helper, info->var.xoffset, info->var.yoffset); return ret; -#elif defined(__FreeBSD__) - return 0; -#endif } static int pan_display_legacy(struct fb_var_screeninfo *var, struct fb_info *info) { -#ifdef __linux__ struct drm_fb_helper *fb_helper = info->par; struct drm_client_dev *client = &fb_helper->client; struct drm_mode_set *modeset; @@ -1502,9 +1485,6 @@ static int pan_display_legacy(struct fb_var_screeninfo *var, mutex_unlock(&client->modeset_mutex); return ret; -#elif defined(__FreeBSD__) - return 0; -#endif } /** @@ -1726,7 +1706,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, static void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth) { -#ifdef __linux__ info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; @@ -1737,13 +1716,8 @@ static void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, info->fix.ypanstep = 1; /* doing it in hw */ info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_NONE; -#endif info->fix.line_length = pitch; -#ifdef __FreeBSD__ - info->fbio.fb_stride = pitch; -#endif - return; } static void drm_fb_helper_fill_var(struct fb_info *info, @@ -1755,19 +1729,15 @@ static void drm_fb_helper_fill_var(struct fb_info *info, WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) || (drm_format_info_block_height(fb->format, 0) > 1)); info->pseudo_palette = fb_helper->pseudo_palette; -#ifdef __linux__ info->var.xres_virtual = fb->width; info->var.yres_virtual = fb->height; -#endif info->var.bits_per_pixel = fb->format->cpp[0] * 8; -#ifdef __linux__ info->var.accel_flags = FB_ACCELF_TEXT; info->var.xoffset = 0; info->var.yoffset = 0; info->var.activate = FB_ACTIVATE_NOW; drm_fb_helper_fill_pixel_fmt(&info->var, fb->format->depth); -#endif info->var.xres = fb_width; info->var.yres = fb_height; @@ -1804,7 +1774,6 @@ void drm_fb_helper_fill_info(struct fb_info *info, sizes->fb_width, sizes->fb_height); info->par = fb_helper; -#ifdef __linux__ /* * The DRM drivers fbdev emulation device name can be confusing if the * driver name also has a "drm" suffix on it. Leading to names such as @@ -1813,7 +1782,6 @@ void drm_fb_helper_fill_info(struct fb_info *info, */ snprintf(info->fix.id, sizeof(info->fix.id), "%sdrmfb", fb_helper->dev->driver->name); -#endif } EXPORT_SYMBOL(drm_fb_helper_fill_info); @@ -1854,16 +1822,13 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper) /* use first connected connector for the physical dimensions */ if (connector->status == connector_status_connected) { -#ifdef __linux__ info->var.width = connector->display_info.width_mm; info->var.height = connector->display_info.height_mm; -#endif break; } } drm_connector_list_iter_end(&conn_iter); -#ifdef __linux__ switch (sw_rotations) { case DRM_MODE_ROTATE_0: info->fbcon_rotate_hint = FB_ROTATE_UR; @@ -1885,7 +1850,6 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper) */ info->fbcon_rotate_hint = FB_ROTATE_UR; } -#endif } /* Note: Drops fb_helper->lock before returning. */ @@ -1918,7 +1882,6 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper, fb_helper->deferred_setup = false; info = fb_helper->fbdev; -#ifdef __linux__ info->var.pixclock = 0; /* Shamelessly allow physical address leaking to userspace */ #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM) @@ -1926,7 +1889,6 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper, #endif /* don't leak any physical addresses to userspace */ info->flags |= FBINFO_HIDE_SMEM_START; -#endif #ifdef __FreeBSD__ info->fbio.fb_video_dev = device_get_parent(fb_helper->dev->dev->bsddev); @@ -2101,15 +2063,16 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev) } EXPORT_SYMBOL(drm_fb_helper_output_poll_changed); -#ifdef __linux__ /* @user: 1=userspace, 0=fbcon */ static int drm_fbdev_fb_open(struct fb_info *info, int user) { struct drm_fb_helper *fb_helper = info->par; +#ifdef __linux__ /* No need to take a ref for fbcon because it unbinds on unregister */ if (user && !try_module_get(fb_helper->dev->driver->fops->owner)) return -ENODEV; +#endif return 0; } @@ -2118,8 +2081,10 @@ static int drm_fbdev_fb_release(struct fb_info *info, int user) { struct drm_fb_helper *fb_helper = info->par; +#ifdef __linux__ if (user) module_put(fb_helper->dev->driver->fops->owner); +#endif return 0; } @@ -2133,8 +2098,10 @@ static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper) return; if (fbi) { +#ifdef __linux__ if (fbi->fbdefio) fb_deferred_io_cleanup(fbi); +#endif if (drm_fbdev_use_shadow_fb(fb_helper)) shadow = fbi->screen_buffer; } @@ -2385,10 +2352,12 @@ static const struct fb_ops drm_fbdev_fb_ops = { .fb_imageblit = drm_fbdev_fb_imageblit, }; +#ifdef __linux__ static struct fb_deferred_io drm_fbdev_defio = { .delay = HZ / 20, .deferred_io = drm_fb_helper_deferred_io, }; +#endif /* * This function uses the client API to create a framebuffer backed by a dumb buffer. @@ -2428,9 +2397,7 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, fbi->fbops = &drm_fbdev_fb_ops; fbi->screen_size = fb->height * fb->pitches[0]; -#ifdef __linux__ fbi->fix.smem_len = fbi->screen_size; -#endif drm_fb_helper_fill_info(fbi, fb_helper, sizes); @@ -2439,9 +2406,11 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, if (!fbi->screen_buffer) return -ENOMEM; +#ifdef __linux__ fbi->fbdefio = &drm_fbdev_defio; fb_deferred_io_init(fbi); +#endif } else { /* buffer is mapped for HW framebuffer */ ret = drm_client_buffer_vmap(fb_helper->buffer, &map); @@ -2611,4 +2580,3 @@ void drm_fbdev_generic_setup(struct drm_device *dev, drm_client_register(&fb_helper->client); } EXPORT_SYMBOL(drm_fbdev_generic_setup); -#endif /* __linux__*/ diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index d661f6ab0f3..608d0b1878a 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -74,7 +74,6 @@ static int intel_fbdev_set_par(struct fb_info *info) return ret; } -#ifdef __linux__ static int intel_fbdev_blank(int blank, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; @@ -103,19 +102,16 @@ static int intel_fbdev_pan_display(struct fb_var_screeninfo *var, return ret; } -#endif static const struct fb_ops intelfb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_set_par = intel_fbdev_set_par, -#ifdef __linux__ .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = intel_fbdev_pan_display, .fb_blank = intel_fbdev_blank, -#endif }; static int intelfb_alloc(struct drm_fb_helper *helper, diff --git a/drivers/gpu/drm/linux_fb.c b/drivers/gpu/drm/linux_fb.c index fdec1b9c958..4c1db19242c 100644 --- a/drivers/gpu/drm/linux_fb.c +++ b/drivers/gpu/drm/linux_fb.c @@ -302,3 +302,47 @@ linux_fb_get_options(const char *connector_name, char **option) return (*option != NULL ? 0 : -ENOENT); } + +void +cfb_fillrect(struct linux_fb_info *info, const struct fb_fillrect *rect) +{ +} + +void +cfb_copyarea(struct linux_fb_info *info, const struct fb_copyarea *area) +{ +} + +void +cfb_imageblit(struct linux_fb_info *info, const struct fb_image *image) +{ +} + +void +sys_fillrect(struct linux_fb_info *info, const struct fb_fillrect *rect) +{ +} + +void +sys_copyarea(struct linux_fb_info *info, const struct fb_copyarea *area) +{ +} + +void +sys_imageblit(struct linux_fb_info *info, const struct fb_image *image) +{ +} + +ssize_t +fb_sys_read(struct linux_fb_info *info, char __user *buf, + size_t count, loff_t *ppos) +{ + return (0); +} + +ssize_t +fb_sys_write(struct linux_fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + return (0); +} diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 9b892109b38..c5587e7b568 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -48,7 +48,6 @@ struct radeon_fbdev { struct radeon_device *rdev; }; -#ifdef __linux__ static int radeonfb_open(struct fb_info *info, int user) { @@ -74,18 +73,15 @@ radeonfb_release(struct fb_info *info, int user) pm_runtime_put_autosuspend(rdev->ddev->dev); return 0; } -#endif /* __linux__ */ static const struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, -#ifdef __linux__ .fb_open = radeonfb_open, .fb_release = radeonfb_release, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, -#endif }; diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 574de10bb5b..ed9d381bcb7 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -203,7 +203,6 @@ drm_fb_helper_from_client(struct drm_client_dev *client) * Helper define to register default implementations of drm_fb_helper * functions. To be used in struct fb_ops of drm drivers. */ -#ifdef __linux__ #define DRM_FB_HELPER_DEFAULT_OPS \ .fb_check_var = drm_fb_helper_check_var, \ .fb_set_par = drm_fb_helper_set_par, \ @@ -213,10 +212,6 @@ drm_fb_helper_from_client(struct drm_client_dev *client) .fb_debug_enter = drm_fb_helper_debug_enter, \ .fb_debug_leave = drm_fb_helper_debug_leave, \ .fb_ioctl = drm_fb_helper_ioctl -#elif defined(__FreeBSD__) -#define DRM_FB_HELPER_DEFAULT_OPS \ - .fb_set_par = drm_fb_helper_set_par -#endif #ifdef CONFIG_DRM_FBDEV_EMULATION void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, @@ -246,7 +241,6 @@ ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos); -#ifdef __linux__ void drm_fb_helper_sys_fillrect(struct fb_info *info, const struct fb_fillrect *rect); void drm_fb_helper_sys_copyarea(struct fb_info *info, @@ -260,15 +254,12 @@ void drm_fb_helper_cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); void drm_fb_helper_cfb_imageblit(struct fb_info *info, const struct fb_image *image); -#endif /* __linux__ */ void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend); void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, bool suspend); -#ifdef __linux__ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); -#endif int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); diff --git a/linuxkpi/bsd/include/uapi/linux/fb.h b/linuxkpi/bsd/include/uapi/linux/fb.h index 7e6e3514188..a57273db7ee 100644 --- a/linuxkpi/bsd/include/uapi/linux/fb.h +++ b/linuxkpi/bsd/include/uapi/linux/fb.h @@ -32,6 +32,177 @@ #define FB_ROTATE_UD 2 #define FB_ROTATE_CCW 3 -#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, uint32_t) -#endif /* _BSD_LKPI_UAPI_FB_H_ */ +#define PICOS2KHZ(a) (1000000000UL/(a)) +#define KHZ2PICOS(a) (1000000000UL/(a)) + +#define FB_TYPE_PACKED_PIXELS 0 +#define FB_TYPE_PLANES 1 +#define FB_TYPE_INTERLEAVED_PLANES 2 +#define FB_TYPE_TEXT 3 +#define FB_TYPE_VGA_PLANES 4 +#define FB_TYPE_FOURCC 5 + +#define FB_VISUAL_MONO01 0 +#define FB_VISUAL_MONO10 1 +#define FB_VISUAL_TRUECOLOR 2 +#define FB_VISUAL_PSEUDOCOLOR 3 +#define FB_VISUAL_DIRECTCOLOR 4 +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 +#define FB_VISUAL_FOURCC 6 + +#define FB_ACCEL_NONE 0 + +struct fb_fix_screeninfo { + char id[16]; +#ifdef __linux__ + unsigned long smem_start; +#elif defined(__FreeBSD__) + vm_paddr_t smem_start; +#endif + + uint32_t smem_len; + uint32_t type; + uint32_t type_aux; + uint32_t visual; + uint16_t xpanstep; + uint16_t ypanstep; + uint16_t ywrapstep; + uint32_t line_length; + unsigned long mmio_start; + + uint32_t mmio_len; + uint32_t accel; + + uint16_t capabilities; + uint16_t reserved[2]; +}; + +struct fb_bitfield { + uint32_t offset; + uint32_t length; + uint32_t msb_right; +}; + +#define FB_ACTIVATE_NOW 0 + +#define FB_ACCELF_TEXT 1 + +struct fb_var_screeninfo { + uint32_t xres; + uint32_t yres; + uint32_t xres_virtual; + uint32_t yres_virtual; + uint32_t xoffset; + uint32_t yoffset; + + uint32_t bits_per_pixel; + uint32_t grayscale; + + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + + uint32_t nonstd; + + uint32_t activate; + + uint32_t height; + uint32_t width; + + uint32_t accel_flags; + + uint32_t pixclock; + uint32_t left_margin; + uint32_t right_margin; + uint32_t upper_margin; + uint32_t lower_margin; + uint32_t hsync_len; + uint32_t vsync_len; + uint32_t sync; + uint32_t vmode; + uint32_t rotate; + uint32_t colorspace; + uint32_t reserved[4]; +}; + +struct fb_cmap { + uint32_t start; + uint32_t len; + uint16_t *red; + uint16_t *green; + uint16_t *blue; + uint16_t *transp; +}; + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + +enum { + FB_BLANK_UNBLANK = VESA_NO_BLANKING, + FB_BLANK_NORMAL = VESA_NO_BLANKING + 1, + FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1, + FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1, + FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1 +}; + +struct fb_vblank { + uint32_t flags; + uint32_t count; + uint32_t vcount; + uint32_t hcount; + uint32_t reserved[4]; +}; + +#define ROP_COPY 0 +#define ROP_XOR 1 + +struct fb_copyarea { + uint32_t dx; + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t sx; + uint32_t sy; +}; + +struct fb_fillrect { + uint32_t dx; + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t color; + uint32_t rop; +}; + +struct fb_image { + uint32_t dx; + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t fg_color; + uint32_t bg_color; + uint8_t depth; + const char *data; + struct fb_cmap cmap; +}; + +struct fbcurpos { + uint16_t x, y; +}; + +struct fb_cursor { + uint16_t set; + uint16_t enable; + uint16_t rop; + const char *mask; + struct fbcurpos hot; + struct fb_image image; +}; + +#endif diff --git a/linuxkpi/gplv2/include/linux/fb.h b/linuxkpi/gplv2/include/linux/fb.h index 1f60b8cd1ff..4c64c180070 100644 --- a/linuxkpi/gplv2/include/linux/fb.h +++ b/linuxkpi/gplv2/include/linux/fb.h @@ -18,32 +18,99 @@ struct linux_fb_info; struct videomode; struct vm_area_struct; -#define KHZ2PICOS(a) (1000000000UL/(a)) - -struct fb_fix_screeninfo { - vm_paddr_t smem_start; - uint32_t smem_len; - uint32_t line_length; -}; - -struct fb_var_screeninfo { - int xres; - int yres; - int bits_per_pixel; +struct fb_blit_caps { + u32 x; + u32 y; + u32 len; + u32 flags; }; struct fb_ops { /* open/release and usage marking */ struct module *owner; + int (*fb_open)(struct linux_fb_info *info, int user); + int (*fb_release)(struct linux_fb_info *info, int user); + + /* For framebuffers with strange non linear layouts or that do not + * work with normal memory mapped access + */ + ssize_t (*fb_read)(struct linux_fb_info *info, char __user *buf, + size_t count, loff_t *ppos); + ssize_t (*fb_write)(struct linux_fb_info *info, const char __user *buf, + size_t count, loff_t *ppos); + + /* checks var and eventually tweaks it to something supported, + * DO NOT MODIFY PAR */ + int (*fb_check_var)(struct fb_var_screeninfo *var, struct linux_fb_info *info); /* set the video mode according to info->var */ int (*fb_set_par)(struct linux_fb_info *info); + /* set color register */ + int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct linux_fb_info *info); + + /* set color registers in batch */ + int (*fb_setcmap)(struct fb_cmap *cmap, struct linux_fb_info *info); + + /* blank display */ + int (*fb_blank)(int blank, struct linux_fb_info *info); + + /* pan display */ + int (*fb_pan_display)(struct fb_var_screeninfo *var, struct linux_fb_info *info); + + /* Draws a rectangle */ + void (*fb_fillrect) (struct linux_fb_info *info, const struct fb_fillrect *rect); + /* Copy data from area to another */ + void (*fb_copyarea) (struct linux_fb_info *info, const struct fb_copyarea *region); + /* Draws a image to the display */ + void (*fb_imageblit) (struct linux_fb_info *info, const struct fb_image *image); + + /* Draws cursor */ + int (*fb_cursor) (struct linux_fb_info *info, struct fb_cursor *cursor); + + /* wait for blit idle, optional */ + int (*fb_sync)(struct linux_fb_info *info); + + /* perform fb specific ioctl (optional) */ + int (*fb_ioctl)(struct linux_fb_info *info, unsigned int cmd, + unsigned long arg); + + /* Handle 32bit compat ioctl (optional) */ + int (*fb_compat_ioctl)(struct linux_fb_info *info, unsigned cmd, + unsigned long arg); + + /* perform fb specific mmap */ + int (*fb_mmap)(struct linux_fb_info *info, struct vm_area_struct *vma); + + /* get capability given var */ + void (*fb_get_caps)(struct linux_fb_info *info, struct fb_blit_caps *caps, + struct fb_var_screeninfo *var); + /* teardown any resources to do with this framebuffer */ void (*fb_destroy)(struct linux_fb_info *info); + + /* called at KDB enter and leave time to prepare the console */ + int (*fb_debug_enter)(struct linux_fb_info *info); + int (*fb_debug_leave)(struct linux_fb_info *info); }; +/* + * Hide smem_start in the FBIOGET_FSCREENINFO IOCTL. This is used by modern DRM + * drivers to stop userspace from trying to share buffers behind the kernel's + * back. Instead dma-buf based buffer sharing should be used. + */ +#define FBINFO_HIDE_SMEM_START 0x200000 + + struct linux_fb_info { + int flags; + /* + * -1 by default, set to a FB_ROTATE_* value by the driver, if it knows + * a lcd is not mounted upright and fbcon should rotate to compensate. + */ + int fbcon_rotate_hint; + struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ @@ -72,8 +139,12 @@ struct linux_fb_info { } ranges[0]; } *apertures; + bool skip_vt_switch; /* no VT switch on suspend/resume required */ + +#ifdef __FreeBSD__ struct fb_info fbio; device_t fb_bsddev; +#endif } __aligned(sizeof(long)); static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { @@ -85,6 +156,24 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { return a; } + /* + * `Generic' versions of the frame buffer device operations + */ + +extern void cfb_fillrect(struct linux_fb_info *info, const struct fb_fillrect *rect); +extern void cfb_copyarea(struct linux_fb_info *info, const struct fb_copyarea *area); +extern void cfb_imageblit(struct linux_fb_info *info, const struct fb_image *image); +/* + * Drawing operations where framebuffer is in system RAM + */ +extern void sys_fillrect(struct linux_fb_info *info, const struct fb_fillrect *rect); +extern void sys_copyarea(struct linux_fb_info *info, const struct fb_copyarea *area); +extern void sys_imageblit(struct linux_fb_info *info, const struct fb_image *image); +extern ssize_t fb_sys_read(struct linux_fb_info *info, char __user *buf, + size_t count, loff_t *ppos); +extern ssize_t fb_sys_write(struct linux_fb_info *info, const char __user *buf, + size_t count, loff_t *ppos); + int linux_register_framebuffer(struct linux_fb_info *fb_info); int linux_unregister_framebuffer(struct linux_fb_info *fb_info); int remove_conflicting_framebuffers(struct apertures_struct *a, From 75da6f7071b756867c5e0bbd13688f9b71271218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 17 Mar 2023 01:23:09 +0100 Subject: [PATCH 04/10] vt(4) integration: Move FreeBSD's `struct fb_info` init into `register_framebuffer()` [Why] Before, it was scattered in several functions in `drm_fb_helper.c`, enclosed in `#ifdef __FreeBSD__`. It made it difficult to follow how the structure was initialized. Now, everything is centralized in a FreeBSD-specific source file. `register_framebuffer()` would redo the job for several struct fields anyway. [How] Everything is derived from Linux' `struct fb_info`, like before. Only a couple fields are initialized from `struct drm_fb_helper`. This means the lower-level `register_framebuffer()` functions knows about the upper DRM layer. --- drivers/gpu/drm/drm_fb_helper.c | 10 ---------- drivers/gpu/drm/linux_fb.c | 9 +++++++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index c2c5bcf0fe3..c02682cc56c 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1741,13 +1741,6 @@ static void drm_fb_helper_fill_var(struct fb_info *info, info->var.xres = fb_width; info->var.yres = fb_height; - -#ifdef __FreeBSD__ // fbio is BSD stuff - info->fbio.fb_name = device_get_nameunit(fb_helper->dev->dev->bsddev); - info->fbio.fb_width = fb->width; - info->fbio.fb_height = fb->height; - info->fbio.fb_depth = info->var.bits_per_pixel; -#endif } /** @@ -1891,9 +1884,6 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper, info->flags |= FBINFO_HIDE_SMEM_START; #ifdef __FreeBSD__ - info->fbio.fb_video_dev = device_get_parent(fb_helper->dev->dev->bsddev); - info->fbio.fb_bpp = bpp_sel; - info->fb_bsddev = fb_helper->dev->dev->bsddev; struct vt_kms_softc *sc = (struct vt_kms_softc *)info->fbio.fb_priv; if (sc) sc->fb_helper = fb_helper; diff --git a/drivers/gpu/drm/linux_fb.c b/drivers/gpu/drm/linux_fb.c index 4c1db19242c..a620b49070d 100644 --- a/drivers/gpu/drm/linux_fb.c +++ b/drivers/gpu/drm/linux_fb.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #undef fb_info #include @@ -191,10 +192,18 @@ static int __register_framebuffer(struct linux_fb_info *fb_info) { int i, err; + struct drm_fb_helper *fb_helper; + + fb_helper = + ((struct vt_kms_softc *)fb_info->fbio.fb_priv)->fb_helper; + fb_info->fb_bsddev = fb_helper->dev->dev->bsddev; + fb_info->fbio.fb_video_dev = device_get_parent(fb_info->fb_bsddev); + fb_info->fbio.fb_name = device_get_nameunit(fb_info->fb_bsddev); fb_info->fbio.fb_type = FBTYPE_PCIMISC; fb_info->fbio.fb_height = fb_info->var.yres; fb_info->fbio.fb_width = fb_info->var.xres; + fb_info->fbio.fb_bpp = fb_info->var.bits_per_pixel; fb_info->fbio.fb_depth = fb_info->var.bits_per_pixel; fb_info->fbio.fb_cmsize = 0; fb_info->fbio.fb_stride = fb_info->fix.line_length; From 215064e30f4da59ad4289e1040e4aee5d9bbbbf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 17 Mar 2023 01:32:11 +0100 Subject: [PATCH 05/10] vt(4) integration: New `vt_drmfb` backend to integrate with `drm_fb_helper` [Why] The goal is to make the framebuffer behavior closer to what happens on Linux. One major difference is that on FreeBSD, we used to pass the screen base address to `vt_fb` during initialization, then `vt_fb` would write directly to that memory region. This worked fine for years. Unfortunately, this broke somehow with the backport of DRM from Linux 5.17. At that point, the screen was not refreshed anymore, even though `vt_fb` wrote pixels to the correct memory region. The only time the screen was refreshed, it was during a vt-switch. The screen then displayed the content of the tty we just switched away, but still, something happened on the screen. And that's the only operation we called into `drm_fb_helper` from `vt_fb`. On Linux, `fbcon` calls into `fbdev`, emulated by `drm_fb_helper` for each access (read & write) to the framebuffer. It never reads or writes to the memory region on its own. [How] Therefore we need a new integration layer to make sure vt(4) calls into `drm_fb_helper` like Linux' fbcon does. We do this by adding a new vt(4) backend called `vt_drmfb`, which replaces `vt_fb`. `vt_drmfb` bridges between: * DRM's `drm_fb_helper` emulation of Linux' fbdev below, and * vt(4) console handling above In other words, it maps fbdev callbacks to vt(4)'s backend expected callbacks. `vt_drmfb` takes care of converting the vt(4) callbacks arguments to whatever is expected by the underlying fbdev emulation. Then, when it's time to write to the actual framebuffer memory, the implementation of `cfb_*` functions are derived from the `vt_fb` "setpixel" code. `vt_drmfb` is maintained inside drm-kmod and is compiled inside drm(4). It is not under `sys/dev/vt/hw`. The reason is that `vt_drmfb` needs to know the `drm_fb_helper` API and must evolve with it. `vt_drmfb` has another difference: it doesn't use a taskqueue(9) to call into `drm_fb_helper as `vt_fb` did. It performs the calls synchronously. `drm_fb_helper` already uses a Linux workqueue to make updates asynchronous with the underlying driver. This simplifies the integration a lot because the whole `fb_mode_task`-related machinery is removed from `drm_os_freebsd.c` and `linux_fb.c`. Because we don't need that taskqueue(9) anymore, this patch also gets rid of the `struct vt_kms_softc` indirection. Now, the `struct drm_fb_helper` pointed is stored directly into FreeBSD's `struct fb_info->fb_priv`. --- drivers/gpu/drm/drm_fb_helper.c | 11 +- drivers/gpu/drm/drm_os_freebsd.c | 58 +---- drivers/gpu/drm/drm_os_freebsd.h | 9 +- drivers/gpu/drm/linux_fb.c | 177 +++++++++++-- drivers/gpu/drm/vt_drmfb.c | 373 +++++++++++++++++++++++++++ drivers/gpu/drm/vt_drmfb.h | 44 ++++ drm/Makefile | 3 +- linuxkpi/bsd/include/uapi/linux/fb.h | 3 + linuxkpi/gplv2/include/linux/fb.h | 1 + 9 files changed, 592 insertions(+), 87 deletions(-) create mode 100644 drivers/gpu/drm/vt_drmfb.c create mode 100644 drivers/gpu/drm/vt_drmfb.h diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index c02682cc56c..0092a8f70d3 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -692,6 +692,13 @@ static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y, clip->y2 = max_t(u32, clip->y2, y + height); spin_unlock_irqrestore(&helper->damage_lock, flags); +#ifdef __FreeBSD__ + if (kdb_active || KERNEL_PANICKED()) { + drm_fb_helper_damage_work(&helper->damage_work); + return; + } +#endif + schedule_work(&helper->damage_work); } @@ -1884,9 +1891,7 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper, info->flags |= FBINFO_HIDE_SMEM_START; #ifdef __FreeBSD__ - struct vt_kms_softc *sc = (struct vt_kms_softc *)info->fbio.fb_priv; - if (sc) - sc->fb_helper = fb_helper; + info->fbio.fb_priv = fb_helper; #endif /* Need to drop locks to avoid recursive deadlock in diff --git a/drivers/gpu/drm/drm_os_freebsd.c b/drivers/gpu/drm/drm_os_freebsd.c index e72743436ea..2048ea5c6fe 100644 --- a/drivers/gpu/drm/drm_os_freebsd.c +++ b/drivers/gpu/drm/drm_os_freebsd.c @@ -33,7 +33,7 @@ SYSCTL_NODE(_dev, OID_AUTO, drm, CTLFLAG_RW, 0, "DRM args (compat)"); SYSCTL_INT(_dev_drm, OID_AUTO, __drm_debug, CTLFLAG_RWTUN, &__drm_debug, 0, "drm debug flags (compat)"); SYSCTL_NODE(_hw, OID_AUTO, dri, CTLFLAG_RW, 0, "DRI args"); SYSCTL_INT(_hw_dri, OID_AUTO, __drm_debug, CTLFLAG_RWTUN, &__drm_debug, 0, "drm debug flags"); -static int skip_ddb; +int skip_ddb; SYSCTL_INT(_dev_drm, OID_AUTO, skip_ddb, CTLFLAG_RWTUN, &skip_ddb, 0, "go straight to dumping core (compat)"); SYSCTL_INT(_hw_dri, OID_AUTO, skip_ddb, CTLFLAG_RWTUN, &skip_ddb, 0, "go straight to dumping core"); #if defined(DRM_DEBUG_LOG_ALL) @@ -44,8 +44,6 @@ int drm_debug_persist = 0; SYSCTL_INT(_dev_drm, OID_AUTO, drm_debug_persist, CTLFLAG_RWTUN, &drm_debug_persist, 0, "keep drm debug flags post-load (compat)"); SYSCTL_INT(_hw_dri, OID_AUTO, drm_debug_persist, CTLFLAG_RWTUN, &drm_debug_persist, 0, "keep drm debug flags post-load"); -static bool already_switching_inside_panic = false; - static struct callout reset_debug_log_handle; static void @@ -117,60 +115,6 @@ unregister_fictitious_range(vm_paddr_t base, size_t size) /* Framebuffer related code */ -/* Call restore out of vt(9) locks. */ -void -vt_restore_fbdev_mode(void *arg, int pending) -{ - struct drm_fb_helper *fb_helper; - struct vt_kms_softc *sc; - struct mm_struct mm; - - sc = (struct vt_kms_softc *)arg; - fb_helper = sc->fb_helper; - linux_set_current(curthread); - if(!fb_helper) { - DRM_DEBUG("fb helper is null!\n"); - return; - } - drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); -} - -int -vt_kms_postswitch(void *arg) -{ - struct vt_kms_softc *sc; - - sc = (struct vt_kms_softc *)arg; - - if (!kdb_active && !KERNEL_PANICKED()) { - taskqueue_enqueue(taskqueue_thread, &sc->fb_mode_task); - - /* XXX the VT_ACTIVATE IOCTL must be synchronous */ - if (curthread->td_proc->p_pid != 0 && - taskqueue_member(taskqueue_thread, curthread) == 0) - taskqueue_drain(taskqueue_thread, &sc->fb_mode_task); - } else { -#ifdef DDB - db_trace_self_depth(10); - mdelay(1000); -#endif - if (already_switching_inside_panic || skip_ddb) { - spinlock_enter(); - doadump(false); - EVENTHANDLER_INVOKE(shutdown_final, RB_NOSYNC); - } - linux_set_current(curthread); - if(!sc->fb_helper) { - DRM_DEBUG("fb helper is null!\n"); - return -1; - } - already_switching_inside_panic = true; - drm_fb_helper_restore_fbdev_mode_unlocked(sc->fb_helper); - already_switching_inside_panic = false; - } - return (0); -} - int drm_dev_alias(struct device *ldev, struct drm_minor *minor, const char *minor_str) { diff --git a/drivers/gpu/drm/drm_os_freebsd.h b/drivers/gpu/drm/drm_os_freebsd.h index cd05e65f370..d2bab7ed20e 100644 --- a/drivers/gpu/drm/drm_os_freebsd.h +++ b/drivers/gpu/drm/drm_os_freebsd.h @@ -20,11 +20,6 @@ __FBSDID("$FreeBSD$"); #define DRM_DEV_UID UID_ROOT #define DRM_DEV_GID GID_VIDEO -struct vt_kms_softc { - struct drm_fb_helper *fb_helper; - struct task fb_mode_task; -}; - /* XXXKIB what is the right code for the FreeBSD ? */ /* kib@ used ENXIO here -- dumbbell@ */ #define EREMOTEIO EIO @@ -35,6 +30,7 @@ struct vt_kms_softc { MALLOC_DECLARE(DRM_MEM_DRIVER); extern devclass_t drm_devclass; +extern int skip_ddb; struct drm_minor; int drm_dev_alias(struct device *dev, struct drm_minor *minor, const char *minor_str); @@ -46,9 +42,6 @@ void vt_unfreeze_main_vd(void); int register_fictitious_range(vm_paddr_t start, vm_paddr_t end); void unregister_fictitious_range(vm_paddr_t start, vm_paddr_t end); -void vt_restore_fbdev_mode(void *arg, int pending); -int vt_kms_postswitch(void *arg); - #if 0 struct linux_fb_info; static inline void vga_switcheroo_unregister_client(struct pci_dev *pdev) {} diff --git a/drivers/gpu/drm/linux_fb.c b/drivers/gpu/drm/linux_fb.c index a620b49070d..4265939f016 100644 --- a/drivers/gpu/drm/linux_fb.c +++ b/drivers/gpu/drm/linux_fb.c @@ -39,7 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include "vt_drmfb.h" #include #include @@ -67,7 +67,8 @@ vt_freeze_main_vd(struct apertures_struct *a) (strcmp(main_vd->vd_driver->vd_name, "efifb") == 0 || strcmp(main_vd->vd_driver->vd_name, "vbefb") == 0 || strcmp(main_vd->vd_driver->vd_name, "ofwfb") == 0 - || strcmp(main_vd->vd_driver->vd_name, "fb") == 0)) { + || strcmp(main_vd->vd_driver->vd_name, "fb") == 0 + || strcmp(main_vd->vd_driver->vd_name, "drmfb") == 0)) { fb = main_vd->vd_softc; for (i = 0; i < a->count; i++) { @@ -95,6 +96,17 @@ vt_unfreeze_main_vd(void) fb->fb_flags &= ~FB_FLAG_NOWRITE; } +/* Call restore out of vt(9) locks. */ +static void +vt_restore_fbdev_mode(void *arg, int pending) +{ + struct linux_fb_info *info; + + info = (struct linux_fb_info *)arg; + linux_set_current(curthread); + info->fbops->fb_set_par(info); +} + void fb_info_print(struct fb_info *t) { @@ -114,14 +126,9 @@ struct linux_fb_info * framebuffer_alloc(size_t size, struct device *dev) { struct linux_fb_info *info; - struct vt_kms_softc *sc; info = malloc(sizeof(*info) + size, LKPI_FB_MEM, M_WAITOK | M_ZERO); - sc = malloc(sizeof(*sc), LKPI_FB_MEM, M_WAITOK | M_ZERO); - TASK_INIT(&sc->fb_mode_task, 0, vt_restore_fbdev_mode, sc); - - info->fbio.fb_priv = sc; - info->fbio.enter = &vt_kms_postswitch; + TASK_INIT(&info->fb_mode_task, 0, vt_restore_fbdev_mode, info); if (size) info->par = info + 1; @@ -134,14 +141,9 @@ framebuffer_alloc(size_t size, struct device *dev) void framebuffer_release(struct linux_fb_info *info) { - struct vt_kms_softc *sc; - if (info == NULL) return; - if (info->fbio.fb_priv) - sc = info->fbio.fb_priv; kfree(info->apertures); - free(info->fbio.fb_priv, LKPI_FB_MEM); free(info, LKPI_FB_MEM); } @@ -194,8 +196,7 @@ __register_framebuffer(struct linux_fb_info *fb_info) int i, err; struct drm_fb_helper *fb_helper; - fb_helper = - ((struct vt_kms_softc *)fb_info->fbio.fb_priv)->fb_helper; + fb_helper = (struct drm_fb_helper *)fb_info->fbio.fb_priv; fb_info->fb_bsddev = fb_helper->dev->dev->bsddev; fb_info->fbio.fb_video_dev = device_get_parent(fb_info->fb_bsddev); fb_info->fbio.fb_name = device_get_nameunit(fb_info->fb_bsddev); @@ -214,14 +215,14 @@ __register_framebuffer(struct linux_fb_info *fb_info) fb_info->fbio.fb_fbd_dev = device_add_child(fb_info->fb_bsddev, "fbd", device_get_unit(fb_info->fb_bsddev)); - /* tell vt_fb to initialize color map */ + /* tell vt_drmfb to initialize color map */ fb_info->fbio.fb_cmsize = 0; if (fb_info->fbio.fb_bpp == 0) { device_printf(fb_info->fbio.fb_fbd_dev, "fb_bpp not set, setting to 8\n"); fb_info->fbio.fb_bpp = 32; } - if ((err = vt_fb_attach(&fb_info->fbio)) != 0) { + if ((err = vt_drmfb_attach(&fb_info->fbio)) != 0) { switch (err) { case EEXIST: device_printf(fb_info->fbio.fb_fbd_dev, @@ -262,7 +263,7 @@ __unregister_framebuffer(struct linux_fb_info *fb_info) mtx_unlock(&Giant); fb_info->fbio.fb_fbd_dev = NULL; } - vt_fb_detach(&fb_info->fbio); + vt_drmfb_detach(&fb_info->fbio); if (fb_info->fbops->fb_destroy) fb_info->fbops->fb_destroy(fb_info); @@ -312,40 +313,179 @@ linux_fb_get_options(const char *connector_name, char **option) return (*option != NULL ? 0 : -ENOENT); } +/* + * Routines to write to the framebuffer. They are used to implement Linux' + * fbdev equivalent functions below. + * + * Copied from `sys/dev/vt/hw/fb/vt_fb.c`. + */ + +static void +fb_mem_wr1(struct linux_fb_info *info, uint32_t offset, uint8_t value) +{ + KASSERT( + (offset < info->screen_size), + ("Offset %#08x out of framebuffer size", offset)); + *(uint8_t *)(info->screen_base + offset) = value; +} + +static void +fb_mem_wr2(struct linux_fb_info *info, uint32_t offset, uint16_t value) +{ + KASSERT( + (offset < info->screen_size), + ("Offset %#08x out of framebuffer size", offset)); + *(uint16_t *)(info->screen_base + offset) = value; +} + +static void +fb_mem_wr4(struct linux_fb_info *info, uint32_t offset, uint32_t value) +{ + KASSERT( + (offset < info->screen_size), + ("Offset %#08x out of framebuffer size", offset)); + *(uint32_t *)(info->screen_base + offset) = value; +} + +static void +fb_setpixel(struct linux_fb_info *info, uint32_t x, uint32_t y, + uint32_t color) +{ + uint32_t bytes_per_pixel; + unsigned int offset; + + bytes_per_pixel = info->var.bits_per_pixel / 8; + offset = info->fix.line_length * y + x * bytes_per_pixel; + + KASSERT((info->screen_base != 0), ("Unmapped framebuffer")); + + switch (bytes_per_pixel) { + case 1: + fb_mem_wr1(info, offset, color); + break; + case 2: + fb_mem_wr2(info, offset, color); + break; + case 3: + fb_mem_wr1(info, offset, (color >> 16) & 0xff); + fb_mem_wr1(info, offset + 1, (color >> 8) & 0xff); + fb_mem_wr1(info, offset + 2, color & 0xff); + break; + case 4: + fb_mem_wr4(info, offset, color); + break; + default: + /* panic? */ + return; + } +} + void cfb_fillrect(struct linux_fb_info *info, const struct fb_fillrect *rect) { + uint32_t x, y; + + if (info->fbio.fb_flags & FB_FLAG_NOWRITE) + return; + + KASSERT( + (rect->rop == ROP_COPY), + ("`rect->rop=%u` is unsupported in cfb_fillrect()", rect->rop)); + + for (y = rect->dy; y < rect->dy + rect->height; ++y) { + for (x = rect->dx; x < rect->dx + rect->width; ++x) { + fb_setpixel(info, x, y, rect->color); + } + } } void cfb_copyarea(struct linux_fb_info *info, const struct fb_copyarea *area) { + panic("cfb_copyarea() not implemented"); } void cfb_imageblit(struct linux_fb_info *info, const struct fb_image *image) { + uint32_t x, y, width, height, xi, yi; + uint32_t bytes_per_img_line, bit, byte, color; + + if (info->fbio.fb_flags & FB_FLAG_NOWRITE) + return; + + KASSERT( + (image->depth == 1), + ("`image->depth=%u` is unsupported in cfb_imageblit()", + image->depth)); + + bytes_per_img_line = (image->width + 7) / 8; + + x = image->dx; + y = image->dy; + width = image->width; + height = image->height; + + if (x + width > info->var.xres) { + if (x >= info->var.xres) + return; + width = info->var.xres - x; + } + if (y + height > info->var.yres) { + if (y >= info->var.yres) + return; + height = info->var.yres - y; + } + + if (image->mask == NULL) { + for (yi = 0; yi < height; ++yi) { + for (xi = 0; xi < width; ++xi) { + byte = yi * bytes_per_img_line + xi / 8; + bit = 0x80 >> (xi % 8); + color = image->data[byte] & bit ? + image->fg_color : image->bg_color; + + fb_setpixel(info, x + xi, y + yi, color); + } + } + } else { + for (yi = 0; yi < height; ++yi) { + for (xi = 0; xi < width; ++xi) { + byte = yi * bytes_per_img_line + xi / 8; + bit = 0x80 >> (xi % 8); + if (image->mask[byte] & bit) { + color = image->fg_color; + + fb_setpixel(info, x + xi, y + yi, color); + } + } + } + } } void sys_fillrect(struct linux_fb_info *info, const struct fb_fillrect *rect) { + cfb_fillrect(info, rect); } void sys_copyarea(struct linux_fb_info *info, const struct fb_copyarea *area) { + cfb_copyarea(info, area); } void sys_imageblit(struct linux_fb_info *info, const struct fb_image *image) { + cfb_imageblit(info, image); } ssize_t fb_sys_read(struct linux_fb_info *info, char __user *buf, size_t count, loff_t *ppos) { + panic("fb_sys_read() not implemented"); return (0); } @@ -353,5 +493,6 @@ ssize_t fb_sys_write(struct linux_fb_info *info, const char __user *buf, size_t count, loff_t *ppos) { + panic("fb_sys_write() not implemented"); return (0); } diff --git a/drivers/gpu/drm/vt_drmfb.c b/drivers/gpu/drm/vt_drmfb.c new file mode 100644 index 00000000000..33c9faa00b1 --- /dev/null +++ b/drivers/gpu/drm/vt_drmfb.c @@ -0,0 +1,373 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2013 The FreeBSD Foundation + * Copyright (c) 2023 Jean-Sébastien Pédron + * + * This initial software `sys/dev/vt/hw/vt_fb.c` was developed by Aleksandr + * Rybalko under sponsorship from the FreeBSD Foundation. + * This file is a copy of the initial file and is modified by Jean-Sébastien + * Pédron. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +#include + +/* + * `drm_fb_helper.h` redefines `fb_info` to be `linux_fb_info` to manage the + * name conflict between the Linux and FreeBSD structures, while avoiding a + * extensive rewrite and use of macros in the original drm_fb_helper.[ch] + * files. + * + * We need to undo this here because we use both structures. + */ +#undef fb_info + +#include + +#include "vt_drmfb.h" + +#define to_drm_fb_helper(fbio) ((struct drm_fb_helper *)fbio->fb_priv) +#define to_linux_fb_info(fbio) (to_drm_fb_helper(fbio)->fbdev) + +vd_init_t vt_drmfb_init; +vd_fini_t vt_drmfb_fini; +vd_blank_t vt_drmfb_blank; +vd_bitblt_bmp_t vt_drmfb_bitblt_bitmap; +vd_drawrect_t vt_drmfb_drawrect; +vd_setpixel_t vt_drmfb_setpixel; +vd_invalidate_text_t vt_drmfb_invalidate_text; +vd_postswitch_t vt_drmfb_postswitch; + +static struct vt_driver vt_drmfb_driver = { + .vd_name = "drmfb", + .vd_init = vt_drmfb_init, + .vd_fini = vt_drmfb_fini, + .vd_blank = vt_drmfb_blank, + /* + * .vd_bitblt_text is unset. + * + * We use the default implementation in vt(4) which copies the + * characters first and bitblt_bmp them in a second step outside of the + * vtbuf lock. Thus the `vd_bitblt_after_vtbuf_unlock` flag set below. + * We need this because vtbuf is a spin mutex and + * `vt_drmfb_bitblt_bitmap()` may sleep. + */ + .vd_bitblt_bmp = vt_drmfb_bitblt_bitmap, + .vd_drawrect = vt_drmfb_drawrect, + .vd_setpixel = vt_drmfb_setpixel, + .vd_invalidate_text = vt_drmfb_invalidate_text, + .vd_postswitch = vt_drmfb_postswitch, + .vd_priority = VD_PRIORITY_GENERIC+20, + .vd_suspend = vt_drmfb_suspend, + .vd_resume = vt_drmfb_resume, + + /* Use vt_fb implementation */ + .vd_fb_ioctl = vt_fb_ioctl, + .vd_fb_mmap = vt_fb_mmap, + + .vd_bitblt_after_vtbuf_unlock = true, +}; + +VT_DRIVER_DECLARE(vt_drmfb, vt_drmfb_driver); + +void +vt_drmfb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) +{ + vt_drmfb_drawrect(vd, x, y, x, y, 1, color); +} + +void +vt_drmfb_drawrect( + struct vt_device *vd, + int x1, int y1, int x2, int y2, int fill, + term_color_t color) +{ + struct fb_info *fbio; + struct linux_fb_info *info; + struct fb_fillrect rect; + + fbio = vd->vd_softc; + info = to_linux_fb_info(fbio); + if (info->fbops->fb_fillrect == NULL) + return; + + KASSERT( + (x2 >= x1), + ("Invalid rectangle X coordinates passed to vd_drawrect: " + "x1=%d > x2=%d", x1, x2)); + KASSERT( + (y2 >= y1), + ("Invalid rectangle Y coordinates passed to vd_drawrect: " + "y1=%d > y2=%d", y1, y2)); + KASSERT( + (fill != 0), + ("`fill=0` argument to vd_drawrect unsupported in vt_drmfb")); + + rect.dx = x1; + rect.dy = y1; + rect.width = x2 - x1 + 1; + rect.height = y2 - y1 + 1; + rect.color = fbio->fb_cmap[color]; + rect.rop = ROP_COPY; + + info->fbops->fb_fillrect(info, &rect); +} + +void +vt_drmfb_blank(struct vt_device *vd, term_color_t color) +{ + struct fb_info *fbio; + struct linux_fb_info *info; + int x1, y1, x2, y2; + + fbio = vd->vd_softc; + info = to_linux_fb_info(fbio); + + x1 = info->var.xoffset; + y1 = info->var.yoffset; + x2 = info->var.xres - 1; + y2 = info->var.yres - 1; + + vt_drmfb_drawrect(vd, x1, y1, x2, y2, 1, color); +} + +void +vt_drmfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, + const uint8_t *pattern, const uint8_t *mask, + unsigned int width, unsigned int height, + unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) +{ + struct fb_info *fbio; + struct linux_fb_info *info; + struct fb_image image; + + fbio = vd->vd_softc; + info = to_linux_fb_info(fbio); + if (info->fbops->fb_imageblit == NULL) + return; + + /* Bound by right and bottom edges. */ + if (y + height > vw->vw_draw_area.tr_end.tp_row) { + if (y >= vw->vw_draw_area.tr_end.tp_row) + return; + height = vw->vw_draw_area.tr_end.tp_row - y; + } + if (x + width > vw->vw_draw_area.tr_end.tp_col) { + if (x >= vw->vw_draw_area.tr_end.tp_col) + return; + width = vw->vw_draw_area.tr_end.tp_col - x; + } + + image.dx = x; + image.dy = y; + image.width = width; + image.height = height; + image.fg_color = fbio->fb_cmap[fg]; + image.bg_color = fbio->fb_cmap[bg]; + image.depth = 1; + image.data = pattern; + image.mask = mask; // Specific to FreeBSD to display the mouse pointer. + + if (!kdb_active && !KERNEL_PANICKED()) + linux_set_current(curthread); + + info->fbops->fb_imageblit(info, &image); +} + +void +vt_drmfb_postswitch(struct vt_device *vd) +{ + struct fb_info *fbio; + struct linux_fb_info *info; + + fbio = vd->vd_softc; + info = to_linux_fb_info(fbio); + + if (!kdb_active && !KERNEL_PANICKED()) { + taskqueue_enqueue(taskqueue_thread, &info->fb_mode_task); + + /* XXX the VT_ACTIVATE IOCTL must be synchronous */ + if (curthread->td_proc->p_pid != 0 && + taskqueue_member(taskqueue_thread, curthread) == 0) + taskqueue_drain(taskqueue_thread, &info->fb_mode_task); + } else { +#ifdef DDB + db_trace_self_depth(10); + mdelay(1000); +#endif + if (skip_ddb) { + spinlock_enter(); + doadump(false); + EVENTHANDLER_INVOKE(shutdown_final, RB_NOSYNC); + } + + if (vd->vd_grabwindow != NULL) { + if (info->fbops->fb_debug_enter) + info->fbops->fb_debug_enter(info); + } else { + if (info->fbops->fb_debug_leave) + info->fbops->fb_debug_leave(info); + } + } +} + +void +vt_drmfb_invalidate_text(struct vt_device *vd, const term_rect_t *area) +{ + unsigned int col, row; + size_t z; + + for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { + for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; + ++col) { + z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; + if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * + PIXEL_WIDTH(VT_FB_MAX_WIDTH)) + continue; + if (vd->vd_drawn) + vd->vd_drawn[z] = 0; + if (vd->vd_drawnfg) + vd->vd_drawnfg[z] = 0; + if (vd->vd_drawnbg) + vd->vd_drawnbg[z] = 0; + if (vd->vd_pos_to_flush) + vd->vd_pos_to_flush[z] = true; + } + } +} + +static int +vt_drmfb_init_colors(struct fb_info *info) +{ + + switch (FBTYPE_GET_BPP(info)) { + case 8: + return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, + 0x7, 5, 0x7, 2, 0x3, 0)); + case 15: + return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, + 0x1f, 10, 0x1f, 5, 0x1f, 0)); + case 16: + return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, + 0x1f, 11, 0x3f, 5, 0x1f, 0)); + case 24: + case 32: /* Ignore alpha. */ + return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, + 0xff, 16, 0xff, 8, 0xff, 0)); + default: + return (1); + } +} + +int +vt_drmfb_init(struct vt_device *vd) +{ + struct fb_info *fbio; + u_int margin; + int bg, err; + term_color_t c; + + fbio = vd->vd_softc; + vd->vd_height = MIN(VT_FB_MAX_HEIGHT, fbio->fb_height); + margin = (fbio->fb_height - vd->vd_height) >> 1; + vd->vd_transpose = margin * fbio->fb_stride; + vd->vd_width = MIN(VT_FB_MAX_WIDTH, fbio->fb_width); + margin = (fbio->fb_width - vd->vd_width) >> 1; + vd->vd_transpose += margin * (fbio->fb_bpp / NBBY); + vd->vd_video_dev = fbio->fb_video_dev; + + if (fbio->fb_size == 0) + return (CN_DEAD); + + if (fbio->fb_pbase == 0 && fbio->fb_vbase == 0) + fbio->fb_flags |= FB_FLAG_NOMMAP; + + if (fbio->fb_cmsize <= 0) { + err = vt_drmfb_init_colors(fbio); + if (err) + return (CN_DEAD); + fbio->fb_cmsize = 16; + } + + c = TC_BLACK; + if (TUNABLE_INT_FETCH("teken.bg_color", &bg) != 0) { + if (bg == TC_WHITE) + bg |= TC_LIGHT; + c = bg; + } + + /* Clear the screen. */ + vd->vd_driver->vd_blank(vd, c); + + return (CN_INTERNAL); +} + +void +vt_drmfb_fini(struct vt_device *vd, void *softc) +{ + vd->vd_video_dev = NULL; +} + +int +vt_drmfb_attach(struct fb_info *fbio) +{ + int ret; + + ret = vt_allocate(&vt_drmfb_driver, fbio); + + return (ret); +} + +int +vt_drmfb_detach(struct fb_info *fbio) +{ + int ret; + + ret = vt_deallocate(&vt_drmfb_driver, fbio); + + return (ret); +} + +void +vt_drmfb_suspend(struct vt_device *vd) +{ + vt_suspend(vd); +} + +void +vt_drmfb_resume(struct vt_device *vd) +{ + vt_resume(vd); +} diff --git a/drivers/gpu/drm/vt_drmfb.h b/drivers/gpu/drm/vt_drmfb.h new file mode 100644 index 00000000000..f054883f71f --- /dev/null +++ b/drivers/gpu/drm/vt_drmfb.h @@ -0,0 +1,44 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2013 The FreeBSD Foundation + * Copyright (c) 2023 Jean-Sébastien Pédron + * + * This initial software `sys/dev/vt/hw/vt_fb.h` was developed by Aleksandr + * Rybalko under sponsorship from the FreeBSD Foundation. + * This file is a copy of the initial file and is modified by Jean-Sébastien + * Pédron. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_VT_HW_FB_VT_DRMFB_H_ +#define _DEV_VT_HW_FB_VT_DRMFB_H_ +/* Generic framebuffer interface call vt_drmfb_attach to init VT(9) */ +int vt_drmfb_attach(struct fb_info *info); +void vt_drmfb_resume(struct vt_device *vd); +void vt_drmfb_suspend(struct vt_device *vd); +int vt_drmfb_detach(struct fb_info *info); + +#endif /* _DEV_VT_HW_FB_VT_DRMFB_H_ */ diff --git a/drm/Makefile b/drm/Makefile index c6354e4ca3f..126dfa66e6e 100644 --- a/drm/Makefile +++ b/drm/Makefile @@ -68,7 +68,8 @@ SRCS= drm_atomic.c \ drm_vblank.c \ drm_vblank_work.c \ drm_vma_manager.c \ - linux_fb.c + linux_fb.c \ + vt_drmfb.c .if !empty(KCONFIG:MDRM_FBDEV_EMULATION) SRCS+= drm_fb_helper.c diff --git a/linuxkpi/bsd/include/uapi/linux/fb.h b/linuxkpi/bsd/include/uapi/linux/fb.h index a57273db7ee..4498c3fa4f5 100644 --- a/linuxkpi/bsd/include/uapi/linux/fb.h +++ b/linuxkpi/bsd/include/uapi/linux/fb.h @@ -190,6 +190,9 @@ struct fb_image { uint8_t depth; const char *data; struct fb_cmap cmap; +#ifdef __FreeBSD__ + const char *mask; +#endif }; struct fbcurpos { diff --git a/linuxkpi/gplv2/include/linux/fb.h b/linuxkpi/gplv2/include/linux/fb.h index 4c64c180070..44ff189dea9 100644 --- a/linuxkpi/gplv2/include/linux/fb.h +++ b/linuxkpi/gplv2/include/linux/fb.h @@ -144,6 +144,7 @@ struct linux_fb_info { #ifdef __FreeBSD__ struct fb_info fbio; device_t fb_bsddev; + struct task fb_mode_task; #endif } __aligned(sizeof(long)); From 3e1fc33014633c26b624b5573c922aea2b8a7b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Sat, 5 Aug 2023 21:27:38 +0200 Subject: [PATCH 06/10] vt(4) integration: Don't return error from `registry_framebuffer()` if one is already installed [Why] Some DRM drivers consider a failure from `registry_framebuffer()` as a fatal one. Also in the future, we may want to support multiple framebuffers at the same time, like Linux. --- drivers/gpu/drm/linux_fb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/linux_fb.c b/drivers/gpu/drm/linux_fb.c index 4265939f016..caadacba9af 100644 --- a/drivers/gpu/drm/linux_fb.c +++ b/drivers/gpu/drm/linux_fb.c @@ -229,6 +229,7 @@ __register_framebuffer(struct linux_fb_info *fb_info) "not attached to vt(4) console; " "another device has precedence (err=%d)\n", err); + err = 0; break; default: device_printf(fb_info->fbio.fb_fbd_dev, From 7477d3957655dcbf8e9e2db744c7b73f5f9301a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Sat, 26 Aug 2023 22:24:13 +0200 Subject: [PATCH 07/10] vt(4) integration: Detach vt_drmfb and device child in reverse order ... compared to the attach order. --- drivers/gpu/drm/linux_fb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/linux_fb.c b/drivers/gpu/drm/linux_fb.c index caadacba9af..de73d816e4e 100644 --- a/drivers/gpu/drm/linux_fb.c +++ b/drivers/gpu/drm/linux_fb.c @@ -258,16 +258,18 @@ __unregister_framebuffer(struct linux_fb_info *fb_info) { int ret = 0; + vt_drmfb_detach(&fb_info->fbio); + if (fb_info->fbio.fb_fbd_dev) { mtx_lock(&Giant); device_delete_child(fb_info->fb_bsddev, fb_info->fbio.fb_fbd_dev); mtx_unlock(&Giant); fb_info->fbio.fb_fbd_dev = NULL; } - vt_drmfb_detach(&fb_info->fbio); if (fb_info->fbops->fb_destroy) fb_info->fbops->fb_destroy(fb_info); + return 0; } From 9af192680e1f8beac73c68c9c51d8dc3f08e3097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 17 Mar 2023 14:01:47 +0100 Subject: [PATCH 08/10] vt(4) integration: Log FB_INFO based on `struct linux_fb_info` ... instead of FreeBSD's `struct fb_info`. [Why] With the introduction of `vt_drmfb`, we try to use `struct linux_fb_info` for every parameters and all callbacks. This is to make sure we use the same values as Linux, just in case we forget to update the corresponding FreeBSD's `struct fb_info`. --- drivers/gpu/drm/linux_fb.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/linux_fb.c b/drivers/gpu/drm/linux_fb.c index de73d816e4e..364fd3b092f 100644 --- a/drivers/gpu/drm/linux_fb.c +++ b/drivers/gpu/drm/linux_fb.c @@ -108,15 +108,16 @@ vt_restore_fbdev_mode(void *arg, int pending) } void -fb_info_print(struct fb_info *t) +fb_info_print(struct linux_fb_info *info) { printf("start FB_INFO:\n"); - printf("type=%d height=%d width=%d depth=%d\n", - t->fb_type, t->fb_height, t->fb_width, t->fb_depth); + printf("height=%d width=%d depth=%d\n", + info->var.yres, info->var.xres, info->var.bits_per_pixel); printf("pbase=0x%lx vbase=0x%lx\n", - t->fb_pbase, t->fb_vbase); - printf("name=%s flags=0x%x stride=%d bpp=%d\n", - t->fb_name, t->fb_flags, t->fb_stride, t->fb_bpp); + info->fix.smem_start, info->screen_base); + printf("name=%s id=%s flags=0x%x stride=%d\n", + info->fbio.fb_name, info->fix.id, info->fbio.fb_flags, + info->fix.line_length); printf("end FB_INFO\n"); } @@ -238,7 +239,7 @@ __register_framebuffer(struct linux_fb_info *fb_info) } return (-err); } - fb_info_print(&fb_info->fbio); + fb_info_print(fb_info); return 0; } From ebbb69767b93f3d65649c70b941f90310a07ab9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 24 Nov 2023 17:39:28 +0100 Subject: [PATCH 09/10] drm: Test `funcs` is not NULL in drm_fb_helper_debug_enter() [Why] At least in i915, it is NULL in my tests because the code behind it was removed a long time ago. We didn't execute this function before the introduction of vt_drmfb, so it didn't cause any problems. --- drivers/gpu/drm/drm_fb_helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 0092a8f70d3..b4f5edbca65 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -169,7 +169,11 @@ int drm_fb_helper_debug_enter(struct fb_info *info) continue; funcs = mode_set->crtc->helper_private; +#ifdef __linux__ if (funcs->mode_set_base_atomic == NULL) +#elif defined(__FreeBSD__) + if (funcs == NULL || funcs->mode_set_base_atomic == NULL) +#endif continue; if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev)) From 63c6d0373585f7b5dba6cc6a6a6e90e51bcc757e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 24 Nov 2023 17:40:48 +0100 Subject: [PATCH 10/10] drm: Drop FreeBSD-specific checks of oops_in_progress [Why] With vt_drmfb, I believe they are not needed anymore. --- drivers/gpu/drm/drm_modeset_lock.c | 56 ------------------------------ 1 file changed, 56 deletions(-) diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 132dd21c3a7..c9732336567 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -138,11 +138,6 @@ void drm_modeset_lock_all(struct drm_device *dev) struct drm_modeset_acquire_ctx *ctx; int ret; -#ifdef __FreeBSD__ - if (oops_in_progress) - return; -#endif - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL | __GFP_NOFAIL); if (WARN_ON(!ctx)) return; @@ -196,11 +191,6 @@ void drm_modeset_unlock_all(struct drm_device *dev) struct drm_mode_config *config = &dev->mode_config; struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; -#ifdef __FreeBSD__ - if (oops_in_progress) - return; -#endif - if (WARN_ON(!ctx)) return; @@ -225,10 +215,8 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) struct drm_crtc *crtc; /* Locking is currently fubar in the panic handler. */ -#ifdef __FreeBSD__ if (oops_in_progress) return; -#endif drm_for_each_crtc(crtc, dev) WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); @@ -250,11 +238,6 @@ EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, uint32_t flags) { -#ifdef __FreeBSD__ - if (oops_in_progress) - return; -#endif - memset(ctx, 0, sizeof(*ctx)); ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class); INIT_LIST_HEAD(&ctx->locked); @@ -270,11 +253,6 @@ EXPORT_SYMBOL(drm_modeset_acquire_init); */ void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx) { -#ifdef __FreeBSD__ - if (oops_in_progress) - return; -#endif - ww_acquire_fini(&ctx->ww_ctx); } EXPORT_SYMBOL(drm_modeset_acquire_fini); @@ -287,11 +265,6 @@ EXPORT_SYMBOL(drm_modeset_acquire_fini); */ void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx) { -#ifdef __FreeBSD__ - if (oops_in_progress) - return; -#endif - if (WARN_ON(ctx->contended)) __drm_stack_depot_print(ctx->stack_depot); @@ -312,11 +285,6 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, { int ret; -#ifdef __FreeBSD__ - if (oops_in_progress) - return 0; -#endif - if (WARN_ON(ctx->contended)) __drm_stack_depot_print(ctx->stack_depot); @@ -371,11 +339,6 @@ int drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx) { struct drm_modeset_lock *contended = ctx->contended; -#ifdef __FreeBSD__ - if (oops_in_progress) - return 0; -#endif - ctx->contended = NULL; ctx->stack_depot = 0; @@ -420,11 +383,6 @@ EXPORT_SYMBOL(drm_modeset_lock_init); int drm_modeset_lock(struct drm_modeset_lock *lock, struct drm_modeset_acquire_ctx *ctx) { -#ifdef __FreeBSD__ - if (oops_in_progress) - return 0; -#endif - if (ctx) return modeset_lock(lock, ctx, ctx->interruptible, false); @@ -444,10 +402,6 @@ EXPORT_SYMBOL(drm_modeset_lock); */ int drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock) { -#ifdef __FreeBSD__ - if (oops_in_progress) - return 0; -#endif return ww_mutex_lock_interruptible(&lock->mutex, NULL); } EXPORT_SYMBOL(drm_modeset_lock_single_interruptible); @@ -458,11 +412,6 @@ EXPORT_SYMBOL(drm_modeset_lock_single_interruptible); */ void drm_modeset_unlock(struct drm_modeset_lock *lock) { -#ifdef __FreeBSD__ - if (oops_in_progress) - return; -#endif - list_del_init(&lock->head); ww_mutex_unlock(&lock->mutex); } @@ -496,11 +445,6 @@ int drm_modeset_lock_all_ctx(struct drm_device *dev, struct drm_plane *plane; int ret; -#ifdef __FreeBSD__ - if (oops_in_progress) - return 0; -#endif - ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx); if (ret) return ret;