1 /** @file
2     Implementation of collecting the statistics on a network interface.
3 
4 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 
10 #include "Snp.h"
11 
12 
13 /**
14   Resets or collects the statistics on a network interface.
15 
16   This function resets or collects the statistics on a network interface. If the
17   size of the statistics table specified by StatisticsSize is not big enough for
18   all the statistics that are collected by the network interface, then a partial
19   buffer of statistics is returned in StatisticsTable, StatisticsSize is set to
20   the size required to collect all the available statistics, and
21   EFI_BUFFER_TOO_SMALL is returned.
22   If StatisticsSize is big enough for all the statistics, then StatisticsTable
23   will be filled, StatisticsSize will be set to the size of the returned
24   StatisticsTable structure, and EFI_SUCCESS is returned.
25   If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
26   If Reset is FALSE, and both StatisticsSize and StatisticsTable are NULL, then
27   no operations will be performed, and EFI_SUCCESS will be returned.
28   If Reset is TRUE, then all of the supported statistics counters on this network
29   interface will be reset to zero.
30 
31   @param This            A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
32   @param Reset           Set to TRUE to reset the statistics for the network interface.
33   @param StatisticsSize  On input the size, in bytes, of StatisticsTable. On output
34                          the size, in bytes, of the resulting table of statistics.
35   @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
36                          contains the statistics. Type EFI_NETWORK_STATISTICS is
37                          defined in "Related Definitions" below.
38 
39   @retval EFI_SUCCESS           The requested operation succeeded.
40   @retval EFI_NOT_STARTED       The Simple Network Protocol interface has not been
41                                 started by calling Start().
42   @retval EFI_BUFFER_TOO_SMALL  StatisticsSize is not NULL and StatisticsTable is
43                                 NULL. The current buffer size that is needed to
44                                 hold all the statistics is returned in StatisticsSize.
45   @retval EFI_BUFFER_TOO_SMALL  StatisticsSize is not NULL and StatisticsTable is
46                                 not NULL. The current buffer size that is needed
47                                 to hold all the statistics is returned in
48                                 StatisticsSize. A partial set of statistics is
49                                 returned in StatisticsTable.
50   @retval EFI_INVALID_PARAMETER StatisticsSize is NULL and StatisticsTable is not
51                                 NULL.
52   @retval EFI_DEVICE_ERROR      The Simple Network Protocol interface has not
53                                 been initialized by calling Initialize().
54   @retval EFI_DEVICE_ERROR      An error was encountered collecting statistics
55                                 from the NIC.
56   @retval EFI_UNSUPPORTED       The NIC does not support collecting statistics
57                                 from the network interface.
58 
59 **/
60 EFI_STATUS
61 EFIAPI
SnpUndi32Statistics(IN EFI_SIMPLE_NETWORK_PROTOCOL * This,IN BOOLEAN Reset,IN OUT UINTN * StatisticsSize,OPTIONAL IN OUT EFI_NETWORK_STATISTICS * StatisticsTable OPTIONAL)62 SnpUndi32Statistics (
63   IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
64   IN BOOLEAN                     Reset,
65   IN OUT UINTN                   *StatisticsSize, OPTIONAL
66   IN OUT EFI_NETWORK_STATISTICS  *StatisticsTable OPTIONAL
67   )
68 {
69   SNP_DRIVER        *Snp;
70   PXE_DB_STATISTICS *Db;
71   UINT64            *Stp;
72   UINT64            Mask;
73   UINTN             Size;
74   UINTN             Index;
75   EFI_TPL           OldTpl;
76   EFI_STATUS        Status;
77 
78   //
79   // Get pointer to SNP driver instance for *This.
80   //
81   if (This == NULL) {
82     return EFI_INVALID_PARAMETER;
83   }
84 
85   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
86 
87   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
88 
89   //
90   // Return error if the SNP is not initialized.
91   //
92   switch (Snp->Mode.State) {
93   case EfiSimpleNetworkInitialized:
94     break;
95 
96   case EfiSimpleNetworkStopped:
97     Status = EFI_NOT_STARTED;
98     goto ON_EXIT;
99 
100   default:
101     Status = EFI_DEVICE_ERROR;
102     goto ON_EXIT;
103   }
104   //
105   // if we are not resetting the counters, we have to have a valid stat table
106   // with >0 size. if no reset, no table and no size, return success.
107   //
108   if (!Reset && StatisticsSize == NULL) {
109     Status = (StatisticsTable != NULL) ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
110     goto ON_EXIT;
111   }
112   //
113   // Initialize UNDI Statistics CDB
114   //
115   Snp->Cdb.OpCode     = PXE_OPCODE_STATISTICS;
116   Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
117   Snp->Cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;
118   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
119   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
120   Snp->Cdb.IFnum      = Snp->IfNum;
121   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
122 
123   if (Reset) {
124     Snp->Cdb.OpFlags  = PXE_OPFLAGS_STATISTICS_RESET;
125     Snp->Cdb.DBsize   = PXE_DBSIZE_NOT_USED;
126     Snp->Cdb.DBaddr   = PXE_DBADDR_NOT_USED;
127     Db                = Snp->Db;
128   } else {
129     Snp->Cdb.OpFlags                = PXE_OPFLAGS_STATISTICS_READ;
130     Snp->Cdb.DBsize                 = (UINT16) sizeof (PXE_DB_STATISTICS);
131     Snp->Cdb.DBaddr                 = (UINT64)(UINTN) (Db = Snp->Db);
132   }
133   //
134   // Issue UNDI command and check result.
135   //
136   DEBUG ((EFI_D_NET, "\nsnp->undi.statistics()  "));
137 
138   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
139 
140   switch (Snp->Cdb.StatCode) {
141   case PXE_STATCODE_SUCCESS:
142     break;
143 
144   case PXE_STATCODE_UNSUPPORTED:
145     DEBUG (
146       (EFI_D_ERROR,
147       "\nsnp->undi.statistics()  %xh:%xh\n",
148       Snp->Cdb.StatFlags,
149       Snp->Cdb.StatCode)
150       );
151 
152     Status = EFI_UNSUPPORTED;
153     goto ON_EXIT;
154 
155   default:
156     DEBUG (
157       (EFI_D_ERROR,
158       "\nsnp->undi.statistics()  %xh:%xh\n",
159       Snp->Cdb.StatFlags,
160       Snp->Cdb.StatCode)
161       );
162 
163     Status = EFI_DEVICE_ERROR;
164     goto ON_EXIT;
165   }
166 
167   if (Reset) {
168     Status = EFI_SUCCESS;
169     goto ON_EXIT;
170   }
171 
172   if (StatisticsTable == NULL) {
173     *StatisticsSize = sizeof (EFI_NETWORK_STATISTICS);
174     Status = EFI_BUFFER_TOO_SMALL;
175     goto ON_EXIT;
176   }
177   //
178   // Convert the UNDI statistics information to SNP statistics
179   // information.
180   //
181   ZeroMem (StatisticsTable, *StatisticsSize);
182   Stp   = (UINT64 *) StatisticsTable;
183   Size  = 0;
184 
185   for (Index = 0, Mask = 1; Index < 64; Index++, Mask = LShiftU64 (Mask, 1), Stp++) {
186     //
187     // There must be room for a full UINT64.  Partial
188     // numbers will not be stored.
189     //
190     if ((Index + 1) * sizeof (UINT64) > *StatisticsSize) {
191       break;
192     }
193 
194     if ((Db->Supported & Mask) != 0) {
195       *Stp  = Db->Data[Index];
196       Size  = Index + 1;
197     } else {
198       SetMem (Stp, sizeof (UINT64), 0xFF);
199     }
200   }
201   //
202   // Compute size up to last supported statistic.
203   //
204   while (++Index < 64) {
205     if ((Db->Supported & (Mask = LShiftU64 (Mask, 1))) != 0) {
206       Size = Index;
207     }
208   }
209 
210   Size *= sizeof (UINT64);
211 
212   if (*StatisticsSize >= Size) {
213     *StatisticsSize = Size;
214     Status = EFI_SUCCESS;
215   } else {
216     *StatisticsSize = Size;
217     Status = EFI_BUFFER_TOO_SMALL;
218   }
219 
220 ON_EXIT:
221   gBS->RestoreTPL (OldTpl);
222 
223   return Status;
224 }
225