Discussion:
Should drm's modetest work when an X server is running?
Daniel Kurtz
2014-03-03 23:53:25 UTC
Permalink
Dear dri developers,

Should libdrm's modetest work when an X server is running?
Should drmOpen(name, NULL) succeed when the drm device is already open?
Is "name" passed to drmOpen() the "drm" name returned by drmGetVersion()?
Or, is it the the kernel driver/module name?

tl;dr

Over the past couple of days I have been trying to get "modetest" from
the libdrm repository to run on my exynos based ARM chromebook.

With an X server running, "modetest" fails like this:
# modetest
trying to open device 'exynos'...failed.
no device found.

Without an X server, "modetest" succeeds:
# modetest
trying to open device 'exynos'...success.
Encoders:
id crtc type possible crtcs possible clones
15 5 TMDS 0x00000001 0x00000003
18 0 TMDS 0x00000002 0x00000003
...

So, why is modetest failing when the X server is running?

If we don't specify a module (-M) or device (-D) on the command line,
modetest searches through a hard coded list of "modules":
const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx",
"omapdrm", "exynos", "tilcdc", "msm" };

For each module, it tries to open it with drmOpen:
dev.fd = drmOpen(modules[i], device);

When checking for "exynos", this becomes...
drmOpen("exynos", NULL), which first calls
-> drmAvailable()
-> drmOpenMinor(0, 1, DRM_NODE_RENDER)
-> drmOpenDevice(makedev(DRM_MAJOR, 0), 0, DRM_NODE_RENDER);
-> this eventually calls open("/dev/dri/card0"), which returns
a valid fd.
drmOpen("exynos", NULL) then calls
-> drmOpenByName("exynos")
-> /* Redundant drmAvailable() check */
-> for i=0:15:
-> drmOpenMinor(i, 1, DRM_NODE_RENDER);
-> if it returns a valid fd: version = drmGetVersion(fd)
-> if version->name == "exynos": id = drmGetBusid(fd);
-> if id != NULL && id != "": Success! return the fd

In other words, drmOpen("exynos", NULL) succeeds if any of
"/dev/dri/card*" can be opened, it drmGetVersion() succeeds and
returns version->name == "exynos", and if drmGetBusid(fd) is NULL or
"". In other words, it opens the first minor number that matches the
DRM "version" name and doesn't already have a busid assigned (ie, the
first matching minor that isn't in use).

So, this explains why modetest works when my X server is stopped. The
drm name matches, and there is no busid, so drmOpen() happily returns
an fd.

