[PATCH] [RFC] modesetting: add zaphod support (v2)

Mario Kleiner mario.kleiner.de at gmail.com
Tue Aug 4 15:18:15 PDT 2015


Hi Dave,

thanks for implementing this!

This one is

Reviewed-and-tested-by: Mario Kleiner <mario.kleiner.de at gmail.com>

I tested on intel/nouveau/radeon-kms with different combos of 
one/two/three x-screen with one/two/three ZaphohHeads outputs and also 
regular single-x-screen multi-display.

In combination with the additional series of patches i just sent out for 
handling > 1 output per x-screen and for some nvidia cards, on top of 
your patch, this works fine on all tested setups.

Maybe we could squash all the Zaphod patches into one patch, throwing 
away my commit messages, so we have one nice patch to show the state of 
the art in ZaphodHeads enablement?

thanks,
-mario

On 07/27/2015 01:43 AM, Dave Airlie wrote:
> From: Dave Airlie <airlied at redhat.com>
>
> This adds zaphod and ZaphodHeads support
> to the the in-server modesetting driver.
>
> this is based on a request from Mario,
> and on the current radeon driver.
>
> v2: fixup vblank fd registring.
>
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
>   hw/xfree86/drivers/modesetting/driver.c          | 191 ++++++++++++++---------
>   hw/xfree86/drivers/modesetting/driver.h          |  32 ++--
>   hw/xfree86/drivers/modesetting/drmmode_display.c |  47 +++++-
>   hw/xfree86/drivers/modesetting/drmmode_display.h |   5 +
>   hw/xfree86/drivers/modesetting/vblank.c          |  23 ++-
>   5 files changed, 209 insertions(+), 89 deletions(-)
>
> diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
> index 324b8bd..5dcc6a0 100644
> --- a/hw/xfree86/drivers/modesetting/driver.c
> +++ b/hw/xfree86/drivers/modesetting/driver.c
> @@ -118,24 +118,17 @@ static SymTabRec Chipsets[] = {
>       {-1, NULL}
>   };
>
> -typedef enum {
> -    OPTION_SW_CURSOR,
> -    OPTION_DEVICE_PATH,
> -    OPTION_SHADOW_FB,
> -    OPTION_ACCEL_METHOD,
> -    OPTION_PAGEFLIP,
> -} modesettingOpts;
> -
>   static const OptionInfoRec Options[] = {
>       {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
>       {OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE},
>       {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE},
>       {OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
>       {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, FALSE},
> +    {OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE},
>       {-1, NULL, OPTV_NONE, {0}, FALSE}
>   };
>
> -int modesettingEntityIndex = -1;
> +int ms_entity_index = -1;
>
>   static MODULESETUPPROTO(Setup);
>
> @@ -187,6 +180,15 @@ Identify(int flags)
>                         Chipsets);
>   }
>
> +modesettingEntPtr ms_ent_priv(ScrnInfoPtr scrn)
> +{
> +    DevUnion     *pPriv;
> +    modesettingPtr ms = modesettingPTR(scrn);
> +    pPriv = xf86GetEntityPrivate(ms->pEnt->index,
> +                                 ms_entity_index);
> +    return pPriv->ptr;
> +}
> +
>   static int
>   open_hw(const char *dev)
>   {
> @@ -366,6 +368,7 @@ ms_platform_probe(DriverPtr driver,
>                     intptr_t match_data)
>   {
>       ScrnInfoPtr scrn = NULL;
> +    EntityInfoPtr pEnt;
>       const char *path = xf86_platform_device_odev_attributes(dev)->path;
>       int scr_flags = 0;
>
> @@ -374,12 +377,39 @@ ms_platform_probe(DriverPtr driver,
>
>       if (probe_hw(path, dev)) {
>           scrn = xf86AllocateScreen(driver, scr_flags);
> +        if (xf86IsEntitySharable(entity_num))
> +            xf86SetEntityShared(entity_num);
>           xf86AddEntityToScreen(scrn, entity_num);
>
>           ms_setup_scrn_hooks(scrn);
>
>           xf86DrvMsg(scrn->scrnIndex, X_INFO,
>                      "using drv %s\n", path ? path : "default device");
> +
> +        pEnt = xf86GetEntityInfo(entity_num);
> +        {
> +            DevUnion *pPriv;
> +            modesettingEntPtr pMSEnt;
> +
> +            xf86SetEntitySharable(entity_num);
> +
> +            if (ms_entity_index == -1)
> +                ms_entity_index = xf86AllocateEntityPrivateIndex();
> +
> +            pPriv = xf86GetEntityPrivate(pEnt->index,
> +                                         ms_entity_index);
> +
> +            xf86SetEntityInstanceForScreen(scrn, pEnt->index, xf86GetNumEntityInstances(pEnt->index) - 1);
> +
> +            if (!pPriv->ptr) {
> +                pPriv->ptr = xnfcalloc(sizeof(modesettingEntRec), 1);
> +                pMSEnt = pPriv->ptr;
> +            } else {
> +                pMSEnt = pPriv->ptr;
> +            }
> +            pMSEnt->platform_dev = dev;
> +        }
> +
>       }
>
>       return scrn != NULL;
> @@ -596,19 +626,25 @@ FreeRec(ScrnInfoPtr pScrn)
>       pScrn->driverPrivate = NULL;
>
>       if (ms->fd > 0) {
> +        modesettingEntPtr ms_ent;
>           int ret;
>
> -        if (ms->pEnt->location.type == BUS_PCI)
> -            ret = drmClose(ms->fd);
> -        else
> +        ms_ent = ms_ent_priv(pScrn);
> +        ms_ent->fd_ref--;
> +        if (!ms_ent->fd_ref) {
> +            if (ms->pEnt->location.type == BUS_PCI)
> +                ret = drmClose(ms->fd);
> +            else
>   #ifdef XF86_PDEV_SERVER_FD
> -        if (!(ms->pEnt->location.type == BUS_PLATFORM &&
> -                  (ms->pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD)))
> +                if (!(ms->pEnt->location.type == BUS_PLATFORM &&
> +                      (ms->pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD)))
>   #endif
> -            ret = close(ms->fd);
> -        (void) ret;
> +                    ret = close(ms->fd);
> +            (void) ret;
> +            ms_ent->fd = 0;
> +        }
>       }
> -    free(ms->Options);
> +    free(ms->drmmode.Options);
>       free(ms);
>
>   }
> @@ -617,7 +653,7 @@ static void
>   try_enable_glamor(ScrnInfoPtr pScrn)
>   {
>       modesettingPtr ms = modesettingPTR(pScrn);
> -    const char *accel_method_str = xf86GetOptValString(ms->Options,
> +    const char *accel_method_str = xf86GetOptValString(ms->drmmode.Options,
>                                                          OPTION_ACCEL_METHOD);
>       Bool do_glamor = (!accel_method_str ||
>                         strcmp(accel_method_str, "glamor") == 0);
> @@ -658,61 +694,26 @@ try_enable_glamor(ScrnInfoPtr pScrn)
>   #define DRM_CAP_CURSOR_HEIGHT 0x9
>   #endif
>
> -static Bool
> -PreInit(ScrnInfoPtr pScrn, int flags)
> +static Bool ms_get_drm_master_fd(ScrnInfoPtr pScrn)
>   {
> -    modesettingPtr ms;
> -    rgb defaultWeight = { 0, 0, 0 };
>       EntityInfoPtr pEnt;
> -    EntPtr msEnt = NULL;
> +    modesettingPtr ms;
> +    modesettingEntPtr ms_ent;
>       char *BusID = NULL;
> -    const char *devicename;
> -    uint64_t value = 0;
> -    int ret;
> -    int bppflags;
> -    int defaultdepth, defaultbpp;
> -
> -    if (pScrn->numEntities != 1)
> -        return FALSE;
> -
> -    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
> -
> -    if (flags & PROBE_DETECT) {
> -        return FALSE;
> -    }
> -
> -    /* Allocate driverPrivate */
> -    if (!GetRec(pScrn))
> -        return FALSE;
>
>       ms = modesettingPTR(pScrn);
> -    ms->SaveGeneration = -1;
> -    ms->pEnt = pEnt;
> +    ms_ent = ms_ent_priv(pScrn);
>
> -    pScrn->displayWidth = 640;  /* default it */
> +    pEnt = ms->pEnt;
>
> -    /* Allocate an entity private if necessary */
> -    if (xf86IsEntityShared(pScrn->entityList[0])) {
> -        msEnt = xf86GetEntityPrivate(pScrn->entityList[0],
> -                                     modesettingEntityIndex)->ptr;
> -        ms->entityPrivate = msEnt;
> -    }
> -    else
> -        ms->entityPrivate = NULL;
> -
> -    if (xf86IsEntityShared(pScrn->entityList[0])) {
> -        if (xf86IsPrimInitDone(pScrn->entityList[0])) {
> -            /* do something */
> -        }
> -        else {
> -            xf86SetPrimInitDone(pScrn->entityList[0]);
> -        }
> +    if (ms_ent->fd) {
> +        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
> +                   " reusing fd for second head\n");
> +        ms->fd = ms_ent->fd;
> +        ms_ent->fd_ref++;
> +        return TRUE;
>       }
>
> -    pScrn->monitor = pScrn->confScreen->monitor;
> -    pScrn->progClock = TRUE;
> -    pScrn->rgbBits = 8;
> -
>   #if XSERVER_PLATFORM_BUS
>       if (pEnt->location.type == BUS_PLATFORM) {
>   #ifdef XF86_PDEV_SERVER_FD
> @@ -749,12 +750,62 @@ PreInit(ScrnInfoPtr pScrn, int flags)
>           ms->fd = drmOpen(NULL, BusID);
>       }
>       else {
> +        const char *devicename;
>           devicename = xf86FindOptionValue(ms->pEnt->device->options, "kmsdev");
>           ms->fd = open_hw(devicename);
>       }
>       if (ms->fd < 0)
>           return FALSE;
>
> +    ms_ent->fd = ms->fd;
> +    ms_ent->fd_ref = 1;
> +    return TRUE;
> +}
> +static Bool
> +PreInit(ScrnInfoPtr pScrn, int flags)
> +{
> +    modesettingPtr ms;
> +    rgb defaultWeight = { 0, 0, 0 };
> +    EntityInfoPtr pEnt;
> +    uint64_t value = 0;
> +    int ret;
> +    int bppflags;
> +    int defaultdepth, defaultbpp;
> +
> +    if (pScrn->numEntities != 1)
> +        return FALSE;
> +
> +    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
> +
> +    if (flags & PROBE_DETECT) {
> +        return FALSE;
> +    }
> +
> +    /* Allocate driverPrivate */
> +    if (!GetRec(pScrn))
> +        return FALSE;
> +
> +    ms = modesettingPTR(pScrn);
> +    ms->SaveGeneration = -1;
> +    ms->pEnt = pEnt;
> +    ms->drmmode.is_secondary = FALSE;
> +    pScrn->displayWidth = 640;  /* default it */
> +
> +    if (xf86IsEntityShared(pScrn->entityList[0])) {
> +        if (xf86IsPrimInitDone(pScrn->entityList[0])) {
> +            ms->drmmode.is_secondary = TRUE;
> +        }
> +        else {
> +            xf86SetPrimInitDone(pScrn->entityList[0]);
> +        }
> +    }
> +
> +    pScrn->monitor = pScrn->confScreen->monitor;
> +    pScrn->progClock = TRUE;
> +    pScrn->rgbBits = 8;
> +
> +    if (!ms_get_drm_master_fd(pScrn))
> +        return FALSE;
>       ms->drmmode.fd = ms->fd;
>
>       pScrn->capabilities = 0;
> @@ -794,17 +845,17 @@ PreInit(ScrnInfoPtr pScrn, int flags)
>
>       /* Process the options */
>       xf86CollectOptions(pScrn, NULL);
> -    if (!(ms->Options = malloc(sizeof(Options))))
> +    if (!(ms->drmmode.Options = malloc(sizeof(Options))))
>           return FALSE;
> -    memcpy(ms->Options, Options, sizeof(Options));
> -    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
> +    memcpy(ms->drmmode.Options, Options, sizeof(Options));
> +    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->drmmode.Options);
>
>       if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
>           return FALSE;
>       if (!xf86SetDefaultVisual(pScrn, -1))
>           return FALSE;
>
> -    if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) {
> +    if (xf86ReturnOptValBool(ms->drmmode.Options, OPTION_SW_CURSOR, FALSE)) {
>           ms->drmmode.sw_cursor = TRUE;
>       }
>
> @@ -823,7 +874,7 @@ PreInit(ScrnInfoPtr pScrn, int flags)
>
>       if (ms->drmmode.glamor) {
>           ms->drmmode.pageflip =
> -            xf86ReturnOptValBool(ms->Options, OPTION_PAGEFLIP, TRUE);
> +            xf86ReturnOptValBool(ms->drmmode.Options, OPTION_PAGEFLIP, TRUE);
>       } else {
>           Bool prefer_shadow = TRUE;
>
> @@ -832,7 +883,7 @@ PreInit(ScrnInfoPtr pScrn, int flags)
>               prefer_shadow = !!value;
>           }
>
> -        ms->drmmode.shadow_enable = xf86ReturnOptValBool(ms->Options,
> +        ms->drmmode.shadow_enable = xf86ReturnOptValBool(ms->drmmode.Options,
>                                                            OPTION_SHADOW_FB,
>                                                            prefer_shadow);
>
> diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h
> index 9ae4966..1166165 100644
> --- a/hw/xfree86/drivers/modesetting/driver.h
> +++ b/hw/xfree86/drivers/modesetting/driver.h
> @@ -44,12 +44,26 @@
>   #include "drmmode_display.h"
>   #define DRV_ERROR(msg)	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, msg);
>
> -typedef struct {
> -    int lastInstance;
> -    int refCount;
> -    ScrnInfoPtr pScrn_1;
> -    ScrnInfoPtr pScrn_2;
> -} EntRec, *EntPtr;
> +typedef enum {
> +    OPTION_SW_CURSOR,
> +    OPTION_DEVICE_PATH,
> +    OPTION_SHADOW_FB,
> +    OPTION_ACCEL_METHOD,
> +    OPTION_PAGEFLIP,
> +    OPTION_ZAPHOD_HEADS,
> +} modesettingOpts;
> +
> +typedef struct
> +{
> +    int fd;
> +    int fd_ref;
> +    unsigned long fd_wakeup_registered; /* server generation for which fd has been registered for wakeup handling */
> +    int fd_wakeup_ref;
> +    unsigned int assigned_crtcs;
> +#ifdef XSERVER_PLATFORM_BUS
> +    struct xf86_platform_device *platform_dev;
> +#endif
> +} modesettingEntRec, *modesettingEntPtr;
>
>   typedef void (*ms_drm_handler_proc)(uint64_t frame,
>                                       uint64_t usec,
> @@ -74,8 +88,6 @@ struct ms_drm_queue {
>   typedef struct _modesettingRec {
>       int fd;
>
> -    EntPtr entityPrivate;
> -
>       int Chipset;
>       EntityInfoPtr pEnt;
>   #if XSERVER_LIBPCIACCESS
> @@ -88,9 +100,6 @@ typedef struct _modesettingRec {
>       Bool noAccel;
>       CloseScreenProcPtr CloseScreen;
>
> -    /* Broken-out options. */
> -    OptionInfoPtr Options;
> -
>       unsigned int SaveGeneration;
>
>       CreateScreenResourcesProcPtr createScreenResources;
> @@ -114,6 +123,7 @@ typedef struct _modesettingRec {
>   } modesettingRec, *modesettingPtr;
>
>   #define modesettingPTR(p) ((modesettingPtr)((p)->driverPrivate))
> +modesettingEntPtr ms_ent_priv(ScrnInfoPtr scrn);
>
>   uint32_t ms_drm_queue_alloc(xf86CrtcPtr crtc,
>                               void *data,
> diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
> index 6a13660..ad9c062 100644
> --- a/hw/xfree86/drivers/modesetting/drmmode_display.c
> +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
> @@ -52,6 +52,39 @@
>
>   static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
>
> +static Bool
> +drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
> +{
> +    int i = 0;
> +    char s1[20];
> +
> +    do {
> +        switch(*s) {
> +        case ',':
> +            s1[i] = '\0';
> +            i = 0;
> +            if (strcmp(s1, output_name) == 0)
> +                return TRUE;
> +            break;
> +        case ' ':
> +        case '\t':
> +        case '\n':
> +        case '\r':
> +            break;
> +        default:
> +            s1[i] = *s;
> +            i++;
> +            break;
> +        }
> +    } while(*s++);
> +
> +    s1[i] = '\0';
> +    if (strcmp(s1, output_name) == 0)
> +        return TRUE;
> +
> +    return FALSE;
> +}
> +
>   int
>   drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
>   {
> @@ -1357,7 +1390,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
>       char name[32];
>       int i;
>       drmModePropertyBlobPtr path_blob = NULL;
> -
> +    const char *s;
>       koutput =
>           drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
>       if (!koutput)
> @@ -1408,6 +1441,18 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
>           }
>       }
>
> +    if (xf86IsEntityShared(pScrn->entityList[0])) {
> +        if ((s = xf86GetOptValString(drmmode->Options, OPTION_ZAPHOD_HEADS))) {
> +            if (!drmmode_zaphod_string_matches(pScrn, s, name))
> +                goto out_free_encoders;
> +        } else {
> +            if (!drmmode->is_secondary && (num != 0))
> +                goto out_free_encoders;
> +            else if (drmmode->is_secondary && (num != 1))
> +                goto out_free_encoders;
> +        }
> +    }
> +
>       output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
>       if (!output) {
>           goto out_free_encoders;
> diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
> index fe363c5..fca68a6 100644
> --- a/hw/xfree86/drivers/modesetting/drmmode_display.h
> +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
> @@ -60,6 +60,9 @@ typedef struct {
>       drmmode_bo front_bo;
>       Bool sw_cursor;
>
> +    /* Broken-out options. */
> +    OptionInfoPtr Options;
> +
>       Bool glamor;
>       Bool shadow_enable;
>       /** Is Option "PageFlip" enabled? */
> @@ -82,6 +85,8 @@ typedef struct {
>       DevPrivateKeyRec pixmapPrivateKeyRec;
>
>       Bool reverse_prime_offload_mode;
> +
> +    Bool is_secondary;
>   } drmmode_rec, *drmmode_ptr;
>
>   typedef struct {
> diff --git a/hw/xfree86/drivers/modesetting/vblank.c b/hw/xfree86/drivers/modesetting/vblank.c
> index 0b7bf9d..77e0848 100644
> --- a/hw/xfree86/drivers/modesetting/vblank.c
> +++ b/hw/xfree86/drivers/modesetting/vblank.c
> @@ -381,7 +381,7 @@ ms_vblank_screen_init(ScreenPtr screen)
>   {
>       ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
>       modesettingPtr ms = modesettingPTR(scrn);
> -
> +    modesettingEntPtr ms_ent = ms_ent_priv(scrn);
>       xorg_list_init(&ms_drm_queue);
>
>       ms->event_context.version = DRM_EVENT_CONTEXT_VERSION;
> @@ -392,9 +392,14 @@ ms_vblank_screen_init(ScreenPtr screen)
>        * feedback on every server generation, so perform the
>        * registration within ScreenInit and not PreInit.
>        */
> -    AddGeneralSocket(ms->fd);
> -    RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
> -                                   ms_drm_wakeup_handler, screen);
> +    if (ms_ent->fd_wakeup_registered != serverGeneration) {
> +        AddGeneralSocket(ms->fd);
> +        RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
> +                                       ms_drm_wakeup_handler, screen);
> +        ms_ent->fd_wakeup_registered = serverGeneration;
> +        ms_ent->fd_wakeup_ref = 1;
> +    } else
> +        ms_ent->fd_wakeup_ref++;
>
>       return TRUE;
>   }
> @@ -404,10 +409,14 @@ ms_vblank_close_screen(ScreenPtr screen)
>   {
>       ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
>       modesettingPtr ms = modesettingPTR(scrn);
> +    modesettingEntPtr ms_ent = ms_ent_priv(scrn);
>
>       ms_drm_abort_scrn(scrn);
>
> -    RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
> -                                 ms_drm_wakeup_handler, screen);
> -    RemoveGeneralSocket(ms->fd);
> +    if (ms_ent->fd_wakeup_registered == serverGeneration &&
> +        !--ms_ent->fd_wakeup_ref) {
> +        RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
> +                                     ms_drm_wakeup_handler, screen);
> +        RemoveGeneralSocket(ms->fd);
> +    }
>   }
>


More information about the xorg-devel mailing list