2 -- Copyright (C) 2016-2017 secunet Security Networks AG
4 -- This program is free software; you can redistribute it and/or modify
5 -- it under the terms of the GNU General Public License as published by
6 -- the Free Software Foundation; either version 2 of the License, or
7 -- (at your option) any later version.
9 -- This program is distributed in the hope that it will be useful,
10 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- GNU General Public License for more details.
16 with HW.DbC.DMA_Buffers;
18 package body HW.DbC.Transfer_Info
20 Refined_State => (State => (Start_Counter, Stats, Xfers))
23 Start_Counter : Word64 := 0; -- Should not overflow
25 type Xfer_Info is record
26 Endpoint : Endpoint_Range;
35 type Xfer_Array is array (Transfer_Id) of Xfer_Info;
37 Xfers : Xfer_Array := Xfer_Array'
38 (Transfer_Id => Xfer_Info'
39 (Endpoint => Endpoint_Range'First,
40 Token => 16#0000_0000_0000_0000#,
43 Status => Error'First,
47 type Stats_Info is record
52 type Stats_Array is array (Endpoint_Range) of Stats_Info;
53 Stats : Stats_Array := (Endpoint_Range => (others => 0));
55 ----------------------------------------------------------------------------
57 function Get_Endpoint (Id : Transfer_Id) return Endpoint_Range
60 return Xfers (Id).Endpoint;
63 function Get_Offset (Id : Transfer_Id) return Natural
66 return Xfers (Id).Offset;
69 procedure Set_Offset (Id : Transfer_Id; Offset : Natural)
72 Xfers (Id).Offset := Offset;
75 function Get_Length (Id : Transfer_Id) return Natural
78 return Xfers (Id).Length;
81 function Get_Status (Id : Transfer_Id) return Error
84 return Xfers (Id).Status;
87 function Physical (Id : Transfer_Id) return Word64
91 return DMA_Buffers.Base + Word64 (Id) * Max_Bulk_Size;
94 ----------------------------------------------------------------------------
97 (Endpoint : in Endpoint_Range;
100 Success : out Boolean)
106 Id := Transfer_Id'First;
107 for I in Transfer_Id loop
108 if not Xfers (I).Started then
110 (Endpoint => Endpoint,
111 Token => Start_Counter,
114 Status => Error'First,
117 Stats (Endpoint).Enqueued :=
118 Stats (Endpoint).Enqueued + Word32 (Length);
119 Start_Counter := Start_Counter + 1;
134 Endpoint : constant Endpoint_Range := Xfers (Id).Endpoint;
137 (Endpoint => Endpoint,
138 Token => Start_Counter,
141 Status => Error'First,
144 Start_Counter := Start_Counter + 1;
145 Stats (Endpoint).Enqueued
146 := Stats (Endpoint).Enqueued + Word32 (Length);
150 (Endpoint : in Endpoint_Range;
151 Length : in out Natural;
152 Offset : out Natural;
153 Id : out Transfer_Id)
158 Max_Counter : Word64;
162 Id := Transfer_Id'First;
163 for I in Transfer_Id loop
164 if Xfers (I).Started and
165 Xfers (I).Endpoint = Endpoint and
166 Xfers (I).Token >= Max_Counter
168 Max_Counter := Xfers (I).Token;
174 Length := Natural'Min (Length, Max_Bulk_Size - Xfers (Id).Length);
175 Offset := Xfers (Id).Length;
176 Xfers (Id).Length := Xfers (Id).Length + Length;
177 Stats (Endpoint).Enqueued
178 := Stats (Endpoint).Enqueued + Word32 (Length);
186 (DMA_Physical : Word64;
187 Remaining_Length : Natural;
194 if Physical (Transfer_Id'First) <= DMA_Physical and
195 DMA_Physical <= Physical (Transfer_Id'Last) and
196 (DMA_Physical - Physical (Transfer_Id'First)) mod Max_Bulk_Size = 0
199 ((DMA_Physical - Physical (Transfer_Id'First)) / Max_Bulk_Size);
200 if Xfers (Id).Started then
201 Xfers (Id).Finished := True;
202 Xfers (Id).Status := Status;
203 Xfers (Id).Offset := 0;
204 if Remaining_Length <= Xfers (Id).Length then
205 Xfers (Id).Length := Xfers (Id).Length - Remaining_Length;
206 Stats (Xfers (Id).Endpoint).Transfered :=
207 Stats (Xfers (Id).Endpoint).Transfered + Word32
209 Stats (Xfers (Id).Endpoint).Lost :=
210 Stats (Xfers (Id).Endpoint).Lost + Word32 (Remaining_Length);
212 Stats (Xfers (Id).Endpoint).Lost :=
213 Stats (Xfers (Id).Endpoint).Lost + Word32 (Xfers (Id).Length);
214 Xfers (Id).Length := 0;
215 Xfers (Id).Status := Controller_Error;
218 pragma Debug (Debug.Put_Reg8
219 ("Spurious finish for transfer", Word8 (Id)));
223 pragma Debug (Debug.Put_Reg64
224 ("WARNING: Invalid DMA pointer", DMA_Physical));
225 pragma Debug (Debug.Put_Reg64
226 (" first DMA address", Physical (Transfer_Id'First)));
227 pragma Debug (Debug.Put_Reg64
228 (" last DMA address", Physical (Transfer_Id'Last)));
233 procedure Reset (Id : Transfer_Id)
236 Xfers (Id).Started := False;
239 ----------------------------------------------------------------------------
242 with function Check (Id : Transfer_Id) return Boolean;
244 (Minimum_Ctr : in out Word64;
245 Id : out Transfer_Id;
246 Success : out Boolean);
249 (Minimum_Ctr : in out Word64;
250 Id : out Transfer_Id;
251 Success : out Boolean)
256 Id := Transfer_Id'First;
257 for I in Transfer_Id loop
258 if Check (I) and Xfers (I).Token >= Minimum_Ctr then
259 if (Success and Xfers (I).Token < Xfers (Id).Token) or
268 Minimum_Ctr := Xfers (Id).Token + 1;
272 function Check_Started (Id : Transfer_Id) return Boolean
275 return Xfers (Id).Started and not Xfers (Id).Finished;
277 procedure Walk_Started_Inst is new Walk (Check_Started);
278 procedure Walk_Started
279 (Minimum_Ctr : in out Word64;
280 Id : out Transfer_Id;
281 Success : out Boolean)
282 renames Walk_Started_Inst;
284 procedure Walk_Finished
285 (Endpoint : in Endpoint_Range;
286 Minimum_Ctr : in out Word64;
287 Id : out Transfer_Id;
288 Success : out Boolean)
290 function Check_Finished (Id : Transfer_Id) return Boolean;
291 function Check_Finished (Id : Transfer_Id) return Boolean
295 Xfers (Id).Endpoint = Endpoint and
296 Xfers (Id).Started and
300 procedure Walk_Finished_Inst is new Walk (Check_Finished);
302 Walk_Finished_Inst (Minimum_Ctr, Id, Success);
305 ----------------------------------------------------------------------------
311 Debug.Put_Line ("DbC statistics:");
312 for EP in Endpoint_Range loop
313 Debug.Put (" Endpoint #");
314 Debug.Put_Int8 (Int8 (EP));
316 Debug.Put (" enqueued: ");
317 Debug.Put_Word32 (Stats (EP).Enqueued);
319 Debug.Put_Int32 (Int32 (Stats (EP).Enqueued));
320 Debug.Put_Line (")");
321 Debug.Put (" transfered: ");
322 Debug.Put_Word32 (Stats (EP).Transfered);
324 Debug.Put_Int32 (Int32 (Stats (EP).Transfered));
325 Debug.Put_Line (")");
326 Debug.Put (" lost: ");
327 Debug.Put_Word32 (Stats (EP).Lost);
329 Debug.Put_Int32 (Int32 (Stats (EP).Lost));
330 Debug.Put_Line (")");
331 Debug.Put (" in queue: ");
333 (Stats (EP).Enqueued - Stats (EP).Transfered - Stats (EP).Lost);
335 Debug.Put_Int32 (Int32
336 (Stats (EP).Enqueued - Stats (EP).Transfered - Stats (EP).Lost));
337 Debug.Put_Line (")");
341 end HW.DbC.Transfer_Info;
343 -- vim: set ts=8 sts=3 sw=3 et: