Home | History | Annotate | Download | only in VirtioNetDxe
      1 /** @file
      2 
      3   Implementation of the SNP.GetStatus() function and its private helpers if
      4   any.
      5 
      6   Copyright (C) 2013, Red Hat, Inc.
      7   Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
      8 
      9   This program and the accompanying materials are licensed and made available
     10   under the terms and conditions of the BSD License which accompanies this
     11   distribution. The full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php
     13 
     14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
     15   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     16 
     17 **/
     18 
     19 #include <Library/BaseLib.h>
     20 #include <Library/UefiBootServicesTableLib.h>
     21 
     22 #include "VirtioNet.h"
     23 
     24 /**
     25   Reads the current interrupt status and recycled transmit buffer status from
     26   a network interface.
     27 
     28   @param  This            The protocol instance pointer.
     29   @param  InterruptStatus A pointer to the bit mask of the currently active
     30                           interrupts If this is NULL, the interrupt status will
     31                           not be read from the device. If this is not NULL, the
     32                           interrupt status will be read from the device. When
     33                           the  interrupt status is read, it will also be
     34                           cleared. Clearing the transmit  interrupt does not
     35                           empty the recycled transmit buffer array.
     36   @param  TxBuf           Recycled transmit buffer address. The network
     37                           interface will not transmit if its internal recycled
     38                           transmit buffer array is full. Reading the transmit
     39                           buffer does not clear the transmit interrupt. If this
     40                           is NULL, then the transmit buffer status will not be
     41                           read. If there are no transmit buffers to recycle and
     42                           TxBuf is not NULL, * TxBuf will be set to NULL.
     43 
     44   @retval EFI_SUCCESS           The status of the network interface was
     45                                 retrieved.
     46   @retval EFI_NOT_STARTED       The network interface has not been started.
     47   @retval EFI_INVALID_PARAMETER One or more of the parameters has an
     48                                 unsupported value.
     49   @retval EFI_DEVICE_ERROR      The command could not be sent to the network
     50                                 interface.
     51   @retval EFI_UNSUPPORTED       This function is not supported by the network
     52                                 interface.
     53 
     54 **/
     55 
     56 EFI_STATUS
     57 EFIAPI
     58 VirtioNetGetStatus (
     59   IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
     60   OUT UINT32                     *InterruptStatus OPTIONAL,
     61   OUT VOID                       **TxBuf OPTIONAL
     62   )
     63 {
     64   VNET_DEV   *Dev;
     65   EFI_TPL    OldTpl;
     66   EFI_STATUS Status;
     67   UINT16     RxCurUsed;
     68   UINT16     TxCurUsed;
     69 
     70   if (This == NULL) {
     71     return EFI_INVALID_PARAMETER;
     72   }
     73 
     74   Dev = VIRTIO_NET_FROM_SNP (This);
     75   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
     76   switch (Dev->Snm.State) {
     77   case EfiSimpleNetworkStopped:
     78     Status = EFI_NOT_STARTED;
     79     goto Exit;
     80   case EfiSimpleNetworkStarted:
     81     Status = EFI_DEVICE_ERROR;
     82     goto Exit;
     83   default:
     84     break;
     85   }
     86 
     87   //
     88   // update link status
     89   //
     90   if (Dev->Snm.MediaPresentSupported) {
     91     UINT16 LinkStatus;
     92 
     93     Status = VIRTIO_CFG_READ (Dev, LinkStatus, &LinkStatus);
     94     if (EFI_ERROR (Status)) {
     95       goto Exit;
     96     }
     97     Dev->Snm.MediaPresent =
     98       (BOOLEAN) ((LinkStatus & VIRTIO_NET_S_LINK_UP) != 0);
     99   }
    100 
    101   //
    102   // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
    103   //
    104   MemoryFence ();
    105   RxCurUsed = *Dev->RxRing.Used.Idx;
    106   TxCurUsed = *Dev->TxRing.Used.Idx;
    107   MemoryFence ();
    108 
    109   if (InterruptStatus != NULL) {
    110     //
    111     // report the receive interrupt if there is data available for reception,
    112     // report the transmit interrupt if we have transmitted at least one buffer
    113     //
    114     *InterruptStatus = 0;
    115     if (Dev->RxLastUsed != RxCurUsed) {
    116       *InterruptStatus |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
    117     }
    118     if (Dev->TxLastUsed != TxCurUsed) {
    119       ASSERT (Dev->TxCurPending > 0);
    120       *InterruptStatus |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
    121     }
    122   }
    123 
    124   if (TxBuf != NULL) {
    125     if (Dev->TxLastUsed == TxCurUsed) {
    126       *TxBuf = NULL;
    127     }
    128     else {
    129       UINT16 UsedElemIdx;
    130       UINT32 DescIdx;
    131 
    132       //
    133       // fetch the first descriptor among those that the hypervisor reports
    134       // completed
    135       //
    136       ASSERT (Dev->TxCurPending > 0);
    137       ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);
    138 
    139       UsedElemIdx = Dev->TxLastUsed++ % Dev->TxRing.QueueSize;
    140       DescIdx = Dev->TxRing.Used.UsedElem[UsedElemIdx].Id;
    141       ASSERT (DescIdx < (UINT32) (2 * Dev->TxMaxPending - 1));
    142 
    143       //
    144       // report buffer address to caller that has been enqueued by caller
    145       //
    146       *TxBuf = (VOID *)(UINTN) Dev->TxRing.Desc[DescIdx + 1].Addr;
    147 
    148       //
    149       // now this descriptor can be used again to enqueue a transmit buffer
    150       //
    151       Dev->TxFreeStack[--Dev->TxCurPending] = (UINT16) DescIdx;
    152     }
    153   }
    154 
    155   Status = EFI_SUCCESS;
    156 
    157 Exit:
    158   gBS->RestoreTPL (OldTpl);
    159   return Status;
    160 }
    161