On Sun, Oct 20, 2013 at 05:31:56PM +0100, Russell King - ARM Linux wrote: > On Sun, Oct 20, 2013 at 02:00:57PM +0100, Russell King - ARM Linux wrote: > > As for imx-drm, there was a warning which preceded that oops. Here's the > > full log, below the "---------" marker - this is from unbinding the imx-drm > > module, and then trying to reboot. > > > > imx-drm is really very broken in the way it tries to bend DRM to be > > used in DT - it doesn't consider the lifetime for anything like the > > CRTCs, connectors or encoders. All these have empty .destroy functions > > to them. If we unbind imx-drm, the top level drm_device tries to be > > destroyed, but it leaves behind all the CRTCs, connectors and encoders, > > causing the first warning because none of the framebuffers got cleaned > > up through that destruction (because the functions did nothing.) > > > > The second one is through trying to clean up the framebuffer, which is > > still in use. > > > > The third one is caused because there's still allocated memory objects > > against the DRM memory manager - again, because nothing has been cleaned > > up. > > Right, so how imx-drm "works" as far as DRM initialization is by a wing > and a prayer at the moment. > > It works like this - the driver relies heavily upon this sequence: > > - imx_drm_init() > - creates an imx_drm_device structure to contain references to other > parts. > - registers the imx-drm platform device and an associated structure. > - the platform device is immediately probed, causing it to be registered > with the DRM subsystem. > - the DRM subsystem creates the drm_device structure, and calls the > drivers ->load method. > - the driver initialises some basic data, places a pointer to the > drm_device into the imx_drm_device and returns > - imx_pd_driver_init() > - registers the imx_pd_driver platform device driver for DT devices > with a compatible string of "fsl,imx-parallel-display" > - such devices will be immediately probed > - these allocate an imx_parallel_display structure, which contains > a drm_connector and drm_encoder structure embedded within. > - these structures are registered into the core of imx_drm, and > via the imx_drm_device structure, are both attached to the > drm_device immediately. > - imx_tve_driver_init() > essentially the same as imx_pd_driver_init() > - imx_ldb_driver_init() > essentially the same as imx_pd_driver_init() > - imx_ipu_driver_init() > - registers a platform driver fot DT devices with a compatible string > of "fsl,imx51-ipu", "fsl,imx53-ipu", or "fsl,imx6q-ipu". > - initialises such devices, and creates two new platform devices > called "imx-ipuv3-crtc", one for each display interface. > - ipu_drm_driver_init() > - registers a platform driver for "imx-ipuv3-crtc" devices. > - for each device found > - it allocates a ipu_crtc device structure, which embeds a drm_crtc > structure. > - it registers a CRTC via imx_drm_add_crtc(). > - this allocates an imx_drm_crtc structure, and eventually registers > the drm_crtc structure against the drm_device > - imx_hdmi_driver_init > similar to imx_pd_driver_init > > All that sequence is in init level 6. The last bit comes in init level 7 > (the late_initcall): > > - imx_fb_helper_init() > - this grabs the drm_device, and calls drm_fbdev_cma_init() on it > hoping that we know the number of CRTCs at this point. This is > held indefinitely. > - the resulting drm_fbdev_cma is saved into the imx_drm_device. > > Now, if the imx-drm device is unbound from its driver, all hell breaks > loose - none of these crtc/connector/encoder structures have a meaningful > destroy function - their destruction is all in their individual driver > "remove" functions. This causes some warnings to be spat out from DRM. > > Amongst this is the "last_close" callback which looks at the imx_drm_device, > sees that drm_fbdev_cma is registered against it, and calls > drm_fbdev_cma_restore_mode() on it. drm_fbdev_cma contains objects which > store a pointer to the drm_device structure that it was registered against, > which exists at this point, so everything is fine. > > The unload proceeds, and eventually the drm_device is freed. > > Now, if we rebind the imx-drm device, causing the probe actions above to > be repeated. imx_drm_device still contains a pointer to the drm_fbdev_cma > object that was allocated... Let's ignore the fact that none of the > sub-modules have re-initialised anything against this new drm_device. > > The real fun comes when you try and unbind it again. This time, the > drm_device which is being torn down isn't the one in drm_fbdev_cma, > but we still call drm_fbdev_cma_restore_mode(). This tries to get a > mutex on the _original_ drm_device->mode_config.mutex, which has been > freed. The result is a kernel oops. > > Now, several things stand out here: piece-meal construction of a > drm_device in this manner is unsafe: > - it relies heavily on all devices already being present at the time that > the above sequence starts, and it assumes that the drivers will probe > immediately, as soon as they are registered. > - the late_initcall() is really a "barrier" on the initialisation sequence: > no CRTCs can be registered after that point. > - it is impossible to tear down and re-create the subsystem when the device > goes wrong as you can never clear out that CMA fbdev helper, even if you > unbind every other device in that setup in the right order. > - each of these drivers is itself a separate loadable module, which means > when built in a modular state and loaded under Ubuntu 12.04, which does > multi-threaded module loading, there is no guarantee of any initialisation > order. > > Really, this kind of hack needs to be outlawed. Trying to bend a subsystem > which has a fairly solid model around a single "device" into this kind of > multi-device for the sake of DT is really buggered. > > This is not an imx-drm specific problem: this the same problem which the > Armada DRM driver would have with DT: DT is based around describing > individual components of hardware separately rather than describing > something at high level. > > I've been looking at what can be done with imx-drm. One thing that > desperately needs sorting is that drm_fbdev_cma thing, which has to be > registered after all CRTCs. The problem is that there is _no way_ to > positively know when all CRTCs have been registered, because they're > separate devices entirely. > > For other stuff, it would require quite an amount of restructuring, so > that sub-modules don't "probe" themselves until the main drm_device is > known to be in place, and clean themselves up in the ->destroy callbacks. > ... maybe. Sorting out the connectors/encoders might actually be the > easier bit of the task, something which I'm currently looking into at > the moment.
Further comments as a result of this: I have a much better solution in place for encoders and connectors. I'm now able to remove and re-add back connectors. This all sounds good, but it doesn't quite work. The reason is that the fb_helper layer caches pointers to the connectors, and number of connectors. This doesn't get updated when we remove and add connectors - which causes another set of problems. A similar problem exists if we add a connector after the fb helper has been initialised. _______________________________________________ devel mailing list de...@linuxdriverproject.org http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel