drm: Improve integration with syscons. Move taskqueue handling to syscons.
authorImre Vadász <imre@vdsz.com>
Sun, 20 Nov 2016 21:01:40 +0000 (22:01 +0100)
committerImre Vadász <imre@vdsz.com>
Mon, 28 Nov 2016 00:08:05 +0000 (01:08 +0100)
* Adds asynctd_lk to syscons' softc to synchronize unregister_framebuffer
  code with the asynchronous screen refresh threads.

* Use a generation counter in syscons to check if sc_update_render() needs
  to update the VT resolution/mode. Remove struct fb_info *fbi pointer
  from scr_stat, and always check the struct fb_info *fbi pointer in the
  softc struct instead.

* Use videio_in_progress flag to make initial fb_set_par call a bit safer.

* Moves driver callbacks from struct fb_info itself into struct fb_ops,
  and adds fb_blank and fb_debug_enter callbacks which will be wired up
  in future commits.

* Add unregister_framebuffer() function to syscons, which is needed for
  cleanly detaching a drm graphics driver which is used as framebuffer
  console. The screen will turn off, blank or display a frozen screen,
  after the graphics driver has detached.

* Use drm_fb_helper_unregister_framebuffer() and drm_fb_helper_release_fbi()
  functions in radeon and i915, which are needed for cleanly detaching the
  drivers.

* With radeonkms detaching and re-attaching is working very reliably
  on an AMD G-T44R APU (i.e. HD6250 graphics).

* Detaching i915 on a Haswell notebook barely worked with several errors,
  and trying to re-attach i915 caused the machine to hang.

sys/dev/drm/drm_fb_helper.c
sys/dev/drm/drm_modeset_lock.c
sys/dev/drm/i915/intel_fbdev.c
sys/dev/drm/include/drm/drm_fb_helper.h
sys/dev/drm/radeon/radeon_fb.c
sys/dev/misc/syscons/scvidctl.c
sys/dev/misc/syscons/syscons.c
sys/dev/misc/syscons/syscons.h
sys/platform/pc64/include/framebuffer.h
sys/platform/pc64/x86_64/machdep.c

index ff06270..6cf9f45 100644 (file)
@@ -252,6 +252,7 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
 
        crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
 }
