The DRM has never been able to support multiple X servers for DRI that
could be chvt'ed between (fast-user-switching...)
This is my first attempt at a patch to provide this support. With it and a
slightly hacked up intel driver I can run two servers with gears on each
and chvt between them (it eventually breaks but I think that is probably a
memory management collision).
The current master switch protocol is simple as, there is set and drop
master, which the driver calls on VT switch. The set blocks ugly waiting
for the master to become available, it may be safe to remove the while or
to change the block to userspace polling on the master. I'm thinking a
nice solution includes some sort of request/notification scheme.
Interrupt handler - userspace plays with the irq lines, I think we could
have issues getting interrupts when we have no master.
Shutdown - if you close server 1 while server 2 is the master, you run
into the biggest wall. As server 1 cannot demand master status until
server 2 gives it up. I'm thinking the nicest way is to just block server
1 until it can be master again, but there may be a way to let it exit
gracefully by switching master on some of its ioctls, but then we'd need
to figure out what to do with any interrupts that arrive while the masters
are switched etc...
Please let me know of any ideas you are having in this area, and whether
I've missed anything obvious I'm just throwing this out there for
discussion, as per usual I've no idea if/when I can get back to finishing
this properly...
also in http://cgit.freedesktop.org/~airlied/drm/log/?h=multi-master
Dave.
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c
index 4265c32..eb7cc0f 100644
--- a/libdrm/xf86drm.c
+++ b/libdrm/xf86drm.c
@@ -2960,3 +2960,20 @@ void drmCloseOnce(int fd)
}
}
}
+
+int drmSetMaster(int fd)
+{
+ int ret;
+
+ fprintf(stderr,"Setting master \n");
+ ret = ioctl(fd, DRM_IOCTL_SET_MASTER, 0);
+ return ret;
+}
+
+int drmDropMaster(int fd)
+{
+ int ret;
+ fprintf(stderr,"Dropping master \n");
+ ret = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0);
+ return ret;
+}
diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h
index 230f54c..e97c968 100644
--- a/libdrm/xf86drm.h
+++ b/libdrm/xf86drm.h
@@ -658,6 +658,9 @@ extern int drmSLLookupNeighbors(void *l, unsigned long key,
extern int drmOpenOnce(void *unused, const char *BusID, int *newlyopened);
extern void drmCloseOnce(int fd);
+extern int drmSetMaster(int fd);
+extern int drmDropMaster(int fd);
+
#include "xf86mm.h"
#endif
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index dbf2a92..23bfeaf 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -262,11 +262,11 @@ struct drm_file;
*/
#define LOCK_TEST_WITH_RETURN( dev, file_priv )\
do { \
- if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \
- dev->lock.file_priv != file_priv ) { \
+ if ( !_DRM_LOCK_IS_HELD( dev->master->lock.hw_lock->lock ) || \
+ dev->master->lock.file_priv != file_priv ) { \
DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\
- __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
- dev->lock.file_priv, file_priv ); \
+ __FUNCTION__, _DRM_LOCK_IS_HELD( dev->master->lock.hw_lock->lock ),\
+ dev->master->lock.file_priv, file_priv ); \
return -EINVAL; \
}\
} while (0)
@@ -409,7 +409,6 @@ enum drm_ref_type {
/** File private data */
struct drm_file {
int authenticated;
- int master;
int minor;
pid_t pid;
uid_t uid;
@@ -431,6 +430,7 @@ struct drm_file {
struct drm_open_hash refd_object_hash[_DRM_NO_REF_TYPES];
struct file *filp;
+ struct drm_master *master; /* this private has a master associated with it */
void *driver_priv;
};
@@ -566,6 +566,7 @@ struct drm_map_list {
struct drm_map *map; /**< mapping */
uint64_t user_token;
struct drm_mm_node *file_offset_node;
+ struct drm_master *master; /** if this map is associated with a specific master */
};
typedef struct drm_map drm_local_map_t;
@@ -605,6 +606,25 @@ struct drm_ati_pcigart_info {
#include "drm_objects.h"
+/* per-master structure */
+struct drm_master {
+
+ struct drm_device *dev;
+
+ char *unique; /**< Unique identifier: e.g., busid */
+ int unique_len; /**< Length of unique field */
+
+ int blocked; /**< Blocked due to VC switch? */
+
+ /** \name Authentication */
+ /[EMAIL PROTECTED] */
+ struct drm_open_hash magiclist;
+ struct list_head magicfree;
+ /[EMAIL PROTECTED] */
+
+ struct drm_lock_data lock; /**< Information on hardware lock */
+};
+
/**
* DRM driver structure. This structure represent the common code for
* a family of cards. There will one drm_device for each card present
@@ -701,13 +721,9 @@ struct drm_head {
*/
struct drm_device {
struct device dev; /**< Linux device */
- char *unique; /**< Unique identifier: e.g., busid */
- int unique_len; /**< Length of unique field */
char *devname; /**< For /proc/interrupts */
int