1/* SPDX-License-Identifier: BSD-3-Clause */
2/*  Copyright (c) 2024, Intel Corporation
3 *  All rights reserved.
4 *
5 *  Redistribution and use in source and binary forms, with or without
6 *  modification, are permitted provided that the following conditions are met:
7 *
8 *   1. Redistributions of source code must retain the above copyright notice,
9 *      this list of conditions and the following disclaimer.
10 *
11 *   2. Redistributions in binary form must reproduce the above copyright
12 *      notice, this list of conditions and the following disclaimer in the
13 *      documentation and/or other materials provided with the distribution.
14 *
15 *   3. Neither the name of the Intel Corporation nor the names of its
16 *      contributors may be used to endorse or promote products derived from
17 *      this software without specific prior written permission.
18 *
19 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 *  POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/**
33 * @file ice_resmgr.c
34 * @brief Resource allocation manager
35 *
36 * Manage device resource allocations for a PF, including assigning queues to
37 * VSIs, or managing interrupt allocations across the PF.
38 *
39 * It can handle contiguous and scattered resource allocations, and upon
40 * assigning them, will fill in the mapping array with a map of
41 * resource IDs to PF-space resource indices.
42 */
43
44#include "ice_resmgr.h"
45
46/**
47 * @var M_ICE_RESMGR
48 * @brief PF resource manager allocation type
49 *
50 * malloc(9) allocation type used by the resource manager code.
51 */
52MALLOC_DEFINE(M_ICE_RESMGR, "ice-resmgr", "Intel(R) 100Gb Network Driver resmgr allocations");
53
54/*
55 * Public resource manager allocation functions
56 */
57
58/**
59 * ice_resmgr_init - Initialize a resource manager structure
60 * @resmgr: structure to track the resource manager state
61 * @num_res: the maximum number of resources it can assign
62 *
63 * Initialize the state of a resource manager structure, allocating space to
64 * assign up to the requested number of resources. Uses bit strings to track
65 * which resources have been assigned. This type of resmgr is intended to be
66 * used for tracking LAN queue assignments between VSIs.
67 */
68int
69ice_resmgr_init(struct ice_resmgr *resmgr, u16 num_res)
70{
71	resmgr->resources = bit_alloc(num_res, M_ICE_RESMGR, M_NOWAIT);
72	if (resmgr->resources == NULL)
73		return (ENOMEM);
74
75	resmgr->num_res = num_res;
76	resmgr->contig_only = false;
77	return (0);
78}
79
80/**
81 * ice_resmgr_init_contig_only - Initialize a resource manager structure
82 * @resmgr: structure to track the resource manager state
83 * @num_res: the maximum number of resources it can assign
84 *
85 * Functions similarly to ice_resmgr_init(), but the resulting resmgr structure
86 * will only allow contiguous allocations. This type of resmgr is intended to
87 * be used with tracking device MSI-X interrupt allocations.
88 */
89int
90ice_resmgr_init_contig_only(struct ice_resmgr *resmgr, u16 num_res)
91{
92	int error;
93
94	error = ice_resmgr_init(resmgr, num_res);
95	if (error)
96		return (error);
97
98	resmgr->contig_only = true;
99	return (0);
100}
101
102/**
103 * ice_resmgr_destroy - Deallocate memory associated with a resource manager
104 * @resmgr: resource manager structure
105 *
106 * De-allocates the bit string associated with this resource manager. It is
107 * expected that this function will not be called until all of the assigned
108 * resources have been released.
109 */
110void
111ice_resmgr_destroy(struct ice_resmgr *resmgr)
112{
113	if (resmgr->resources != NULL) {
114#ifdef INVARIANTS
115		int set;
116
117		bit_count(resmgr->resources, 0, resmgr->num_res, &set);
118		MPASS(set == 0);
119#endif
120
121		free(resmgr->resources, M_ICE_RESMGR);
122		resmgr->resources = NULL;
123	}
124	resmgr->num_res = 0;
125}
126
127/*
128 * Resource allocation functions
129 */
130
131/**
132 * ice_resmgr_assign_contiguous - Assign contiguous mapping of resources
133 * @resmgr: resource manager structure
134 * @idx: memory to store mapping, at least num_res wide
135 * @num_res: the number of resources to assign
136 *
137 * Assign num_res number of contiguous resources into the idx mapping. On
138 * success, idx will be updated to map each index to a PF resource.
139 *
140 * This function guarantees that the resource mapping will be contiguous, and
141 * will fail if that is not possible.
142 */
143int
144ice_resmgr_assign_contiguous(struct ice_resmgr *resmgr, u16 *idx, u16 num_res)
145{
146	int start, i;
147
148	bit_ffc_area(resmgr->resources, resmgr->num_res, num_res, &start);
149	if (start < 0)
150		return (ENOSPC);
151
152	/* Set each bit and update the index array */
153	for (i = 0; i < num_res; i++) {
154		bit_set(resmgr->resources, start + i);
155		idx[i] = start + i;
156	}
157
158	return (0);
159}
160
161/**
162 * ice_resmgr_assign_scattered - Assign possibly scattered resources
163 * @resmgr: the resource manager structure
164 * @idx: memory to store associated resource mapping, at least num_res wide
165 * @num_res: the number of resources to assign
166 *
167 * Assign num_res number of resources into the idx_mapping. On success, idx
168 * will be updated to map each index to a PF-space resource.
169 *
170 * Queues may be allocated non-contiguously, and this function requires that
171 * num_res be less than the ICE_MAX_SCATTERED_QUEUES due to hardware
172 * limitations on scattered queue assignment.
173 */
174int
175ice_resmgr_assign_scattered(struct ice_resmgr *resmgr, u16 *idx, u16 num_res)
176{
177	int index = 0, i;
178
179	/* Scattered allocations won't work if they weren't allowed at resmgr
180	 * creation time.
181	 */
182	if (resmgr->contig_only)
183		return (EPERM);
184
185	/* Hardware can only support a limited total of scattered queues for
186	 * a single VSI
187	 */
188	if (num_res > ICE_MAX_SCATTERED_QUEUES)
189		return (EOPNOTSUPP);
190
191	for (i = 0; i < num_res; i++) {
192		bit_ffc_at(resmgr->resources, index, resmgr->num_res, &index);
193		if (index < 0)
194			goto err_no_space;
195
196		bit_set(resmgr->resources, index);
197		idx[i] = index;
198	}
199	return (0);
200
201err_no_space:
202	/* Release any resources we did assign up to this point. */
203	ice_resmgr_release_map(resmgr, idx, i);
204	return (ENOSPC);
205}
206
207/**
208 * ice_resmgr_release_map - Release previously assigned resource mapping
209 * @resmgr: the resource manager structure
210 * @idx: previously assigned resource mapping
211 * @num_res: number of resources in the mapping
212 *
213 * Clears the assignment of each resource in the provided resource index. Updates
214 * the idx to indicate that each of the virtual indexes have invalid resource
215 * mappings by assigning them to ICE_INVALID_RES_IDX.
216 */
217void
218ice_resmgr_release_map(struct ice_resmgr *resmgr, u16 *idx, u16 num_res)
219{
220	int i;
221
222	for (i = 0; i < num_res; i++) {
223		if (idx[i] < resmgr->num_res)
224			bit_clear(resmgr->resources, idx[i]);
225		idx[i] = ICE_INVALID_RES_IDX;
226	}
227}
228