1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2018-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 #include "utils/nvbitvector.h"
24 
25 /**
26  * @brief   Returns the size, in bytes, of this bitvector.
27  * @note    due to the compiler trick of storing the last index within a
28  *          structure pointer in the data, the minimum size of an NV_BITEVECTOR
29  *          will be the size of one pointer on a given architecture. If the
30  *          storage size of the underlying data is changed to something less
31  *          than the size of a pointer on a given architecture, then two
32  *          libraries running on different architectures transferring bitvectors
33  *          between them may disagree on the value of the direct sizeof operator
34  *          on a struct of an NV_BITVECTOR derivative. This version of SizeOf
35  *          should be agreeable to all architectures, and should be used instead
36  *          of sizeof to marshall data between libraries running on different
37  *          architectures.
38  */
39 NvU32
bitVectorSizeOf_IMPL(const NV_BITVECTOR * pBitVector,NvU16 bitVectorLast)40 bitVectorSizeOf_IMPL
41 (
42     const NV_BITVECTOR *pBitVector,
43     NvU16 bitVectorLast
44 )
45 {
46     NV_ASSERT_OR_RETURN(NULL != pBitVector, 0);
47 
48     return NV_BITVECTOR_BYTE_SIZE(bitVectorLast);
49 }
50 
51 /**
52  * @brief Clears all flags in pBitVector.
53  */
54 NV_STATUS
bitVectorClrAll_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast)55 bitVectorClrAll_IMPL
56 (
57     NV_BITVECTOR *pBitVector,
58     NvU16 bitVectorLast
59 )
60 {
61     NvLength byteSize = NV_BITVECTOR_BYTE_SIZE(bitVectorLast);
62     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
63 
64     portMemSet(&pBitVector->qword, 0x0, byteSize);
65     return NV_OK;
66 }
67 
68 /**
69  * @brief Clears the flag in pBitVector according to bit index idx
70  */
71 NV_STATUS
bitVectorClr_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,NvU16 idx)72 bitVectorClr_IMPL
73 (
74     NV_BITVECTOR *pBitVector,
75     NvU16 bitVectorLast,
76     NvU16 idx
77 )
78 {
79     NvU64 *qword;
80     NvU32 qwordIdx = NV_BITVECTOR_IDX(idx);
81     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(idx);
82 
83     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
84     NV_ASSERT_OR_RETURN(idx < bitVectorLast, NV_ERR_INVALID_ARGUMENT);
85 
86     qword = (NvU64 *)&pBitVector->qword;
87     qword[qwordIdx] &= ~NVBIT64(qwordOffset);
88     return NV_OK;
89 }
90 
91 /**
92  * @brief Clears all flags within a range in pBitVector
93  */
94 NV_STATUS
bitVectorClrRange_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,NV_RANGE range)95 bitVectorClrRange_IMPL
96 (
97     NV_BITVECTOR *pBitVector,
98     NvU16 bitVectorLast,
99     NV_RANGE range
100 )
101 {
102     NvU64 *qword;
103     NvU16 idx;
104     NV_STATUS status = NV_OK;
105 
106     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
107     NV_ASSERT_OR_RETURN(rangeContains(rangeMake(0, bitVectorLast - 1), range),
108                         NV_ERR_INVALID_ARGUMENT);
109 
110     qword = (NvU64 *)&pBitVector->qword;
111     for (idx = (NvU16)range.lo; idx <= (NvU16)range.hi; ++idx)
112     {
113         if ((0 == NV_BITVECTOR_OFFSET(idx)) &&
114             (rangeContains(range, rangeMake(idx + 63, idx + 63))))
115         {
116             qword[NV_BITVECTOR_IDX(idx)] = 0x0;
117             idx += 63;
118             continue;
119         }
120 
121         status = bitVectorClr_IMPL(pBitVector, bitVectorLast, idx);
122         if (NV_OK != status)
123         {
124             return status;
125         }
126     }
127 
128     return status;
129 }
130 
131 /**
132  * @brief Sets all flags in pBitVector
133  */
134 NV_STATUS
bitVectorSetAll_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast)135 bitVectorSetAll_IMPL
136 (
137     NV_BITVECTOR *pBitVector,
138     NvU16 bitVectorLast
139 )
140 {
141     NvU64 *qword;
142     NvLength byteSize = NV_BITVECTOR_BYTE_SIZE(bitVectorLast);
143     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorLast);
144     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorLast - 1);
145 
146     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
147 
148     qword = (NvU64 *)&pBitVector->qword;
149     portMemSet(qword, NV_U8_MAX, byteSize);
150     qword[arraySize - 1] &= (NV_U64_MAX >> (63 - qwordOffset));
151 
152     return NV_OK;
153 }
154 
155 /**
156  * @brief Sets the flag in pBitVector according to bit index idx
157  */
158 NV_STATUS
bitVectorSet_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,NvU16 idx)159 bitVectorSet_IMPL
160 (
161     NV_BITVECTOR *pBitVector,
162     NvU16 bitVectorLast,
163     NvU16 idx
164 )
165 {
166     NvU64 *qword;
167     NvU32 qwordIdx = NV_BITVECTOR_IDX(idx);
168     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(idx);
169 
170     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
171 
172     qword = (NvU64 *)&pBitVector->qword;
173     qword[qwordIdx] |= NVBIT64(qwordOffset);
174 
175     return NV_OK;
176 }
177 
178 /**
179  * @brief Sets all flags within a range in pBitVector
180  */
181 NV_STATUS
bitVectorSetRange_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,NV_RANGE range)182 bitVectorSetRange_IMPL
183 (
184     NV_BITVECTOR *pBitVector,
185     NvU16 bitVectorLast,
186     NV_RANGE range
187 )
188 {
189     NvU64 *qword;
190     NvU16 idx;
191     NV_STATUS status = NV_OK;
192 
193     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
194     NV_ASSERT_OR_RETURN(rangeContains(rangeMake(0, bitVectorLast - 1), range),
195                         NV_ERR_INVALID_ARGUMENT);
196 
197     qword = (NvU64 *)&pBitVector->qword;
198     for (idx = (NvU16)range.lo; idx <= (NvU16)range.hi; ++idx)
199     {
200         if ((0 == NV_BITVECTOR_OFFSET(idx)) &&
201             (rangeContains(range, rangeMake(idx + 63, idx + 63))))
202         {
203             qword[NV_BITVECTOR_IDX(idx)] = (NV_U64_MAX);
204             idx += 63;
205             continue;
206         }
207 
208         status = bitVectorSet_IMPL(pBitVector, bitVectorLast, idx);
209         if (NV_OK != status)
210         {
211             return status;
212         }
213     }
214 
215     return status;
216 }
217 
218 /**
219  * @brief Toggles the flag in pBitVector according to bit index idx
220  */
221 NV_STATUS
bitVectorInv_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,NvU16 idx)222 bitVectorInv_IMPL
223 (
224     NV_BITVECTOR *pBitVector,
225     NvU16 bitVectorLast,
226     NvU16 idx
227 )
228 {
229     NvU64 *qword;
230     NvU32 qwordIdx = NV_BITVECTOR_IDX(idx);
231     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(idx);
232 
233     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
234 
235     qword = (NvU64 *)&pBitVector->qword;
236     qword[qwordIdx] ^= NVBIT64(qwordOffset);
237 
238     return NV_OK;
239 }
240 
241 /**
242  * @brief Toggles all flags within a range in pBitVector
243  */
244 NV_STATUS
bitVectorInvRange_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,NV_RANGE range)245 bitVectorInvRange_IMPL
246 (
247     NV_BITVECTOR *pBitVector,
248     NvU16 bitVectorLast,
249     NV_RANGE range
250 )
251 {
252     NvU64 *qword;
253     NvU16 idx;
254     NV_STATUS status = NV_OK;
255 
256     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
257     NV_ASSERT_OR_RETURN(rangeContains(rangeMake(0, bitVectorLast - 1), range),
258                         NV_ERR_INVALID_ARGUMENT);
259 
260     qword = (NvU64 *)&pBitVector->qword;
261     for (idx = (NvU16)range.lo; idx <= (NvU16)range.hi; ++idx)
262     {
263         if ((0 == NV_BITVECTOR_OFFSET(idx)) &&
264             (rangeContains(range, rangeMake(idx + 63, idx + 63))))
265         {
266             qword[NV_BITVECTOR_IDX(idx)] = ~qword[NV_BITVECTOR_IDX(idx)];
267             idx += 63;
268             continue;
269         }
270 
271         status = bitVectorInv_IMPL(pBitVector, bitVectorLast, idx);
272         if (NV_OK != status)
273         {
274             return status;
275         }
276     }
277 
278     return status;
279 }
280 
281 /**
282  * @brief Initializes a NV_BITVECTOR with the bit indices contained within
283  *        pIndices set.
284  */
285 NV_STATUS
bitVectorFromArrayU16_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,NvU16 * pIndices,NvU32 indicesSize)286 bitVectorFromArrayU16_IMPL
287 (
288     NV_BITVECTOR *pBitVector,
289     NvU16 bitVectorLast,
290     NvU16 *pIndices,
291     NvU32 indicesSize
292 )
293 {
294     NV_STATUS status = NV_OK;
295     NvU32 i;
296 
297     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
298     NV_ASSERT_OR_RETURN(NULL != pIndices, NV_ERR_INVALID_ARGUMENT);
299     NV_ASSERT_OR_RETURN(0 != indicesSize, NV_ERR_INVALID_ARGUMENT);
300 
301     status = bitVectorClrAll_IMPL(pBitVector, bitVectorLast);
302     if (NV_OK != status)
303     {
304         return status;
305     }
306 
307     for (i = 0; i < indicesSize; ++i)
308     {
309         status = bitVectorSet_IMPL(pBitVector, bitVectorLast, pIndices[i]);
310         if (NV_OK != status)
311         {
312             return status;
313         }
314     }
315 
316     return status;
317 }
318 
319 /**
320  * @brief Checks if all flags in pBitVector are set
321  */
322 NvBool
bitVectorTestAllSet_IMPL(const NV_BITVECTOR * pBitVector,NvU16 bitVectorLast)323 bitVectorTestAllSet_IMPL
324 (
325     const NV_BITVECTOR *pBitVector,
326     NvU16 bitVectorLast
327 )
328 {
329     const NvU64 *qword;
330     NvU32 idx;
331     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorLast);
332     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorLast - 1);
333     NvU64 mask;
334 
335     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_FALSE);
336 
337     qword = (const NvU64 *)&pBitVector->qword;
338     for (idx = 0; idx < arraySize; idx++)
339     {
340         mask = (idx < arraySize - 1) ? NV_U64_MAX :
341                (NV_U64_MAX >> (63 - qwordOffset));
342 
343         if (mask != (qword[idx] & mask))
344         {
345             return NV_FALSE;
346         }
347     }
348 
349     return NV_TRUE;
350 }
351 
352 /**
353  * @brief Checks if all flags in pBitVector are cleared
354  */
355 NvBool
bitVectorTestAllCleared_IMPL(const NV_BITVECTOR * pBitVector,NvU16 bitVectorLast)356 bitVectorTestAllCleared_IMPL
357 (
358     const NV_BITVECTOR *pBitVector,
359     NvU16 bitVectorLast
360 )
361 {
362     const NvU64 *qword;
363     NvU32 idx;
364     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorLast);
365     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorLast - 1);
366     NvU64 mask;
367 
368     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_FALSE);
369 
370     qword = (const NvU64 *)&pBitVector->qword;
371     for (idx = 0; idx < arraySize; idx++)
372     {
373         mask = (idx < arraySize - 1) ? NV_U64_MAX :
374                (NV_U64_MAX >> (63 - qwordOffset));
375 
376         if (0x0 != (qword[idx] & mask))
377         {
378             return NV_FALSE;
379         }
380     }
381 
382     return NV_TRUE;
383 }
384 
385 /**
386  * @brief Checks if two bitVectors are equivalent
387  */
388 NvBool
bitVectorTestEqual_IMPL(const NV_BITVECTOR * pBitVectorA,NvU16 bitVectorALast,const NV_BITVECTOR * pBitVectorB,NvU16 bitVectorBLast)389 bitVectorTestEqual_IMPL
390 (
391     const NV_BITVECTOR *pBitVectorA,
392     NvU16 bitVectorALast,
393     const NV_BITVECTOR *pBitVectorB,
394     NvU16 bitVectorBLast
395 )
396 {
397     const NvU64 *qwordA;
398     const NvU64 *qwordB;
399     NvU32 idx;
400     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorALast);
401     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorALast - 1);
402     NvU64 mask;
403 
404     NV_ASSERT_OR_RETURN(NULL != pBitVectorA, NV_ERR_INVALID_ARGUMENT);
405     NV_ASSERT_OR_RETURN(NULL != pBitVectorB, NV_ERR_INVALID_ARGUMENT);
406     NV_ASSERT_OR_RETURN((bitVectorALast == bitVectorBLast), NV_ERR_INVALID_ARGUMENT);
407 
408     qwordA = (const NvU64 *)&pBitVectorA->qword;
409     qwordB = (const NvU64 *)&pBitVectorB->qword;
410     for (idx = 0; idx < arraySize; idx++)
411     {
412         mask = (idx < arraySize - 1) ? NV_U64_MAX :
413                (NV_U64_MAX >> (63 - qwordOffset));
414 
415         if ((qwordA[idx] & mask) != (qwordB[idx] & mask))
416         {
417             return NV_FALSE;
418         }
419     }
420 
421     return NV_TRUE;
422 }
423 
424 /**
425  * @brief Checks if the set of set flags in bitVectorA is a subset of the set of
426  *        set flags in bitVectorB.
427  */
428 NvBool
bitVectorTestIsSubset_IMPL(const NV_BITVECTOR * pBitVectorA,NvU16 bitVectorALast,const NV_BITVECTOR * pBitVectorB,NvU16 bitVectorBLast)429 bitVectorTestIsSubset_IMPL
430 (
431     const NV_BITVECTOR *pBitVectorA,
432     NvU16 bitVectorALast,
433     const NV_BITVECTOR *pBitVectorB,
434     NvU16 bitVectorBLast
435 )
436 {
437     const NvU64 *qwordA;
438     const NvU64 *qwordB;
439     NvU32 idx;
440     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorALast);
441     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorALast - 1);
442     NvU64 mask;
443 
444     NV_ASSERT_OR_RETURN(NULL != pBitVectorA, NV_ERR_INVALID_ARGUMENT);
445     NV_ASSERT_OR_RETURN(NULL != pBitVectorB, NV_ERR_INVALID_ARGUMENT);
446     NV_ASSERT_OR_RETURN((bitVectorALast == bitVectorBLast), NV_ERR_INVALID_ARGUMENT);
447 
448     qwordA = (const NvU64 *)&pBitVectorA->qword;
449     qwordB = (const NvU64 *)&pBitVectorB->qword;
450     for (idx = 0; idx < arraySize; idx++)
451     {
452         mask = (idx < arraySize - 1) ? NV_U64_MAX :
453                (NV_U64_MAX >> (63 - qwordOffset));
454 
455         if (((qwordA[idx] & mask) & (qwordB[idx] & mask)) != (qwordA[idx] & mask))
456         {
457             return NV_FALSE;
458         }
459     }
460 
461     return NV_TRUE;
462 }
463 
464 /**
465  * @brief Checks if the flag according to bit index idx in pBitVector is set
466  */
467 NvBool
bitVectorTest_IMPL(const NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,NvU16 idx)468 bitVectorTest_IMPL
469 (
470     const NV_BITVECTOR *pBitVector,
471     NvU16 bitVectorLast,
472     NvU16 idx
473 )
474 {
475     const NvU64 *qword;
476     NvU32 qwordIdx = NV_BITVECTOR_IDX(idx);
477     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(idx);
478 
479     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_FALSE);
480     NV_ASSERT_OR_RETURN(idx < bitVectorLast, NV_FALSE);
481 
482     qword = (const NvU64 *)&pBitVector->qword;
483     return !!(qword[qwordIdx] & NVBIT64(qwordOffset));
484 }
485 
486 /**
487  * @brief Computes the intersection of flags in pBitVectorA and pBitVectorB, and
488  *        stores the result in pBitVectorDst
489  *
490  * @param[out] pBitVectorDst Destination
491  * @param[in]  pBitVectorA   First operand
492  * @param[in]  pBitVectorB   Second operand
493  *
494  * @note it is valid for the same bitVector to be both destination and operand
495  *       for this operation
496  */
497 NV_STATUS
bitVectorAnd_IMPL(NV_BITVECTOR * pBitVectorDst,NvU16 bitVectorDstLast,const NV_BITVECTOR * pBitVectorA,NvU16 bitVectorALast,const NV_BITVECTOR * pBitVectorB,NvU16 bitVectorBLast)498 bitVectorAnd_IMPL
499 (
500     NV_BITVECTOR *pBitVectorDst,
501     NvU16 bitVectorDstLast,
502     const NV_BITVECTOR *pBitVectorA,
503     NvU16 bitVectorALast,
504     const NV_BITVECTOR *pBitVectorB,
505     NvU16 bitVectorBLast
506 )
507 {
508     NvU64 *qwordDst;
509     const NvU64 *qwordA;
510     const NvU64 *qwordB;
511     NvU32 idx;
512     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorDstLast);
513     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorDstLast - 1);
514     NvU64 mask;
515 
516     NV_ASSERT_OR_RETURN(NULL != pBitVectorDst, NV_ERR_INVALID_ARGUMENT);
517     NV_ASSERT_OR_RETURN(NULL != pBitVectorA, NV_ERR_INVALID_ARGUMENT);
518     NV_ASSERT_OR_RETURN(NULL != pBitVectorB, NV_ERR_INVALID_ARGUMENT);
519     NV_ASSERT_OR_RETURN(((bitVectorDstLast == bitVectorALast) && (bitVectorALast ==
520                         bitVectorBLast)), NV_ERR_INVALID_ARGUMENT);
521 
522     qwordDst = (NvU64 *)&pBitVectorDst->qword;
523     qwordA   = (const NvU64 *)&pBitVectorA->qword;
524     qwordB   = (const NvU64 *)&pBitVectorB->qword;
525     for (idx = 0; idx < arraySize; idx++)
526     {
527         mask = (idx < arraySize - 1) ? NV_U64_MAX :
528                (NV_U64_MAX >> (63 - qwordOffset));
529 
530         qwordDst[idx] = (qwordA[idx] & qwordB[idx]) & mask;
531     }
532 
533     return NV_OK;
534 }
535 
536 /**
537  * @brief Computes the union of flags in pBitVectorA and pBitVectorB, and stores
538  *        the result in pBitVectorDst
539  *
540  * @param[out] pBitVectorDst Destination
541  * @param[in]  pBitVectorA   First operand
542  * @param[in]  pBitVectorB   Second operand
543  *
544  * @note it is valid for the same bitVector to be both destination and operand
545  *       for this operation
546  */
547 NV_STATUS
bitVectorOr_IMPL(NV_BITVECTOR * pBitVectorDst,NvU16 bitVectorDstLast,const NV_BITVECTOR * pBitVectorA,NvU16 bitVectorALast,const NV_BITVECTOR * pBitVectorB,NvU16 bitVectorBLast)548 bitVectorOr_IMPL
549 (
550     NV_BITVECTOR *pBitVectorDst,
551     NvU16 bitVectorDstLast,
552     const NV_BITVECTOR *pBitVectorA,
553     NvU16 bitVectorALast,
554     const NV_BITVECTOR *pBitVectorB,
555     NvU16 bitVectorBLast
556 )
557 {
558     NvU64 *qwordDst;
559     const NvU64 *qwordA;
560     const NvU64 *qwordB;
561     NvU32 idx;
562     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorDstLast);
563     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorDstLast - 1);
564     NvU64 mask;
565 
566     NV_ASSERT_OR_RETURN(NULL != pBitVectorDst, NV_ERR_INVALID_ARGUMENT);
567     NV_ASSERT_OR_RETURN(NULL != pBitVectorA, NV_ERR_INVALID_ARGUMENT);
568     NV_ASSERT_OR_RETURN(NULL != pBitVectorB, NV_ERR_INVALID_ARGUMENT);
569     NV_ASSERT_OR_RETURN(((bitVectorDstLast == bitVectorALast) && (bitVectorALast ==
570                         bitVectorBLast)), NV_ERR_INVALID_ARGUMENT);
571 
572     qwordDst = (NvU64 *)&pBitVectorDst->qword;
573     qwordA   = (const NvU64 *)&pBitVectorA->qword;
574     qwordB   = (const NvU64 *)&pBitVectorB->qword;
575     for (idx = 0; idx < arraySize; idx++)
576     {
577         mask = (idx < arraySize - 1) ? NV_U64_MAX :
578                (NV_U64_MAX >> (63 - qwordOffset));
579 
580         qwordDst[idx] = (qwordA[idx] | qwordB[idx]) & mask;
581     }
582 
583     return NV_OK;
584 }
585 
586 /**
587  * @brief Computes the exclusive OR of flags in pBitVectorA and pBitVectorB, and stores
588  *        the result in pBitVectorDst
589  *
590  * @param[out] pBitVectorDst Destination
591  * @param[in]  pBitVectorA   First operand
592  * @param[in]  pBitVectorB   Second operand
593  *
594  * @note it is valid for the same bitVector to be both destination and operand
595  *       for this operation
596  */
597 NV_STATUS
bitVectorXor_IMPL(NV_BITVECTOR * pBitVectorDst,NvU16 bitVectorDstLast,const NV_BITVECTOR * pBitVectorA,NvU16 bitVectorALast,const NV_BITVECTOR * pBitVectorB,NvU16 bitVectorBLast)598 bitVectorXor_IMPL
599 (
600     NV_BITVECTOR *pBitVectorDst,
601     NvU16 bitVectorDstLast,
602     const NV_BITVECTOR *pBitVectorA,
603     NvU16 bitVectorALast,
604     const NV_BITVECTOR *pBitVectorB,
605     NvU16 bitVectorBLast
606 )
607 {
608     NvU64 *qwordDst;
609     const NvU64 *qwordA;
610     const NvU64 *qwordB;
611     NvU32 idx;
612     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorDstLast);
613     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorDstLast - 1);
614     NvU64 mask;
615 
616     NV_ASSERT_OR_RETURN(NULL != pBitVectorDst, NV_ERR_INVALID_ARGUMENT);
617     NV_ASSERT_OR_RETURN(NULL != pBitVectorA, NV_ERR_INVALID_ARGUMENT);
618     NV_ASSERT_OR_RETURN(NULL != pBitVectorB, NV_ERR_INVALID_ARGUMENT);
619     NV_ASSERT_OR_RETURN(((bitVectorDstLast == bitVectorALast) && (bitVectorALast ==
620                         bitVectorBLast)), NV_ERR_INVALID_ARGUMENT);
621 
622     qwordDst = (NvU64 *)&pBitVectorDst->qword;
623     qwordA   = (const NvU64 *)&pBitVectorA->qword;
624     qwordB   = (const NvU64 *)&pBitVectorB->qword;
625     for (idx = 0; idx < arraySize; idx++)
626     {
627         mask = (idx < arraySize - 1) ? NV_U64_MAX :
628                (NV_U64_MAX >> (63 - qwordOffset));
629 
630         qwordDst[idx] = (qwordA[idx] ^ qwordB[idx]) & mask;
631     }
632 
633     return NV_OK;
634 }
635 
636 /**
637  * @brief Causes the set of raised flags in pBitVectorDst to be equal to the
638  *        complement of the set of raised flags in pBitVectorSrc.
639  *
640  * @param[out] pBitVectorDst Destination
641  * @param[in]  pBitVectorSrc Source
642  *
643  * @note it is valid for the same bitVector to be both destination and
644  *       source for this operation
645  */
646 NV_STATUS
bitVectorComplement_IMPL(NV_BITVECTOR * pBitVectorDst,NvU16 bitVectorDstLast,const NV_BITVECTOR * pBitVectorSrc,NvU16 bitVectorSrcLast)647 bitVectorComplement_IMPL
648 (
649     NV_BITVECTOR *pBitVectorDst,
650     NvU16 bitVectorDstLast,
651     const NV_BITVECTOR *pBitVectorSrc,
652     NvU16 bitVectorSrcLast
653 )
654 {
655     NvU64 *qwordDst;
656     const NvU64 *qwordSrc;
657     NvU32 idx;
658     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorDstLast);
659     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorDstLast - 1);
660     NvU64 mask;
661 
662     NV_ASSERT_OR_RETURN(NULL != pBitVectorDst, NV_ERR_INVALID_ARGUMENT);
663     NV_ASSERT_OR_RETURN(NULL != pBitVectorSrc, NV_ERR_INVALID_ARGUMENT);
664     NV_ASSERT_OR_RETURN(((bitVectorDstLast == bitVectorSrcLast)), NV_ERR_INVALID_ARGUMENT);
665 
666     qwordDst = (NvU64 *)&pBitVectorDst->qword;
667     qwordSrc = (const NvU64 *)&pBitVectorSrc->qword;
668     for (idx = 0; idx < arraySize; idx++)
669     {
670         mask = (idx < arraySize - 1) ? NV_U64_MAX :
671                (NV_U64_MAX >> (63 - qwordOffset));
672 
673         qwordDst[idx] = (~qwordSrc[idx]) & mask;
674     }
675 
676     return NV_OK;
677 }
678 
679 /**
680  * @brief Causes the set of raised flags in pBitVectorDst to be equal to the set
681  *        of raised flags in pBitVectorSrc.
682  *
683  * @param[out] pBitVectorDst Destination
684  * @param[in]  pBitVectorSrc Source
685  *
686  * @note it is \b invalid for the same bitVector to be both destination and
687  *       source for this operation
688  */
689 NV_STATUS
bitVectorCopy_IMPL(NV_BITVECTOR * pBitVectorDst,NvU16 bitVectorDstLast,const NV_BITVECTOR * pBitVectorSrc,NvU16 bitVectorSrcLast)690 bitVectorCopy_IMPL
691 (
692     NV_BITVECTOR *pBitVectorDst,
693     NvU16 bitVectorDstLast,
694     const NV_BITVECTOR *pBitVectorSrc,
695     NvU16 bitVectorSrcLast
696 )
697 {
698     NvLength byteSizeDst = NV_BITVECTOR_BYTE_SIZE(bitVectorDstLast);
699     NvLength byteSizeSrc = NV_BITVECTOR_BYTE_SIZE(bitVectorSrcLast);
700 
701     NV_ASSERT_OR_RETURN(NULL != pBitVectorDst, NV_ERR_INVALID_ARGUMENT);
702     NV_ASSERT_OR_RETURN(NULL != pBitVectorSrc, NV_ERR_INVALID_ARGUMENT);
703     NV_ASSERT_OR_RETURN(bitVectorDstLast == bitVectorSrcLast, NV_ERR_INVALID_ARGUMENT);
704     NV_ASSERT_OR_RETURN(pBitVectorDst != pBitVectorSrc, NV_WARN_NOTHING_TO_DO);
705 
706     portMemCopy(&pBitVectorDst->qword, byteSizeDst, &pBitVectorSrc->qword, byteSizeSrc);
707     return NV_OK;
708 }
709 
710 /**
711  * @brief Returns the bit index of the first set flag in pBitVector.
712  *
713  * @note in the absence of set flags in pBitVector, the index of the first
714  *       invalid flag is returned.
715  */
716 NvU32
bitVectorCountTrailingZeros_IMPL(const NV_BITVECTOR * pBitVector,NvU16 bitVectorLast)717 bitVectorCountTrailingZeros_IMPL
718 (
719     const NV_BITVECTOR *pBitVector,
720     NvU16 bitVectorLast
721 )
722 {
723     const NvU64 *qword;
724     NvU32 idx;
725     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorLast);
726     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorLast - 1);
727     NvU64 mask;
728 
729     NV_ASSERT_OR_RETURN(NULL != pBitVector, 0);
730 
731     qword = (const NvU64 *)&pBitVector->qword;
732     for (idx = 0; idx < arraySize; idx++)
733     {
734         mask = (idx < arraySize - 1) ? NV_U64_MAX :
735                (NV_U64_MAX >> (63 - qwordOffset));
736 
737         if (0x0 != (qword[idx] & mask))
738         {
739             return ((idx * (sizeof(NvU64) * 8)) +
740                     portUtilCountTrailingZeros64(qword[idx] & mask));
741         }
742     }
743 
744     return bitVectorLast;
745 }
746 
747 /**
748  * @brief Returns the bit index of the last set flag in pBitVector.
749  *
750  * @note in the absence of set flags in pBitVector, the index of the first
751  *       invalid flag is returned.
752  */
753 NvU32
bitVectorCountLeadingZeros_IMPL(const NV_BITVECTOR * pBitVector,NvU16 bitVectorLast)754 bitVectorCountLeadingZeros_IMPL
755 (
756     const NV_BITVECTOR *pBitVector,
757     NvU16 bitVectorLast
758 )
759 {
760     const NvU64 *qword;
761     NvU32 idx;
762     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorLast);
763     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorLast - 1);
764     NvU32 qwordUnused = 63 - qwordOffset;
765     NvU64 mask;
766 
767     NV_ASSERT_OR_RETURN(NULL != pBitVector, 0);
768 
769     qword = (const NvU64 *)&pBitVector->qword;
770     for (idx = (arraySize - 1); idx != (NvU32)-1; idx--)
771     {
772         mask = (idx < arraySize - 1) ? NV_U64_MAX :
773                (NV_U64_MAX >> (63 - qwordOffset));
774 
775         if (0x0 != qword[idx])
776         {
777             //
778             // We're counting from the MSB, and we have to subtract the unused
779             // portion of the bitvector from the output
780             //
781             return (((arraySize - idx - 1) * (sizeof(NvU64) * 8)) +
782                     portUtilCountLeadingZeros64(qword[idx] & mask)) -
783                     qwordUnused;
784         }
785     }
786 
787     return bitVectorLast;
788 }
789 
790 /**
791  * @brief Returns the number of set bits in the bitvector.
792  */
793 NvU32
bitVectorCountSetBits_IMPL(const NV_BITVECTOR * pBitVector,NvU16 bitVectorLast)794 bitVectorCountSetBits_IMPL
795 (
796     const NV_BITVECTOR *pBitVector,
797     NvU16 bitVectorLast
798 )
799 {
800     const NvU64 *qword;
801     NvU32 idx;
802     NvU32 arraySize = NV_BITVECTOR_ARRAY_SIZE(bitVectorLast);
803     NvU32 qwordOffset = NV_BITVECTOR_OFFSET(bitVectorLast - 1);
804     NvU64 mask;
805     NvU32 count;
806 
807     NV_ASSERT_OR_RETURN(NULL != pBitVector, 0);
808 
809     count = 0;
810     qword = (const NvU64 *)&pBitVector->qword;
811     for (idx = 0; idx < arraySize; idx++)
812     {
813         mask = (idx < arraySize - 1) ? NV_U64_MAX :
814                (NV_U64_MAX >> (63 - qwordOffset));
815         count += nvPopCount64(qword[idx] & mask);
816     }
817 
818     return count;
819 }
820 
821 /**
822  * @brief Exports the bitVector data to an NvU64 raw bitmask array.
823  */
824 NV_STATUS
bitVectorToRaw_IMPL(const NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,void * pRawMask,NvU32 rawMaskSize)825 bitVectorToRaw_IMPL
826 (
827     const NV_BITVECTOR *pBitVector,
828     NvU16 bitVectorLast,
829     void *pRawMask,
830     NvU32 rawMaskSize
831 )
832 {
833     const NvLength byteSize = NV_BITVECTOR_BYTE_SIZE(bitVectorLast);
834 
835     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
836     NV_ASSERT_OR_RETURN(NULL != pRawMask, NV_ERR_INVALID_ARGUMENT);
837     NV_ASSERT_OR_RETURN(rawMaskSize >= byteSize, NV_ERR_BUFFER_TOO_SMALL);
838 
839     portMemCopy(pRawMask, byteSize, &pBitVector->qword, byteSize);
840     return NV_OK;
841 }
842 
843 /**
844  * @brief Imports the bitVector data from an Nvu64 raw bitmask array.
845  */
846 NV_STATUS
bitVectorFromRaw_IMPL(NV_BITVECTOR * pBitVector,NvU16 bitVectorLast,const void * pRawMask,NvU32 rawMaskSize)847 bitVectorFromRaw_IMPL
848 (
849     NV_BITVECTOR *pBitVector,
850     NvU16 bitVectorLast,
851     const void *pRawMask,
852     NvU32 rawMaskSize
853 )
854 {
855     const NvLength byteSize = NV_BITVECTOR_BYTE_SIZE(bitVectorLast);
856 
857     NV_ASSERT_OR_RETURN(NULL != pBitVector, NV_ERR_INVALID_ARGUMENT);
858     NV_ASSERT_OR_RETURN(NULL != pRawMask, NV_ERR_INVALID_ARGUMENT);
859     NV_ASSERT_OR_RETURN(rawMaskSize >= byteSize, NV_ERR_BUFFER_TOO_SMALL);
860 
861     portMemCopy(&pBitVector->qword, byteSize, pRawMask, byteSize);
862     return NV_OK;
863 }
864 
865