The Light Display Manager doesn’t start on Odroid XU4 on the recent mainline kernels with exynos_defconfig. I first noticed this problem during the Linux 4.8 rc testing and this problem persists in 4.9-rc1. I want to share the root-cause, and a work-around in this post.
I’m running kernel 4.9.0-rc1 with exynos_defconfig on Ubuntu 16.04 with HDMI. Light Display Manager (lightdm) fails with the following errors.
Starting Light Display Manager... [ OK ] Started Light Display Manager. [ 15.538629] [drm:exynos_drm_framebuffer_init] *ERROR* Non-contiguous GEM mem. [ 15.546149] [drm:exynos_drm_framebuffer_init] *ERROR* Non-contiguous GEM mem. [ OK ] Stopped Light Display Manager.
This block repeats a few times until systemd gives up on starting lightdm. The system is operational with functioning serial console and networking, however the display doesn’t work.
What Causes this problem?
The following sequence of events is what leads to this problem
- The user space calls exynos_drm_gem_create_ioctl() with the EXYNOS_BO_NONCONTIG request to allocate GEM buffers.
- exynos_drm_gem_create() creates non-contiguous GEM buffers as requested.
- exynos_user_fb_create() comes along later and validates the GEM buffers to associate them to frame-buffer. The validation in check_fb_gem_memory_type() detects non-contiguous buffers without IOMMU. Non-contiguous frame buffers can only be supported when IOMMU is enabled, exynos_drm_framebuffer_init() fails.
- At this point, there is no recovery and lightdm fails
After digging into the user space angle on the problem, it turns out that xf86-video-armsoc/src/drmmode_exynos/drmmode_exynos.c assumes contiguous allocations are not supported in some Exynos DRM versions. This change was introduced in the following commit
if (create_gem->buf_type == ARMSOC_BO_SCANOUT) - create_exynos.flags = EXYNOS_BO_CONTIG; - else - create_exynos.flags = EXYNOS_BO_NONCONTIG; + + /* Contiguous allocations are not supported in some exynos drm versions. + * When they are supported all allocations are effectively contiguous + * anyway, so for simplicity we always request non contiguous buffers. + */ + create_exynos.flags = EXYNOS_BO_NONCONTIG;
There might have been logic in exynos_drm that forced Contiguous GEM buffers. At least, that is what this comment suggests. This assumption doesn’t appear to be a good one and I’m not sure if this change was made to fix a bug. After IOMMU support was added, this assumption is no longer true. Hence, the recent mainline kernels have a mismatch with the installed xserver-xorg-video-armsoc 1.4.0-0ubuntu2 armhf X.Org X server on my Odroid XU4.
Enabling CONFIG_EXYNOS_IOMMU solves the problem in my case. However, enabling CONFIG_EXYNOS_IOMMU in exynos_defconfig might break non-IOMMU Exynos platforms.
What’s the solution
There are a couple of possible solutions for this problem that worked for me.
- Fix xf86-video-armsoc to ask for EXYNOS_BO_CONTIG for ARMSOC_BO_SCANOUT and EXYNOS_BO_NONCONTIG in all other cases. With this change, display manager now starts. However, it turns out xf86-video-armsoc is obsoleted in favor of xf86-video-modesetting. The last update to xf86-video-armsoc git was 3 years ago and appears to be inactive.
diff --git a/src/drmmode_exynos/drmmode_exynos.c b/src/drmmode_exynos/drmmode_exynos.c index 91723df..45b2edd 100644 --- a/src/drmmode_exynos/drmmode_exynos.c +++ b/src/drmmode_exynos/drmmode_exynos.c @@ -126,11 +126,10 @@ static int create_custom_gem(int fd, struct armsoc_create_gem *create_gem) assert((create_gem->buf_type == ARMSOC_BO_SCANOUT) || (create_gem->buf_type == ARMSOC_BO_NON_SCANOUT)); - /* Contiguous allocations are not supported in some exynos drm versions. - * When they are supported all allocations are effectively contiguous - * anyway, so for simplicity we always request non contiguous buffers. - */ - create_exynos.flags = EXYNOS_BO_NONCONTIG; + if (create_gem->buf_type == ARMSOC_BO_SCANOUT) + create_exynos.flags = EXYNOS_BO_CONTIG; + else + create_exynos.flags = EXYNOS_BO_NONCONTIG; ret = drmIoctl(fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &create_exynos); if (ret)
- I settled on using xf86-video-modesetting instead of xf86-video-armsoc as a solution. I removed xf86-video-armsoc from my system, brought in the latest xf86-video-modesetting, compiled, and installed it on my system. xf86-video-modesetting uses dumb_create interface instead of DRM_IOCTL_EXYNOS_GEM_CREATE, hence doesn’t suffer from the CONTIG vs NONCONTIG problem.
Exposing CONTIG and NONCONTIG to userspace appears to be causing problems when exynos drm driver determines it can’t support non-contig GEM buffers during frame-buffer initialization, after the userspace allocates them. I am working on finding solution for this problem.