From 5e9e979fae229480d1a4af4f247c0251cb2852f9 Mon Sep 17 00:00:00 2001 From: Fedora X Ninjas Date: Fri, 12 Apr 2013 10:16:21 +1000 Subject: [PATCH] fix GPU hotplugging while VT switched. Backports 3 patches from upstream into one. --- hw/xfree86/common/xf86.h | 1 + hw/xfree86/common/xf86Events.c | 15 +++++++++- hw/xfree86/common/xf86Init.c | 2 +- hw/xfree86/common/xf86Xinput.c | 2 +- hw/xfree86/common/xf86platformBus.c | 19 +++++++++++++ hw/xfree86/common/xf86platformBus.h | 4 +++ hw/xfree86/os-support/linux/lnx_platform.c | 45 ++++++++++++++++++++++++++---- hw/xfree86/os-support/solaris/sun_init.c | 2 +- hw/xfree86/os-support/xf86_OSproc.h | 3 ++ include/hotplug.h | 1 + 10 files changed, 85 insertions(+), 9 deletions(-) diff --git a/hw/xfree86/common/xf86.h b/hw/xfree86/common/xf86.h index 1514c26..828d958 100644 --- a/hw/xfree86/common/xf86.h +++ b/hw/xfree86/common/xf86.h @@ -243,6 +243,7 @@ extern _X_EXPORT void xf86InterceptSigIll(void (*sigillhandler) (void)); extern _X_EXPORT Bool xf86EnableVTSwitch(Bool new); extern _X_EXPORT void xf86ProcessActionEvent(ActionEvent action, void *arg); extern _X_EXPORT void xf86PrintBacktrace(void); +extern _X_EXPORT Bool xf86VTOwner(void); /* xf86Helper.c */ diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c index d92174e..7a35250 100644 --- a/hw/xfree86/common/xf86Events.c +++ b/hw/xfree86/common/xf86Events.c @@ -84,6 +84,7 @@ #include "dpmsproc.h" #endif +#include "xf86platformBus.h" /* * This is a toggling variable: * FALSE = No VT switching keys have been pressed last time around @@ -428,7 +429,7 @@ xf86VTSwitch(void) * Since all screens are currently all in the same state it is sufficient * check the first. This might change in future. */ - if (xf86Screens[0]->vtSema) { + if (xf86VTOwner()) { DebugF("xf86VTSwitch: Leaving, xf86Exiting is %s\n", BOOLTOSTRING((dispatchException & DE_TERMINATE) ? TRUE : FALSE)); @@ -561,6 +562,9 @@ xf86VTSwitch(void) for (ih = InputHandlers; ih; ih = ih->next) xf86EnableInputHandler(ih); + /* check for any new output devices */ + xf86platformVTProbe(); + OsReleaseSIGIO(); } } @@ -769,3 +773,12 @@ DDXRingBell(int volume, int pitch, int duration) { xf86OSRingBell(volume, pitch, duration); } + +Bool +xf86VTOwner(void) +{ + /* at system startup xf86Screens[0] won't be set - but we will own the VT */ + if (xf86NumScreens == 0) + return TRUE; + return xf86Screens[0]->vtSema; +} diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c index a34d7c1..142ce95 100644 --- a/hw/xfree86/common/xf86Init.c +++ b/hw/xfree86/common/xf86Init.c @@ -829,7 +829,7 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv) if (serverGeneration != 1) { xf86Resetting = TRUE; /* All screens are in the same state, so just check the first */ - if (!xf86Screens[0]->vtSema) { + if (!xf86VTOwner()) { #ifdef HAS_USL_VTS ioctl(xf86Info.consoleFd, VT_RELDISP, VT_ACKACQ); #endif diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index bee407b..26c03c6 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -870,7 +870,7 @@ xf86NewInputDevice(InputInfoPtr pInfo, DeviceIntPtr *pdev, BOOL enable) } /* Enable it if it's properly initialised and we're currently in the VT */ - if (enable && dev->inited && dev->startup && xf86Screens[0]->vtSema) { + if (enable && dev->inited && dev->startup && xf86VTOwner()) { OsBlockSignals(); EnableDevice(dev, TRUE); if (!dev->enabled) { diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c index 4ccb005..0b0f846 100644 --- a/hw/xfree86/common/xf86platformBus.c +++ b/hw/xfree86/common/xf86platformBus.c @@ -114,6 +114,11 @@ xf86_get_platform_device_attrib(struct xf86_platform_device *device, int attrib_ return NULL; } +Bool +xf86_get_platform_device_unowned(int index) +{ + return xf86_platform_devices[index].attribs->unowned; +} /* * xf86IsPrimaryPlatform() -- return TRUE if primary device @@ -502,4 +507,18 @@ xf86platformRemoveDevice(int index) out: return; } + +/* called on return from VT switch to find any new devices */ +void xf86platformVTProbe(void) +{ + int i; + + for (i = 0; i < xf86_num_platform_devices; i++) { + if (xf86_platform_devices[i].attribs->unowned == FALSE) + continue; + + xf86_platform_devices[i].attribs->unowned = FALSE; + xf86PlatformReprobeDevice(i, xf86_platform_devices[i].attribs); + } +} #endif diff --git a/hw/xfree86/common/xf86platformBus.h b/hw/xfree86/common/xf86platformBus.h index 49afc24..4e17578 100644 --- a/hw/xfree86/common/xf86platformBus.h +++ b/hw/xfree86/common/xf86platformBus.h @@ -46,6 +46,8 @@ extern int xf86_remove_platform_device(int dev_index); extern Bool xf86_add_platform_device_attrib(int index, int attrib_id, char *attrib_str); +extern Bool +xf86_get_platform_device_unowned(int index); extern int xf86platformAddDevice(int index); @@ -59,6 +61,8 @@ xf86PlatformDeviceCheckBusID(struct xf86_platform_device *device, const char *bu extern _X_EXPORT int xf86PlatformMatchDriver(char *matches[], int nmatches); + +extern void xf86platformVTProbe(void); #endif #endif diff --git a/hw/xfree86/os-support/linux/lnx_platform.c b/hw/xfree86/os-support/linux/lnx_platform.c index 76f5583..21768ee 100644 --- a/hw/xfree86/os-support/linux/lnx_platform.c +++ b/hw/xfree86/os-support/linux/lnx_platform.c @@ -18,7 +18,7 @@ #include "hotplug.h" static Bool -get_drm_info(struct OdevAttributes *attribs, char *path) +get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index) { drmSetVersion sv; char *buf; @@ -37,10 +37,14 @@ get_drm_info(struct OdevAttributes *attribs, char *path) return FALSE; } - xf86_add_platform_device(attribs); + /* for a delayed probe we've already added the device */ + if (delayed_index == -1) { + xf86_add_platform_device(attribs); + delayed_index = xf86_num_platform_devices - 1; + } buf = drmGetBusid(fd); - xf86_add_platform_device_attrib(xf86_num_platform_devices - 1, + xf86_add_platform_device_attrib(delayed_index, ODEV_ATTRIB_BUSID, buf); drmFreeBusid(buf); close(fd); @@ -89,6 +93,23 @@ xf86PlatformDeviceCheckBusID(struct xf86_platform_device *device, const char *bu } void +xf86PlatformReprobeDevice(int index, struct OdevAttributes *attribs) +{ + Bool ret; + char *dpath; + dpath = xf86_get_platform_attrib(index, ODEV_ATTRIB_PATH); + + ret = get_drm_info(attribs, dpath, index); + if (ret == FALSE) { + xf86_remove_platform_device(index); + return; + } + ret = xf86platformAddDevice(index); + if (ret == -1) + xf86_remove_platform_device(index); +} + +void xf86PlatformDeviceProbe(struct OdevAttributes *attribs) { struct OdevAttribute *attrib; @@ -119,7 +140,15 @@ xf86PlatformDeviceProbe(struct OdevAttributes *attribs) LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n", path); - ret = get_drm_info(attribs, path); + if (!xf86VTOwner()) { + /* if we don't currently own the VT then don't probe the device, + just mark it as unowned for later use */ + attribs->unowned = TRUE; + xf86_add_platform_device(attribs); + return; + } + + ret = get_drm_info(attribs, path, -1); if (ret == FALSE) goto out_free; @@ -138,6 +167,9 @@ void NewGPUDeviceRequest(struct OdevAttributes *attribs) if (old_num == xf86_num_platform_devices) return; + if (xf86_get_platform_device_unowned(xf86_num_platform_devices - 1) == TRUE) + return; + ret = xf86platformAddDevice(xf86_num_platform_devices-1); if (ret == -1) xf86_remove_platform_device(xf86_num_platform_devices-1); @@ -171,7 +203,10 @@ void DeleteGPUDeviceRequest(struct OdevAttributes *attribs) ErrorF("xf86: remove device %d %s\n", index, syspath); - xf86platformRemoveDevice(index); + if (xf86_get_platform_device_unowned(index) == TRUE) + xf86_remove_platform_device(index); + else + xf86platformRemoveDevice(index); out: config_odev_free_attribute_list(attribs); } diff --git a/hw/xfree86/os-support/solaris/sun_init.c b/hw/xfree86/os-support/solaris/sun_init.c index 4b75a98..68527a5 100644 --- a/hw/xfree86/os-support/solaris/sun_init.c +++ b/hw/xfree86/os-support/solaris/sun_init.c @@ -274,7 +274,7 @@ xf86OpenConsole(void) * this is to make sure we don't continue until the activate * signal is received. */ - if (!xf86Screens[0]->vtSema) + if (!xf86VTOwner()) sleep(5); } #endif /* HAS_USL_VTS */ diff --git a/hw/xfree86/os-support/xf86_OSproc.h b/hw/xfree86/os-support/xf86_OSproc.h index ea2b16e..6be5946 100644 --- a/hw/xfree86/os-support/xf86_OSproc.h +++ b/hw/xfree86/os-support/xf86_OSproc.h @@ -223,6 +223,9 @@ extern _X_EXPORT void xf86InitVidMem(void); #include "hotplug.h" void xf86PlatformDeviceProbe(struct OdevAttributes *attribs); + +void +xf86PlatformReprobeDevice(int index, struct OdevAttributes *attribs); #endif _XFUNCPROTOEND diff --git a/include/hotplug.h b/include/hotplug.h index 2a95b45..29a22c4 100644 --- a/include/hotplug.h +++ b/include/hotplug.h @@ -40,6 +40,7 @@ struct OdevAttribute { struct OdevAttributes { struct xorg_list list; + Bool unowned; }; struct OdevAttributes * -- 1.8.2