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