> On Feb 5, 2016, at 10:47 AM, Ryan Harkin <[email protected]> wrote: > > Hi Andrew, > > On 5 February 2016 at 18:39, Andrew Fish <[email protected]> wrote: >> >>> On Feb 5, 2016, at 10:36 AM, Ryan Harkin <[email protected]> wrote: >>> >>> Hi Laszlo, >>> >>> On 5 February 2016 at 17:19, Laszlo Ersek <[email protected]> wrote: >>>> On 02/05/16 17:35, Ryan Harkin wrote: >>>>> Hello all, >>>>> >>>>> I'm having a problem that is platform specific, but perhaps more of a >>>>> generic problem. >>>>> >>>>> When ARM's Juno board boots, not all devices are connected. The first >>>>> boot creates the boot variables and sets their order, meaning that we >>>>> get the following list on the first attempt: >>>>> >>>>> EFI Misc Device >>>>> EFI Misc Device 1 >>>>> EFI Internal Shell >>>>> >>>>> Intel BDS then attempts to boot from one of the devices and ends up in >>>>> Shell. After exiting Shell, the Intel BDS console GUI comes up. >>>>> Selecting the Boot Manager option shows more devices being connected >>>>> and the list becomes longer: >>>>> >>>>> EFI Misc Device >>>>> EFI Misc Device 1 >>>>> EFI Internal Shell >>>>> EFI Hard Drive >>>>> EFI Network >>>>> >>>>> Subsequent boots will never attempt to boot from Hard Drive or Network >>>>> because Shell will always succeed. That is not good. >>>>> >>>>> Leif has a patch in his working tree that solves this problem [1] by >>>>> making the platform call BdsLibConnectAll() at init time. So now, the >>>>> first time boot order looks sane: >>>>> >>>>> EFI Misc Device >>>>> EFI Misc Device 1 >>>>> EFI Hard Drive >>>>> EFI Network >>>>> EFI Internal Shell >>>>> >>>>> However, then the board is booting, the "EFI Network" fails to boot >>>>> the first time and so the board drops back to Shell again: >>>>> >>>>> Warning: LAN9118 Driver in stopped state >>>>> Link timeout in auto-negotiation. >>>>> Lan9118: Auto Negociation not supported. >>>>> EhcExecTransfer: transfer failed with 2 >>>>> EhcControlTransfer: error - Device Error, transfer - 2 >>>>> Buffer: EFI Hard Drive >>>>> Booting EFI Misc Device >>>>> Booting EFI Misc Device 1 >>>>> Booting EFI Hard Drive >>>>> Booting EFI Network >>>>> Warning: LAN9118 Driver not initialized >>>>> Link timeout in auto-negotiation. >>>>> Lan9118: Auto Negociation not supported. >>>>> Booting EFI Internal Shell >>>>> >>>>> Exiting Shell drops the user back to the Intel BDS UI. Selecting >>>>> "Continue" then succeeds in booting from the EFI Network: >>>>> >>>>> Booting EFI Misc Device >>>>> Booting EFI Misc Device 1 >>>>> Booting EFI Hard Drive >>>>> Booting EFI Network >>>>> ..MnpFreeTxBuf: Duplicated recycle report from SNP. >>>>> MnpFreeTxBuf: Duplicated recycle report from SNP. >>>>> [snip repeated SNP errors] >>>>> >>>>> If I duplicate the call to BdsLibConnectAll() [2], then boot works as >>>>> expected. On first boot, the boot order is created correctly and EFI >>>>> Network pulls down a file and boots it. >>>>> >>>>> I'm assuming that the 2nd call is connecting things that didn't >>>>> connect the first time. And from that, I suspect/guess that perhaps >>>>> they didn't connect due to either ordering or timing. >>>>> >>>>> Is there a recommended way to set the order things are connected? Is >>>>> it even possible to specify dependencies or order? And if so, how do >>>>> we work out what the order should be? >>>> >>>> I cannot give a coherent answer, just a few thoughts. >>>> >>>> (1) I think BdsLibConnectAll() actually succeeds for the first time as >>>> well. All devices are enumerated, all drivers are connected, aren't >>>> they? The boot order is a separate question. >>>> >>> >>> Yes, you're right, they are all connected because they all appear in >>> the boot list. >>> >>> >>>> (2) The network, the NIC, or the NIC driver are more probable suspects. >>>> If I see right, you always have a misc / misc1 / hd / network sequence >>>> of attempts, it's just that on the first few occasions, the network >>>> fails. ("Link timeout in auto-negotiation".) >>>> >>> >>> Correct. >>> >>> >>>> (3) I think repeated BdsLibConnectAll() calls may only give more time to >>>> the NIC to bring itself into working shape. What if you keep only one >>>> BdsLibConnectAll(), and replace the second BdsLibConnectAll() with a >>>> sizeable gBS->Stall()? >>>> >>> >>> Eureka! I replace the 2nd BdsLibConnectAll() with >>> "gBS->Stall(500000);" (0.5 seconds) and this works every time also. >>> >>> So time to negociate (sic) would seem like the culprit. I suppose a >>> 2nd BdsLibConnectAll() buys the NIC some time. >>> >>> I'm left wondering if the "Boot EFI Network" option should actually be >>> waiting for negotiation, however. I'm sure it's common on first boot >>> that the network needs a little time to negotiate. I'll look into >>> that. Perhaps there is a setting or an override to tell it to be >>> patient? >>> >> >> This is either a bug in the driver, or a bug in the config of the PXE server. >> > > I doubt it's a bug in the server: negotiation here refers to the the > NIC training on the network, so the server isn't involved at this > stage. >
OK I was thinking the PXE Server could have been configured with timeout values that were too short or something like that. > But a bug in the driver is a distinct possibility. > If adding gBS->Stlall() fixes you issue it IS a bug in the driver. Thanks, Andrew Fish > Thanks, > Ryan. > > >> Thanks, >> >> Andrew Fish >> >>> >>>> (4) What the boot order should be can be influenced by the platform BDS >>>> lib, in the PlatformBdsPolicyBehavior() function. >>>> >>>> Namely, the BdsEntry() function in >>>> "MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c" initializes the >>>> "BootOptionList" variable to an empty list. Then it calls >>>> PlatformBdsPolicyBehavior(), which takes "BootOptionList" as an >>>> input/output parameter -- if it wishes, it can populate it. >>>> >>>> In ArmVirtPkg and in OvmfPkg, we perform the following steps in >>>> PlatformBdsPolicyBehavior(): >>>> >>>> (a) connect the console(s) >>>> >>>> (b) BdsLibConnectAll() >>>> >>>> (c) BdsLibEnumerateAllBootOption (BootOptionList) -- this relies on the >>>> presence of all devices, from the previous step. This function (in >>>> "IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c") has extensive >>>> documentation in its leading comment. >>>> >>>> It will enumerate everything sensible (modifying BootOrder as well I >>>> think), and output a BootOptionList that contains all the possible boot >>>> options, in a sane order. Sanity means, if I remember correctly, that >>>> all options that existed previously and were referenced by BootOrder, >>>> retain their positions at the front of the list, and any new >>>> auto-detected boot options are tacked to the end. >>>> >>>> (d) SetBootOrderFromQemu (BootOptionList) -- this is the really platform >>>> specific part for massaging the boot order. We read through >>>> BootOptionList -- we don't modify it --, do various calculations, and >>>> then rewrite the BootOrder variable. Importantly, all Boot#### variables >>>> that become *unreferenced* by BootOrder as a result of this, must be >>>> deleted (otherwise they constitute a leak). Again, BootOptionList is not >>>> modified. >>>> >>>> (e) BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder") -- it >>>> rebuilds BootOptionList from the new BootOrder contents. (We are again >>>> in PlatformBdsPolicyBehavior(), where BootOptionList counts as >>>> input/output.) >>>> >>>> On a physical platform, I think you just go with (b) and (c), and then >>>> let the user customize the boot order. Next time you boot, (c) will >>>> respect that. >>>> >>> >>> Excellent answer, thanks. It looks like (c) is exactly the thing I'm >>> looking for. For example, make HDD boot before USB. That sort of >>> thing. >>> >>> I'm quite happy that once the default boot order has been set that it >>> stays that way unless the user changes it. I don't (think I) want to >>> customise the boot order after the initial boot. >>> >>> >>>> There are further possibilities; there is a "boot mode" HOB with which >>>> your low-level platform code can control your BDS policy, in order to >>>> speed up things. See BdsLibGetBootMode() and the macros in >>>> "MdePkg/Include/Pi/PiBootMode.h". Those macros are documented in one of >>>> the PI spec volumes. >>>> >>>> For example, I think BOOT_ASSUMING_NO_CONFIGURATION_CHANGES is meant to >>>> be very fast (no need to connect all devices to all drivers), but such a >>>> HOB must be produced by your own PEI phase somehow -- you must know for >>>> example that the chassis was never opened while the machine was off. >>>> >>>> FWIW, OVMF only uses BOOT_WITH_FULL_CONFIGURATION, and >>>> BOOT_ON_S3_RESUME, and these two are differentiated in OVMF's PEI phase >>>> by reading a CMOS register. >>>> >>>> Anyway, I think what you need is: >>>> - call BdsLibConnectAll() exactly once >>>> - give that NIC more time (?) >>>> - if you'd like to regenerate all possible boot options *at the end* of >>>> BootOrder that the user may have deleted (or have become available by >>>> installing new hardware), call BdsLibEnumerateAllBootOption() too. >>>> >>> >>> Yes, that sounds about right. I have concerns about the negotiation >>> timing, but the boot order hacking sounds like what I'm looking for. >>> >>> Thanks again, >>> Ryan. >>> >>> >>>> Laszlo >>>> >>>>> >>>>> Regards, >>>>> Ryan. >>>>> >>>>> [1] >>>>> https://git.linaro.org/uefi/linaro-edk2.git/commitdiff/bfbd0ef1a182e1baa120f66ad2c6838ef48ff48c >>>>> [2] >>>>> https://git.linaro.org/landing-teams/working/arm/edk2.git/commitdiff/25320ba4e447a843daaf7c603ec87afae3c2a120 >>>>> >>>> >>> _______________________________________________ >>> edk2-devel mailing list >>> [email protected] >>> https://lists.01.org/mailman/listinfo/edk2-devel >> > _______________________________________________ > edk2-devel mailing list > [email protected] > https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