+#endif
 
 /**
  * drm_fb_helper_debug_enter - implementation for ->fb_debug_enter
@@ -272,7 +273,9 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
                                continue;
 
                        funcs = mode_set->crtc->helper_private;
+#if 0
                        drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
+#endif
                        funcs->mode_set_base_atomic(mode_set->crtc,
                                                    mode_set->fb,
                                                    mode_set->x,
@@ -285,6 +288,7 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_enter);
 
+#if 0
 /* Find the real fb for a given fb helper CRTC */
 static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
 {
@@ -553,6 +557,7 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
 #else
 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 #endif
+#endif
 
 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
@@ -595,14 +600,20 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
  */
 int drm_fb_helper_blank(int blank, struct fb_info *info)
 {
+#ifdef __DragonFly__
+       if (panicstr)
+               return -EBUSY;
+#else
        if (oops_in_progress)
                return -EBUSY;
+#endif
 
        switch (blank) {
        /* Display: On; HSync: On, VSync: On */
        case FB_BLANK_UNBLANK:
                drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
                break;
+#if 0
        /* Display: Off; HSync: On, VSync: On */
        case FB_BLANK_NORMAL:
                drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
@@ -615,6 +626,7 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
        case FB_BLANK_VSYNC_SUSPEND:
                drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
                break;
+#endif
        /* Display: Off; HSync: Off, VSync: Off */
        case FB_BLANK_POWERDOWN:
                drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
@@ -623,7 +635,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_crtc_free(struct drm_fb_helper *helper)
 {
@@ -776,7 +787,6 @@ err_release:
 }
 EXPORT_SYMBOL(drm_fb_helper_alloc_fbi);
 
-#if 0
 /**
  * drm_fb_helper_unregister_fbi - unregister fb_info framebuffer device
  * @fb_helper: driver-allocated fbdev helper
@@ -790,7 +800,6 @@ void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
                unregister_framebuffer(fb_helper->fbdev);
 }
 EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
-#endif
 
 /**
  * drm_fb_helper_release_fbi - dealloc fb_info and its members
@@ -1207,6 +1216,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
        return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_check_var);
+#endif
 
 /**
  * drm_fb_helper_set_par - implementation for ->fb_set_par
@@ -1219,15 +1229,24 @@ EXPORT_SYMBOL(drm_fb_helper_check_var);
 int drm_fb_helper_set_par(struct fb_info *info)
 {
        struct drm_fb_helper *fb_helper = info->par;
+#if 0
        struct fb_var_screeninfo *var = &info->var;
+#endif
 
+#ifdef __DragonFly__
+       if (panicstr)
+               return -EBUSY;
+#else
        if (oops_in_progress)
                return -EBUSY;
+#endif
 
+#if 0
        if (var->pixclock != 0) {
                DRM_ERROR("PIXEL CLOCK SET\n");
                return -EINVAL;
        }
+#endif
 
        drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
 
@@ -1235,6 +1254,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_set_par);
 
+#if 0
 static int pan_display_atomic(struct fb_var_screeninfo *var,
                              struct fb_info *info)
 {
@@ -1344,30 +1364,6 @@ unlock:
 EXPORT_SYMBOL(drm_fb_helper_pan_display);
 #endif
 
-#ifdef __DragonFly__
-static void
-do_restore_fbdev_mode(void *context, int pending)
-{
-       struct drm_fb_helper *fb_helper = context;
-
-       if (!fb_helper->fb)
-               return;
-
-       drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
-}
-
-static void
-sc_restore_fbdev_mode(struct fb_info *info)
-{
-       struct drm_fb_helper *fb_helper = info->par;
-
-       if (!fb_helper->fb)
-               return;
-
-       taskqueue_enqueue(taskqueue_thread[0], &fb_helper->fb_mode_task);
-}
-#endif
-
 /*
  * Allocates the backing storage and sets up the fbdev info structure through
  * the ->fb_probe callback and then registers the fbdev and sets up the panic
@@ -1501,15 +1497,12 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 #ifdef __DragonFly__
        TUNABLE_INT_FETCH("kern.kms_console", &kms_console);
        if (kms_console) {
-               TASK_INIT(&fb_helper->fb_mode_task, 0, do_restore_fbdev_mode,
-                   fb_helper);
-               info->restore = &sc_restore_fbdev_mode;
                if (register_framebuffer(info) < 0)
                        return -EINVAL;
-       }
-#endif
 
-#if 0
+               list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
+       }
+#else
        info->var.pixclock = 0;
        if (register_framebuffer(info) < 0)
                return -EINVAL;
@@ -2221,9 +2214,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
        drm_modeset_lock_all(dev);
        drm_setup_crtcs(fb_helper);
        drm_modeset_unlock_all(dev);
-#if 0
        drm_fb_helper_set_par(fb_helper->fbdev);
-#endif
 
        return 0;
 }
index d747d3c..3c30a9c 100644 (file)
@@ -243,7 +243,10 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
        struct drm_crtc *crtc;
 
        /* Locking is currently fubar in the panic handler. */
-#if 0
+#ifdef __DragonFly__
+       if (panicstr)
+               return;
+#else
        if (oops_in_progress)
                return;
 #endif
index 1d9381f..843f5f3 100644 (file)
@@ -41,7 +41,6 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
-#if 0
 static int intel_fbdev_set_par(struct fb_info *info)
 {
        struct drm_fb_helper *fb_helper = info->par;
@@ -78,6 +77,7 @@ static int intel_fbdev_blank(int blank, struct fb_info *info)
        return ret;
 }
 
+#if 0
 static int intel_fbdev_pan_display(struct fb_var_screeninfo *var,
                                   struct fb_info *info)
 {
@@ -96,21 +96,29 @@ static int intel_fbdev_pan_display(struct fb_var_screeninfo *var,
 
        return ret;
 }
+#endif
 
 static struct fb_ops intelfb_ops = {
+#if 0
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
+#endif
        .fb_set_par = intel_fbdev_set_par,
+#if 0
        .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,
+#endif
        .fb_blank = intel_fbdev_blank,
+#if 0
        .fb_setcmap = drm_fb_helper_setcmap,
+#endif
        .fb_debug_enter = drm_fb_helper_debug_enter,
+#if 0
        .fb_debug_leave = drm_fb_helper_debug_leave,
-};
 #endif
+};
 
 static int intelfb_alloc(struct drm_fb_helper *helper,
                         struct drm_fb_helper_surface_size *sizes)
@@ -240,10 +248,9 @@ static int intelfb_create(struct drm_fb_helper *helper,
        info->depth = sizes->surface_bpp;
        info->paddr = dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj);
        info->is_vga_boot_display = vga_pci_is_boot_display(vga_dev);
-       info->vaddr =
-           (vm_offset_t)pmap_mapdev_attr(info->paddr,
-               sizes->surface_height * info->stride,
+       info->vaddr = (vm_offset_t)pmap_mapdev_attr(info->paddr, size,
                VM_MEMATTR_WRITE_COMBINING);
+       info->fbops = intelfb_ops;
 #else
        strcpy(info->fix.id, "inteldrmfb");
 
@@ -537,10 +544,8 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
 static void intel_fbdev_destroy(struct drm_device *dev,
                                struct intel_fbdev *ifbdev)
 {
-#if 0
        drm_fb_helper_unregister_fbi(&ifbdev->helper);
        drm_fb_helper_release_fbi(&ifbdev->helper);
-#endif
 
        drm_fb_helper_fini(&ifbdev->helper);
 
index d8f689e..8b4a17e 100644 (file)
@@ -144,10 +144,6 @@ struct drm_fb_helper {
         * does not require ASYNC commits).
         */
        bool atomic;
-
-#ifdef __DragonFly__
-       struct task fb_mode_task;
-#endif
 };
 
 #define CONFIG_DRM_FBDEV_EMULATION 1
index acf440f..196bf18 100644 (file)
@@ -45,21 +45,27 @@ struct radeon_fbdev {
        struct radeon_device *rdev;
 };
 
-#ifdef DUMBBELL_WIP
 static struct fb_ops radeonfb_ops = {
+#if 0
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
+#endif
        .fb_set_par = drm_fb_helper_set_par,
+#if 0
        .fb_fillrect = cfb_fillrect,
        .fb_copyarea = cfb_copyarea,
        .fb_imageblit = cfb_imageblit,
        .fb_pan_display = drm_fb_helper_pan_display,
+#endif
        .fb_blank = drm_fb_helper_blank,
+#if 0
        .fb_setcmap = drm_fb_helper_setcmap,
+#endif
        .fb_debug_enter = drm_fb_helper_debug_enter,
+#if 0
        .fb_debug_leave = drm_fb_helper_debug_leave,
+#endif
 };
-#endif /* DUMBBELL_WIP */
 
 
 int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
@@ -249,6 +255,11 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        info->stride = fb->pitches[0];
        info->depth = sizes->surface_bpp;
        info->is_vga_boot_display = vga_pci_is_boot_display(vga_dev);
+#ifdef __DragonFly__
+       info->fbops = radeonfb_ops;
+#else
+       info->fbops = &radeonfb_ops;
+#endif
 
        DRM_INFO("fb mappable at 0x%jX\n",  info->paddr);
        DRM_INFO("vram apper at 0x%lX\n",  (unsigned long)rdev->mc.aper_base);
@@ -279,27 +290,13 @@ void radeon_fb_output_poll_changed(struct radeon_device *rdev)
 
 static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
 {
-       /* XXX unconfigure fb_info from syscons */
-#ifdef DUMBBELL_WIP
-       struct fb_info *info;
-#endif /* DUMBBELL_WIP */
        struct radeon_framebuffer *rfb = &rfbdev->rfb;
 
-#ifdef DUMBBELL_WIP
-       if (rfbdev->helper.fbdev) {
-               info = rfbdev->helper.fbdev;
-
-               unregister_framebuffer(info);
-               if (info->cmap.len)
-                       fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
-#endif /* DUMBBELL_WIP */
+       drm_fb_helper_unregister_fbi(&rfbdev->helper);
+       drm_fb_helper_release_fbi(&rfbdev->helper);
 
        if (rfb->obj) {
-               DRM_UNLOCK(dev); /* Work around lock recursion. dumbbell@ */
                radeonfb_destroy_pinned_object(rfb->obj);
-               DRM_LOCK(dev);
                rfb->obj = NULL;
        }
        drm_fb_helper_fini(&rfbdev->helper);
index 250cf1b..f1213c5 100644 (file)
@@ -433,7 +433,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
     if (scp == NULL)           /* tp == SC_MOUSE */
        return ENOIOCTL;
     adp = scp->sc->adp;
-    if (adp == NULL && scp->fbi == NULL)       /* shouldn't happen??? */
+    if (adp == NULL && scp->sc->fbi == NULL)   /* shouldn't happen??? */
        return ENODEV;
 
     lwkt_gettoken(&tty_token);
@@ -441,7 +441,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
 
     case CONS_CURRENTADP:      /* get current adapter index */
     case FBIO_ADAPTER:
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
            ret = ENODEV;
        } else {
            ret = fb_ioctl(adp, FBIO_ADAPTER, data);
@@ -451,7 +451,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
 
     case CONS_CURRENT:         /* get current adapter type */
     case FBIO_ADPTYPE:
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
            ret = ENODEV;
        } else {
            ret = fb_ioctl(adp, FBIO_ADPTYPE, data);
@@ -461,7 +461,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
 
     case CONS_ADPINFO:         /* adapter information */
     case FBIO_ADPINFO:
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
            lwkt_reltoken(&tty_token);
            return ENODEV;
        }
@@ -485,7 +485,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
 #ifndef SC_NO_MODE_CHANGE
     case CONS_SET:
     case FBIO_SETMODE:         /* set video mode */
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
                lwkt_reltoken(&tty_token);
                if (*(int *)data != 0)
                        return ENODEV;
@@ -513,7 +513,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
 
     case CONS_MODEINFO:                /* get mode information */
     case FBIO_MODEINFO:
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
            /* Fabricate some mode information for KMS framebuffer */
            video_info_t *vinfo = (video_info_t *)data;
            vinfo->vi_mode = 0;
@@ -536,7 +536,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
 
     case CONS_FINDMODE:                /* find a matching video mode */
     case FBIO_FINDMODE:
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
            ret = ENODEV;
        } else {
            ret = fb_ioctl(adp, FBIO_FINDMODE, data);
@@ -550,7 +550,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
            lwkt_reltoken(&tty_token);
            return ENODEV;      /* XXX */
        }
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
            lwkt_reltoken(&tty_token);
            return ENODEV;
        }
@@ -563,7 +563,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
            lwkt_reltoken(&tty_token);
            return ENODEV;      /* XXX */
        }
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
            ret = ENODEV;
        } else {
            ret = fb_ioctl(adp, FBIO_GETWINORG, data);
@@ -579,7 +579,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
            lwkt_reltoken(&tty_token);
            return ENODEV;      /* XXX */
        }
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
            ret = ENODEV;
        } else {
            ret = fb_ioctl(adp, cmd, data);
@@ -604,7 +604,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
            lwkt_reltoken(&tty_token);
            return ENODEV;      /* XXX */
        }
