xref: /linux/drivers/infiniband/hw/ionic/ionic_res.h (revision 4f38da1f027ea2c9f01bb71daa7a299c191b6940)
1*f3bdbd42SAbhijit Gangurde /* SPDX-License-Identifier: GPL-2.0 */
2*f3bdbd42SAbhijit Gangurde /* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
3*f3bdbd42SAbhijit Gangurde 
4*f3bdbd42SAbhijit Gangurde #ifndef _IONIC_RES_H_
5*f3bdbd42SAbhijit Gangurde #define _IONIC_RES_H_
6*f3bdbd42SAbhijit Gangurde 
7*f3bdbd42SAbhijit Gangurde #include <linux/kernel.h>
8*f3bdbd42SAbhijit Gangurde #include <linux/idr.h>
9*f3bdbd42SAbhijit Gangurde 
10*f3bdbd42SAbhijit Gangurde /**
11*f3bdbd42SAbhijit Gangurde  * struct ionic_resid_bits - Number allocator based on IDA
12*f3bdbd42SAbhijit Gangurde  *
13*f3bdbd42SAbhijit Gangurde  * @inuse:      IDA handle
14*f3bdbd42SAbhijit Gangurde  * @inuse_size: Highest ID limit for IDA
15*f3bdbd42SAbhijit Gangurde  */
16*f3bdbd42SAbhijit Gangurde struct ionic_resid_bits {
17*f3bdbd42SAbhijit Gangurde 	struct ida inuse;
18*f3bdbd42SAbhijit Gangurde 	unsigned int inuse_size;
19*f3bdbd42SAbhijit Gangurde };
20*f3bdbd42SAbhijit Gangurde 
21*f3bdbd42SAbhijit Gangurde /**
22*f3bdbd42SAbhijit Gangurde  * ionic_resid_init() - Initialize a resid allocator
23*f3bdbd42SAbhijit Gangurde  * @resid:  Uninitialized resid allocator
24*f3bdbd42SAbhijit Gangurde  * @size:   Capacity of the allocator
25*f3bdbd42SAbhijit Gangurde  *
26*f3bdbd42SAbhijit Gangurde  * Return: Zero on success, or negative error number
27*f3bdbd42SAbhijit Gangurde  */
28*f3bdbd42SAbhijit Gangurde static inline void ionic_resid_init(struct ionic_resid_bits *resid,
29*f3bdbd42SAbhijit Gangurde 				    unsigned int size)
30*f3bdbd42SAbhijit Gangurde {
31*f3bdbd42SAbhijit Gangurde 	resid->inuse_size = size;
32*f3bdbd42SAbhijit Gangurde 	ida_init(&resid->inuse);
33*f3bdbd42SAbhijit Gangurde }
34*f3bdbd42SAbhijit Gangurde 
35*f3bdbd42SAbhijit Gangurde /**
36*f3bdbd42SAbhijit Gangurde  * ionic_resid_destroy() - Destroy a resid allocator
37*f3bdbd42SAbhijit Gangurde  * @resid:  Resid allocator
38*f3bdbd42SAbhijit Gangurde  */
39*f3bdbd42SAbhijit Gangurde static inline void ionic_resid_destroy(struct ionic_resid_bits *resid)
40*f3bdbd42SAbhijit Gangurde {
41*f3bdbd42SAbhijit Gangurde 	ida_destroy(&resid->inuse);
42*f3bdbd42SAbhijit Gangurde }
43*f3bdbd42SAbhijit Gangurde 
44*f3bdbd42SAbhijit Gangurde /**
45*f3bdbd42SAbhijit Gangurde  * ionic_resid_get_shared() - Allocate an available shared resource id
46*f3bdbd42SAbhijit Gangurde  * @resid:   Resid allocator
47*f3bdbd42SAbhijit Gangurde  * @min:     Smallest valid resource id
48*f3bdbd42SAbhijit Gangurde  * @size:    One after largest valid resource id
49*f3bdbd42SAbhijit Gangurde  *
50*f3bdbd42SAbhijit Gangurde  * Return: Resource id, or negative error number
51*f3bdbd42SAbhijit Gangurde  */
52*f3bdbd42SAbhijit Gangurde static inline int ionic_resid_get_shared(struct ionic_resid_bits *resid,
53*f3bdbd42SAbhijit Gangurde 					 unsigned int min,
54*f3bdbd42SAbhijit Gangurde 					 unsigned int size)
55*f3bdbd42SAbhijit Gangurde {
56*f3bdbd42SAbhijit Gangurde 	return ida_alloc_range(&resid->inuse, min, size - 1, GFP_KERNEL);
57*f3bdbd42SAbhijit Gangurde }
58*f3bdbd42SAbhijit Gangurde 
59*f3bdbd42SAbhijit Gangurde /**
60*f3bdbd42SAbhijit Gangurde  * ionic_resid_get() - Allocate an available resource id
61*f3bdbd42SAbhijit Gangurde  * @resid: Resid allocator
62*f3bdbd42SAbhijit Gangurde  *
63*f3bdbd42SAbhijit Gangurde  * Return: Resource id, or negative error number
64*f3bdbd42SAbhijit Gangurde  */
65*f3bdbd42SAbhijit Gangurde static inline int ionic_resid_get(struct ionic_resid_bits *resid)
66*f3bdbd42SAbhijit Gangurde {
67*f3bdbd42SAbhijit Gangurde 	return ionic_resid_get_shared(resid, 0, resid->inuse_size);
68*f3bdbd42SAbhijit Gangurde }
69*f3bdbd42SAbhijit Gangurde 
70*f3bdbd42SAbhijit Gangurde /**
71*f3bdbd42SAbhijit Gangurde  * ionic_resid_put() - Free a resource id
72*f3bdbd42SAbhijit Gangurde  * @resid:  Resid allocator
73*f3bdbd42SAbhijit Gangurde  * @id:     Resource id
74*f3bdbd42SAbhijit Gangurde  */
75*f3bdbd42SAbhijit Gangurde static inline void ionic_resid_put(struct ionic_resid_bits *resid, int id)
76*f3bdbd42SAbhijit Gangurde {
77*f3bdbd42SAbhijit Gangurde 	ida_free(&resid->inuse, id);
78*f3bdbd42SAbhijit Gangurde }
79*f3bdbd42SAbhijit Gangurde 
80*f3bdbd42SAbhijit Gangurde /**
81*f3bdbd42SAbhijit Gangurde  * ionic_bitid_to_qid() - Transform a resource bit index into a queue id
82*f3bdbd42SAbhijit Gangurde  * @bitid:           Bit index
83*f3bdbd42SAbhijit Gangurde  * @qgrp_shift:      Log2 number of queues per queue group
84*f3bdbd42SAbhijit Gangurde  * @half_qid_shift:  Log2 of half the total number of queues
85*f3bdbd42SAbhijit Gangurde  *
86*f3bdbd42SAbhijit Gangurde  * Return: Queue id
87*f3bdbd42SAbhijit Gangurde  *
88*f3bdbd42SAbhijit Gangurde  * Udma-constrained queues (QPs and CQs) are associated with their udma by
89*f3bdbd42SAbhijit Gangurde  * queue group. Even queue groups are associated with udma0, and odd queue
90*f3bdbd42SAbhijit Gangurde  * groups with udma1.
91*f3bdbd42SAbhijit Gangurde  *
92*f3bdbd42SAbhijit Gangurde  * For allocating queue ids, we want to arrange the bits into two halves,
93*f3bdbd42SAbhijit Gangurde  * with the even queue groups of udma0 in the lower half of the bitset,
94*f3bdbd42SAbhijit Gangurde  * and the odd queue groups of udma1 in the upper half of the bitset.
95*f3bdbd42SAbhijit Gangurde  * Then, one or two calls of find_next_zero_bit can examine all the bits
96*f3bdbd42SAbhijit Gangurde  * for queues of an entire udma.
97*f3bdbd42SAbhijit Gangurde  *
98*f3bdbd42SAbhijit Gangurde  * For example, assuming eight queue groups with qgrp qids per group:
99*f3bdbd42SAbhijit Gangurde  *
100*f3bdbd42SAbhijit Gangurde  * bitid 0*qgrp..1*qgrp-1 : qid 0*qgrp..1*qgrp-1
101*f3bdbd42SAbhijit Gangurde  * bitid 1*qgrp..2*qgrp-1 : qid 2*qgrp..3*qgrp-1
102*f3bdbd42SAbhijit Gangurde  * bitid 2*qgrp..3*qgrp-1 : qid 4*qgrp..5*qgrp-1
103*f3bdbd42SAbhijit Gangurde  * bitid 3*qgrp..4*qgrp-1 : qid 6*qgrp..7*qgrp-1
104*f3bdbd42SAbhijit Gangurde  * bitid 4*qgrp..5*qgrp-1 : qid 1*qgrp..2*qgrp-1
105*f3bdbd42SAbhijit Gangurde  * bitid 5*qgrp..6*qgrp-1 : qid 3*qgrp..4*qgrp-1
106*f3bdbd42SAbhijit Gangurde  * bitid 6*qgrp..7*qgrp-1 : qid 5*qgrp..6*qgrp-1
107*f3bdbd42SAbhijit Gangurde  * bitid 7*qgrp..8*qgrp-1 : qid 7*qgrp..8*qgrp-1
108*f3bdbd42SAbhijit Gangurde  *
109*f3bdbd42SAbhijit Gangurde  * There are three important ranges of bits in the qid.  There is the udma
110*f3bdbd42SAbhijit Gangurde  * bit "U" at qgrp_shift, which is the least significant bit of the group
111*f3bdbd42SAbhijit Gangurde  * index, and determines which udma a queue is associated with.
112*f3bdbd42SAbhijit Gangurde  * The bits of lesser significance we can call the idx bits "I", which are
113*f3bdbd42SAbhijit Gangurde  * the index of the queue within the group.  The bits of greater significance
114*f3bdbd42SAbhijit Gangurde  * we can call the grp bits "G", which are other bits of the group index that
115*f3bdbd42SAbhijit Gangurde  * do not determine the udma.  Those bits are just rearranged in the bit index
116*f3bdbd42SAbhijit Gangurde  * in the bitset.  A bitid has the udma bit in the most significant place,
117*f3bdbd42SAbhijit Gangurde  * then the grp bits, then the idx bits.
118*f3bdbd42SAbhijit Gangurde  *
119*f3bdbd42SAbhijit Gangurde  * bitid: 00000000000000 U GGG IIIIII
120*f3bdbd42SAbhijit Gangurde  * qid:   00000000000000 GGG U IIIIII
121*f3bdbd42SAbhijit Gangurde  *
122*f3bdbd42SAbhijit Gangurde  * Transforming from bit index to qid, or from qid to bit index, can be
123*f3bdbd42SAbhijit Gangurde  * accomplished by rearranging the bits by masking and shifting.
124*f3bdbd42SAbhijit Gangurde  */
125*f3bdbd42SAbhijit Gangurde static inline u32 ionic_bitid_to_qid(u32 bitid, u8 qgrp_shift,
126*f3bdbd42SAbhijit Gangurde 				     u8 half_qid_shift)
127*f3bdbd42SAbhijit Gangurde {
128*f3bdbd42SAbhijit Gangurde 	u32 udma_bit =
129*f3bdbd42SAbhijit Gangurde 		(bitid & BIT(half_qid_shift)) >> (half_qid_shift - qgrp_shift);
130*f3bdbd42SAbhijit Gangurde 	u32 grp_bits = (bitid & GENMASK(half_qid_shift - 1, qgrp_shift)) << 1;
131*f3bdbd42SAbhijit Gangurde 	u32 idx_bits = bitid & (BIT(qgrp_shift) - 1);
132*f3bdbd42SAbhijit Gangurde 
133*f3bdbd42SAbhijit Gangurde 	return grp_bits | udma_bit | idx_bits;
134*f3bdbd42SAbhijit Gangurde }
135*f3bdbd42SAbhijit Gangurde 
136*f3bdbd42SAbhijit Gangurde /**
137*f3bdbd42SAbhijit Gangurde  * ionic_qid_to_bitid() - Transform a queue id into a resource bit index
138*f3bdbd42SAbhijit Gangurde  * @qid:            queue index
139*f3bdbd42SAbhijit Gangurde  * @qgrp_shift:     Log2 number of queues per queue group
140*f3bdbd42SAbhijit Gangurde  * @half_qid_shift: Log2 of half the total number of queues
141*f3bdbd42SAbhijit Gangurde  *
142*f3bdbd42SAbhijit Gangurde  * Return: Resource bit index
143*f3bdbd42SAbhijit Gangurde  *
144*f3bdbd42SAbhijit Gangurde  * This is the inverse of ionic_bitid_to_qid().
145*f3bdbd42SAbhijit Gangurde  */
146*f3bdbd42SAbhijit Gangurde static inline u32 ionic_qid_to_bitid(u32 qid, u8 qgrp_shift, u8 half_qid_shift)
147*f3bdbd42SAbhijit Gangurde {
148*f3bdbd42SAbhijit Gangurde 	u32 udma_bit = (qid & BIT(qgrp_shift)) << (half_qid_shift - qgrp_shift);
149*f3bdbd42SAbhijit Gangurde 	u32 grp_bits = (qid & GENMASK(half_qid_shift, qgrp_shift + 1)) >> 1;
150*f3bdbd42SAbhijit Gangurde 	u32 idx_bits = qid & (BIT(qgrp_shift) - 1);
151*f3bdbd42SAbhijit Gangurde 
152*f3bdbd42SAbhijit Gangurde 	return udma_bit | grp_bits | idx_bits;
153*f3bdbd42SAbhijit Gangurde }
154*f3bdbd42SAbhijit Gangurde #endif /* _IONIC_RES_H_ */
155