Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 1 Mar 2015 12:54:23 +0000 (UTC)
From:      Jean-Sebastien Pedron <dumbbell@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r279488 - in head/sys: dev/drm2 dev/drm2/radeon dev/fb dev/vt dev/vt/hw/fb dev/vt/hw/vga sys
Message-ID:  <201503011254.t21CsNX1040293@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201503011254.t21CsNX1040293>