summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@arm.linux.org.uk>2015-10-27 16:12:10 +0000
committerRussell King <rmk@arm.linux.org.uk>2015-11-08 20:09:05 +0000
commit3b6f36cfdc4a190ec636478134810e9cc77d6e0c (patch)
tree778e9fc775383a6cf5b8cb05fe1257eaef11590b
parent33d263ad7d77dd08cc1bc426ce90aeff16834103 (diff)
src: add support for Xorg platform bus and non-root servers
Add support for the Xorg platform bus DRM device discovery, which allows DDX to work on systems that run the X server as a non-root user. This adapts the KMS device only to this new model. This is made more complex by bugs in the X server: the X server proceeds to call the legacy probe method even after screens have been discovered via the platformProbe method when the last device to be probed fails (eg, due to the last device being a GPU device.) We work around that by always opening the DRM device at probe time, and issuing a SetVersion call, which causes subsequent probe attempts to fail. If we are running on a server which passes us the DRM device's file descriptor, or a server running non-root, we must not attempt to drop and regain the DRM master status ourselves; this will be managed for us by the X server and other system components. Signed-off-by: Russell King <rmk@arm.linux.org.uk>
-rw-r--r--src/armada_drm.c79
-rw-r--r--src/armada_module.c177
-rw-r--r--src/common_drm.c90
-rw-r--r--src/common_drm.h14
4 files changed, 285 insertions, 75 deletions
diff --git a/src/armada_drm.c b/src/armada_drm.c
index 585e285..14de490 100644
--- a/src/armada_drm.c
+++ b/src/armada_drm.c
@@ -33,9 +33,6 @@
#define CURSOR_MAX_WIDTH 64
#define CURSOR_MAX_HEIGHT 32
-#define DRM_MODULE_NAMES "armada-drm", "imx-drm"
-#define DRM_DEFAULT_BUS_ID NULL
-
const OptionInfoRec armada_drm_options[] = {
{ OPTION_XV_ACCEL, "XvAccel", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_XV_PREFEROVL, "XvPreferOverlay", OPTV_BOOLEAN, {0}, TRUE },
@@ -440,7 +437,7 @@ static Bool armada_drm_ScreenInit(SCREEN_INIT_ARGS_DECL)
Bool use_kms_bo;
Bool ret;
- if (drmSetMaster(drm->fd)) {
+ if (!common_drm_get_master(drm->dev)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"[drm] set master failed: %s\n", strerror(errno));
return FALSE;
@@ -572,29 +569,13 @@ static int armada_get_cap(int fd, uint64_t cap, uint64_t *val, int scrnIndex,
return err;
}
-static const char *drm_module_names[] = { DRM_MODULE_NAMES };
-
-static Bool armada_drm_open_master(ScrnInfoPtr pScrn)
+static Bool armada_drm_alloc(ScrnInfoPtr pScrn,
+ struct common_drm_device *drm_dev)
{
struct all_drm_info *drm;
- EntityInfoPtr pEnt;
- drmSetVersion sv;
- const char *busid = DRM_DEFAULT_BUS_ID;
uint64_t val;
- unsigned i;
int err;
- pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
- if (pEnt) {
- if (pEnt->device->busID)
- busid = pEnt->device->busID;
- free(pEnt);
- }
-
- if (busid)
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using BusID \"%s\"\n",
- busid);
-
drm = calloc(1, sizeof *drm);
if (!drm)
return FALSE;
@@ -602,59 +583,32 @@ static Bool armada_drm_open_master(ScrnInfoPtr pScrn)
drm->common.cursor_max_width = CURSOR_MAX_WIDTH;
drm->common.cursor_max_height = CURSOR_MAX_HEIGHT;
drm->common.private = &drm->armada;
-
- for (i = 0; i < ARRAY_SIZE(drm_module_names); i++) {
- drm->common.fd = drmOpen(drm_module_names[i], busid);
- if (drm->common.fd >= 0)
- break;
- }
-
- if (drm->common.fd < 0) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "[drm] Failed to open DRM device for %s: %s\n",
- busid, strerror(errno));
- goto err_free;
- }
-
- /*
- * Check that what we opened was a master or a master-capable FD
- * by setting the version of the interface we'll use to talk to it.
- */
- sv.drm_di_major = 1;
- sv.drm_di_minor = 1;
- sv.drm_dd_major = -1;
- sv.drm_dd_minor = -1;
- err = drmSetInterfaceVersion(drm->common.fd, &sv);
- if (err) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "[drm] failed to set DRM interface version: %s\n",
- strerror(errno));
- goto err_drm_close;
- }
+ drm->common.fd = drm_dev->fd;
+ drm->common.dev = drm_dev;
if (armada_get_cap(drm->common.fd, DRM_CAP_PRIME, &val,
pScrn->scrnIndex, "DRM_CAP_PRIME"))
- goto err_drm_close;
+ goto err_free;
if (!(val & DRM_PRIME_CAP_EXPORT)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"[drm] kernel doesn't support prime export.\n");
- goto err_drm_close;
+ goto err_free;
}
if (armada_get_cap(drm->common.fd, DRM_CAP_DUMB_BUFFER, &val,
pScrn->scrnIndex, "DRM_CAP_DUMB_BUFFER"))
- goto err_drm_close;
+ goto err_free;
if (!val) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"[drm] kernel doesn't support dumb buffer.\n");
- goto err_drm_close;
+ goto err_free;
}
err = drm_armada_init(drm->common.fd, &drm->armada.bufmgr);
if (err) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"[drm] failed to initialize Armada DRM manager.\n");
- goto err_drm_close;
+ goto err_free;
}
SET_DRM_INFO(pScrn, &drm->common);
@@ -666,8 +620,6 @@ static Bool armada_drm_open_master(ScrnInfoPtr pScrn)
return TRUE;
- err_drm_close:
- drmClose(drm->common.fd);
err_free:
free(drm);
return FALSE;
@@ -691,6 +643,7 @@ static void armada_drm_FreeScreen(FREE_SCREEN_ARGS_DECL)
static Bool armada_drm_PreInit(ScrnInfoPtr pScrn, int flags)
{
+ struct common_drm_device *drm_dev;
rgb defaultWeight = { 0, 0, 0 };
int flags24;
@@ -700,11 +653,13 @@ static Bool armada_drm_PreInit(ScrnInfoPtr pScrn, int flags)
if (flags & PROBE_DETECT)
return FALSE;
- if (!armada_drm_open_master(pScrn)) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Failed to become DRM master.\n");
+ /* Get the device we detected at probe time */
+ drm_dev = common_entity_get_dev(pScrn->entityList[0]);
+ if (!drm_dev)
+ return FALSE;
+
+ if (!armada_drm_alloc(pScrn, drm_dev))
return FALSE;
- }
/* Limit the maximum framebuffer size to 16MB */
pScrn->videoRam = 16 * 1048576;
diff --git a/src/armada_module.c b/src/armada_module.c
index 8b50442..eef3c75 100644
--- a/src/armada_module.c
+++ b/src/armada_module.c
@@ -8,6 +8,15 @@
#include "config.h"
#endif
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+
+#include "xf86.h"
+#ifdef XSERVER_PLATFORM_BUS
+#include "xf86platformBus.h"
+#endif
+
#include "armada_drm.h"
#include "armada_accel.h"
#include "common_drm.h"
@@ -17,6 +26,11 @@
#define ARMADA_NAME "armada"
#define ARMADA_DRIVER_NAME "armada"
+#define DRM_MODULE_NAMES "armada-drm", "imx-drm"
+#define DRM_DEFAULT_BUS_ID NULL
+
+static const char *drm_module_names[] = { DRM_MODULE_NAMES };
+
/* Supported "chipsets" */
static SymTabRec armada_chipsets[] = {
// { 0, "88AP16x" },
@@ -101,6 +115,16 @@ static void armada_identify(int flags)
ipu_chipsets);
}
+static void armada_init_screen(ScrnInfoPtr pScrn)
+{
+ pScrn->driverVersion = ARMADA_VERSION;
+ pScrn->driverName = ARMADA_DRIVER_NAME;
+ pScrn->name = ARMADA_NAME;
+ pScrn->Probe = NULL;
+
+ armada_drm_init_screen(pScrn);
+}
+
static Bool armada_probe(DriverPtr drv, int flags)
{
GDevPtr *devSections;
@@ -116,22 +140,38 @@ static Bool armada_probe(DriverPtr drv, int flags)
for (i = 0; i < numDevSections; i++) {
ScrnInfoPtr pScrn;
- int entity;
+ const char *busid = DRM_DEFAULT_BUS_ID;
+ int entity, fd, j;
+
+ if (devSections[i]->busID)
+ busid = devSections[i]->busID;
+
+ for (j = 0; j < ARRAY_SIZE(drm_module_names); j++) {
+ fd = drmOpen(drm_module_names[j], busid);
+ if (fd >= 0)
+ break;
+ }
+
+ if (fd < 0)
+ continue;
+
+ if (!common_drm_fd_is_master(fd))
+ continue;
entity = xf86ClaimNoSlot(drv, 0, devSections[i], TRUE);
+ common_alloc_dev(entity, fd, NULL, TRUE);
+
pScrn = xf86ConfigFbEntity(NULL, 0, entity,
NULL, NULL, NULL, NULL);
+ if (!pScrn)
+ continue;
- if (pScrn) {
- foundScreen = TRUE;
+ if (busid)
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Using BusID \"%s\"\n", busid);
- pScrn->driverVersion = ARMADA_VERSION;
- pScrn->driverName = ARMADA_DRIVER_NAME;
- pScrn->name = ARMADA_NAME;
- pScrn->Probe = NULL;
-
- armada_drm_init_screen(pScrn);
- }
+ foundScreen = TRUE;
+ armada_init_screen(pScrn);
}
free(devSections);
@@ -166,11 +206,125 @@ armada_driver_func(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
flag = (CARD32*)ptr;
(*flag) = 0;
return TRUE;
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,0)
+ case SUPPORTS_SERVER_FDS:
+ return TRUE;
+#endif
default:
return FALSE;
}
}
+#ifdef XSERVER_PLATFORM_BUS
+static Bool armada_is_kms(int fd)
+{
+ drmVersionPtr version;
+ drmModeResPtr res;
+ Bool has_connectors;
+
+ version = drmGetVersion(fd);
+ if (!version)
+ return FALSE;
+ drmFreeVersion(version);
+
+ res = drmModeGetResources(fd);
+ if (!res)
+ return FALSE;
+
+ has_connectors = res->count_connectors > 0;
+ drmModeFreeResources(res);
+
+ return has_connectors;
+}
+
+static struct common_drm_device *armada_create_dev(int entity_num,
+ struct xf86_platform_device *dev)
+{
+ struct common_drm_device *drm_dev;
+ const char *path;
+ Bool ddx_managed_master;
+ int fd, our_fd = -1;
+
+ path = xf86_get_platform_device_attrib(dev, ODEV_ATTRIB_PATH);
+ if (!path)
+ goto err_free;
+
+#ifdef ODEV_ATTRIB_FD
+ fd = xf86_get_platform_device_int_attrib(dev, ODEV_ATTRIB_FD, -1);
+#else
+ fd = -1;
+#endif
+ if (fd != -1) {
+ ddx_managed_master = FALSE;
+ if (!armada_is_kms(fd))
+ goto err_free;
+ } else {
+ ddx_managed_master = TRUE;
+ our_fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ if (our_fd == -1)
+ goto err_free;
+
+ if (!armada_is_kms(our_fd)) {
+ close(our_fd);
+ goto err_free;
+ }
+
+ if (!common_drm_fd_is_master(our_fd)) {
+ close(our_fd);
+ goto err_free;
+ }
+
+ fd = our_fd;
+ }
+
+ /* If we're running unprivileged, don't drop master status */
+ if (geteuid())
+ ddx_managed_master = FALSE;
+
+ drm_dev = common_alloc_dev(entity_num, fd, path, ddx_managed_master);
+ if (!drm_dev && our_fd != -1)
+ close(our_fd);
+
+ return drm_dev;
+
+ err_free:
+ return NULL;
+}
+
+static int armada_create_screen(DriverPtr drv, int entity_num,
+ struct common_drm_device *drm_dev)
+{
+ ScrnInfoPtr pScrn;
+
+ pScrn = xf86AllocateScreen(drv, 0);
+ if (!pScrn)
+ return FALSE;
+
+ xf86AddEntityToScreen(pScrn, entity_num);
+
+ armada_init_screen(pScrn);
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Added screen for KMS device %s\n", drm_dev->kms_path);
+
+ return TRUE;
+}
+
+static Bool armada_platform_probe(DriverPtr drv, int entity_num, int flags,
+ struct xf86_platform_device *dev, intptr_t match_data)
+{
+ struct common_drm_device *drm_dev;
+
+ drm_dev = common_entity_get_dev(entity_num);
+ if (!drm_dev)
+ drm_dev = armada_create_dev(entity_num, dev);
+ if (!drm_dev)
+ return FALSE;
+
+ return armada_create_screen(drv, entity_num, drm_dev);
+}
+#endif
+
_X_EXPORT DriverRec armada_driver = {
.driverVersion = ARMADA_VERSION,
.driverName = ARMADA_DRIVER_NAME,
@@ -178,6 +332,9 @@ _X_EXPORT DriverRec armada_driver = {
.Probe = armada_probe,
.AvailableOptions = armada_available_options,
.driverFunc = armada_driver_func,
+#ifdef XSERVER_PLATFORM_BUS
+ .platformProbe = armada_platform_probe,
+#endif
};
#ifdef XFree86LOADER
diff --git a/src/common_drm.c b/src/common_drm.c
index b92b71c..e2468eb 100644
--- a/src/common_drm.c
+++ b/src/common_drm.c
@@ -1277,12 +1277,16 @@ Bool common_drm_EnterVT(VT_FUNC_ARGS_DECL)
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
int i;
- if (drmSetMaster(drm->fd))
+ if (!common_drm_get_master(drm->dev)) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"[drm] set master failed: %s\n", strerror(errno));
+ return FALSE;
+ }
- if (!xf86SetDesiredModes(pScrn))
+ if (!xf86SetDesiredModes(pScrn)) {
+ common_drm_put_master(drm->dev);
return FALSE;
+ }
/* Disable unused CRTCs */
for (i = 0; i < xf86_config->num_crtc; i++) {
@@ -1306,7 +1310,7 @@ void common_drm_LeaveVT(VT_FUNC_ARGS_DECL)
xf86_hide_cursors(pScrn);
- drmDropMaster(drm->fd);
+ common_drm_put_master(drm->dev);
}
void common_drm_FreeScreen(FREE_SCREEN_ARGS_DECL)
@@ -1475,3 +1479,83 @@ int common_drm_vblank_wait(ScrnInfoPtr pScrn, xf86CrtcPtr crtc,
return ret;
}
+
+
+static int common_entity_key = -1;
+
+struct common_drm_device *common_entity_get_dev(int entity_num)
+{
+ if (common_entity_key == -1)
+ common_entity_key = xf86AllocateEntityPrivateIndex();
+ if (common_entity_key == -1)
+ return NULL;
+
+ return xf86GetEntityPrivate(entity_num, common_entity_key)->ptr;
+}
+
+static void common_entity_set_dev(int entity_num, struct common_drm_device *dev)
+{
+ if (common_entity_key == -1)
+ common_entity_key = xf86AllocateEntityPrivateIndex();
+
+ xf86GetEntityPrivate(entity_num, common_entity_key)->ptr = dev;
+}
+
+struct common_drm_device *common_alloc_dev(int entity_num, int fd,
+ const char *path, Bool ddx_managed_master)
+{
+ struct common_drm_device *drm_dev;
+
+ drm_dev = malloc(sizeof *drm_dev);
+ if (!drm_dev)
+ return NULL;
+
+ drm_dev->fd = fd;
+ drm_dev->master_count = !ddx_managed_master;
+
+ if (path) {
+ drm_dev->kms_path = strdup(path);
+ if (!drm_dev->kms_path) {
+ free(drm_dev);
+ return NULL;
+ }
+ } else {
+ drm_dev->kms_path = NULL;
+ }
+
+ common_entity_set_dev(entity_num, drm_dev);
+
+ return drm_dev;
+}
+
+/*
+ * Check that what we opened was a master or a master-capable FD
+ * by setting the version of the interface we'll use to talk to it.
+ */
+Bool common_drm_fd_is_master(int fd)
+{
+ drmSetVersion sv;
+
+ sv.drm_di_major = 1;
+ sv.drm_di_minor = 1;
+ sv.drm_dd_major = -1;
+ sv.drm_dd_minor = -1;
+
+ return drmSetInterfaceVersion(fd, &sv) == 0;
+}
+
+Bool common_drm_get_master(struct common_drm_device *drm_dev)
+{
+ if (drm_dev->master_count++)
+ return TRUE;
+
+ return drmSetMaster(drm_dev->fd) ? FALSE : TRUE;
+}
+
+void common_drm_put_master(struct common_drm_device *drm_dev)
+{
+ assert(drm_dev->master_count);
+
+ if (--drm_dev->master_count == 0)
+ drmDropMaster(drm_dev->fd);
+}
diff --git a/src/common_drm.h b/src/common_drm.h
index 702a920..537c88d 100644
--- a/src/common_drm.h
+++ b/src/common_drm.h
@@ -7,6 +7,12 @@
struct common_drm_event;
+struct common_drm_device {
+ int fd;
+ int master_count;
+ const char *kms_path;
+};
+
struct common_crtc_info {
int drm_fd;
unsigned num;
@@ -31,6 +37,7 @@ struct drm_udev_info {
struct common_drm_info {
int fd;
+ struct common_drm_device *dev;
uint32_t fb_id;
drmModeResPtr mode_res;
drmEventContext event_context;
@@ -110,4 +117,11 @@ void common_drm_FreeScreen(FREE_SCREEN_ARGS_DECL);
/* Present extension support */
Bool common_present_init(ScreenPtr pScreen);
+struct common_drm_device *common_entity_get_dev(int entity_num);
+struct common_drm_device *common_alloc_dev(int entity_num, int fd,
+ const char *path, Bool ddx_managed_master);
+Bool common_drm_fd_is_master(int fd);
+Bool common_drm_get_master(struct common_drm_device *drm_dev);
+void common_drm_put_master(struct common_drm_device *drm_dev);
+
#endif