Home | History | Annotate | Download | only in SnpDxe
      1 /** @file
      2   Implementation of reading the current interrupt status and recycled transmit
      3   buffer status from a network interface.
      4 
      5 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials are licensed
      7 and made available under the terms and conditions of the BSD License which
      8 accompanies this distribution. The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "Snp.h"
     17 
     18 /**
     19   Call undi to get the status of the interrupts, get the list of recycled transmit
     20   buffers that completed transmitting. The recycled transmit buffer address will
     21   be saved into Snp->RecycledTxBuf.
     22 
     23   @param  Snp                     Pointer to snp driver structure.
     24   @param  InterruptStatusPtr      A non null pointer to contain the interrupt
     25                                   status.
     26   @param  GetTransmittedBuf       Set to TRUE to retrieve the recycled transmit
     27                                   buffer address.
     28 
     29   @retval EFI_SUCCESS         The status of the network interface was retrieved.
     30   @retval EFI_DEVICE_ERROR    The command could not be sent to the network
     31                               interface.
     32 
     33 **/
     34 EFI_STATUS
     35 PxeGetStatus (
     36   SNP_DRIVER *Snp,
     37   UINT32     *InterruptStatusPtr,
     38   BOOLEAN    GetTransmittedBuf
     39   )
     40 {
     41   PXE_DB_GET_STATUS *Db;
     42   UINT16            InterruptFlags;
     43   UINT32            Index;
     44   UINT64            *Tmp;
     45 
     46   Tmp               = NULL;
     47   Db                = Snp->Db;
     48   Snp->Cdb.OpCode   = PXE_OPCODE_GET_STATUS;
     49 
     50   Snp->Cdb.OpFlags  = 0;
     51 
     52   if (GetTransmittedBuf) {
     53     Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS;
     54     ZeroMem (Db->TxBuffer, sizeof (Db->TxBuffer));
     55   }
     56 
     57   if (InterruptStatusPtr != NULL) {
     58     Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_INTERRUPT_STATUS;
     59   }
     60 
     61   if (Snp->MediaStatusSupported) {
     62     Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_MEDIA_STATUS;
     63   }
     64 
     65   Snp->Cdb.CPBsize  = PXE_CPBSIZE_NOT_USED;
     66   Snp->Cdb.CPBaddr  = PXE_CPBADDR_NOT_USED;
     67 
     68   //
     69   // size DB for return of one buffer
     70   //
     71   Snp->Cdb.DBsize     = (UINT16) ((sizeof (PXE_DB_GET_STATUS) - sizeof (Db->TxBuffer)) + sizeof (Db->TxBuffer[0]));
     72 
     73   Snp->Cdb.DBaddr     = (UINT64)(UINTN) Db;
     74 
     75   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
     76   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
     77   Snp->Cdb.IFnum      = Snp->IfNum;
     78   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
     79 
     80   //
     81   // Issue UNDI command and check result.
     82   //
     83   DEBUG ((EFI_D_NET, "\nSnp->undi.get_status()  "));
     84 
     85   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
     86 
     87   if (Snp->Cdb.StatCode != EFI_SUCCESS) {
     88     DEBUG (
     89       (EFI_D_NET,
     90       "\nSnp->undi.get_status()  %xh:%xh\n",
     91       Snp->Cdb.StatFlags,
     92       Snp->Cdb.StatFlags)
     93       );
     94 
     95     return EFI_DEVICE_ERROR;
     96   }
     97   //
     98   // report the values back..
     99   //
    100   if (InterruptStatusPtr != NULL) {
    101     InterruptFlags      = (UINT16) (Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK);
    102 
    103     *InterruptStatusPtr = 0;
    104 
    105     if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_RECEIVE) == PXE_STATFLAGS_GET_STATUS_RECEIVE) {
    106       *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
    107     }
    108 
    109     if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_TRANSMIT) == PXE_STATFLAGS_GET_STATUS_TRANSMIT) {
    110       *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
    111     }
    112 
    113     if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_COMMAND) == PXE_STATFLAGS_GET_STATUS_COMMAND) {
    114       *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
    115     }
    116 
    117     if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_SOFTWARE) == PXE_STATFLAGS_GET_STATUS_SOFTWARE) {
    118       *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
    119     }
    120 
    121   }
    122 
    123   if (GetTransmittedBuf) {
    124     if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) == 0) {
    125       //
    126       // UNDI has written some transmitted buffer addresses into the DB. Store them into Snp->RecycledTxBuf.
    127       //
    128       for (Index = 0; Index < MAX_XMIT_BUFFERS; Index++) {
    129         if (Db->TxBuffer[Index] != 0) {
    130           if (Snp->RecycledTxBufCount == Snp->MaxRecycledTxBuf) {
    131             //
    132             // Snp->RecycledTxBuf is full, reallocate a new one.
    133             //
    134             if ((Snp->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT) >= SNP_MAX_TX_BUFFER_NUM) {
    135               return EFI_DEVICE_ERROR;
    136             }
    137             Tmp = AllocatePool (sizeof (UINT64) * (Snp->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT));
    138             if (Tmp == NULL) {
    139               return EFI_DEVICE_ERROR;
    140             }
    141             CopyMem (Tmp, Snp->RecycledTxBuf, sizeof (UINT64) * Snp->RecycledTxBufCount);
    142             FreePool (Snp->RecycledTxBuf);
    143             Snp->RecycledTxBuf    =  Tmp;
    144             Snp->MaxRecycledTxBuf += SNP_TX_BUFFER_INCREASEMENT;
    145           }
    146           Snp->RecycledTxBuf[Snp->RecycledTxBufCount] = Db->TxBuffer[Index];
    147           Snp->RecycledTxBufCount++;
    148         }
    149       }
    150     }
    151   }
    152 
    153   //
    154   // Update MediaPresent field of EFI_SIMPLE_NETWORK_MODE if the UNDI support
    155   // returning media status from GET_STATUS command
    156   //
    157   if (Snp->MediaStatusSupported) {
    158     Snp->Snp.Mode->MediaPresent =
    159       (BOOLEAN) (((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA) != 0) ? FALSE : TRUE);
    160   }
    161 
    162   return EFI_SUCCESS;
    163 }
    164 
    165 /**
    166   Reads the current interrupt status and recycled transmit buffer status from a
    167   network interface.
    168 
    169   This function gets the current interrupt and recycled transmit buffer status
    170   from the network interface. The interrupt status is returned as a bit mask in
    171   InterruptStatus. If InterruptStatus is NULL, the interrupt status will not be
    172   read. If TxBuf is not NULL, a recycled transmit buffer address will be retrieved.
    173   If a recycled transmit buffer address is returned in TxBuf, then the buffer has
    174   been successfully transmitted, and the status for that buffer is cleared. If
    175   the status of the network interface is successfully collected, EFI_SUCCESS
    176   will be returned. If the driver has not been initialized, EFI_DEVICE_ERROR will
    177   be returned.
    178 
    179   @param This            A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
    180   @param InterruptStatus A pointer to the bit mask of the currently active
    181                          interrupts (see "Related Definitions"). If this is NULL,
    182                          the interrupt status will not be read from the device.
    183                          If this is not NULL, the interrupt status will be read
    184                          from the device. When the interrupt status is read, it
    185                          will also be cleared. Clearing the transmit interrupt does
    186                          not empty the recycled transmit buffer array.
    187   @param TxBuf           Recycled transmit buffer address. The network interface
    188                          will not transmit if its internal recycled transmit
    189                          buffer array is full. Reading the transmit buffer does
    190                          not clear the transmit interrupt. If this is NULL, then
    191                          the transmit buffer status will not be read. If there
    192                          are no transmit buffers to recycle and TxBuf is not NULL,
    193                          TxBuf will be set to NULL.
    194 
    195   @retval EFI_SUCCESS           The status of the network interface was retrieved.
    196   @retval EFI_NOT_STARTED       The network interface has not been started.
    197   @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
    198                                 EFI_SIMPLE_NETWORK_PROTOCOL structure.
    199   @retval EFI_DEVICE_ERROR      The command could not be sent to the network
    200                                 interface.
    201 
    202 **/
    203 EFI_STATUS
    204 EFIAPI
    205 SnpUndi32GetStatus (
    206   IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
    207   OUT UINT32                     *InterruptStatus, OPTIONAL
    208   OUT VOID                       **TxBuf           OPTIONAL
    209   )
    210 {
    211   SNP_DRIVER  *Snp;
    212   EFI_TPL     OldTpl;
    213   EFI_STATUS  Status;
    214 
    215   if (This == NULL) {
    216     return EFI_INVALID_PARAMETER;
    217   }
    218 
    219   if (InterruptStatus == NULL && TxBuf == NULL) {
    220     return EFI_INVALID_PARAMETER;
    221   }
    222 
    223   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
    224 
    225   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    226 
    227   if (Snp == NULL) {
    228     return EFI_DEVICE_ERROR;
    229   }
    230 
    231   switch (Snp->Mode.State) {
    232   case EfiSimpleNetworkInitialized:
    233     break;
    234 
    235   case EfiSimpleNetworkStopped:
    236     Status = EFI_NOT_STARTED;
    237     goto ON_EXIT;
    238 
    239   default:
    240     Status = EFI_DEVICE_ERROR;
    241     goto ON_EXIT;
    242   }
    243 
    244   if (Snp->RecycledTxBufCount == 0 && TxBuf != NULL) {
    245     Status = PxeGetStatus (Snp, InterruptStatus, TRUE);
    246   } else {
    247     Status = PxeGetStatus (Snp, InterruptStatus, FALSE);
    248   }
    249 
    250   if (TxBuf != NULL) {
    251     //
    252     // Get a recycled buf from Snp->RecycledTxBuf
    253     //
    254     if (Snp->RecycledTxBufCount == 0) {
    255       *TxBuf = NULL;
    256     } else {
    257       Snp->RecycledTxBufCount--;
    258       *TxBuf = (VOID *) (UINTN) Snp->RecycledTxBuf[Snp->RecycledTxBufCount];
    259     }
    260   }
    261 
    262 ON_EXIT:
    263   gBS->RestoreTPL (OldTpl);
    264 
    265   return Status;
    266 }
    267