Hi Laszlo

> -----Original Message-----
> From: Laszlo Ersek [mailto:ler...@redhat.com]
> Sent: Friday, February 23, 2018 4:29 PM
> To: Udit Kumar <udit.ku...@nxp.com>; Pankaj Bansal
> <pankaj.ban...@nxp.com>; Leif Lindholm <leif.lindh...@linaro.org>
> Cc: michael.d.kin...@intel.com; edk2-devel@lists.01.org;
> ard.biesheu...@linaro.org; Meenakshi Aggarwal
> <meenakshi.aggar...@nxp.com>
> Subject: Re: [edk2] [PATCH edk2-platforms 01/39] Silicon/NXP: Add support
> for Big Endian Mmio APIs
> 
> On 02/23/18 11:39, Udit Kumar wrote:
> >
> >
> >> -----Original Message-----
> >> From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of
> >> Laszlo Ersek
> >> Sent: Friday, February 23, 2018 2:51 PM
> >> To: Pankaj Bansal <pankaj.ban...@nxp.com>; Leif Lindholm
> >> <leif.lindh...@linaro.org>
> >> Cc: michael.d.kin...@intel.com; edk2-devel@lists.01.org;
> >> ard.biesheu...@linaro.org
> >> Subject: Re: [edk2] [PATCH edk2-platforms 01/39] Silicon/NXP: Add
> support
> >> for Big Endian Mmio APIs
> >>
> >> On 02/23/18 09:40, Pankaj Bansal wrote:
> >>> Hi All
> >>>
> >>>> -----Original Message-----
> >>>> From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf
> Of
> >>>> Laszlo Ersek
> >>>> Sent: Thursday, February 22, 2018 7:26 PM
> >>>> To: Leif Lindholm <leif.lindh...@linaro.org>
> >>>> Cc: michael.d.kin...@intel.com; edk2-devel@lists.01.org;
> >>>> ard.biesheu...@linaro.org
> >>>> Subject: Re: [edk2] [PATCH edk2-platforms 01/39] Silicon/NXP: Add
> >> support
> >>>> for Big Endian Mmio APIs
> >>>>
> >>>> On 02/22/18 12:52, Leif Lindholm wrote:
> >>>>> On Thu, Feb 22, 2018 at 09:34:05AM +0100, Laszlo Ersek wrote:
> >>>>
> >>>>>>> But that brings back the complication as to how we have a driver
> >>>>>>> that needs an LE IO library to write output, and a BE IO library to
> >>>>>>> manipulate the hardware.
> >>>>>>
> >>>>>> Can you please explain the "write output" use case more precisely?
> >>>>>>
> >>>>>> My thinking would be this:
> >>>>>>
> >>>>>> - Use the IoLib class directly for "writing output" in little endian
> >>>>>> byte order (which is still unclear to me sorry).
> >>>>>
> >>>>> If the IoLib class is mapped to a an instance that byte-swaps (hereto
> >>>>> referred to as BeIoLib if IoLibSwap is unsuitable), would we not then
> >>>>> end up mapping the non-swapping, currently implemented in
> >>>>> BaseLibIoIntrinsic, variant as BeIoLib? Or if not, do we end up
> >>>>> needing to duplicated all IoLib implementation .infs to provide an
> >>>>> IoLib and a BeIoLib for each?
> >>>>>
> >>>>> It's at that point I burst an aneurysm.
> >>>>> Am I overthinking/underthinking this?
> >>>>
> >>>> We need two library classes, one for talking to LE devices and another
> to
> >> BE
> >>>> devices. These should be usable in a given module at the same time, as
> >> Ard
> >>>> says.
> >>>>
> >>>> Both library classes need to work on both LE and BE CPUs (working
> from
> >> your
> >>>> suggestion that UEFI might grow BE CPU support at some point).
> >>>> Whether that is implemented by dumb, separate library instances
> >> (yielding in
> >>>> total 2*2=4 library instances), or by smart, CPU-endianness-agnostic
> >> library
> >>>> instances (in total, 2), is a different question.
> >>>>
> >>>> Note that such "smarts" could be less than trivial to implement:
> >>>> - check CPU endianness in each library API?
> >>>> - or check in the lib constructor only, and flip some function pointers?
> >>>> - use a dynamic PCD for caching CPU endianness?
> >>>> - use a HOB for the same?
> >>>> - use a lib global variable (for caching only on the module level)?
> >>>>
> >>>> I think the solution that saves the most on the *source* code size is:
> >>>> - introduce the BeIoLib class
> >>>> - duplicate the MMIO functions from BaseIoLibIntrinsic to the one
> >>>>   BeIoLib instance that we introduce
> >>>> - modify the MMIO functions in *both* lib instances (original LE, and
> >>>>   new BE), like this:
> >>>>
> >>>>   - If the CPU architecture is known to be bound to a single endianness,
> >>>>     then hardcode the appropriate operation. This can be done with
> >>>>     preprocessor macros, or with the architecture support of INF files /
> >>>>     separate source files. For example, on IA32 and X64, the IoLib
> >>>>     instance should work transparently, unconditionally, and the BeIoLib
> >>>>     instance should byte-swap, unconditionally.
> >>>>
> >>>>   - On other CPU arches, all the wider-than-byte MMIO functions, in
> >>>>     *both* lib instances should do something like this:
> >>>>
> >>>>     //
> >>>>     // at file scope
> >>>>     //
> >>>>     STATIC CONST UINT16 mOne = 1;
> >>>>
> >>>>     //
> >>>>     // at function scope
> >>>>     //
> >>>>     if (*(CONST UINT8 *)&mOne == 1) {
> >>>>       //
> >>>>       // CPU in LE mode:
> >>>>       // - work transparently in the IoLib instance
> >>>>       // - byte-swap in the BeIoLib instance
> >>>>       //
> >>>>     } else {
> >>>>       //
> >>>>       // CPU in BE mode:
> >>>>       // - byte-swap in the IoLib instance
> >>>>       // - work transparently in the BeIoLib instance
> >>>>       //
> >>>>     }
> >>>
> >>> I suggest this approach :
> >>>
> >>> 1. Add BeMmio* functions in existing IoLib. BeMmio* functions will
> swap
> >> the input before write and swap output after read and so on.
> >>>     Mmio* functions will not perform any byte swapping
> >>> 2. create second instance (a copy) of this IoLib for CPUs that are Big
> Endian.
> >> We can call it BigEndianIoLib.
> >>>      In this library Mmio* functions will swap the input before write and
> >> swap output after read and so on.
> >>>      BeMmio* functions will not perform any byte swapping.
> >>> 3. Include the instance of IoLib in dsc file based on cpu endianness that
> the
> >> platform wants to use. i.e.
> >>>     If BIG_ENDIAN == FALSE
> >>>        IoLib | ..\..\..\IoLib
> >>>    Else
> >>>       IoLib | ..\..\..\BigEndianIoLib
> >>> 4. The devices that are Big endian in platform will always call BeMmio*
> >> functions. They need not check CPU endianness.
> >>> 5. The devices that are Little endian in platform will always call Mmio*
> >> functions. They need not check CPU endianness.
> >>
> >> This can work too, but there is a downside: a large number of IoLib
> >> instances exist in the tree already. If you add the BeMmio* functions to
> >> the existent IoLib class, you'll have to duplicate the implementation to
> >> all instances (identically, I think).
> >>
> >> We've had this debate in the past. Back then it was about IoFifo
> >> routines. I argued for an IoFifo lib class. Ultimately the IoFifo
> >> routines were added to IoLib, and they had to be implemented for many
> >> more library instances than client code would have actually required.
> >> (See the series at 13a50a6fe1dc..2b631390f9f5.) In turn this runs the
> >> risk of adding untested code.
> >>
> >> Regarding the instances for BE CPUs: the name should likely be
> >> BaseIoLibBigEndian or something similar. In lib instance names, the lib
> >> class name is usually prefixed with the firmware phases where the
> >> instance is usable, and hints about the implementation or constraints
> >> are added as a suffix.
> >
> > I see like below
> > CPU                         IP              Call                    Lib
> > LE                  LE              MMIO                    BaseIoLib
> > LE                  BE              SwappedMMIO             BaseIoLibEx
> > BE                  BE              MMIO                    BaseIoLib
> > BE                  LE              SwappedMMIO
> BaseIoLibEx
> 
> In my opinion, this is wrong. The "Call" column should not vary with CPU
> endianness, it should only vary with "IP" (device) endianness.
> 
> Basically you are putting the entire work on the driver code, to figure
> out whether swapping will be necessary or not. For that, the driver has
> to consult the byte order of *both* the CPU *and* the device, and then
> call "transparent" or "swapped" MMIO functions.
>
> What I am suggesting is that the driver care about device byte order
> only. This will determine whether the driver calls MmioWrite32() or
> BeMmioWrite32().

