On Thu, 2025-12-18 at 21:59 +0900, Alexandre Courbot wrote:
> So this `if` branch is really special-casing the generic bootloader. But
> at the end of the day it just does these things:
>
> - Write an `ImemNonSecure` section,
> - Write an `Dmem` section,
> - Program the `TRANSCFG` register so the bootloader can initiate the DMA
> transfer.
>
> The first two steps can be expressed as a set of `FalconLoadTarget`s.
> That way they can be handled by the non-generic-bootloader path, and we
> can remove the `gbl` argument.
Hmmm... that would require that I implement FalconLoadParams for
GenericBootloader. That's not a
bad idea. I'm not sure how I would build the Dmem FalconLoadTarget, however,
given that it needs to
reference data from the FRTS FalconFirmware object.
impl FalconLoadParams for GenericBootloader {
fn imem_sec_load_params(&self) -> FalconLoadTarget {
FalconLoadTarget {
}
}
fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> {
FalconLoadTarget {
}
}
fn dmem_load_params(&self) -> FalconLoadTarget {
FalconLoadTarget {
// How do I extract data from the FRTS firmware image here?
}
}
}
> So `FwsecFirmware` could have an optional member that contains both the
> generic bootloader and the `BootloaderDmemDescV2` corresponding to it.
> If that optional member is `Some`, then it returns the `FalconLoadTarget`s
> corresponding to the generic bootloader. Otherwise, it behaves as
> before.
>
> Interestingly there is no `ImemSecure` section to write so I guess we
> will have to make `imem_sec_load_params` return an `Option` as well.
>
> And `NV_PFALCON_FBIF_TRANSCFG` is always programmed as the worst thing
> that can happen is that we don't use the DMA engine if there is no
> generic bootloader.
Yeah, I don't understand why this is being programmed at all in the PIO case,
but that's what
Nouveau does:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c#n132
>
> > + // The Generic Bootloader exists only on Turing and GA100. To
> > avoid a bogus
> > + // console error message on other platforms, only try to load it
> > if it's
> > + // supposed to be there.
> > + let gbl_fw = if chipset < Chipset::GA102 {
> > + super::request_firmware(dev, chipset, "gen_bootloader",
> > FIRMWARE_VERSION)
> > + } else {
> > + Err(ENOENT)
> > + };
>
> Using `Err` to indicate no firmware means that we will proceed even if
> `request_firmware` returns an error. This should be:
>
> let gbl_fw = if chipset < Chipset::GA102 {
> Some(super::request_firmware(dev, chipset, "gen_bootloader",
> FIRMWARE_VERSION)?)
> } else {
> None
> };
Ok.
>
> > +
> > + let gbl = match gbl_fw {
> > + Ok(fw) => {
> > + let hdr = fw
> > + .data()
> > + .get(0..size_of::<BinHdr>())
> > + .and_then(BinHdr::from_bytes_copy)
> > + .ok_or(EINVAL)?;
> > +
> > + let desc_offset = usize::from_safe_cast(hdr.header_offset);
> > + let desc = fw
> > + .data()
> > + .get(desc_offset..desc_offset +
> > size_of::<BootloaderDesc>())
> > + .and_then(BootloaderDesc::from_bytes_copy)
> > + .ok_or(EINVAL)?;
> > +
> > + let ucode_start = usize::from_safe_cast(hdr.data_offset);
> > + let ucode_size = usize::from_safe_cast(hdr.data_size);
> > + let ucode_data = fw
> > + .data()
> > + .get(ucode_start..ucode_start + ucode_size)
> > + .ok_or(EINVAL)?;
> > +
> > + let mut ucode = KVec::new();
> > + ucode.extend_from_slice(ucode_data, GFP_KERNEL)?;
> > +
> > + Some(GenericBootloader { desc, ucode })
> > + }
> > + Err(_) => None,
> > + };
> > +
>
> Actually, let's put that code into a new `GenBootloader` type. You can
> follow the example of `BooterFirmware`, which is quite similar (only a
> bit more complex).
Sorry, I'm a bit confused. What's the difference between GenBootloader and
GenericBootloader?
Can't I just add a new() constructor to GenericBootloader?