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.

But a bug in the driver is a distinct possibility.

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

Reply via email to