<div dir="ltr"><br><br>On Wed, Jul 15, 2015 at 2:34 AM, Daniel Vetter <<a href="mailto:daniel@ffwll.ch">daniel@ffwll.ch</a>> wrote:<br>><br>> On Tue, Jul 14, 2015 at 01:37:32PM -0700, Greg KH wrote:<br>> > On Tue, Jul 14, 2015 at 11:22:35AM +0200, Daniel Vetter wrote:<br>> > > On Mon, Jul 13, 2015 at 09:36:45AM -0700, <a href="mailto:jay.p.patel@intel.com">jay.p.patel@intel.com</a> wrote:<br>> > > > From: Jay Patel <<a href="mailto:jay.p.patel@intel.com">jay.p.patel@intel.com</a>><br>> > > ><br>> > > > NOTE: This is an interim solution which is targeted towards<br>> > > > Chrome OS/Android to be used until a long term solution is available.<br>> > > ><br>> > > > In this patch, request_firmware() is called in a worker thread<br>> > > > which initially waits for file system to be initialized and then<br>> > > > attempts to load the firmware.<br>> > ><br>> > > Aside: I posted a bunch of proof-of-principle patches to clean up dmc<br>> > > loading and convert over to using an explicit workqueue. They're being<br>> > > tested/made-to-actually-work right now I think.<br>> > ><br>> > > > "request_firmware_nowait()" is also using an asynchronous thread<br>> > > > running concurrently with the rest of the system initialization.<br>> > > > However, it tries to load firmware only once without checking the<br>> > > > sytem status and fails most of the time.<br>> > > ><br>> > > > Change-Id: I2cb16a768e54a85f48a6682d9690b4c8af844668<br>> ><br>> > What's this line for?  :)<br>> ><br>> > > > Signed-off-by: Jay Patel <<a href="mailto:jay.p.patel@intel.com">jay.p.patel@intel.com</a>><br>> > > > ---<br>> > > >  drivers/gpu/drm/i915/i915_drv.c  |  2 ++<br>> > > >  drivers/gpu/drm/i915/intel_csr.c | 58 ++++++++++++++++++++++++++++++++--------<br>> > > >  2 files changed, 49 insertions(+), 11 deletions(-)<br>> > > ><br>> > > > diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c<br>> > > > index 8c8407d..eb6f7e3 100644<br>> > > > --- a/drivers/gpu/drm/i915/i915_drv.c<br>> > > > +++ b/drivers/gpu/drm/i915/i915_drv.c<br>> > > > @@ -559,6 +559,7 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)<br>> > > >  void i915_firmware_load_error_print(const char *fw_path, int err)<br>> > > >  {<br>> > > >   DRM_ERROR("failed to load firmware %s (%d)\n", fw_path, err);<br>> > > > + DRM_ERROR("The firmware file may be missing\n");<br>> > > ><br>> > > >   /*<br>> > > >    * If the reason is not known assume -ENOENT since that's the most<br>> > > > @@ -574,6 +575,7 @@ void i915_firmware_load_error_print(const char *fw_path, int err)<br>> > > >     "The driver is built-in, so to load the firmware you need to\n"<br>> > > >     "include it either in the kernel (see CONFIG_EXTRA_FIRMWARE) or\n"<br>> > > >     "in your initrd/initramfs image.\n");<br>> > > > +<br>> > > >  }<br>> > > ><br>> > > >  static void intel_suspend_encoders(struct drm_i915_private *dev_priv)<br>> > > > diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c<br>> > > > index 9311cdd..8d1f08c 100644<br>> > > > --- a/drivers/gpu/drm/i915/intel_csr.c<br>> > > > +++ b/drivers/gpu/drm/i915/intel_csr.c<br>> > > > @@ -349,7 +349,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)<br>> > > >   /* load csr program during system boot, as needed for DC states */<br>> > > >   intel_csr_load_program(dev);<br>> > > >   fw_loaded = true;<br>> > > > -<br>> > > > + DRM_INFO("CSR Firmware Loaded\n");<br>> > > >  out:<br>> > > >   if (fw_loaded)<br>> > > >           intel_runtime_pm_put(dev_priv);<br>> > > > @@ -359,11 +359,46 @@ out:<br>> > > >   release_firmware(fw);<br>> > > >  }<br>> > > ><br>> > > > +struct csr_firmware_work {<br>> > > > + struct work_struct work;<br>> > > > + struct module *module;<br>> > > > + struct drm_device *dev;<br>> > > > +};<br>> > > > +<br>> > > > +/* csr_firmware_work_func() - thread function for loading the firmware*/<br>> > > > +static void csr_firmware_work_func(struct work_struct *work)<br>> > > > +{<br>> > > > + const struct firmware *fw;<br>> > > > + const struct csr_firmware_work *fw_work = container_of(work, struct csr_firmware_work, work);<br>> > > > + int ret;<br>> > > > + struct drm_device *dev = fw_work->dev;<br>> > > > + struct drm_i915_private *dev_priv = dev->dev_private;<br>> > > > + struct intel_csr *csr = &dev_priv->csr;<br>> > > > +<br>> > > > + /* Wait until root filesystem is loaded in case the firmware<br>> > > > +  * is not built-in but in /lib/firmware */<br>> > > > + while(system_state !=  SYSTEM_RUNNING){<br>> > > > +         msleep(500);<br>> > > > + }<br>> > ><br>> > > Yeah, not going to merge that right now until we've had a decent<br>> > > discussion with Greg KH (since imo his stance of every driver creating<br>> > > it's own retry loop just doesn't work, especially not with gfx where init<br>> > > is hairy and you just don't want to retry without end).<br>> ><br>> > Exactly, this type of thing isn't good at all (especially given that<br>> > the code isn't even checkpatch clean...)<br>> ><br>> > Don't do this.  If you really want to somehow handle built-in drivers<br>> > that need firmware before the root filesystem is present, then use the<br>> > async firmware loading interface, don't sit and spin, that's crazy.<br>><br>> This code is called from a work queue already to facilitate async loading.<br>> I want an explicit work queue so that we properly sync with it everywhere<br>> like driver unload or resume (otherwise we need a completion or<br>> something). And with an explicit worker I can put the entire init sequence<br>> for that component of the gpu in there, which means whether we require<br>> firmware or no doesn't change how the driver is loaded. Unified driver<br>> load paths is a fairly strict requirement I have (because otherwise<br>> testing is nigh impossible due to combinatorial explosion). I also don't<br>> want to ever reattempt loading the firmware since those kind of fallback<br>> paths are equally horrible from a testing perspective. If fw loading fails<br>> for some reason we'll just move on and declare that particular gpu part<br>> dead/unsupported.<br>><br>> The other issue with request_firmware_nowait is that it doesn't do the<br>> uevent + udev fallback afaiui, see<br>><br>> commit 5a1379e8748a5cfa3eb068f812d61bde849ef76c<br>> Author: Takashi Iwai <<a href="mailto:tiwai@suse.de">tiwai@suse.de</a>><br>> Date:   Wed Jun 4 17:48:15 2014 +0200<br>><br>>     firmware loader: allow disabling of udev as firmware loader<br>><br>> Only request_firmware seems to do that combo.<br>><br>> > > Aside: Another solution might be the wait_for_rootfs from<br>> > ><br>> > > <a href="http://www.gossamer-threads.com/lists/linux/kernel/2010793">http://www.gossamer-threads.com/lists/linux/kernel/2010793</a><br>> > ><br>> > > But if Greg insists that each driver needs to solve this themselves then<br>> > > I'll pull something like this into upstream, but probably with a Kconfig<br>> > > option to disable it for normal linux userspace.<br>> ><br>> > "solve" this by just not sitting and spining, wait for userspace to load<br>> > your firmware if it needs it.  Or, even better yet, if you really need<br>> > firmare at early boot before a rootfs, build the firmware into the<br>> > kernel image, like we used to do for a few decades.<br>><br>> That's exactly what this tries to do (not in a terribly pretty way I<br>> admit).<br>><br>> And building the firmware into the image isn't an option since that seems<br>> to freak out legal or something like that. And loading modules really<br>> early in initrd (like it's done on desktop linux distros) is also not<br>> something since for a pile of reasons cros/android want monolithic kernel<br>> images.<br>><br>> > > The other option would<br>> > > be to use CONFIG_FW_LOADER_USERSPACE_FALLBACK udev helper. That might be<br>> > > an option for intel android, but it sounds like not something cros wants<br>> > > to do. Therefore<br>> ><br>> > why would chromeos not want to use the udev helper?<br>><br>> I'm trying to sell them on it and haven't yet figured out why it's not ok,<br>> but it seems to be a popular request. Other folks also came up with<br>> similar hacks (the wait_for_rootfs one linked above) so I'm assume it's<br>> not entirely context free. On these machines everything is static making a<br>> lot of hotplug processing unecessary.<div><br></div><div>Finally got some time to chase this down - it's not a technical limitation</div><div>(ChromeOS does use udev) - it's a violation of the security model. With direct</div><div>kernel loading of firmware, checks can happen that ensure the firmware is</div><div>coming from the dm-verity RO-mounted root fs. If a userspace process is</div><div>providing the firmware through the sysfs entry, there's no way to verify that</div><div>the firmware is coming from a trusted file/partition, as the kernel has no</div><div>knowledge of the source of the incoming data.</div><div><br></div><div>-James</div><div><br></div><div><br>><br>> > > Acked-by: Daniel Vetter <<a href="mailto:daniel.vetter@ffwll.ch">daniel.vetter@ffwll.ch</a>><br>> > ><br>> > > Also adding Greg so he knows what's happening here.<br>> ><br>> > Ick, please don't take this as-is.<br>><br>> Well I'd prefer if request_firmware just handles this for me since it<br>> seems to be a general need. But I'm ok with carrying this around in i915<br>> only too.<br>> -Daniel<br>> --<br>> Daniel Vetter<br>> Software Engineer, Intel Corporation<br>> <a href="http://blog.ffwll.ch">http://blog.ffwll.ch</a><br>> _______________________________________________<br>> Intel-gfx mailing list<br>> <a href="mailto:Intel-gfx@lists.freedesktop.org">Intel-gfx@lists.freedesktop.org</a><br>> <a href="http://lists.freedesktop.org/mailman/listinfo/intel-gfx">http://lists.freedesktop.org/mailman/listinfo/intel-gfx</a><br><br><br><br><br>--<br><br><br>James Ausmus<br>ChromeOS Integration Architect<br>SSG-OTC ChromeOS Integration</div></div>