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