xref: /freebsd/sys/dev/ixl/ixl_pf_qmgr.c (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
1 /******************************************************************************
2 
3   Copyright (c) 2013-2018, Intel Corporation
4   All rights reserved.
5 
6   Redistribution and use in source and binary forms, with or without
7   modification, are permitted provided that the following conditions are met:
8 
9    1. Redistributions of source code must retain the above copyright notice,
10       this list of conditions and the following disclaimer.
11 
12    2. Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in the
14       documentation and/or other materials provided with the distribution.
15 
16    3. Neither the name of the Intel Corporation nor the names of its
17       contributors may be used to endorse or promote products derived from
18       this software without specific prior written permission.
19 
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   POSSIBILITY OF SUCH DAMAGE.
31 
32 ******************************************************************************/
33 
34 
35 #include "ixl_pf_qmgr.h"
36 
37 static int	ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr *qmgr, int num);
38 
39 int
40 ixl_pf_qmgr_init(struct ixl_pf_qmgr *qmgr, u16 num_queues)
41 {
42 	if (num_queues < 1)
43 		return (EINVAL);
44 
45 	qmgr->num_queues = num_queues;
46 	qmgr->qinfo = malloc(num_queues * sizeof(struct ixl_pf_qmgr_qinfo),
47 	    M_IXL, M_ZERO | M_NOWAIT);
48 	if (qmgr->qinfo == NULL)
49 		return ENOMEM;
50 
51 	return (0);
52 }
53 
54 int
55 ixl_pf_qmgr_alloc_contiguous(struct ixl_pf_qmgr *qmgr, u16 num, struct ixl_pf_qtag *qtag)
56 {
57 	int i;
58 	int avail;
59 	int block_start;
60 	u16 alloc_size;
61 
62 	if (qtag == NULL || num < 1)
63 		return (EINVAL);
64 
65 	/* We have to allocate in power-of-two chunks, so get next power of two */
66 	alloc_size = (u16)next_power_of_two(num);
67 
68 	/* Don't try if there aren't enough queues */
69 	avail = ixl_pf_qmgr_get_num_free(qmgr);
70 	if (avail < alloc_size)
71 		return (ENOSPC);
72 
73 	block_start = ixl_pf_qmgr_find_free_contiguous_block(qmgr, alloc_size);
74 	if (block_start < 0)
75 		return (ENOSPC);
76 
77 	/* Mark queues as allocated */
78 	for (i = block_start; i < block_start + alloc_size; i++)
79 		qmgr->qinfo[i].allocated = true;
80 
81 	bzero(qtag, sizeof(*qtag));
82 	qtag->qmgr = qmgr;
83 	qtag->type = IXL_PF_QALLOC_CONTIGUOUS;
84 	qtag->qidx[0] = block_start;
85 	qtag->num_allocated = alloc_size;
86 	qtag->num_active = num;
87 
88 	return (0);
89 }
90 
91 /*
92  * NB: indices is u16 because this is the queue index width used in the Add VSI AQ command
93  */
94 int
95 ixl_pf_qmgr_alloc_scattered(struct ixl_pf_qmgr *qmgr, u16 num, struct ixl_pf_qtag *qtag)
96 {
97 	int i;
98 	int avail, count = 0;
99 	u16 alloc_size;
100 
101 	if (qtag == NULL || num < 1 || num > 16)
102 		return (EINVAL);
103 
104 	/* We have to allocate in power-of-two chunks, so get next power of two */
105 	alloc_size = (u16)next_power_of_two(num);
106 
107 	avail = ixl_pf_qmgr_get_num_free(qmgr);
108 	if (avail < alloc_size)
109 		return (ENOSPC);
110 
111 	bzero(qtag, sizeof(*qtag));
112 	qtag->qmgr = qmgr;
113 	qtag->type = IXL_PF_QALLOC_SCATTERED;
114 	qtag->num_active = num;
115 	qtag->num_allocated = alloc_size;
116 
117 	for (i = 0; i < qmgr->num_queues; i++) {
118 		if (!qmgr->qinfo[i].allocated) {
119 			qtag->qidx[count] = i;
120 			count++;
121 			qmgr->qinfo[i].allocated = true;
122 			if (count == alloc_size)
123 				return (0);
124 		}
125 	}
126 
127 	// Shouldn't get here
128 	return (EDOOFUS);
129 }
130 
131 int
132 ixl_pf_qmgr_release(struct ixl_pf_qmgr *qmgr, struct ixl_pf_qtag *qtag)
133 {
134 	u16 i, qidx;
135 
136 	if (qtag == NULL)
137 		return (EINVAL);
138 
139 	if (qtag->type == IXL_PF_QALLOC_SCATTERED) {
140 		for (i = 0; i < qtag->num_allocated; i++) {
141 			qidx = qtag->qidx[i];
142 			bzero(&qmgr->qinfo[qidx], sizeof(qmgr->qinfo[qidx]));
143 		}
144 	} else {
145 		u16 first_index = qtag->qidx[0];
146 		for (i = first_index; i < first_index + qtag->num_allocated; i++)
147 			bzero(&qmgr->qinfo[i], sizeof(qmgr->qinfo[qidx]));
148 	}
149 
150 	qtag->qmgr = NULL;
151 	return (0);
152 }
153 
154 int
155 ixl_pf_qmgr_get_num_queues(struct ixl_pf_qmgr *qmgr)
156 {
157 	return (qmgr->num_queues);
158 }
159 
160 /*
161  * ERJ: This assumes the info array isn't longer than INT_MAX.
162  * This assumption might cause a y3k bug or something, I'm sure.
163  */
164 int
165 ixl_pf_qmgr_get_num_free(struct ixl_pf_qmgr *qmgr)
166 {
167 	int count = 0;
168 
169 	for (int i = 0; i < qmgr->num_queues; i++) {
170 		if (!qmgr->qinfo[i].allocated)
171 			count++;
172 	}
173 
174 	return (count);
175 }
176 
177 int
178 ixl_pf_qmgr_get_first_free(struct ixl_pf_qmgr *qmgr, u16 start)
179 {
180 	int i;
181 
182 	if (start > qmgr->num_queues - 1)
183 		return (-EINVAL);
184 
185 	for (i = start; i < qmgr->num_queues; i++) {
186 		if (qmgr->qinfo[i].allocated)
187 			continue;
188 		else
189 			return (i);
190 	}
191 
192 	// No free queues
193 	return (-ENOSPC);
194 }
195 
196 void
197 ixl_pf_qmgr_destroy(struct ixl_pf_qmgr *qmgr)
198 {
199 	free(qmgr->qinfo, M_IXL);
200 	qmgr->qinfo = NULL;
201 }
202 
203 void
204 ixl_pf_qmgr_mark_queue_enabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
205 {
206 	MPASS(qtag != NULL);
207 
208 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
209 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
210 	if (tx)
211 		qmgr->qinfo[pf_qidx].tx_enabled = true;
212 	else
213 		qmgr->qinfo[pf_qidx].rx_enabled = true;
214 }
215 
216 void
217 ixl_pf_qmgr_mark_queue_disabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
218 {
219 	MPASS(qtag != NULL);
220 
221 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
222 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
223 	if (tx)
224 		qmgr->qinfo[pf_qidx].tx_enabled = false;
225 	else
226 		qmgr->qinfo[pf_qidx].rx_enabled = false;
227 }
228 
229 void
230 ixl_pf_qmgr_mark_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
231 {
232 	MPASS(qtag != NULL);
233 
234 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
235 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
236 	if (tx)
237 		qmgr->qinfo[pf_qidx].tx_configured = true;
238 	else
239 		qmgr->qinfo[pf_qidx].rx_configured = true;
240 }
241 
242 bool
243 ixl_pf_qmgr_is_queue_enabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
244 {
245 	MPASS(qtag != NULL);
246 
247 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
248 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
249 	if (tx)
250 		return (qmgr->qinfo[pf_qidx].tx_enabled);
251 	else
252 		return (qmgr->qinfo[pf_qidx].rx_enabled);
253 }
254 
255 bool
256 ixl_pf_qmgr_is_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
257 {
258 	MPASS(qtag != NULL);
259 
260 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
261 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
262 	if (tx)
263 		return (qmgr->qinfo[pf_qidx].tx_configured);
264 	else
265 		return (qmgr->qinfo[pf_qidx].rx_configured);
266 }
267 
268 void
269 ixl_pf_qmgr_clear_queue_flags(struct ixl_pf_qtag *qtag)
270 {
271 	MPASS(qtag != NULL);
272 
273 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
274 	for (u16 i = 0; i < qtag->num_allocated; i++) {
275 		u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, i);
276 
277 		qmgr->qinfo[pf_qidx].tx_configured = 0;
278 		qmgr->qinfo[pf_qidx].rx_configured = 0;
279 		qmgr->qinfo[pf_qidx].rx_enabled = 0;
280 		qmgr->qinfo[pf_qidx].tx_enabled = 0;
281 	}
282 }
283 
284 u16
285 ixl_pf_qidx_from_vsi_qidx(struct ixl_pf_qtag *qtag, u16 index)
286 {
287 	MPASS(index < qtag->num_allocated);
288 
289 	if (qtag->type == IXL_PF_QALLOC_CONTIGUOUS)
290 		return qtag->first_qidx + index;
291 	else
292 		return qtag->qidx[index];
293 }
294 
295 /* Static Functions */
296 
297 static int
298 ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr *qmgr, int num)
299 {
300 	int i;
301 	int count = 0;
302 	bool block_started = false;
303 	int possible_start;
304 
305 	for (i = 0; i < qmgr->num_queues; i++) {
306 		if (!qmgr->qinfo[i].allocated) {
307 			if (!block_started) {
308 				block_started = true;
309 				possible_start = i;
310 			}
311 			count++;
312 			if (count == num)
313 				return (possible_start);
314 		} else { /* this queue is already allocated */
315 			block_started = false;
316 			count = 0;
317 		}
318 	}
319 
320 	/* Can't find a contiguous block of the requested size */
321 	return (-1);
322 }
323 
324