Home | History | Annotate | Download | only in SnpDxe
      1 /** @file
      2   This file contains the callback routines for undi3.1.
      3   the callback routines for Undi3.1 have an extra parameter UniqueId which
      4   stores the interface context for the NIC that snp is trying to talk.
      5 
      6 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "Snp.h"
     18 
     19 /**
     20   Acquire or release a lock of the exclusive access to a critical section of the
     21   code/data.
     22 
     23   This is a callback routine supplied to UNDI3.1 at undi_start time.
     24   New callbacks for 3.1: there won't be a virtual2physical callback for UNDI 3.1
     25   because undi3.1 uses the MemMap call to map the required address by itself!
     26 
     27   @param UniqueId  This was supplied to UNDI at Undi_Start, SNP uses this to
     28                       store Undi interface context (Undi does not read or write
     29                       this variable).
     30   @param Enable    Non-zero indicates acquire; Zero indicates release.
     31 
     32 **/
     33 VOID
     34 EFIAPI
     35 SnpUndi32CallbackBlock (
     36   IN UINT64 UniqueId,
     37   IN UINT32 Enable
     38   )
     39 {
     40   SNP_DRIVER  *Snp;
     41 
     42   Snp = (SNP_DRIVER *) (UINTN) UniqueId;
     43   //
     44   // tcpip was calling snp at tpl_notify and when we acquire a lock that was
     45   // created at a lower level (TPL_CALLBACK) it gives an assert!
     46   //
     47   if (Enable != 0) {
     48     EfiAcquireLock (&Snp->Lock);
     49   } else {
     50     EfiReleaseLock (&Snp->Lock);
     51   }
     52 }
     53 
     54 /**
     55   Delay MicroSeconds of micro seconds.
     56 
     57   This is a callback routine supplied to UNDI at undi_start time.
     58 
     59   @param UniqueId      This was supplied to UNDI at Undi_Start, SNP uses this to
     60                        store Undi interface context (Undi does not read or write
     61                        this variable).
     62   @param MicroSeconds  Number of micro seconds to pause, ususlly multiple of 10.
     63 
     64 **/
     65 VOID
     66 EFIAPI
     67 SnpUndi32CallbackDelay (
     68   IN UINT64 UniqueId,
     69   IN UINT64 MicroSeconds
     70   )
     71 {
     72   if (MicroSeconds != 0) {
     73     gBS->Stall ((UINTN) MicroSeconds);
     74   }
     75 }
     76 
     77 /**
     78   IO routine for UNDI3.1.
     79 
     80   This is a callback routine supplied to UNDI at undi_start time.
     81 
     82   @param UniqueId       This was supplied to UNDI at Undi_Start, SNP uses this
     83                         to store Undi interface context (Undi does not read or
     84                         write this variable).
     85   @param ReadOrWrite    Indicates read or write, IO or Memory.
     86   @param NumBytes       Number of bytes to read or write.
     87   @param MemOrPortAddr  IO or memory address to read from or write to.
     88   @param BufferPtr      Memory location to read into or that contains the bytes
     89                         to write.
     90 
     91 **/
     92 VOID
     93 EFIAPI
     94 SnpUndi32CallbackMemio (
     95   IN UINT64     UniqueId,
     96   IN UINT8      ReadOrWrite,
     97   IN UINT8      NumBytes,
     98   IN UINT64     MemOrPortAddr,
     99   IN OUT UINT64 BufferPtr
    100   )
    101 {
    102   SNP_DRIVER                *Snp;
    103   EFI_PCI_IO_PROTOCOL_WIDTH Width;
    104 
    105   Snp   = (SNP_DRIVER *) (UINTN) UniqueId;
    106 
    107   Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
    108   switch (NumBytes) {
    109   case 2:
    110     Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
    111     break;
    112 
    113   case 4:
    114     Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
    115     break;
    116 
    117   case 8:
    118     Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
    119     break;
    120   }
    121 
    122   switch (ReadOrWrite) {
    123   case PXE_IO_READ:
    124     Snp->PciIo->Io.Read (
    125                      Snp->PciIo,
    126                      Width,
    127                      Snp->IoBarIndex,      // BAR 1 (for 32bit regs), IO base address
    128                      MemOrPortAddr,
    129                      1,                    // count
    130                      (VOID *) (UINTN) BufferPtr
    131                      );
    132     break;
    133 
    134   case PXE_IO_WRITE:
    135     Snp->PciIo->Io.Write (
    136                      Snp->PciIo,
    137                      Width,
    138                      Snp->IoBarIndex,      // BAR 1 (for 32bit regs), IO base address
    139                      MemOrPortAddr,
    140                      1,                    // count
    141                      (VOID *) (UINTN) BufferPtr
    142                      );
    143     break;
    144 
    145   case PXE_MEM_READ:
    146     Snp->PciIo->Mem.Read (
    147                       Snp->PciIo,
    148                       Width,
    149                       Snp->MemoryBarIndex,  // BAR 0, Memory base address
    150                       MemOrPortAddr,
    151                       1,                    // count
    152                       (VOID *) (UINTN) BufferPtr
    153                       );
    154     break;
    155 
    156   case PXE_MEM_WRITE:
    157     Snp->PciIo->Mem.Write (
    158                       Snp->PciIo,
    159                       Width,
    160                       Snp->MemoryBarIndex,  // BAR 0, Memory base address
    161                       MemOrPortAddr,
    162                       1,                    // count
    163                       (VOID *) (UINTN) BufferPtr
    164                       );
    165     break;
    166   }
    167 
    168   return ;
    169 }
    170 
    171 /**
    172   Map a CPU address to a device address.
    173 
    174   This is a callback routine supplied to UNDI at undi_start time.
    175 
    176   @param UniqueId      This was supplied to UNDI at Undi_Start, SNP uses this to
    177                        store Undi interface context (Undi does not read or write
    178                        this variable).
    179   @param CpuAddr       Virtual address to be mapped.
    180   @param NumBytes      Size of memory to be mapped.
    181   @param Direction     Direction of data flow for this memory's usage:
    182                        cpu->device, device->cpu or both ways.
    183   @param DeviceAddrPtr Pointer to return the mapped device address.
    184 
    185 **/
    186 VOID
    187 EFIAPI
    188 SnpUndi32CallbackMap (
    189   IN UINT64     UniqueId,
    190   IN UINT64     CpuAddr,
    191   IN UINT32     NumBytes,
    192   IN UINT32     Direction,
    193   IN OUT UINT64 DeviceAddrPtr
    194   )
    195 {
    196   EFI_PHYSICAL_ADDRESS          *DevAddrPtr;
    197   EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;
    198   UINTN                         BuffSize;
    199   SNP_DRIVER                    *Snp;
    200   UINTN                         Index;
    201   EFI_STATUS                    Status;
    202 
    203   BuffSize    = (UINTN) NumBytes;
    204   Snp         = (SNP_DRIVER *) (UINTN) UniqueId;
    205   DevAddrPtr  = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;
    206 
    207   if (CpuAddr == 0) {
    208     *DevAddrPtr = 0;
    209     return ;
    210   }
    211 
    212   switch (Direction) {
    213   case TO_AND_FROM_DEVICE:
    214     DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;
    215     break;
    216 
    217   case FROM_DEVICE:
    218     DirectionFlag = EfiPciIoOperationBusMasterWrite;
    219     break;
    220 
    221   case TO_DEVICE:
    222     DirectionFlag = EfiPciIoOperationBusMasterRead;
    223     break;
    224 
    225   default:
    226     *DevAddrPtr = 0;
    227     //
    228     // any non zero indicates error!
    229     //
    230     return ;
    231   }
    232   //
    233   // find an unused map_list entry
    234   //
    235   for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
    236     if (Snp->MapList[Index].VirtualAddress == 0) {
    237       break;
    238     }
    239   }
    240 
    241   if (Index >= MAX_MAP_LENGTH) {
    242     DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));
    243     *DevAddrPtr = 0;
    244     return ;
    245   }
    246 
    247   Snp->MapList[Index].VirtualAddress = (EFI_PHYSICAL_ADDRESS) CpuAddr;
    248 
    249   Status = Snp->PciIo->Map (
    250                          Snp->PciIo,
    251                          DirectionFlag,
    252                          (VOID *) (UINTN) CpuAddr,
    253                          &BuffSize,
    254                          DevAddrPtr,
    255                          &(Snp->MapList[Index].MapCookie)
    256                          );
    257   if (Status != EFI_SUCCESS) {
    258     *DevAddrPtr                        = 0;
    259     Snp->MapList[Index].VirtualAddress = 0;
    260   }
    261 
    262   return ;
    263 }
    264 
    265 /**
    266   Unmap an address that was previously mapped using map callback.
    267 
    268   This is a callback routine supplied to UNDI at undi_start time.
    269 
    270   @param UniqueId    This was supplied to UNDI at Undi_Start, SNP uses this to
    271                      store. Undi interface context (Undi does not read or write
    272                      this variable).
    273   @param CpuAddr     Virtual address that was mapped.
    274   @param NumBytes    Size of memory mapped.
    275   @param Direction   Direction of data flow for this memory's usage:
    276                      cpu->device, device->cpu or both ways.
    277   @param DeviceAddr  The mapped device address.
    278 
    279 **/
    280 VOID
    281 EFIAPI
    282 SnpUndi32CallbackUnmap (
    283   IN UINT64 UniqueId,
    284   IN UINT64 CpuAddr,
    285   IN UINT32 NumBytes,
    286   IN UINT32 Direction,
    287   IN UINT64 DeviceAddr
    288   )
    289 {
    290   SNP_DRIVER  *Snp;
    291   UINT16      Index;
    292 
    293   Snp = (SNP_DRIVER *) (UINTN) UniqueId;
    294 
    295   for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
    296     if (Snp->MapList[Index].VirtualAddress == CpuAddr) {
    297       break;
    298     }
    299   }
    300 
    301   if (Index >= MAX_MAP_LENGTH) {
    302     DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));
    303     return ;
    304   }
    305 
    306   Snp->PciIo->Unmap (Snp->PciIo, Snp->MapList[Index].MapCookie);
    307   Snp->MapList[Index].VirtualAddress = 0;
    308   Snp->MapList[Index].MapCookie      = NULL;
    309   return ;
    310 }
    311 
    312 /**
    313   Synchronize the virtual buffer contents with the mapped buffer contents.
    314 
    315   This is a callback routine supplied to UNDI at undi_start time. The virtual
    316   and mapped buffers need not correspond to the same physical memory (especially
    317   if the virtual address is > 4GB). Depending on the direction for which the
    318   buffer is mapped, undi will need to synchronize their contents whenever it
    319   writes to/reads from the buffer using either the cpu address or the device
    320   address.
    321   EFI does not provide a sync call since virt=physical, we should just do the
    322   synchronization ourselves here.
    323 
    324   @param UniqueId    This was supplied to UNDI at Undi_Start, SNP uses this to
    325                      store Undi interface context (Undi does not read or write
    326                      this variable).
    327   @param CpuAddr     Virtual address that was mapped.
    328   @param NumBytes    Size of memory mapped.
    329   @param Direction   Direction of data flow for this memory's usage:
    330                      cpu->device, device->cpu or both ways.
    331   @param DeviceAddr  The mapped device address.
    332 
    333 **/
    334 VOID
    335 EFIAPI
    336 SnpUndi32CallbackSync (
    337   IN UINT64             UniqueId,
    338   IN UINT64             CpuAddr,
    339   IN UINT32             NumBytes,
    340   IN UINT32             Direction,
    341   IN UINT64             DeviceAddr
    342   )
    343 {
    344   if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {
    345     return ;
    346 
    347   }
    348 
    349   switch (Direction) {
    350   case FROM_DEVICE:
    351     CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);
    352     break;
    353 
    354   case TO_DEVICE:
    355     CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);
    356     break;
    357   }
    358 
    359   return ;
    360 }
    361