blob: 7ecf2077d9918bf2db46d9c5def49d65b53c7eae [file] [log] [blame]
developer02e65912023-08-17 16:33:10 +08001/* adapter_sglist.c
2 *
3 * Packet Engine Control (PEC) Scatter Gather list API implementation.
4 *
5 */
6
7/*****************************************************************************
8* Copyright (c) 2008-2022 by Rambus, Inc. and/or its subsidiaries.
9*
10* This program is free software: you can redistribute it and/or modify
11* it under the terms of the GNU General Public License as published by
12* the Free Software Foundation, either version 2 of the License, or
13* any later version.
14*
15* This program is distributed in the hope that it will be useful,
16* but WITHOUT ANY WARRANTY; without even the implied warranty of
17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18* GNU General Public License for more details.
19*
20* You should have received a copy of the GNU General Public License
21* along with this program. If not, see <http://www.gnu.org/licenses/>.
22*****************************************************************************/
23
24
25/*----------------------------------------------------------------------------
26 * This module implements (provides) the following interface(s):
27 */
28
29#include "api_pec_sg.h" // PEC_SG_* (the API we implement here)
30
31
32/*----------------------------------------------------------------------------
33 * This module uses (requires) the following interface(s):
34 */
35
36// Default Adapter PEC configuration
37#include "c_adapter_pec.h"
38
39// DMABuf API
40#include "api_dmabuf.h" // DMABuf_*
41
42// Adapter DMABuf internal API
43#include "adapter_dmabuf.h"
44
45// Logging API
46#include "log.h"
47
48// Driver Framework DMAResource API
49#include "dmares_types.h" // DMAResource_Handle_t
50#include "dmares_mgmt.h" // DMAResource management functions
51#include "dmares_rw.h" // DMAResource buffer access.
52#include "dmares_addr.h" // DMAResource addr translation functions.
53#include "dmares_buf.h" // DMAResource buffer allocations
54
55// Driver Framework C Run-Time Library API
56#include "clib.h" // memcpy, memset
57
58// Driver Framework Basic Definitions API
59#include "basic_defs.h" // bool, uint32_t
60
61
62/*----------------------------------------------------------------------------
63 * Definitions and macros
64 */
65
66#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
67
68// our internal definition of a scatter/gather list
69// the DMA buffer for SGList store this (variable-length) structure
70typedef struct
71{
72 unsigned int ListCapacity;
73
74 struct
75 {
76 DMABuf_Handle_t Handle;
77 unsigned int ByteCount; // set by PEC_SGList_Write and PEC_Packet_Get
78 } Entries[1]; // variable-size allocated!!!
79
80} PEC_SGList_t;
81
82
83/*----------------------------------------------------------------------------
84 * Adapter_Handle2SGList
85 *
86 * This function validates that the DMAResource handle is indeed an
87 * SGList handle
88 * and then returns the pointer to the PEC_SGList_t structure contained in
89 * the buffer related to this handle.
90 */
91static PEC_SGList_t *
92Adapter_Handle2SGListPtr(
93 DMABuf_Handle_t SGList_Handle)
94{
95 DMAResource_Handle_t * DMA_Handle =
96 Adapter_DMABuf_Handle2DMAResourceHandle(SGList_Handle);
97 DMAResource_Record_t * Rec_p;
98 if (DMAResource_IsValidHandle(DMA_Handle))
99 Rec_p = DMAResource_Handle2RecordPtr(DMA_Handle);
100 else
101 return NULL;
102
103 // ensure it is an SGList
104 if (Rec_p->sg.IsSGList != true)
105 return NULL;
106
107 return Adapter_DMAResource_HostAddr(
108 Adapter_DMABuf_Handle2DMAResourceHandle(SGList_Handle));
109
110}
111
112
113/*----------------------------------------------------------------------------
114 * Adapter_SGList_CalcAllocSize
115 *
116 * This function calculates the size of the buffer to be allocated to hold
117 * an PEC_SGList_t with a given capacity.
118 */
119static inline unsigned int
120Adapter_SGList_CalcAllocSize(
121 const unsigned int ListCapacity)
122{
123 PEC_SGList_t SG;
124 unsigned int S = sizeof(PEC_SGList_t);
125
126 S += (ListCapacity - 1) * sizeof(SG.Entries[1]);
127
128 return S;
129}
130#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
131
132
133/*----------------------------------------------------------------------------
134 * PEC_SGList_Create
135 *
136 * This function must be used to create a list that can hold references to
137 * packet buffer fragments. The returned handle can be used in PEC_Packet_Put
138 * instead of a normal (contiguous) buffers.
139 *
140 * ListCapacity (input)
141 * The number of scatter and/or gather fragments that this list can hold.
142 *
143 * SGList_Handle_p (output)
144 * Pointer to the output parameter that will be filled in with the handle
145 * that represents the newly created SGList.
146 */
147PEC_Status_t
148PEC_SGList_Create(
149 const unsigned int ListCapacity,
150 DMABuf_Handle_t * const SGList_Handle_p)
151{
152#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
153 DMAResource_AddrPair_t HostAddr;
154 int dmares;
155 DMAResource_Properties_t Props;
156
157 ZEROINIT(Props);
158
159 if (ListCapacity == 0 ||
160 SGList_Handle_p == NULL)
161 {
162 return PEC_ERROR_BAD_PARAMETER;
163 }
164
165 // initialize the output parameter
166 *SGList_Handle_p = DMABuf_NULLHandle;
167
168 Props.Size = Adapter_SGList_CalcAllocSize(ListCapacity);
169 Props.Alignment = Adapter_DMAResource_Alignment_Get();
170
171 dmares = DMAResource_Alloc(Props, &HostAddr, &SGList_Handle_p->p);
172 if (dmares != 0)
173 return PEC_ERROR_INTERNAL;
174
175 // set the special flag in the DMA Resource record for SGLists
176 {
177 DMAResource_Handle_t DMAHandle;
178 DMAResource_Record_t * Rec_p;
179
180 DMAHandle = SGList_Handle_p->p;
181 Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
182
183 if (!Rec_p)
184 {
185 // corner case - avoid memory leak
186 DMAResource_Release(Adapter_DMABuf_Handle2DMAResourceHandle(
187 *SGList_Handle_p));
188 *SGList_Handle_p = DMABuf_NULLHandle;
189
190 return PEC_ERROR_INTERNAL;
191 }
192
193 Rec_p->sg.IsSGList = true;
194 }
195
196 // initialize the SGList
197 {
198 PEC_SGList_t * const p = HostAddr.Address_p;
199 memset(p, 0, Props.Size);
200 p->ListCapacity = ListCapacity;
201 }
202
203 return PEC_STATUS_OK;
204#else
205 IDENTIFIER_NOT_USED(ListCapacity);
206 IDENTIFIER_NOT_USED(SGList_Handle_p);
207
208 return PEC_ERROR_NOT_IMPLEMENTED;
209#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
210}
211
212
213/*----------------------------------------------------------------------------
214 * PEC_SGList_Destroy
215 *
216 * This function must be used to destroy a SGList that was previously created
217 * with PEC_SGList_Create. The potentially referred fragments in the list are
218 * not freed by the implementation!
219 *
220 * SGList_Handle (input)
221 * The handle to the SGList as returned by PEC_SGList_Create.
222 *
223 * DMABuf_Release may be called instead of this function.
224 */
225PEC_Status_t
226PEC_SGList_Destroy(
227 DMABuf_Handle_t SGList_Handle)
228{
229#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
230 int dmares;
231
232 dmares = DMAResource_Release(
233 Adapter_DMABuf_Handle2DMAResourceHandle(SGList_Handle));
234
235 if (dmares == 0)
236 return PEC_STATUS_OK;
237
238 return PEC_ERROR_BAD_HANDLE;
239#else
240 IDENTIFIER_NOT_USED(SGList_Handle.p);
241
242 return PEC_ERROR_NOT_IMPLEMENTED;
243#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
244}
245
246
247/*----------------------------------------------------------------------------
248 * PEC_SGList_Write
249 */
250PEC_Status_t
251PEC_SGList_Write(
252 DMABuf_Handle_t SGList_Handle,
253 const unsigned int Index,
254 DMABuf_Handle_t FragmentHandle,
255 const unsigned int FragmentByteCount)
256{
257#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
258 PEC_SGList_t * SGList_p;
259
260 SGList_p = Adapter_Handle2SGListPtr(SGList_Handle);
261 if (SGList_p == NULL)
262 return PEC_ERROR_BAD_HANDLE;
263
264 if (Index >= SGList_p->ListCapacity)
265 return PEC_ERROR_BAD_PARAMETER;
266
267 SGList_p->Entries[Index].Handle = FragmentHandle;
268 SGList_p->Entries[Index].ByteCount = FragmentByteCount;
269
270 return PEC_STATUS_OK;
271#else
272 IDENTIFIER_NOT_USED(SGList_Handle.p);
273 IDENTIFIER_NOT_USED(Index);
274 IDENTIFIER_NOT_USED(FragmentHandle.p);
275 IDENTIFIER_NOT_USED(FragmentByteCount);
276
277 return PEC_ERROR_NOT_IMPLEMENTED;
278#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
279}
280
281
282/*----------------------------------------------------------------------------
283 * PEC_SGList_Read
284 */
285PEC_Status_t
286PEC_SGList_Read(
287 DMABuf_Handle_t SGList_Handle,
288 const unsigned int Index,
289 DMABuf_Handle_t * const FragmentHandle_p,
290 unsigned int * const FragmentSizeInBytes_p,
291 uint8_t ** const FragmentPtr_p)
292{
293#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
294 PEC_SGList_t * SGList_p;
295
296 // initialize the output parameters
297 {
298 if (FragmentHandle_p)
299 *FragmentHandle_p = DMABuf_NULLHandle;
300
301 if (FragmentSizeInBytes_p)
302 *FragmentSizeInBytes_p = 0;
303
304 if (FragmentPtr_p)
305 *FragmentPtr_p = NULL;
306 }
307
308 SGList_p = Adapter_Handle2SGListPtr(SGList_Handle);
309 if (SGList_p == NULL)
310 return PEC_ERROR_BAD_HANDLE;
311
312 if (Index >= SGList_p->ListCapacity)
313 return PEC_ERROR_BAD_PARAMETER;
314
315 // fill in the output parameters
316 {
317 if (FragmentHandle_p)
318 *FragmentHandle_p = SGList_p->Entries[Index].Handle;
319
320 if (FragmentSizeInBytes_p)
321 *FragmentSizeInBytes_p = SGList_p->Entries[Index].ByteCount;
322
323 if (FragmentPtr_p)
324 {
325 // retrieve the host address from the DMA resource record
326 DMAResource_Handle_t DMAHandle;
327 DMAResource_Record_t * Rec_p;
328
329 DMAHandle = Adapter_DMABuf_Handle2DMAResourceHandle(
330 SGList_p->Entries[Index].Handle);
331 Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
332 if (Rec_p)
333 {
334 // it is a valid handle
335 *FragmentPtr_p = Adapter_DMAResource_HostAddr(DMAHandle);
336 }
337 }
338 }
339
340 return PEC_STATUS_OK;
341#else
342 IDENTIFIER_NOT_USED(SGList_Handle.p);
343 IDENTIFIER_NOT_USED(Index);
344 IDENTIFIER_NOT_USED(FragmentHandle_p);
345 IDENTIFIER_NOT_USED(FragmentSizeInBytes_p);
346 IDENTIFIER_NOT_USED(FragmentPtr_p);
347
348 return PEC_ERROR_NOT_IMPLEMENTED;
349#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
350}
351
352
353/*----------------------------------------------------------------------------
354 * PEC_SGList_GetCapacity
355 */
356PEC_Status_t
357PEC_SGList_GetCapacity(
358 DMABuf_Handle_t SGList_Handle,
359 unsigned int * const ListCapacity_p)
360{
361#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
362 PEC_SGList_t * SGList_p;
363
364 if (ListCapacity_p == NULL)
365 return PEC_ERROR_BAD_PARAMETER;
366
367 // initialize the output parameter
368 *ListCapacity_p = 0;
369
370 SGList_p = Adapter_Handle2SGListPtr(SGList_Handle);
371 if (SGList_p != NULL)
372 *ListCapacity_p = SGList_p->ListCapacity;
373
374 return PEC_STATUS_OK;
375#else
376 IDENTIFIER_NOT_USED(SGList_Handle.p);
377 IDENTIFIER_NOT_USED(ListCapacity_p);
378
379 return PEC_ERROR_NOT_IMPLEMENTED;
380#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
381}
382
383
384
385/* end of file adapter_pec_sglist.c */