Message ID | 20131016180735.GI25034@n2100.arm.linux.org.uk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote: > Sorry, but I don't think imx-drm is driving the hardware correctly, and > I know that Greg wants it moved out of drivers/staging, but frankly it > seems to be far from ready for that. Certainly the HDMI parts seems to > be especially problematical. I want it out of staging if it's working properly. Yours is the first report of it not working properly, and in fact, probably one of the first users of the driver, as I haven't gotten any reports of it working or not at all over the years. thanks, greg k-h
On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote: > On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote: > > Sorry, but I don't think imx-drm is driving the hardware correctly, and > > I know that Greg wants it moved out of drivers/staging, but frankly it > > seems to be far from ready for that. Certainly the HDMI parts seems to > > be especially problematical. > > I want it out of staging if it's working properly. Yours is the first > report of it not working properly, and in fact, probably one of the > first users of the driver, as I haven't gotten any reports of it working > or not at all over the years. Well, part of that is because I have this other thing called Armada DRM, which is a similar thing to imx-drm, except for the Marvell Dove SoCs, so it's been really quite easy to get a full Ubuntu 12.04 up and running on the IMX SoC I have here. As part of that effort, I'm now using my Armada DRM Xorg driver with imx-drm to test this stuff out. (Bearing in mind that IMX and Dove use the same Vivante GPU, there's some sense in getting my Xorg Armada DRM driver working on both.) I'm not aware of there being any X drivers for imx-drm (google turns up nothing), which might be a reason why it hasn't been well tested and has also languished in drivers/staging for soo long. Alternatively, maybe my google searching sucks, or it is out there somewhere but hidden from googlebot? To be fair, so far most of the problems I'm finding are with the HDMI addition to imx-drm rather than imx-drm itself: there's been the lockdep problem and the clock polarity problem which the HDMI stuff discovered. Looking at the todo list for moving it out of staging, we have: - get DRM Maintainer review for this code - Wait for common display framework to hit mainline and update the IPU driver to use it. This will most probably make changes to the devicetree bindings necessary. - Factor out more code to common helper functions - decide where to put the base driver. It is not specific to a subsystem and would be used by DRM/KMS and media/V4L2 (1) is quite a difficult task: I'm waiting for a review of the Armada DRM stuff, which I'm hoping will make the next merge window. Rob Clark is looking at that but has been distracted recently from completing it. (2) CDF... has been around in RFC according to LWN.net but doesn't seem to make much in the way of progress from what I can see, despite there allegedly being "many developers show[ing] interest in the first RFC". CDF is over a year old now - first RFC 17 Aug 2012, second 22 Nov 2012, third 9 Aug 2013. (3) is an on-going effort and really isn't a reason for it to stay in staging. (4) is probably the biggest issue. The problem there is that the IMX display subsystem is very flexible: it's basically a set of DMA engines on the front, and behind that a fair number of modules implementing facilities like image rotation, display driving and image capture. Display driving alone involves setting up waveforms and writing some microcode to tell the thing what to do on certain events (like end of frame etc.) Hence it doesn't fit well into any particular "Linux" subsystem. In this regard, it's a victim of its own flexibility. I think the biggest problem though is its complexity. It doesn't fit into the "single device for a card" model which DRM has. It's made up from several separate devices, which is all very well, but it leads to it having its own private "framework" to glue all the different devices together - which adds a layer of indirection and makes the code harder to understand. As for trying to work out how any of this stuff works - even though I have the manual which describes all the registers, I'm struggling with it because there seems to be bits which just aren't documented and its not always obvious that the code can be relied upon either. That all said, I don't think throwing this out of the kernel will do it any good what so ever - that will just mean that there's even less potential eyes looking at it. Yes, some of that is my own selfishness here - I don't want to have to carry this hunk of code around in my tree and then be lumbered with trying to get it into mainline myself!
On Wed, Oct 16, 2013 at 08:02:11PM +0100, Russell King - ARM Linux wrote: > On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote: > > On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote: > > > Sorry, but I don't think imx-drm is driving the hardware correctly, and > > > I know that Greg wants it moved out of drivers/staging, but frankly it > > > seems to be far from ready for that. Certainly the HDMI parts seems to > > > be especially problematical. > > > > I want it out of staging if it's working properly. Yours is the first > > report of it not working properly, and in fact, probably one of the > > first users of the driver, as I haven't gotten any reports of it working > > or not at all over the years. > > Well, part of that is because I have this other thing called Armada DRM, > which is a similar thing to imx-drm, except for the Marvell Dove SoCs, > so it's been really quite easy to get a full Ubuntu 12.04 up and running > on the IMX SoC I have here. > > As part of that effort, I'm now using my Armada DRM Xorg driver with > imx-drm to test this stuff out. (Bearing in mind that IMX and Dove use > the same Vivante GPU, there's some sense in getting my Xorg Armada DRM > driver working on both.) > > I'm not aware of there being any X drivers for imx-drm (google turns > up nothing), which might be a reason why it hasn't been well tested > and has also languished in drivers/staging for soo long. Alternatively, > maybe my google searching sucks, or it is out there somewhere but > hidden from googlebot? There is no X driver for imx-drm. I once tested it with the xf86-modesetting driver which worked with a few patches back then. These patches are now part of the modesetting driver. We have a wrapper tool here which we use to configure the KMS part and pass the framebuffers to QT. > > To be fair, so far most of the problems I'm finding are with the HDMI > addition to imx-drm rather than imx-drm itself: there's been the lockdep > problem and the clock polarity problem which the HDMI stuff discovered. > > Looking at the todo list for moving it out of staging, we have: > > - get DRM Maintainer review for this code > - Wait for common display framework to hit mainline and update the IPU > driver to use it. This will most probably make changes to the devicetree > bindings necessary. > - Factor out more code to common helper functions > - decide where to put the base driver. It is not specific to a subsystem > and would be used by DRM/KMS and media/V4L2 > > (1) is quite a difficult task: I'm waiting for a review of the Armada DRM > stuff, which I'm hoping will make the next merge window. Rob Clark is > looking at that but has been distracted recently from completing it. We have waited for quite a long time aswell before we decided to push the imx-drm driver to staging to at least get more exposure for the driver. The situation is, well... unsatisfying. > > (2) CDF... has been around in RFC according to LWN.net but doesn't seem to > make much in the way of progress from what I can see, despite there > allegedly being "many developers show[ing] interest in the first RFC". > CDF is over a year old now - first RFC 17 Aug 2012, second 22 Nov 2012, > third 9 Aug 2013. From what I heard Laurent is still committed to mainline CDF. > > (3) is an on-going effort and really isn't a reason for it to stay in > staging. > > (4) is probably the biggest issue. The problem there is that the IMX > display subsystem is very flexible: it's basically a set of DMA engines > on the front, and behind that a fair number of modules implementing > facilities like image rotation, display driving and image capture. > Display driving alone involves setting up waveforms and writing some > microcode to tell the thing what to do on certain events (like end > of frame etc.) Hence it doesn't fit well into any particular "Linux" > subsystem. In this regard, it's a victim of its own flexibility. > > I think the biggest problem though is its complexity. It doesn't fit > into the "single device for a card" model which DRM has. It's made > up from several separate devices, which is all very well, but it leads > to it having its own private "framework" to glue all the different > devices together - which adds a layer of indirection and makes the code > harder to understand. I tried adding generic stuff to DRM to support this and failed badly due to resistance of the maintainers. I didn't get much input what I should do better or different (besides a general "make it a helper library"). Also nobody seemed to understand the problems I had with the multi device nature of the i.MX IPU. I think we made ourselves comfortable with being in the kernel, even if it's only in staging. We should move forward instead and see how we get the driver into the kernel. Sascha
Hi Russell, Am Mittwoch, den 16.10.2013, 20:02 +0100 schrieb Russell King - ARM Linux: > On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote: > > On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote: > > > Sorry, but I don't think imx-drm is driving the hardware correctly, and > > > I know that Greg wants it moved out of drivers/staging, but frankly it > > > seems to be far from ready for that. Certainly the HDMI parts seems to > > > be especially problematical. > > > > I want it out of staging if it's working properly. Yours is the first > > report of it not working properly, and in fact, probably one of the > > first users of the driver, as I haven't gotten any reports of it working > > or not at all over the years. > > Well, part of that is because I have this other thing called Armada DRM, > which is a similar thing to imx-drm, except for the Marvell Dove SoCs, > so it's been really quite easy to get a full Ubuntu 12.04 up and running > on the IMX SoC I have here. > > As part of that effort, I'm now using my Armada DRM Xorg driver with > imx-drm to test this stuff out. (Bearing in mind that IMX and Dove use > the same Vivante GPU, there's some sense in getting my Xorg Armada DRM > driver working on both.) > > I'm not aware of there being any X drivers for imx-drm (google turns > up nothing), which might be a reason why it hasn't been well tested > and has also languished in drivers/staging for soo long. Alternatively, > maybe my google searching sucks, or it is out there somewhere but > hidden from googlebot? > X.Org isn't the center of the world anymore. For some general purpose distros this might still hold true for some time, but certainly not for the use-cases we test this driver with. For most of our embedded use-cases we currently use the FBdev emulation (phasing this out at the moment) or the apps are sitting right on top of the raw KMS APIs, rather than on top of a display server. We also did some experiments with Wayland (Weston) on top of imx-drm, which worked quite well. There might be dragons hiding in some corners for the more general purpose use-cases and we are happy to have you test the driver and provide valuable reports. > To be fair, so far most of the problems I'm finding are with the HDMI > addition to imx-drm rather than imx-drm itself: there's been the lockdep > problem and the clock polarity problem which the HDMI stuff discovered. > > Looking at the todo list for moving it out of staging, we have: > > - get DRM Maintainer review for this code > - Wait for common display framework to hit mainline and update the IPU > driver to use it. This will most probably make changes to the devicetree > bindings necessary. > - Factor out more code to common helper functions > - decide where to put the base driver. It is not specific to a subsystem > and would be used by DRM/KMS and media/V4L2 > > (1) is quite a difficult task: I'm waiting for a review of the Armada DRM > stuff, which I'm hoping will make the next merge window. Rob Clark is > looking at that but has been distracted recently from completing it. > > (2) CDF... has been around in RFC according to LWN.net but doesn't seem to > make much in the way of progress from what I can see, despite there > allegedly being "many developers show[ing] interest in the first RFC". > CDF is over a year old now - first RFC 17 Aug 2012, second 22 Nov 2012, > third 9 Aug 2013. > Philipp has a prototype of CDF on imx-drm working internally and I suspect he will be able to post patches shortly after ELCE. > (3) is an on-going effort and really isn't a reason for it to stay in > staging. > > (4) is probably the biggest issue. The problem there is that the IMX > display subsystem is very flexible: it's basically a set of DMA engines > on the front, and behind that a fair number of modules implementing > facilities like image rotation, display driving and image capture. > Display driving alone involves setting up waveforms and writing some > microcode to tell the thing what to do on certain events (like end > of frame etc.) Hence it doesn't fit well into any particular "Linux" > subsystem. In this regard, it's a victim of its own flexibility. We are aiming to do the same thing as the Tegra host1x driver: move the IPU core to drivers/gpu and export API for other drivers to use. This may mean we still have to keep the DRM part in staging (at least until the CDF thing is sorted, as this prevents us from setting the devicetree bindings in stone), but at least should be a step in the right direction. Regards, Lucas
On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote: > On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote: > > Sorry, but I don't think imx-drm is driving the hardware correctly, and > > I know that Greg wants it moved out of drivers/staging, but frankly it > > seems to be far from ready for that. Certainly the HDMI parts seems to > > be especially problematical. > > I want it out of staging if it's working properly. Yours is the first > report of it not working properly, and in fact, probably one of the > first users of the driver, as I haven't gotten any reports of it working > or not at all over the years. Next problem... unbinding, rebinding, and then unbinding the imx-drm device produces the nice oops below. I've not debugged this yet. Alignment trap: not handling instruction e1932f9f at [<c00758ec>] Unhandled fault: alignment exception (0x001) at 0x6e72666f Internal error: : 1 [#1] SMP ARM Modules linked in: fuse bnep rfcomm bluetooth CPU: 0 PID: 1125 Comm: bash Tainted: G W 3.12.0-rc4+ #123 task: d0d6ec00 ti: d7ff2000 task.ti: d7ff2000 PC is at __lock_acquire+0x1a8/0x1e14 LR is at lock_acquire+0x68/0x7c pc : [<c00758f0>] lr : [<c0077aa8>] psr: 20070093 sp : d7ff3cc8 ip : 00000000 fp : d7ff3d54 r10: db2a6334 r9 : 00000000 r8 : 6e72656b r7 : c0846208 r6 : c08852cc r5 : d0d6ec00 r4 : 00000002 r3 : 6e72666f r2 : db2a6334 r1 : 00000001 r0 : d7ff2000 Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c53c7d Table: 20df804a DAC: 00000015 Process bash (pid: 1125, stack limit = 0xd7ff2240) Stack: (0xd7ff3cc8 to 0xd7ff4000) 3cc0: 00000006 00000007 c0cd22f0 00000006 d7ff3d1c d7ff3ce8 3ce0: c00782f8 c0075050 00000001 00000000 db801f00 d7ff2000 c0078648 d7ff2000 3d00: 00000001 d7ff3e08 d7ff3e60 d7ff3dd8 d7ff3d3c d7ff3d20 00000000 d7ff3e08 3d20: d7ff3d7c d7ff3d30 c0072a58 00000000 d7ff2000 60070013 d0d6ec00 d7ff2000 3d40: c06679c8 d0d6ec00 d7ff3d8c d7ff3d58 c0077aa8 c0075754 00000002 00000000 3d60: 00000000 c02ff27c 00000000 00000002 db2a62fc c02ff27c c08852cc 00000000 3d80: d7ff3de4 d7ff3d90 c05f80c4 c0077a4c 00000002 00000000 c02ff27c c0072a20 3da0: dad64000 d7ff3e24 d7ff3df8 d7ff3e04 d7ff3e5c d0d6f000 c013f1c8 db322880 3dc0: db2a6440 db2a6000 c0872568 00000008 c06679c8 db286000 d7ff3e04 d7ff3de8 3de0: c02ff27c c05f8074 db280f00 db322880 db2a6000 db29b810 d7ff3e1c d7ff3e08 3e00: c02f13ac c02ff268 d0e55000 c087265c d7ff3e2c d7ff3e20 c0464d7c c02f1398 3e20: d7ff3e54 d7ff3e30 c02f506c c0464d68 d0e55000 c087265c db29b810 c0872568 3e40: 00000008 db286000 d7ff3e74 d7ff3e58 c02fa284 c02f503c c087265c c087265c 3e60: db29b810 00000008 d7ff3e8c d7ff3e78 c02fb900 c02fa258 db29b810 c0872678 3e80: d7ff3e9c d7ff3e90 c0464d54 c02fb8d4 d7ff3eac d7ff3ea0 c0312bfc c0464d44 3ea0: d7ff3ec4 d7ff3eb0 c03113b0 c0312be8 db29b844 db29b810 d7ff3edc d7ff3ec8 3ec0: c0311434 c0311344 c0872678 c085b588 d7ff3efc d7ff3ee0 c03103ac c0311418 3ee0: c941b300 c941b318 d7ff3f70 db28c280 d7ff3f0c d7ff3f00 c030f934 c0310338 3f00: d7ff3f3c d7ff3f10 c013d7d0 c030f918 d7ff3f70 dbb5e600 00000008 003ba408 3f20: d7ff3f70 00000000 00000000 00000008 d7ff3f6c d7ff3f40 c00db77c c013d6d4 3f40: 00000001 c000eb44 dbb5e600 00000000 d7ff3f70 003ba408 00000000 00000008 3f60: d7ff3fa4 d7ff3f70 c00dbb58 c00db6b8 00000000 00000000 d7ff3f94 b6f7fa78 3f80: 00000008 003ba408 00000004 c000eb44 d7ff2000 00000000 00000000 d7ff3fa8 3fa0: c000e980 c00dbb18 b6f7fa78 00000008 00000001 003ba408 00000008 00000000 3fc0: b6f7fa78 00000008 003ba408 00000004 bee5c9ec 000a6094 00000000 003f7f08 3fe0: 00000000 bee5c96c b6eee747 b6f2611c 40070010 00000001 00000138 00000020 Backtrace: [<c0075748>] (__lock_acquire+0x0/0x1e14) from [<c0077aa8>] (lock_acquire+0x68/0x7c) [<c0077a40>] (lock_acquire+0x0/0x7c) from [<c05f80c4>] (mutex_lock_nested+0x5c/0x394) r7:00000000 r6:c08852cc r5:c02ff27c r4:db2a62fc [<c05f8068>] (mutex_lock_nested+0x0/0x394) from [<c02ff27c>] (drm_modeset_lock_all+0x20/0x58) [<c02ff25c>] (drm_modeset_lock_all+0x0/0x58) from [<c02f13ac>] (drm_fbdev_cma_restore_mode+0x20/0x34) r6:db29b810 r5:db2a6000 r4:db322880 r3:db280f00 [<c02f138c>] (drm_fbdev_cma_restore_mode+0x0/0x34) from [<c0464d7c>] (imx_drm_driver_lastclose+0x20/0x24) r5:c087265c r4:d0e55000 [<c0464d5c>] (imx_drm_driver_lastclose+0x0/0x24) from [<c02f506c>] (drm_lastclose+0x3c/0x174) [<c02f5030>] (drm_lastclose+0x0/0x174) from [<c02fa284>] (drm_put_dev+0x38/0x154) [<c02fa24c>] (drm_put_dev+0x0/0x154) from [<c02fb900>] (drm_platform_exit+0x38/0x5c) r7:00000008 r6:db29b810 r5:c087265c r4:c087265c [<c02fb8c8>] (drm_platform_exit+0x0/0x5c) from [<c0464d54>] (imx_drm_platform_remove+0x1c/0x24) r5:c0872678 r4:db29b810 [<c0464d38>] (imx_drm_platform_remove+0x0/0x24) from [<c0312bfc>] (platform_drv_remove+0x20/0x24) [<c0312bdc>] (platform_drv_remove+0x0/0x24) from [<c03113b0>] (__device_release_driver+0x78/0xd4) [<c0311338>] (__device_release_driver+0x0/0xd4) from [<c0311434>] (device_release_driver+0x28/0x34) r5:db29b810 r4:db29b844 [<c031140c>] (device_release_driver+0x0/0x34) from [<c03103ac>] (unbind_store+0x80/0x98) r5:c085b588 r4:c0872678 [<c031032c>] (unbind_store+0x0/0x98) from [<c030f934>] (drv_attr_store+0x28/0x34) r7:db28c280 r6:d7ff3f70 r5:c941b318 r4:c941b300 [<c030f90c>] (drv_attr_store+0x0/0x34) from [<c013d7d0>] (sysfs_write_file+0x108/0x188) [<c013d6c8>] (sysfs_write_file+0x0/0x188) from [<c00db77c>] (vfs_write+0xd0/0x19c) [<c00db6ac>] (vfs_write+0x0/0x19c) from [<c00dbb58>] (SyS_write+0x4c/0x78) [<c00dbb0c>] (SyS_write+0x0/0x78) from [<c000e980>] (ret_fast_syscall+0x0/0x48) Code: 0affffbd e2883f41 f593f000 e1932f9f (e2822001) ---[ end trace f2924517b64a28f4 ]---
Another problem. After performing several modesets, the IPU seems to lock up and produce no syncs or output data. I've seen this many times over the last week while testing out various aspects of imx-drm, and had put it down to problems with the clocking arrangement getting its settings wrong. Now that I've sorted all that though, and I still have the problem, there's something else going on. What I see is: - the HDMI clock is running correctly (right frequency and unmodulated) - the TMDS data lines show signs of there being some data (probably control, guard bands and data islands from the frame composer in the HDMI interface). The data lines are definitely lacking image data though. - reading the various status registers indicates that all FIFOs within the IPU are empty. - the attached TV says that there is no HDMI signal. One of my tests has been to cycle through all display resolutions from the smallest width to the largest, leaving each one set for 30 seconds. This will occasionally provoke the problem, but obviously is rather slow to do so. I tried this with a less demanding test last night as far as a change in the settings: switching between 720p at 50 and 60Hz. The clocks for these two modes are the same at 74.25MHz, and the vertical timing parameters are identical. The only timing difference is with the horizontal parameters: 1280x720 (0x41) 74.2MHz +HSync +VSync +preferred h: width 1280 start 1390 end 1430 total 1650 skew 0 clock 45.0KHz v: height 720 start 725 end 730 total 750 clock 60.0Hz 1280x720 (0x4f) 74.2MHz +HSync +VSync h: width 1280 start 1720 end 1760 total 1980 skew 0 clock 37.5KHz v: height 720 start 725 end 730 total 750 clock 50.0Hz This dies within a couple of minutes. I haven't gathered enough information to tell whether it always dies when switching from 50 -> 60Hz or whether it's any switch. My test for this is basically: while :; do xrandr -s 1280x720 -r 50 sleep 5 xrandr -s 1280x720 -r 60 sleep 5 done
On Sun, Oct 20, 2013 at 01:04:34AM +0100, Russell King - ARM Linux wrote: > On Wed, Oct 16, 2013 at 11:31:07AM -0700, Greg Kroah-Hartman wrote: > > On Wed, Oct 16, 2013 at 07:07:35PM +0100, Russell King - ARM Linux wrote: > > > Sorry, but I don't think imx-drm is driving the hardware correctly, and > > > I know that Greg wants it moved out of drivers/staging, but frankly it > > > seems to be far from ready for that. Certainly the HDMI parts seems to > > > be especially problematical. > > > > I want it out of staging if it's working properly. Yours is the first > > report of it not working properly, and in fact, probably one of the > > first users of the driver, as I haven't gotten any reports of it working > > or not at all over the years. > > Next problem... unbinding, rebinding, and then unbinding the imx-drm > device produces the nice oops below. I've not debugged this yet. I've been tweaking the ARM oops format slightly (I hope this isn't going to end up breaking any tools... it's only a minor change.) I've been using this as a way of testing it. The change here is using %ps instead of %pS for the first symbolic print in each entry (it's always the start of the function). The other change is fixing the saved register set so saves including r10 get printed - and its better formatted. 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. Finally, the oops at the end. I thought that's a candidate for enabling kobject debugging and release debugging, but as soon as I do, it perversely goes away! Eventually I managed to reproduce it, and it's the same bug which was investigated recently wrt sysfs lifetimes. I would test David's fix for this, but it *isn't* generated against an -rc kernel, it rejects fairly horribly. Since it happens without kobject debugging enabled, it would be good to get the fix in for 3.12-rc. David? kobject: 'card0' (db2bfc18): kobject_add_internal: parent: 'drm', set: 'devices' kobject: 'card0' (db2bfc18): kobject_uevent_env kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0' [drm] Supports vblank timestamp caching Rev 1 (10.10.2010). [drm] No driver support for vblank timestamp query. ... kobject: 'card0' (db2bfc18): kobject_uevent_env kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0' kobject: 'imx-hdmi' (db293840): kobject_uevent_env kobject: 'imx-hdmi' (db293840): fill_kobj_path: path = '/bus/platform/drivers/imx-hdmi' ... kobject: 'card0' (db2bfc18): kobject_uevent_env kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0' kobject: 'card0-HDMI-A-1' (db837020): kobject_uevent_env kobject: 'card0-HDMI-A-1' (db837020): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0/card0-HDMI-A-1' ... kobject: 'card0' (db2bfc18): kobject_uevent_env kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0' kobject: 'card0-HDMI-A-1' (db837020): kobject_uevent_env kobject: 'card0-HDMI-A-1' (db837020): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0/card0-HDMI-A-1' ... kobject: 'card0' (db2bfc18): kobject_uevent_env kobject: 'card0' (db2bfc18): fill_kobj_path: path = '/devices/platform/imx-drm/drm/card0' kobject: 'drm' (db28fb00): kobject_release, parent db2bf418 (delayed) [drm] Module unloaded kobject: 'controlD64' (db2bf818): kobject_cleanup, parent (null) kobject: 'controlD64' (db2bf818): calling ktype release kobject: 'controlD64': free name kobject: 'drm' (db28fb00): kobject_cleanup, parent db2bf418 kobject: 'drm' (db28fb00): auto cleanup kobject_del kobject: 'drm' (db28fb00): calling ktype release kobject: 'drm': free name ... WARNING: CPU: 0 PID: 1027 at /home/rmk/git/linux-rmk/include/linux/kref.h:47 kobject_get+0x60/0x74() Modules linked in: fuse rfcomm bnep bluetooth CPU: 0 PID: 1027 Comm: reboot Tainted: G W 3.12.0-rc4+ #128 Backtrace: [<c001218c>] (dump_backtrace) from [<c0012328>] (show_stack+0x18/0x1c) r6:c0646298 r5:0000002f r4:00000000 r3:00000000 [<c0012310>] (show_stack) from [<c05f6a78>] (dump_stack+0x70/0x90) [<c05f6a08>] (dump_stack) from [<c00233a0>] (warn_slowpath_common+0x6c/0x8c) r4:00000000 r3:db142400 [<c0023334>] (warn_slowpath_common) from [<c00233e4>] (warn_slowpath_null+0x24/0x2c) r8:c088361c r7:db837024 r6:c0dc7fa4 r5:c08834f2 r4:db2bfc18 ^^^^^^^^ kobject address [<c00233c0>] (warn_slowpath_null) from [<c027fbc8>] (kobject_get+0x60/0x74) [<c027fb68>] (kobject_get) from [<c030dbfc>] (get_device+0x1c/0x24) r5:00000000 r4:db837018 [<c030dbe0>] (get_device) from [<c030fb0c>] (device_shutdown+0x90/0x19c) ------------------- WARNING: CPU: 0 PID: 997 at /home/rmk/git/linux-rmk/drivers/gpu/drm/drm_crtc.c:4036 drm_mode_config_cleanup+0x250/0x25c() Modules linked in: fuse bnep rfcomm bluetooth CPU: 0 PID: 997 Comm: bash Not tainted 3.12.0-rc4+ #127 Backtrace: [<c001218c>] (dump_backtrace) from [<c0012328>] (show_stack+0x18/0x1c) r6:c065dc74 r5:00000fc4 r4:00000000 r3:00000000 [<c0012310>] (show_stack) from [<c05f5f90>] (dump_stack+0x70/0x90) [<c05f5f20>] (dump_stack) from [<c00233a0>] (warn_slowpath_common+0x6c/0x8c) r4:00000000 r3:d7c75a00 [<c0023334>] (warn_slowpath_common) from [<c00233e4>] (warn_slowpath_null+0x24/0x2c) r8:db2a64cc r7:db2a6410 r6:db2a64c0 r5:db2a6000 r4:db2a64c0 [<c00233c0>] (warn_slowpath_null) from [<c03008b0>] (drm_mode_config_cleanup+0x250/0x25c) [<c0300660>] (drm_mode_config_cleanup) from [<c0465494>] (imx_drm_driver_unload+0x1c/0x2c) r10:db286000 r9:c06679c8 r8:00000008 r7:c0872568 r6:db29b810 r5:c087265c r4:db280f00 r3:d7c75a00 [<c0465478>] (imx_drm_driver_unload) from [<c02fa29c>] (drm_put_dev+0x50/0x154) r4:db2a6000 r3:c0465478 [<c02fa24c>] (drm_put_dev) from [<c02fb900>] (drm_platform_exit+0x38/0x5c) r7:00000008 r6:db29b810 r5:c087265c r4:c087265c [<c02fb8c8>] (drm_platform_exit) from [<c0464d54>] (imx_drm_platform_remove+0x1c/0x24) r5:c0872678 r4:db29b810 [<c0464d38>] (imx_drm_platform_remove) from [<c0312bfc>] (platform_drv_remove+0x20/0x24) [<c0312bdc>] (platform_drv_remove) from [<c03113b0>] (__device_release_driver+0x78/0xd4) [<c0311338>] (__device_release_driver) from [<c0311434>] (device_release_driver+0x28/0x34) r5:db29b810 r4:db29b844 [<c031140c>] (device_release_driver) from [<c03103ac>] (unbind_store+0x80/0x98) r5:c085b588 r4:c0872678 [<c031032c>] (unbind_store) from [<c030f934>] (drv_attr_store+0x28/0x34) r7:db28c280 r6:d7d9ff70 r5:d7d9a898 r4:d7d9a880 [<c030f90c>] (drv_attr_store) from [<c013d7d0>] (sysfs_write_file+0x108/0x188) [<c013d6c8>] (sysfs_write_file) from [<c00db77c>] (vfs_write+0xd0/0x19c) r10:00000008 r9:00000000 r8:00000000 r7:d7d9ff70 r6:0132f408 r5:00000008 r4:d7df5d00 r3:d7d9ff70 [<c00db6ac>] (vfs_write) from [<c00dbb58>] (SyS_write+0x4c/0x78) r10:00000008 r8:00000000 r7:0132f408 r6:d7d9ff70 r5:00000000 r4:d7df5d00 [<c00dbb0c>] (SyS_write) from [<c000e980>] (ret_fast_syscall+0x0/0x48) r10:00000000 r9:d7d9e000 r8:c000eb44 r7:00000004 r6:0132f408 r5:00000008 r4:b6f72a78 ---[ end trace 44f221ca42d7ae54 ]--- ------------[ cut here ]------------ WARNING: CPU: 0 PID: 997 at /home/rmk/git/linux-rmk/drivers/gpu/drm/drm_crtc.c:571 drm_framebuffer_remove+0x10c/0x118() Modules linked in: fuse bnep rfcomm bluetooth CPU: 0 PID: 997 Comm: bash Tainted: G W 3.12.0-rc4+ #127 Backtrace: [<c001218c>] (dump_backtrace) from [<c0012328>] (show_stack+0x18/0x1c) r6:c065dc74 r5:0000023b r4:00000000 r3:00000000 [<c0012310>] (show_stack) from [<c05f5f90>] (dump_stack+0x70/0x90) [<c05f5f20>] (dump_stack) from [<c00233a0>] (warn_slowpath_common+0x6c/0x8c) r4:00000000 r3:d7c75a00 [<c0023334>] (warn_slowpath_common) from [<c00233e4>] (warn_slowpath_null+0x24/0x2c) r8:db2a6000 r7:db2a6410 r6:db2a64c0 r5:dae7b280 r4:db32ea00 [<c00233c0>] (warn_slowpath_null) from [<c0300654>] (drm_framebuffer_remove+0x10c/0x118) [<c0300548>] (drm_framebuffer_remove) from [<c0300800>] (drm_mode_config_cleanup+0x1a0/0x25c) r10:00200200 r9:00100100 r8:db2a64cc r7:db2a6410 r6:db2a64c0 r5:db2a6000 r4:db32ea00 [<c0300660>] (drm_mode_config_cleanup) from [<c0465494>] (imx_drm_driver_unload+0x1c/0x2c) r10:db286000 r9:c06679c8 r8:00000008 r7:c0872568 r6:db29b810 r5:c087265c r4:db280f00 r3:d7c75a00 [<c0465478>] (imx_drm_driver_unload) from [<c02fa29c>] (drm_put_dev+0x50/0x154) r4:db2a6000 r3:c0465478 [<c02fa24c>] (drm_put_dev) from [<c02fb900>] (drm_platform_exit+0x38/0x5c) r7:00000008 r6:db29b810 r5:c087265c r4:c087265c [<c02fb8c8>] (drm_platform_exit) from [<c0464d54>] (imx_drm_platform_remove+0x1c/0x24) r5:c0872678 r4:db29b810 [<c0464d38>] (imx_drm_platform_remove) from [<c0312bfc>] (platform_drv_remove+0x20/0x24) [<c0312bdc>] (platform_drv_remove) from [<c03113b0>] (__device_release_driver+0x78/0xd4) [<c0311338>] (__device_release_driver) from [<c0311434>] (device_release_driver+0x28/0x34) r5:db29b810 r4:db29b844 [<c031140c>] (device_release_driver) from [<c03103ac>] (unbind_store+0x80/0x98) r5:c085b588 r4:c0872678 [<c031032c>] (unbind_store) from [<c030f934>] (drv_attr_store+0x28/0x34) r7:db28c280 r6:d7d9ff70 r5:d7d9a898 r4:d7d9a880 [<c030f90c>] (drv_attr_store) from [<c013d7d0>] (sysfs_write_file+0x108/0x188) [<c013d6c8>] (sysfs_write_file) from [<c00db77c>] (vfs_write+0xd0/0x19c) r10:00000008 r9:00000000 r8:00000000 r7:d7d9ff70 r6:0132f408 r5:00000008 r4:d7df5d00 r3:d7d9ff70 [<c00db6ac>] (vfs_write) from [<c00dbb58>] (SyS_write+0x4c/0x78) r10:00000008 r8:00000000 r7:0132f408 r6:d7d9ff70 r5:00000000 r4:d7df5d00 [<c00dbb0c>] (SyS_write) from [<c000e980>] (ret_fast_syscall+0x0/0x48) r10:00000000 r9:d7d9e000 r8:c000eb44 r7:00000004 r6:0132f408 r5:00000008 r4:b6f72a78 ---[ end trace 44f221ca42d7ae55 ]--- ------------[ cut here ]------------ WARNING: CPU: 0 PID: 997 at /home/rmk/git/linux-rmk/drivers/gpu/drm/drm_mm.c:578 drm_mm_takedown+0x2c/0x34() Memory manager not clean during takedown. Modules linked in: fuse bnep rfcomm bluetooth CPU: 0 PID: 997 Comm: bash Tainted: G W 3.12.0-rc4+ #127 Backtrace: [<c001218c>] (dump_backtrace) from [<c0012328>] (show_stack+0x18/0x1c) r6:c065dbc8 r5:00000242 r4:00000000 r3:00000000 [<c0012310>] (show_stack) from [<c05f5f90>] (dump_stack+0x70/0x90) [<c05f5f20>] (dump_stack) from [<c00233a0>] (warn_slowpath_common+0x6c/0x8c) r4:d7d9fdf8 r3:d7c75a00 [<c0023334>] (warn_slowpath_common) from [<c0023464>] (warn_slowpath_fmt+0x38/0x40) r8:00000008 r7:c0872568 r6:db2a6110 r5:db286080 r4:db286080 [<c0023430>] (warn_slowpath_fmt) from [<c02fd5f0>] (drm_mm_takedown+0x2c/0x34) r3:db2860ac r2:c065dbfc [<c02fd5c4>] (drm_mm_takedown) from [<c030b3d0>] (drm_vma_offset_manager_destroy+0x1c/0x28) [<c030b3b4>] (drm_vma_offset_manager_destroy) from [<c02f6d94>] (drm_gem_destroy+0x1c/0x30) r4:db2a6000 r3:00003000 [<c02f6d78>] (drm_gem_destroy) from [<c02fa384>] (drm_put_dev+0x138/0x154) r5:db2a6110 r4:db2a6000 [<c02fa24c>] (drm_put_dev) from [<c02fb900>] (drm_platform_exit+0x38/0x5c) r7:00000008 r6:db29b810 r5:c087265c r4:c087265c [<c02fb8c8>] (drm_platform_exit) from [<c0464d54>] (imx_drm_platform_remove+0x1c/0x24) r5:c0872678 r4:db29b810 [<c0464d38>] (imx_drm_platform_remove) from [<c0312bfc>] (platform_drv_remove+0x20/0x24) [<c0312bdc>] (platform_drv_remove) from [<c03113b0>] (__device_release_driver+0x78/0xd4) [<c0311338>] (__device_release_driver) from [<c0311434>] (device_release_driver+0x28/0x34) r5:db29b810 r4:db29b844 [<c031140c>] (device_release_driver) from [<c03103ac>] (unbind_store+0x80/0x98) r5:c085b588 r4:c0872678 [<c031032c>] (unbind_store) from [<c030f934>] (drv_attr_store+0x28/0x34) r7:db28c280 r6:d7d9ff70 r5:d7d9a898 r4:d7d9a880 [<c030f90c>] (drv_attr_store) from [<c013d7d0>] (sysfs_write_file+0x108/0x188) [<c013d6c8>] (sysfs_write_file) from [<c00db77c>] (vfs_write+0xd0/0x19c) r10:00000008 r9:00000000 r8:00000000 r7:d7d9ff70 r6:0132f408 r5:00000008 r4:d7df5d00 r3:d7d9ff70 [<c00db6ac>] (vfs_write) from [<c00dbb58>] (SyS_write+0x4c/0x78) r10:00000008 r8:00000000 r7:0132f408 r6:d7d9ff70 r5:00000000 r4:d7df5d00 [<c00dbb0c>] (SyS_write) from [<c000e980>] (ret_fast_syscall+0x0/0x48) r10:00000000 r9:d7d9e000 r8:c000eb44 r7:00000004 r6:0132f408 r5:00000008 r4:b6f72a78 ---[ end trace 44f221ca42d7ae56 ]--- [drm] Module unloaded Alignment trap: not handling instruction e1932f9f at [<c00758ec>] Unhandled fault: alignment exception (0x001) at 0x63700b11 Internal error: : 1 [#1] SMP ARM Modules linked in: fuse bnep rfcomm bluetooth CPU: 0 PID: 1050 Comm: reboot Tainted: G W 3.12.0-rc4+ #127 task: d7f68000 ti: d7f4a000 task.ti: d7f4a000 PC is at __lock_acquire+0x1a8/0x1e14 LR is at lock_acquire+0x68/0x7c pc : [<c00758f0>] lr : [<c0077aa8>] psr: 200f0093 sp : d7f4bd18 ip : 00000000 fp : d7f4bda4 r10: db2ac07c r9 : 00000000 r8 : 63700a0d r7 : c0846208 r6 : c08852cc r5 : d7f68000 r4 : 00000002 r3 : 63700b11 r2 : db2ac07c r1 : 00000001 r0 : d7f4a000 Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c53c7d Table: 27f0404a DAC: 00000015 Process reboot (pid: 1050, stack limit = 0xd7f4a240) Stack: (0xd7f4bd18 to 0xd7f4c000) bd00: d7f4bdb4 00000002 bd20: d7f68000 c08852cc 00000001 00000074 00000002 db83ac18 d7f4bdd4 00000000 bd40: c0075a50 c0075050 c00782f8 d7f4a000 8c10a086 0000000a 00000000 d7f4a000 bd60: c0cd22f0 d7f683a0 d7f4bdac 00000000 00546074 00000000 c098f118 00000000 bd80: d7f4a000 600f0013 d7f68000 d7f4a000 d7f4a000 d7f68000 d7f4bddc d7f4bda8 bda0: c0077aa8 c0075754 00000002 00000000 00000000 c030f814 00000000 c088131c bdc0: db2ac044 c030f814 c08852cc 00000000 d7f4be34 d7f4bde0 c05f80c4 c0077a4c bde0: 00000002 00000000 c030f814 c0dc5b64 db2acc1c db83ac08 db2ac010 c0dc5b64 be00: db2b0024 c088131c db83ac08 db2b0018 db2ac010 c0dc5b64 db2b0024 c088131c be20: d7f4a000 00000000 d7f4be5c d7f4be38 c030f814 c05f8074 c0883788 00000000 be40: c0844cc8 00000000 00000003 c000eb44 d7f4be6c d7f4be60 c0048988 c030f74c be60: d7f4be84 d7f4be70 c00489a0 c0048958 01234567 4321fedc d7f4bfa4 d7f4be88 be80: c0048af4 c0048998 000000a8 db3bee50 00076046 00000000 0000000e d7f4a000 bea0: d7f4bea0 db42310c d7f4bea8 00000000 00000000 00000000 db265970 00000001 bec0: d7f4bedc d7f4bed0 c00a9050 00000000 d7f4a000 600f0013 d7f68000 00000007 bee0: c084192c b6f04714 d7f4bfb0 00000000 00000000 b6f52f3c d7f4bfac d7f4bf08 bf00: c00084b0 c0019e60 00000002 db422ff0 db85d088 c0836300 c083c934 db422ff0 bf20: db422ff0 db423040 d7f4bf54 d7f4bf38 c00f47f8 d7f4a000 c000e9a4 d7f4a000 bf40: c000ea10 d7f68000 00000001 00000000 d7f4a000 b6f52f3c d7f4bf84 d7f4bf68 bf60: c00784cc c0078294 00000000 00000000 bebff7b4 00000058 d7f4bf94 d7f4bf88 bf80: c00785a4 c00783e4 00000000 00000000 bebff7b4 00000058 00000000 d7f4bfa8 bfa0: c000e980 c0048a18 00000000 00000000 fee1dead 28121969 01234567 00000003 bfc0: 00000000 00000000 bebff7b4 00000058 00000000 00000000 b6f52f3c 00000000 bfe0: 00000058 bebff624 b6ea0a1d b6e2b276 20000030 fee1dead 00222c40 002d394c Backtrace: [<c0075748>] (__lock_acquire) from [<c0077aa8>] (lock_acquire+0x68/0x7c) r10:d7f68000 r9:d7f4a000 r8:d7f4a000 r7:d7f68000 r6:600f0013 r5:d7f4a000 r4:00000000 [<c0077a40>] (lock_acquire) from [<c05f80c4>] (mutex_lock_nested+0x5c/0x394) r7:00000000 r6:c08852cc r5:c030f814 r4:db2ac044 [<c05f8068>] (mutex_lock_nested) from [<c030f814>] (device_shutdown+0xd4/0x19c) r10:00000000 r9:d7f4a000 r8:c088131c r7:db2b0024 r6:c0dc5b64 r5:db2ac010 r4:db2b0018 [<c030f740>] (device_shutdown) from [<c0048988>] (kernel_restart_prepare+0x3c/0x40) r8:c000eb44 r7:00000003 r6:00000000 r5:c0844cc8 r4:00000000 r3:c0883788 [<c004894c>] (kernel_restart_prepare) from [<c00489a0>] (kernel_restart+0x14/0x68) [<c004898c>] (kernel_restart) from [<c0048af4>] (SyS_reboot+0xe8/0x1cc) r4:4321fedc r3:01234567 [<c0048a0c>] (SyS_reboot) from [<c000e980>] (ret_fast_syscall+0x0/0x48) r7:00000058 r6:bebff7b4 r5:00000000 r4:00000000 Code: 0affffbd e2883f41 f593f000 e1932f9f (e2822001) ---[ end trace 44f221ca42d7ae57 ]---
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.
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.
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index ca0450b..942dda6 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -133,7 +133,6 @@ struct imx_hdmi { struct i2c_adapter *ddc; void __iomem *regs; - struct fb_videomode fb_mode; spinlock_t enable_lock; spinlock_t lock; unsigned long pixel_clk_rate; @@ -1221,20 +1220,18 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi) hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1); } -static void hdmi_av_composer(struct imx_hdmi *hdmi) +static void hdmi_av_composer(struct imx_hdmi *hdmi, + const struct drm_display_mode *mode) { u8 inv_val; - struct fb_videomode *fb_mode = &hdmi->fb_mode; struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; - int hblank, vblank; + int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; - vmode->mhsyncpolarity = ((fb_mode->sync & FB_SYNC_HOR_HIGH_ACT) != 0); - vmode->mvsyncpolarity = ((fb_mode->sync & FB_SYNC_VERT_HIGH_ACT) != 0); - vmode->minterlaced = ((fb_mode->vmode & FB_VMODE_INTERLACED) != 0); - vmode->mpixelclock = (fb_mode->xres + fb_mode->left_margin + - fb_mode->right_margin + fb_mode->hsync_len) * (fb_mode->yres + - fb_mode->upper_margin + fb_mode->lower_margin + - fb_mode->vsync_len) * fb_mode->refresh; + vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC); + vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC); + vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); + vmode->mpixelclock = mode->htotal * mode->vtotal * + drm_mode_vrefresh(mode); dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); @@ -1272,38 +1269,40 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi) hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF); - /* Set up horizontal active pixel region width */ - hdmi_writeb(hdmi, fb_mode->xres >> 8, HDMI_FC_INHACTV1); - hdmi_writeb(hdmi, fb_mode->xres, HDMI_FC_INHACTV0); + /* Set up horizontal active pixel width */ + hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1); + hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0); - /* Set up vertical blanking pixel region width */ - hdmi_writeb(hdmi, fb_mode->yres >> 8, HDMI_FC_INVACTV1); - hdmi_writeb(hdmi, fb_mode->yres, HDMI_FC_INVACTV0); + /* Set up vertical active lines */ + hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1); + hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0); /* Set up horizontal blanking pixel region width */ - hblank = fb_mode->left_margin + fb_mode->right_margin + - fb_mode->hsync_len; + hblank = mode->htotal - mode->hdisplay; hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1); hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0); /* Set up vertical blanking pixel region width */ - vblank = fb_mode->upper_margin + fb_mode->lower_margin + - fb_mode->vsync_len; + vblank = mode->vtotal - mode->vdisplay; hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK); /* Set up HSYNC active edge delay width (in pixel clks) */ - hdmi_writeb(hdmi, fb_mode->right_margin >> 8, HDMI_FC_HSYNCINDELAY1); - hdmi_writeb(hdmi, fb_mode->right_margin, HDMI_FC_HSYNCINDELAY0); + h_de_hs = mode->hsync_start - mode->hdisplay; + hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1); + hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0); /* Set up VSYNC active edge delay (in pixel clks) */ - hdmi_writeb(hdmi, fb_mode->lower_margin, HDMI_FC_VSYNCINDELAY); + v_de_vs = mode->vsync_start - mode->vdisplay; + hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY); /* Set up HSYNC active pulse width (in pixel clks) */ - hdmi_writeb(hdmi, fb_mode->hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1); - hdmi_writeb(hdmi, fb_mode->hsync_len, HDMI_FC_HSYNCINWIDTH0); + hsync_len = mode->hsync_end - mode->hsync_start; + hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1); + hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0); /* Set up VSYNC active edge delay (in pixel clks) */ - hdmi_writeb(hdmi, fb_mode->vsync_len, HDMI_FC_VSYNCINWIDTH); + vsync_len = mode->vsync_end - mode->vsync_start; + hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH); } static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi) @@ -1383,42 +1382,13 @@ static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi) HDMI_IH_MUTE_FC_STAT2); } -static inline void -convert_to_video_timing(struct fb_videomode *timing, - struct drm_display_mode *mode) -{ - memset(timing, 0, sizeof(*timing)); - - timing->pixclock = mode->clock * 1000; - timing->refresh = drm_mode_vrefresh(mode); - - timing->xres = mode->hdisplay; - timing->left_margin = mode->hsync_start - mode->hdisplay; - timing->hsync_len = mode->hsync_end - mode->hsync_start; - timing->right_margin = mode->htotal - mode->hsync_end; - - timing->yres = mode->vdisplay; - timing->upper_margin = mode->vsync_start - mode->vdisplay; - timing->vsync_len = mode->vsync_end - mode->vsync_start; - timing->lower_margin = mode->vtotal - mode->vsync_end; - - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - timing->vmode = FB_VMODE_INTERLACED; - else - timing->vmode = FB_VMODE_NONINTERLACED; - - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - timing->vmode |= FB_VMODE_DOUBLE; -} - static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) { int ret; - convert_to_video_timing(&hdmi->fb_mode, mode); hdmi_disable_overflow_interrupts(hdmi); - hdmi->vic = 6; + hdmi->vic = drm_match_cea_mode(mode); if (!hdmi->vic) { dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n"); @@ -1461,7 +1431,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) hdmi->hdmi_data.video_mode.mdataenablepolarity = true; /* HDMI Initialization Step B.1 */ - hdmi_av_composer(hdmi); + hdmi_av_composer(hdmi, mode); /* HDMI Initializateion Step B.2 */ ret = imx_hdmi_phy_init(hdmi);