[PATCH xserver 4/4] xfree86: promote one GPU screen if (NumScreens == 0 && NumGPUScreens > 0)

Laszlo Ersek lersek at redhat.com
Tue Sep 6 20:32:13 UTC 2016


On 09/06/16 14:46, Hans de Goede wrote:
> Hi,
> 
> On 06-09-16 13:47, Laszlo Ersek wrote:
>> Adding Matt and Ard
>>
>> On 09/06/16 00:32, Dave Airlie wrote:
> 
> <snip>
> 
>> Picking different primaries on different boots sounds perfectly
>> acceptable to me as long as:
>> - no explicit DeviceId.BusID is specified by the user,
>> - no primary emerges otherwise,
>> - there are several secondaries.
>>
>> This behavior is clearly not ideal in the long term (like at the third,
>> fourth, fifth etc boots of the same machine), but the user can trivially
>> fix it *after* the installation finishes (by setting Device.BusID).
>> Plus, the suggested documentation (man page) and the server log are
>> clear about it.
>>
>> Importantly, the suggested behavior (even if non-deterministic) is
>> clearly superior to the X Server not starting at all. "Output somewhere"
>> is better than no output at all. (And, in 99% of the cases, there's only
>> one secondary, which gives exactly the expected result.)
>>
>> ... If it made the series acceptable, I'd be happy to tweak patch #4 so
>> that the code get active only for
>>
>>   (NumScreens == 0 && NumGPUScreens == 1)
> 
> I agree that this is a reasonable thing to do, if there is only
> one GPUScreen we don't get the problem of which GPUScreen to pick
> and then falling back to the single available GPUScreen seems
> like the sensible thing to do.
> 
> That still leaves the problem though, that as I wrote on your original
> submission, doing this after the probing is done is too late, because
> the flags argumet passed into the probeSingleDevice call in
> hw/xfree86/common/xf86platformBus.c: xf86platformProbeDev()
> (and passed into the driver from there)  must match if the screen is
> going to be a normal screen or a GPU-screen.

It is true that patch #3 does not take care of this universally (i.e.,
in a future-proof way).

It does take care of all of the *current* effects of
PLATFORM_PROBE_GPU_SCREEN, which is that the modesetting driver sets
XF86_ALLOCATE_GPU_SCREEN for xf86AllocateScreen().

That in turn makes a difference for the "scrnIndex" and "is_gpu" fields
of the newly allocated ScrnInfoRec object.

And, patch #3 does handle those as part of the promotion.

If the modesetting driver (or any other driver) used
PLATFORM_PROBE_GPU_SCREEN for anything more than passing
XF86_ALLOCATE_GPU_SCREEN to xf86AllocateScreen(), then this approach
wouldn't work.

> 
> Hmm, looking at this closer, the easy fix I had in mind is not
> possible, at least not in the place where I wanted to add it.
> 
> Looking even further, we should already do a fallback to the first
> non-primary dev for seat0 servers and at the right time (before calling
> probe), take a look at: hw/xfree86/common/xf86Bus.c: xf86BusProbe()
> 
> void
> xf86BusProbe(void)
> {
> #ifdef XSERVER_PLATFORM_BUS
>     xf86platformProbe();
>     if (ServerIsNotSeat0() && xf86_num_platform_devices > 0)
>         return;
> #endif
> #ifdef XSERVER_LIBPCIACCESS
>     xf86PciProbe();
> #endif
> #if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__)
>     xf86SbusProbe();
> #endif
> #ifdef XSERVER_PLATFORM_BUS
>     xf86platformPrimary();
> #endif
> }
> 
> A normal server is seat0, so ServerIsNotSeat0() returns False
> and we end up calling xf86platformPrimary() at the end of the
> function which falls back to the first non-primary dev.
> 
> The only reason this would not work is if xf86PciProbe()
> has set primaryBus.type to a value other then BUS_NONE.

Sure, that does happen (I've been aware of it, but I haven't realized it
as a problem); in this part of the function:

    /* If we haven't found a primary device try a different heuristic */
    if (primaryBus.type == BUS_NONE && num) {
        for (i = 0; i < num; i++) {
            uint16_t command;

            info = xf86PciVideoInfo[i];
            pci_device_cfg_read_u16(info, &command, 4);

            if ((command & PCI_CMD_MEM_ENABLE)
                && ((num == 1) || IS_VGA(info->device_class))) {
                if (primaryBus.type == BUS_NONE) {
                    primaryBus.type = BUS_PCI;
                    primaryBus.id.pci = info;

IS_VGA does not apply to virtio-gpu-pci, but num==1 does.

Also, virtio-gpu-pci has MMIO decoding enabled in the command register,
because virtio-gpu-pci is virtio-1.0 only, and it uses an MMIO BAR for
virtio register access and signaling.

The corresponding log snippet is

[   190.155] (II) xfree86: Adding drm device (/dev/dri/card0)
[   389.067] (--) PCI:*(0:0:1:0) 1af4:1050:1af4:1100 rev 1, Mem @
0x10040000/4096, 0x8000000000/8388608, BIOS @ 0x????????/65536

Note the "*" in "PCI:*" -- that comes from

    /* Print a summary of the video devices found */
    for (k = 0; k < num; k++) {
        const char *prim = " ";
        Bool memdone = FALSE, iodone = FALSE;

        info = xf86PciVideoInfo[k];

        if (!PCIALWAYSPRINTCLASSES(info->device_class))
            continue;

        if (xf86IsPrimaryPci(info))
            prim = "*";

        xf86Msg(X_PROBED, "PCI:%s(%u:%u:%u:%u) %04x:%04x:%04x:%04x ", prim,
                info->domain, info->bus, info->dev, info->func,
                info->vendor_id, info->device_id,
                info->subvendor_id, info->subdevice_id);

> So I think we need to figure out why the existing fallback
> path is not working.

It's because the num==1 part makes xf86PciProbe() assign BUS_PCI to
primaryBus.type.

Here's a more complete call tree:

  InitOutput()

    xf86BusProbe()
      xf86platformProbe()
      xf86PciProbe()
        primaryBus.type := BUS_PCI /* due to num == 1 */
      xf86platformPrimary()
        /* does nothing */

    xf86BusConfig()
      xf86CallDriverProbe()
        foundScreen := xf86platformProbeDev()
          /* xf86PlatformDeviceCheckBusID() is never called because
           * the user never specified Device.BusID */

          /* xf86IsPrimaryPlatform() does not match
           * because primaryBus.type == BUS_PCI */

          /* autoAddGPU is TRUE, so we call: */
          probeSingleDevice(... PLATFORM_PROBE_GPU_SCREEN ...)
          /* and because that succeeds, we set: */
          foundScreen := TRUE

      /* the libpciaccess branch is not reached
       * because foundScreen is TRUE from xf86platformProbeDev() */

I looked into why xf86IsPrimaryPlatform() wouldn't match this device in
xf86platformProbeDev(). Here's my notes from earlier, standing in
xf86IsPrimaryPlatform():

      - primaryBus.type == BUS_PCI

      - primaryBus.id.pci == 0x671600 (pointer to "struct pci_device")

      - xf86_platform_devices[0].attribs->busid == "pci:0000:00:01.0"
        (good, it matches the location of the virtio-gpu-pci device)

      - xf86_platform_devices[0].pdev == 0x670d80 (pointer to a
        different "struct pci_device" object)

      - however, the *contents* of "*primaryBus.id.pci" and
        "*xf86_platform_devices[0].pdev" are identical! They both
        describe the "virtio-gpu-pci" device.

      This means that xf86IsPrimaryPlatform() returns false despite
      "primaryBus" describing the exact same PCI device as
      "xf86_platform_devices[0]".

> I suggest adding a bunch of
> 
> xf86Msg(X_INFO, "mesage text here %d\n", anintnumber);
> 
> Calls to xf86BusProbe() and xf86platformPrimary() to
> figure out why this is not working.

Thanks
Laszlo



More information about the xorg-devel mailing list