> In turn, whether or not those functions byte-swap, according to CPU byte
> order, is an internal matter of the libraries.
> 
>   IP  Call           Lib      CPU  Byte-swap within Lib
>   --  -------------  -------  ---  --------------------
>   LE  MmioWrite32    IoLib    LE   no
>   LE  MmioWrite32    IoLib    BE   yes
>   BE  BeMmioWrite32  BeIoLib  LE   yes
>   BE  BeMmioWrite32  BeIoLib  BE   no
> 
> Obviously, the end result is the same; the question is what *concepts*
> the device driver has to care about.

> Under your scheme, every device driver has to care about concepts such
> as "device byte order", "cpu byte order", and "swapping".
> 
> Under my scheme, every device driver has to care about "device byte order".

Thanks for detailing .
May be I was not clear in previous email by saying 

>> I am calling BaseIoLibEx for extend the feature of CPU endianness In this 
>> case SwappedMMIO could be MmioToBe or MmioToLe Let this this new 
>> lib BaseIoLibEx decide endianness of CPU based upon Pcd, hob list etc and do 
>> conversion if needed.

I think, more or less we are saying same thing.

I am saying for new development will use MmioToBe or MmioToLe based upon IP 
mode, 
Whereas you are referring as MmioWrite32 and BeMmioWrite32 to be used. 

The difference what I see, between your proposal and mine
You are saying , to do swapping in MmioWrite32 based upon CPU mode.
Whereas I am referring to new APIs. 

Anyway , I am ok with your proposal , which looks more inline w.r.t current 
edk-2 code 

Thanks
Udit 

> Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to