Author: dumbbell Date: Sun Mar 1 12:54:22 2015 New Revision: 279488 URL: https://svnweb.freebsd.org/changeset/base/279488
Log: vt(4): Add support to "downgrade" from eg. vt_fb to vt_vga The main purpose of this feature is to be able to unload a KMS driver. When going back from the current vt(4) backend to the previous backend, the previous backend is reinitialized with the special VDF_DOWNGRADE flag set. Then the current driver is terminated with the new "vd_fini" callback. In the case of vt_fb and vt_vga, this allows the former to pass the vgapci device vt_fb used to vt_vga so the device can be rePOSTed. Differential Revision: https://reviews.freebsd.org/D687 Modified: head/sys/dev/drm2/drm_fb_helper.c head/sys/dev/drm2/radeon/radeon_fb.c head/sys/dev/fb/fbd.c head/sys/dev/vt/hw/fb/vt_fb.c head/sys/dev/vt/hw/fb/vt_fb.h head/sys/dev/vt/hw/vga/vt_vga.c head/sys/dev/vt/vt.h head/sys/dev/vt/vt_core.c head/sys/sys/fbio.h Modified: head/sys/dev/drm2/drm_fb_helper.c ============================================================================== --- head/sys/dev/drm2/drm_fb_helper.c Sun Mar 1 12:47:36 2015 (r279487) +++ head/sys/dev/drm2/drm_fb_helper.c Sun Mar 1 12:54:22 2015 (r279488) @@ -937,19 +937,21 @@ int drm_fb_helper_single_fb_probe(struct info->fb_priv = sc; info->enter = &vt_kms_postswitch; + kdev = fb_helper->dev->device; + info->fb_video_dev = device_get_parent(kdev); + /* set the fb pointer */ for (i = 0; i < fb_helper->crtc_count; i++) { fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; } if (new_fb) { - device_t fbd; int ret; - kdev = fb_helper->dev->device; - fbd = device_add_child(kdev, "fbd", device_get_unit(kdev)); - if (fbd != NULL) - ret = device_probe_and_attach(fbd); + info->fb_fbd_dev = device_add_child(kdev, "fbd", + device_get_unit(kdev)); + if (info->fb_fbd_dev != NULL) + ret = device_probe_and_attach(info->fb_fbd_dev); else ret = ENODEV; #ifdef DEV_VT Modified: head/sys/dev/drm2/radeon/radeon_fb.c ============================================================================== --- head/sys/dev/drm2/radeon/radeon_fb.c Sun Mar 1 12:47:36 2015 (r279487) +++ head/sys/dev/drm2/radeon/radeon_fb.c Sun Mar 1 12:54:22 2015 (r279488) @@ -291,6 +291,8 @@ static int radeon_fbdev_destroy(struct d if (rfbdev->helper.fbdev) { info = rfbdev->helper.fbdev; + if (info->fb_fbd_dev != NULL) + device_delete_child(dev->device, info->fb_fbd_dev); free(info->fb_priv, DRM_MEM_KMS); free(info, DRM_MEM_KMS); } Modified: head/sys/dev/fb/fbd.c ============================================================================== --- head/sys/dev/fb/fbd.c Sun Mar 1 12:47:36 2015 (r279487) +++ head/sys/dev/fb/fbd.c Sun Mar 1 12:54:22 2015 (r279488) @@ -263,6 +263,8 @@ fbd_unregister(struct fb_info* info) LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) { if (entry->fb_info == info) { LIST_REMOVE(entry, fb_list); + if (LIST_EMPTY(&fb_list_head)) + vt_fb_detach(info); free(entry, M_DEVBUF); return (0); } Modified: head/sys/dev/vt/hw/fb/vt_fb.c ============================================================================== --- head/sys/dev/vt/hw/fb/vt_fb.c Sun Mar 1 12:47:36 2015 (r279487) +++ head/sys/dev/vt/hw/fb/vt_fb.c Sun Mar 1 12:54:22 2015 (r279488) @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); static struct vt_driver vt_fb_driver = { .vd_name = "fb", .vd_init = vt_fb_init, + .vd_fini = vt_fb_fini, .vd_blank = vt_fb_blank, .vd_bitblt_text = vt_fb_bitblt_text, .vd_bitblt_bmp = vt_fb_bitblt_bitmap, @@ -419,6 +420,7 @@ vt_fb_init(struct vt_device *vd) info = vd->vd_softc; vd->vd_height = info->fb_height; vd->vd_width = info->fb_width; + vd->vd_video_dev = info->fb_video_dev; if (info->fb_size == 0) return (CN_DEAD); @@ -442,6 +444,13 @@ vt_fb_init(struct vt_device *vd) return (CN_INTERNAL); } +void +vt_fb_fini(struct vt_device *vd, void *softc) +{ + + vd->vd_video_dev = NULL; +} + int vt_fb_attach(struct fb_info *info) { @@ -451,6 +460,15 @@ vt_fb_attach(struct fb_info *info) return (0); } +int +vt_fb_detach(struct fb_info *info) +{ + + vt_deallocate(&vt_fb_driver, info); + + return (0); +} + void vt_fb_suspend(struct vt_device *vd) { Modified: head/sys/dev/vt/hw/fb/vt_fb.h ============================================================================== --- head/sys/dev/vt/hw/fb/vt_fb.h Sun Mar 1 12:47:36 2015 (r279487) +++ head/sys/dev/vt/hw/fb/vt_fb.h Sun Mar 1 12:54:22 2015 (r279488) @@ -35,8 +35,10 @@ int vt_fb_attach(struct fb_info *info); void vt_fb_resume(struct vt_device *vd); void vt_fb_suspend(struct vt_device *vd); +int vt_fb_detach(struct fb_info *info); vd_init_t vt_fb_init; +vd_fini_t vt_fb_fini; vd_blank_t vt_fb_blank; vd_bitblt_text_t vt_fb_bitblt_text; vd_bitblt_bmp_t vt_fb_bitblt_bitmap; Modified: head/sys/dev/vt/hw/vga/vt_vga.c ============================================================================== --- head/sys/dev/vt/hw/vga/vt_vga.c Sun Mar 1 12:47:36 2015 (r279487) +++ head/sys/dev/vt/hw/vga/vt_vga.c Sun Mar 1 12:54:22 2015 (r279488) @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <dev/vt/vt.h> #include <dev/vt/hw/vga/vt_vga_reg.h> +#include <dev/pci/pcivar.h> #include <machine/bus.h> @@ -1213,6 +1214,9 @@ vga_init(struct vt_device *vd) sc = vd->vd_softc; textmode = 0; + if (vd->vd_flags & VDF_DOWNGRADE && vd->vd_video_dev != NULL) + vga_pci_repost(vd->vd_video_dev); + #if defined(__amd64__) || defined(__i386__) sc->vga_fb_tag = X86_BUS_SPACE_MEM; sc->vga_fb_handle = KERNBASE + VGA_MEM_BASE; Modified: head/sys/dev/vt/vt.h ============================================================================== --- head/sys/dev/vt/vt.h Sun Mar 1 12:47:36 2015 (r279487) +++ head/sys/dev/vt/vt.h Sun Mar 1 12:54:22 2015 (r279488) @@ -89,7 +89,8 @@ SYSCTL_INT(_kern_vt, OID_AUTO, _name, CT struct vt_driver; -void vt_allocate(struct vt_driver *, void *); +void vt_allocate(const struct vt_driver *, void *); +void vt_deallocate(const struct vt_driver *, void *); typedef unsigned int vt_axis_t; @@ -124,6 +125,9 @@ struct vt_device { struct vt_pastebuf vd_pastebuf; /* (?) Copy/paste buf. */ const struct vt_driver *vd_driver; /* (c) Graphics driver. */ void *vd_softc; /* (u) Driver data. */ + const struct vt_driver *vd_prev_driver;/* (?) Previous driver. */ + void *vd_prev_softc; /* (?) Previous driver data. */ + device_t vd_video_dev; /* (?) Video adapter. */ #ifndef SC_NO_CUTPASTE struct vt_mouse_cursor *vd_mcursor; /* (?) Cursor bitmap. */ term_color_t vd_mcursor_fg; /* (?) Cursor fg color. */ @@ -150,6 +154,7 @@ struct vt_device { #define VDF_INITIALIZED 0x20 /* vtterm_cnprobe already done. */ #define VDF_MOUSECURSOR 0x40 /* Mouse cursor visible. */ #define VDF_QUIET_BELL 0x80 /* Disable bell. */ +#define VDF_DOWNGRADE 0x8000 /* The driver is being downgraded. */ int vd_keyboard; /* (G) Keyboard index. */ unsigned int vd_kbstate; /* (?) Device unit. */ unsigned int vd_unit; /* (c) Device unit. */ @@ -301,6 +306,7 @@ struct vt_window { typedef int vd_init_t(struct vt_device *vd); typedef int vd_probe_t(struct vt_device *vd); +typedef void vd_fini_t(struct vt_device *vd, void *softc); typedef void vd_postswitch_t(struct vt_device *vd); typedef void vd_blank_t(struct vt_device *vd, term_color_t color); typedef void vd_bitblt_text_t(struct vt_device *vd, const struct vt_window *vw, @@ -323,6 +329,7 @@ struct vt_driver { /* Console attachment. */ vd_probe_t *vd_probe; vd_init_t *vd_init; + vd_fini_t *vd_fini; /* Drawing. */ vd_blank_t *vd_blank; Modified: head/sys/dev/vt/vt_core.c ============================================================================== --- head/sys/dev/vt/vt_core.c Sun Mar 1 12:47:36 2015 (r279487) +++ head/sys/dev/vt/vt_core.c Sun Mar 1 12:54:22 2015 (r279488) @@ -180,6 +180,8 @@ static struct vt_window vt_conswindow; static struct vt_device vt_consdev = { .vd_driver = NULL, .vd_softc = NULL, + .vd_prev_driver = NULL, + .vd_prev_softc = NULL, .vd_flags = VDF_INVALID, .vd_windows = { [VT_CONSWINDOW] = &vt_conswindow, }, .vd_curwindow = &vt_conswindow, @@ -2598,31 +2600,11 @@ vt_resize(struct vt_device *vd) } } -void -vt_allocate(struct vt_driver *drv, void *softc) +static void +vt_replace_backend(const struct vt_driver *drv, void *softc) { struct vt_device *vd; - if (!vty_enabled(VTY_VT)) - return; - - if (main_vd->vd_driver == NULL) { - main_vd->vd_driver = drv; - printf("VT: initialize with new VT driver \"%s\".\n", - drv->vd_name); - } else { - /* - * Check if have rights to replace current driver. For example: - * it is bad idea to replace KMS driver with generic VGA one. - */ - if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { - printf("VT: Driver priority %d too low. Current %d\n ", - drv->vd_priority, main_vd->vd_driver->vd_priority); - return; - } - printf("VT: Replacing driver \"%s\" with new \"%s\".\n", - main_vd->vd_driver->vd_name, drv->vd_name); - } vd = main_vd; if (vd->vd_flags & VDF_ASYNC) { @@ -2644,9 +2626,44 @@ vt_allocate(struct vt_driver *drv, void VT_LOCK(vd); vd->vd_flags &= ~VDF_TEXTMODE; - vd->vd_driver = drv; - vd->vd_softc = softc; - vd->vd_driver->vd_init(vd); + if (drv != NULL) { + /* + * We want to upgrade from the current driver to the + * given driver. + */ + + vd->vd_prev_driver = vd->vd_driver; + vd->vd_prev_softc = vd->vd_softc; + vd->vd_driver = drv; + vd->vd_softc = softc; + + vd->vd_driver->vd_init(vd); + } else if (vd->vd_prev_driver != NULL && vd->vd_prev_softc != NULL) { + /* + * No driver given: we want to downgrade to the previous + * driver. + */ + const struct vt_driver *old_drv; + void *old_softc; + + old_drv = vd->vd_driver; + old_softc = vd->vd_softc; + + vd->vd_driver = vd->vd_prev_driver; + vd->vd_softc = vd->vd_prev_softc; + vd->vd_prev_driver = NULL; + vd->vd_prev_softc = NULL; + + vd->vd_flags |= VDF_DOWNGRADE; + + vd->vd_driver->vd_init(vd); + + if (old_drv->vd_fini) + old_drv->vd_fini(vd, old_softc); + + vd->vd_flags &= ~VDF_DOWNGRADE; + } + VT_UNLOCK(vd); /* Update windows sizes and initialize last items. */ @@ -2692,6 +2709,52 @@ vt_resume_handler(void *priv) } void +vt_allocate(const struct vt_driver *drv, void *softc) +{ + + if (!vty_enabled(VTY_VT)) + return; + + if (main_vd->vd_driver == NULL) { + main_vd->vd_driver = drv; + printf("VT: initialize with new VT driver \"%s\".\n", + drv->vd_name); + } else { + /* + * Check if have rights to replace current driver. For example: + * it is bad idea to replace KMS driver with generic VGA one. + */ + if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { + printf("VT: Driver priority %d too low. Current %d\n ", + drv->vd_priority, main_vd->vd_driver->vd_priority); + return; + } + printf("VT: Replacing driver \"%s\" with new \"%s\".\n", + main_vd->vd_driver->vd_name, drv->vd_name); + } + + vt_replace_backend(drv, softc); +} + +void +vt_deallocate(const struct vt_driver *drv, void *softc) +{ + + if (!vty_enabled(VTY_VT)) + return; + + if (main_vd->vd_prev_driver == NULL || + main_vd->vd_driver != drv || + main_vd->vd_softc != softc) + return; + + printf("VT: Switching back from \"%s\" to \"%s\".\n", + main_vd->vd_driver->vd_name, main_vd->vd_prev_driver->vd_name); + + vt_replace_backend(NULL, NULL); +} + +void vt_suspend(struct vt_device *vd) { int error; Modified: head/sys/sys/fbio.h ============================================================================== --- head/sys/sys/fbio.h Sun Mar 1 12:47:36 2015 (r279487) +++ head/sys/sys/fbio.h Sun Mar 1 12:54:22 2015 (r279488) @@ -128,6 +128,9 @@ struct fb_info { struct cdev *fb_cdev; + device_t fb_fbd_dev; /* "fbd" device. */ + device_t fb_video_dev; /* Video adapter. */ + fb_enter_t *enter; fb_leave_t *leave; fb_setblankmode_t *setblankmode; _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"