xref: /freebsd/sys/dev/ixl/ixl_pf_qmgr.c (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
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 /*$FreeBSD$*/
34 
35 
36 #include "ixl_pf_qmgr.h"
37 
38 static int	ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr *qmgr, int num);
39 
40 int
41 ixl_pf_qmgr_init(struct ixl_pf_qmgr *qmgr, u16 num_queues)
42 {
43 	if (num_queues < 1)
44 		return (EINVAL);
45 
46 	qmgr->num_queues = num_queues;
47 	qmgr->qinfo = malloc(num_queues * sizeof(struct ixl_pf_qmgr_qinfo),
48 	    M_IXL, M_ZERO | M_NOWAIT);
49 	if (qmgr->qinfo == NULL)
50 		return ENOMEM;
51 
52 	return (0);
53 }
54 
55 int
56 ixl_pf_qmgr_alloc_contiguous(struct ixl_pf_qmgr *qmgr, u16 num, struct ixl_pf_qtag *qtag)
57 {
58 	int i;
59 	int avail;
60 	int block_start;
61 	u16 alloc_size;
62 
63 	if (qtag == NULL || num < 1)
64 		return (EINVAL);
65 
66 	/* We have to allocate in power-of-two chunks, so get next power of two */
67 	alloc_size = (u16)next_power_of_two(num);
68 
69 	/* Don't try if there aren't enough queues */
70 	avail = ixl_pf_qmgr_get_num_free(qmgr);
71 	if (avail < alloc_size)
72 		return (ENOSPC);
73 
74 	block_start = ixl_pf_qmgr_find_free_contiguous_block(qmgr, alloc_size);
75 	if (block_start < 0)
76 		return (ENOSPC);
77 
78 	/* Mark queues as allocated */
79 	for (i = block_start; i < block_start + alloc_size; i++)
80 		qmgr->qinfo[i].allocated = true;
81 
82 	bzero(qtag, sizeof(*qtag));
83 	qtag->qmgr = qmgr;
84 	qtag->type = IXL_PF_QALLOC_CONTIGUOUS;
85 	qtag->qidx[0] = block_start;
86 	qtag->num_allocated = alloc_size;
87 	qtag->num_active = num;
88 
89 	return (0);
90 }
91 
92 /*
93  * NB: indices is u16 because this is the queue index width used in the Add VSI AQ command
94  */
95 int
96 ixl_pf_qmgr_alloc_scattered(struct ixl_pf_qmgr *qmgr, u16 num, struct ixl_pf_qtag *qtag)
97 {
98 	int i;
99 	int avail, count = 0;
100 	u16 alloc_size;
101 
102 	if (qtag == NULL || num < 1 || num > 16)
103 		return (EINVAL);
104 
105 	/* We have to allocate in power-of-two chunks, so get next power of two */
106 	alloc_size = (u16)next_power_of_two(num);
107 
108 	avail = ixl_pf_qmgr_get_num_free(qmgr);
109 	if (avail < alloc_size)
110 		return (ENOSPC);
111 
112 	bzero(qtag, sizeof(*qtag));
113 	qtag->qmgr = qmgr;
114 	qtag->type = IXL_PF_QALLOC_SCATTERED;
115 	qtag->num_active = num;
116 	qtag->num_allocated = alloc_size;
117 
118 	for (i = 0; i < qmgr->num_queues; i++) {
119 		if (!qmgr->qinfo[i].allocated) {
120 			qtag->qidx[count] = i;
121 			count++;
122 			qmgr->qinfo[i].allocated = true;
123 			if (count == alloc_size)
124 				return (0);
125 		}
126 	}
127 
128 	// Shouldn't get here
129 	return (EDOOFUS);
130 }
131 
132 int
133 ixl_pf_qmgr_release(struct ixl_pf_qmgr *qmgr, struct ixl_pf_qtag *qtag)
134 {
135 	u16 i, qidx;
136 
137 	if (qtag == NULL)
138 		return (EINVAL);
139 
140 	if (qtag->type == IXL_PF_QALLOC_SCATTERED) {
141 		for (i = 0; i < qtag->num_allocated; i++) {
142 			qidx = qtag->qidx[i];
143 			bzero(&qmgr->qinfo[qidx], sizeof(qmgr->qinfo[qidx]));
144 		}
145 	} else {
146 		u16 first_index = qtag->qidx[0];
147 		for (i = first_index; i < first_index + qtag->num_allocated; i++)
148 			bzero(&qmgr->qinfo[i], sizeof(qmgr->qinfo[qidx]));
149 	}
150 
151 	qtag->qmgr = NULL;
152 	return (0);
153 }
154 
155 int
156 ixl_pf_qmgr_get_num_queues(struct ixl_pf_qmgr *qmgr)
157 {
158 	return (qmgr->num_queues);
159 }
160 
161 /*
162  * ERJ: This assumes the info array isn't longer than INT_MAX.
163  * This assumption might cause a y3k bug or something, I'm sure.
164  */
165 int
166 ixl_pf_qmgr_get_num_free(struct ixl_pf_qmgr *qmgr)
167 {
168 	int count = 0;
169 
170 	for (int i = 0; i < qmgr->num_queues; i++) {
171 		if (!qmgr->qinfo[i].allocated)
172 			count++;
173 	}
174 
175 	return (count);
176 }
177 
178 int
179 ixl_pf_qmgr_get_first_free(struct ixl_pf_qmgr *qmgr, u16 start)
180 {
181 	int i;
182 
183 	if (start > qmgr->num_queues - 1)
184 		return (-EINVAL);
185 
186 	for (i = start; i < qmgr->num_queues; i++) {
187 		if (qmgr->qinfo[i].allocated)
188 			continue;
189 		else
190 			return (i);
191 	}
192 
193 	// No free queues
194 	return (-ENOSPC);
195 }
196 
197 void
198 ixl_pf_qmgr_destroy(struct ixl_pf_qmgr *qmgr)
199 {
200 	free(qmgr->qinfo, M_IXL);
201 	qmgr->qinfo = NULL;
202 }
203 
204 void
205 ixl_pf_qmgr_mark_queue_enabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
206 {
207 	MPASS(qtag != NULL);
208 
209 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
210 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
211 	if (tx)
212 		qmgr->qinfo[pf_qidx].tx_enabled = true;
213 	else
214 		qmgr->qinfo[pf_qidx].rx_enabled = true;
215 }
216 
217 void
218 ixl_pf_qmgr_mark_queue_disabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
219 {
220 	MPASS(qtag != NULL);
221 
222 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
223 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
224 	if (tx)
225 		qmgr->qinfo[pf_qidx].tx_enabled = false;
226 	else
227 		qmgr->qinfo[pf_qidx].rx_enabled = false;
228 }
229 
230 void
231 ixl_pf_qmgr_mark_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
232 {
233 	MPASS(qtag != NULL);
234 
235 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
236 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
237 	if (tx)
238 		qmgr->qinfo[pf_qidx].tx_configured = true;
239 	else
240 		qmgr->qinfo[pf_qidx].rx_configured = true;
241 }
242 
243 bool
244 ixl_pf_qmgr_is_queue_enabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
245 {
246 	MPASS(qtag != NULL);
247 
248 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
249 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
250 	if (tx)
251 		return (qmgr->qinfo[pf_qidx].tx_enabled);
252 	else
253 		return (qmgr->qinfo[pf_qidx].rx_enabled);
254 }
255 
256 bool
257 ixl_pf_qmgr_is_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
258 {
259 	MPASS(qtag != NULL);
260 
261 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
262 	u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, vsi_qidx);
263 	if (tx)
264 		return (qmgr->qinfo[pf_qidx].tx_configured);
265 	else
266 		return (qmgr->qinfo[pf_qidx].rx_configured);
267 }
268 
269 void
270 ixl_pf_qmgr_clear_queue_flags(struct ixl_pf_qtag *qtag)
271 {
272 	MPASS(qtag != NULL);
273 
274 	struct ixl_pf_qmgr *qmgr = qtag->qmgr;
275 	for (u16 i = 0; i < qtag->num_allocated; i++) {
276 		u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, i);
277 
278 		qmgr->qinfo[pf_qidx].tx_configured = 0;
279 		qmgr->qinfo[pf_qidx].rx_configured = 0;
280 		qmgr->qinfo[pf_qidx].rx_enabled = 0;
281 		qmgr->qinfo[pf_qidx].tx_enabled = 0;
282 	}
283 }
284 
285 u16
286 ixl_pf_qidx_from_vsi_qidx(struct ixl_pf_qtag *qtag, u16 index)
287 {
288 	MPASS(index < qtag->num_allocated);
289 
290 	if (qtag->type == IXL_PF_QALLOC_CONTIGUOUS)
291 		return qtag->first_qidx + index;
292 	else
293 		return qtag->qidx[index];
294 }
295 
296 /* Static Functions */
297 
298 static int
299 ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr *qmgr, int num)
300 {
301 	int i;
302 	int count = 0;
303 	bool block_started = false;
304 	int possible_start;
305 
306 	for (i = 0; i < qmgr->num_queues; i++) {
307 		if (!qmgr->qinfo[i].allocated) {
308 			if (!block_started) {
309 				block_started = true;
310 				possible_start = i;
311 			}
312 			count++;
313 			if (count == num)
314 				return (possible_start);
315 		} else { /* this queue is already allocated */
316 			block_started = false;
317 			count = 0;
318 		}
319 	}
320 
321 	/* Can't find a contiguous block of the requested size */
322 	return (-1);
323 }
324 
325