But on a system with intel graphics (i915), modetest works even with
the X server running, why?
It turns out that there is another chunk of code in drmOpenByName(),
that is linux only, and implements "Backward-compatibility /proc
support". In a loop it reads "/proc/dri/*/name" and matches the first
field against the "name" passed in to drmOpenByName(). If this
matches:
* if there are 3 fields, the 3rd field is passed to drmOpenByBusid()
* if there were only 2 fields, the 2nd field is parsed as a long and
passed as the dev parameter to drmOpenDevice().

"On my intel machine, the first field is "i915", the same name
returned as the version->name for drmGetVersion(), so we end up doing
something like drmOpenByBusid("pci:0000:00:02.0), which succeeds
because that matches what is returned by drmGetBusid().

$ cat /proc/dri/0/name
i915 0000:00:02.0 pci:0000:00:02.0

But, for exynos, the the driver name is actually "exynos-drm", so the
check fails, and drmOpen("exynos", NULL) fails.

# cat /proc/dri/0/name
exynos-drm exynos-drm platform:exynos-drm:00

I'm obviously using an older kernel. From the kernel git log, I see
that danvet recently removed the entire proc interface. So, does that
mean that on up to date kernels modetest (and the other libdrm tests)
will now also fail for intel if X is running (since the proc back door
is no longer available)?
Is this "working as intended"?

-Dan
David Herrmann
2014-03-04 00:07:04 UTC
Permalink
Hi
Post by Daniel Kurtz
Dear dri developers,
Should libdrm's modetest work when an X server is running?
Should drmOpen(name, NULL) succeed when the drm device is already open?
Is "name" passed to drmOpen() the "drm" name returned by drmGetVersion()?
Or, is it the the kernel driver/module name?
Don't use drmOpen(). Seriously, there's no reason for it. There is
open(), use it, don't bother with all that legacy. And if legacy code
uses drmOpen(), it's really easy to fix it to just use plain open().
The wrappers made sense when we had UMS or maybe with xf86-video
drivers. But for anything else, just use udev to enumerate the
drm-devices and then open() the node. If you don't like udev, iterate
over /dev/dri/.

Regarding modetest: yes, it's supposed to work while an xserver is
running, as long as you run it on a separate VT. Furthermore, the
drivers obviously need to be KMS drivers for both, otherwise behavior
is undefined, anyway. However, drmOpen() is known to fail in such
situations, so my recommendation is to fix modetest. I doubt that we
will revert kernel changes for /proc just to make drmOpen() work in
multi-gfx systems again.

Thanks
David
Post by Daniel Kurtz
tl;dr
Over the past couple of days I have been trying to get "modetest" from
the libdrm repository to run on my exynos based ARM chromebook.
# modetest
trying to open device 'exynos'...failed.
no device found.
# modetest
trying to open device 'exynos'...success.
id crtc type possible crtcs possible clones
15 5 TMDS 0x00000001 0x00000003
18 0 TMDS 0x00000002 0x00000003
...
So, why is modetest failing when the X server is running?
If we don't specify a module (-M) or device (-D) on the command line,
const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx",
"omapdrm", "exynos", "tilcdc", "msm" };
dev.fd = drmOpen(modules[i], device);
When checking for "exynos", this becomes...
drmOpen("exynos", NULL), which first calls
-> drmAvailable()
-> drmOpenMinor(0, 1, DRM_NODE_RENDER)
-> drmOpenDevice(makedev(DRM_MAJOR, 0), 0, DRM_NODE_RENDER);
-> this eventually calls open("/dev/dri/card0"), which returns
a valid fd.
drmOpen("exynos", NULL) then calls
-> drmOpenByName("exynos")
-> /* Redundant drmAvailable() check */
-> drmOpenMinor(i, 1, DRM_NODE_RENDER);
-> if it returns a valid fd: version = drmGetVersion(fd)
-> if version->name == "exynos": id = drmGetBusid(fd);
-> if id != NULL && id != "": Success! return the fd
In other words, drmOpen("exynos", NULL) succeeds if any of
"/dev/dri/card*" can be opened, it drmGetVersion() succeeds and
returns version->name == "exynos", and if drmGetBusid(fd) is NULL or
"". In other words, it opens the first minor number that matches the
DRM "version" name and doesn't already have a busid assigned (ie, the
first matching minor that isn't in use).
So, this explains why modetest works when my X server is stopped. The
drm name matches, and there is no busid, so drmOpen() happily returns
an fd.
But on a system with intel graphics (i915), modetest works even with
the X server running, why?
It turns out that there is another chunk of code in drmOpenByName(),
that is linux only, and implements "Backward-compatibility /proc
support". In a loop it reads "/proc/dri/*/name" and matches the first
field against the "name" passed in to drmOpenByName(). If this
* if there are 3 fields, the 3rd field is passed to drmOpenByBusid()
* if there were only 2 fields, the 2nd field is parsed as a long and
passed as the dev parameter to drmOpenDevice().
"On my intel machine, the first field is "i915", the same name
returned as the version->name for drmGetVersion(), so we end up doing
something like drmOpenByBusid("pci:0000:00:02.0), which succeeds
because that matches what is returned by drmGetBusid().
$ cat /proc/dri/0/name
i915 0000:00:02.0 pci:0000:00:02.0
But, for exynos, the the driver name is actually "exynos-drm", so the
check fails, and drmOpen("exynos", NULL) fails.
# cat /proc/dri/0/name
exynos-drm exynos-drm platform:exynos-drm:00
I'm obviously using an older kernel. From the kernel git log, I see
that danvet recently removed the entire proc interface. So, does that
mean that on up to date kernels modetest (and the other libdrm tests)
will now also fail for intel if X is running (since the proc back door
is no longer available)?
Is this "working as intended"?
-Dan
_______________________________________________
dri-devel mailing list
http://lists.freedesktop.org/mailman/listinfo/dri-devel
Rob Clark
2014-03-04 00:14:27 UTC
Permalink
Post by Daniel Kurtz
But, for exynos, the the driver name is actually "exynos-drm", so the
check fails, and drmOpen("exynos", NULL) fails.
# cat /proc/dri/0/name
exynos-drm exynos-drm platform:exynos-drm:00
oh, hmm, yeah, I guess you break a few assumptions if the drm name !=
device name.. I guess mostly nobody notices because usually xserver
uses drmOpen() and mesa just open()'s the device file path passed from
xserver.

BR,
-R

Loading...