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
PxeGetStatus(SNP_DRIVER * Snp,UINT32 * InterruptStatusPtr,BOOLEAN GetTransmittedBuf)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
SnpUndi32GetStatus(IN EFI_SIMPLE_NETWORK_PROTOCOL * This,OUT UINT32 * InterruptStatus,OPTIONAL OUT VOID ** TxBuf OPTIONAL)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