-       if (scp->fbi != NULL) {
+       if (scp->sc->fbi != NULL) {
            ret = ENODEV;
        } else {
            ret = fb_ioctl(adp, cmd, data);
@@ -626,7 +626,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
            /* restore fonts & palette ! */
 #if 0
 #ifndef SC_NO_FONT_LOADING
-           if (scp->fbi == NULL && ISFONTAVAIL(adp->va_flags)
+           if (scp->sc->fbi == NULL && ISFONTAVAIL(adp->va_flags)
                && !(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) {
                /*
                 * FONT KLUDGE
@@ -643,12 +643,12 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
 #endif
 
 #ifndef SC_NO_PALETTE_LOADING
-           if (scp->fbi == NULL)
+           if (scp->sc->fbi == NULL)
                load_palette(adp, scp->sc->palette);
 #endif
 
            /* move hardware cursor out of the way */
-           if (scp->fbi == NULL)
+           if (scp->sc->fbi == NULL)
                (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
            /* FALL THROUGH */
 
@@ -683,7 +683,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
                lwkt_reltoken(&tty_token);
                return EINVAL;
             }
-           if (scp->fbi != NULL) {
+           if (scp->sc->fbi != NULL) {
                lwkt_reltoken(&tty_token);
                return ENODEV;
            }
@@ -732,7 +732,7 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
 
 #ifdef SC_PIXEL_MODE
     case KDRASTER:             /* set pixel (raster) display mode */
-       if (scp->fbi != NULL || ISUNKNOWNSC(scp) || ISTEXTSC(scp)) {
+       if (scp->sc->fbi != NULL || ISUNKNOWNSC(scp) || ISTEXTSC(scp)) {
            lwkt_reltoken(&tty_token);
            return ENODEV;
        }
@@ -834,11 +834,11 @@ sc_update_render(scr_stat *scp)
        if (scp->rndr == NULL)
                return;
 
-       if (scp->fbi == scp->sc->fbi)
+       if (scp->fbi_generation == scp->sc->fbi_generation)
                return;
 
        crit_enter();
-       scp->fbi = scp->sc->fbi;
+       scp->fbi_generation = scp->sc->fbi_generation;
        /* Needed in case we are implicitly leaving PIXEL_MODE here */
        if (scp->model != V_INFO_MM_OTHER)
                scp->model = V_INFO_MM_TEXT;
@@ -887,8 +887,8 @@ sc_update_render(scr_stat *scp)
        }
        /* Implicitly leave PIXEL_MODE, but stay in UNKNOWN mode */
        scp->status &= ~(PIXEL_MODE | MOUSE_VISIBLE);
-       scp->xpixel = scp->fbi->width;
-       scp->ypixel = scp->fbi->height;
+       scp->xpixel = scp->sc->fbi->width;
+       scp->ypixel = scp->sc->fbi->height;
 
        /*
         * Assume square pixels for now
index d1c0d4c..d0f901e 100644 (file)
@@ -46,6 +46,7 @@
 #include <sys/priv.h>
 #include <sys/signalvar.h>
 #include <sys/sysctl.h>
+#include <sys/taskqueue.h>
 #include <sys/tty.h>
 #include <sys/kernel.h>
 #include <sys/cons.h>
@@ -126,6 +127,12 @@ static     void            none_saver(sc_softc_t *sc, int blank) { }
 static void            (*current_saver)(sc_softc_t *, int) = none_saver;
 #endif
 
+/*
+ * Lock for asynchronous screen update thread, needed to safely modify the
+ * framebuffer information.
+ */
+static struct lock     sc_asynctd_lk;
+
 #if !defined(SC_NO_FONT_LOADING) && defined(SC_DFLT_FONT)
 #include "font.h"
 #endif
@@ -180,6 +187,8 @@ static int and_region(int *s1, int *e1, int s2, int e2);
 static void scrn_update(scr_stat *scp, int show_cursor, int flags);
 static void scrn_update_thread(void *arg);
 
+static void sc_fb_set_par(void *context, int pending);
+
 #if NSPLASH > 0
 static int scsplash_callback(int event, void *arg);
 static void scsplash_saver(sc_softc_t *sc, int show);
@@ -323,21 +332,87 @@ register_framebuffer(struct fb_info *info)
        }
 
        /* Ignore this framebuffer if we already switched to KMS framebuffer */
-       if (sc->fbi != NULL && sc->fbi != &efi_fb_info) {
+       if (sc->fbi != NULL && sc->fbi != &efi_fb_info &&
+           sc->fbi != sc->dummy_fb_info) {
                lwkt_reltoken(&tty_token);
                return 0;
        }
 
+       if (sc->fb_set_par_task == NULL) {
+               sc->fb_set_par_task = kmalloc(sizeof(struct task),
+                   M_SYSCONS, M_WAITOK | M_ZERO);
+       }
+       TASK_INIT(sc->fb_set_par_task, 0, sc_fb_set_par, sc);
+
+       /*
+        * Make sure that console messages don't interfere too much with
+        * modesetting.
+        */
+       atomic_add_int(&sc->videoio_in_progress, 1);
+
+       /* Lock against synchronous and asynchronous screen updates */
+       lockmgr(&sc_asynctd_lk, LK_EXCLUSIVE);
+       syscons_lock();
        sc->fbi = info;
+       sc->fbi_generation++;
+       syscons_unlock();
 
        sc_update_render(sc->cur_scp);
-       if (sc->fbi->restore != NULL)
-           sc->fbi->restore(sc->fbi);
+       if (info->fbops.fb_set_par != NULL)
+               info->fbops.fb_set_par(info);
+       atomic_add_int(&sc->videoio_in_progress, -1);
 
+       lockmgr(&sc_asynctd_lk, LK_RELEASE);
        lwkt_reltoken(&tty_token);
        return 0;
 }
 
+void
+unregister_framebuffer(struct fb_info *info)
+{
+       sc_softc_t *sc;
+
+       lwkt_gettoken(&tty_token);
+       sc = sc_get_softc(0, (sc_console_unit == 0) ? SC_KERNEL_CONSOLE : 0);
+       if (sc == NULL) {
+               lwkt_reltoken(&tty_token);
+               kprintf("%s: sc_get_softc(%d, %d) returned NULL\n", __func__,
+                   0, (sc_console_unit == 0) ? SC_KERNEL_CONSOLE : 0);
+               return;
+       }
+
+       if (sc->fbi != info) {
+               lwkt_reltoken(&tty_token);
+               return;
+       }
+
+       if (sc->fb_set_par_task != NULL &&
+           taskqueue_cancel(taskqueue_thread[0], sc->fb_set_par_task, NULL)) {
+               taskqueue_drain(taskqueue_thread[0], sc->fb_set_par_task);
+       }
+
+       if (sc->dummy_fb_info == NULL) {
+               sc->dummy_fb_info = kmalloc(sizeof(struct fb_info),
+                   M_SYSCONS, M_WAITOK | M_ZERO);
+       } else {
+               memset(sc->dummy_fb_info, 0, sizeof(struct fb_info));
+       }
+       *sc->dummy_fb_info = *sc->fbi;
+       sc->dummy_fb_info->vaddr = 0;
+       sc->dummy_fb_info->fbops.fb_set_par = NULL;
+       sc->dummy_fb_info->fbops.fb_blank = NULL;
+       sc->dummy_fb_info->fbops.fb_debug_enter = NULL;
+
+       /* Lock against synchronous and asynchronous screen updates */
+       lockmgr(&sc_asynctd_lk, LK_EXCLUSIVE);
+       syscons_lock();
+       sc->fbi = sc->dummy_fb_info;
+       syscons_unlock();
+       lockmgr(&sc_asynctd_lk, LK_RELEASE);
+
+       lwkt_reltoken(&tty_token);
+}
+
 void
 sc_font_scale(scr_stat *scp, int max_cols, int max_rows)
 {
@@ -2270,10 +2345,26 @@ scrn_update_thread(void *arg)
                                tsleep(&scp->asynctd, PINTERLOCKED, "wait", 0);
                }
                scp->queue_update_td = 0;
+               lockmgr(&sc_asynctd_lk, LK_EXCLUSIVE);
                atomic_add_int(&scp->sc->videoio_in_progress, 1);
                scrn_update(scp, scp->show_cursor, SCRN_BULKUNLOCK);
                atomic_add_int(&scp->sc->videoio_in_progress, -1);
+               lockmgr(&sc_asynctd_lk, LK_RELEASE);
+       }
+}
+
+static void
+sc_fb_set_par(void *context, int pending)
+{
+       sc_softc_t *sc = context;
+       scr_stat *scp = sc->cur_scp;
+
+       lwkt_gettoken(&tty_token);
+       if (ISTEXTSC(scp) &&
+           sc->fbi != NULL && sc->fbi->fbops.fb_set_par != NULL) {
+               sc->fbi->fbops.fb_set_par(sc->fbi);
        }
+       lwkt_reltoken(&tty_token);
 }
 
 #if NSPLASH > 0
@@ -2418,12 +2509,12 @@ set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border)
     }
     scp->mode = mode;
     if (set_mode(scp) == 0) {
-       if (scp->fbi == NULL &&
+       if (scp->sc->fbi == NULL &&
            scp->sc->adp->va_info.vi_flags & V_INFO_GRAPHICS) {
            scp->status |= GRAPHICS_MODE;
        }
 #ifndef SC_NO_PALETTE_LOADING
-       if (scp->fbi == NULL && pal != NULL)
+       if (scp->sc->fbi == NULL && pal != NULL)
            load_palette(scp->sc->adp, pal);
 #endif
        sc_set_border(scp, border);
@@ -2462,7 +2553,7 @@ restore_scrn_saver_mode(scr_stat *scp, int changemode)
     }
     if (set_mode(scp) == 0) {
 #ifndef SC_NO_PALETTE_LOADING
-       if (scp->fbi == NULL)
+       if (scp->sc->fbi == NULL)
            load_palette(scp->sc->adp, scp->sc->palette);
 #endif
        --scrn_blanked;
@@ -2869,8 +2960,19 @@ exchange_scr(sc_softc_t *sc)
     update_kbd_state(scp, scp->status, LOCK_MASK, TRUE);
 
     mark_all(scp);
-    if (scp->sc->fbi != NULL && scp->sc->fbi->restore != NULL)
-       scp->sc->fbi->restore(scp->sc->fbi);
+
+    /*
+     * Restore DRM framebuffer console mode if necessary.
+     * Especially avoid modesetting when switching to a vt which is in
+     * graphics mode, because the fb_set_par() from the taskqueue thread
+     * might race with the modesetting ioctl from the userland application.
+     */
+    if (ISTEXTSC(scp) && !ISTEXTSC(sc->old_scp) &&
+       sc->fbi != NULL && sc->fbi->fbops.fb_set_par != NULL &&
+       sc->fb_set_par_task != NULL) {
+       taskqueue_enqueue(taskqueue_thread[0], sc->fb_set_par_task);
+    }
+
     lwkt_reltoken(&tty_token);
 }
 
@@ -2997,6 +3099,7 @@ scinit(int unit, int flags)
        /* Don't replace already registered drm framebuffer here */
        if (sc->fbi == NULL) {
            sc->fbi = &efi_fb_info;
+           sc->fbi_generation++;
        }
     } else if (sc->adapter >= 0) {
        vid_release(sc->adp, (void *)&sc->adapter);
@@ -3085,7 +3188,7 @@ scinit(int unit, int flags)
        sc->cur_scp = scp;
 
        /* copy screen to temporary buffer */
-       if (scp->fbi == NULL) {
+       if (scp->sc->fbi == NULL) {
            sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
                        (void *)scp->sc->adp->va_window, FALSE);
            if (ISTEXTSC(scp))
@@ -3360,16 +3463,16 @@ init_scp(sc_softc_t *sc, int vty, scr_stat *scp)
     scp->sc = sc;
     scp->status = 0;
     scp->mode = sc->initial_mode;
-    scp->fbi = sc->fbi;
+    scp->fbi_generation = sc->fbi_generation;
     callout_init_mp(&scp->blink_screen_ch);
-    if (scp->fbi == NULL) {
+    if (scp->sc->fbi == NULL) {
        lwkt_gettoken(&tty_token);
        (*vidsw[sc->adapter]->get_info)(sc->adp, scp->mode, &info);
        lwkt_reltoken(&tty_token);
     }
-    if (scp->fbi != NULL) {
-       scp->xpixel = scp->fbi->width;
-       scp->ypixel = scp->fbi->height;
+    if (scp->sc->fbi != NULL) {
+       scp->xpixel = sc->fbi->width;
+       scp->ypixel = sc->fbi->height;
        scp->font_width = 8;
        scp->font_height = 16;
 
index 8dad3a9..83e69ac 100644 (file)
@@ -199,7 +199,10 @@ typedef struct sc_softc {
        struct video_adapter *adp;
        int             initial_mode;           /* initial video mode */
 
+       uint64_t        fbi_generation;         /* increment on fbi update */
        struct fb_info  *fbi;
+       struct fb_info  *dummy_fb_info;
+       struct task     *fb_set_par_task;
 
        int             first_vty;
        int             vtys;
@@ -255,7 +258,7 @@ typedef struct scr_stat {
        struct sc_rndr_sw *rndr;                /* renderer */
        sc_vtb_t        scr;
        sc_vtb_t        vtb;
-       struct fb_info  *fbi;
+       uint64_t        fbi_generation;         /* track fb_info updates */
 
        int             xpos;                   /* current X position */
        int             ypos;                   /* current Y position */
index bf98f7f..838f1a7 100644 (file)
@@ -5,6 +5,14 @@
 
 #include <sys/bus.h>
 
+struct fb_info;
+
+struct fb_ops {
+       int (*fb_set_par)(struct fb_info *);
+       int (*fb_blank)(int, struct fb_info *);
+       int (*fb_debug_enter)(struct fb_info *);
+};
+
 struct fb_info {
        vm_offset_t vaddr;
        vm_paddr_t paddr;
@@ -14,13 +22,14 @@ struct fb_info {
        uint16_t depth;
        int is_vga_boot_display;
        void *par;
-       void (*restore)(struct fb_info *);
+       struct fb_ops fbops;
        device_t device;
 };
 
 int probe_efi_fb(int early);
 
 int register_framebuffer(struct fb_info *fb_info);
+void unregister_framebuffer(struct fb_info *fb_info);
 
 extern struct fb_info efi_fb_info;
 
index bdbcb97..669dd37 100644 (file)
@@ -1845,7 +1845,9 @@ probe_efi_fb(int early)
        } else {
                efi_fb_init_vaddr(0);
        }
-       efi_fb_info.restore = NULL;
+       efi_fb_info.fbops.fb_set_par = NULL;
+       efi_fb_info.fbops.fb_blank = NULL;
+       efi_fb_info.fbops.fb_debug_enter = NULL;
        efi_fb_info.device = NULL;
 
        return 0;