]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ixl/ixl_pf_qmgr.c
zfs: merge openzfs/zfs@03e9caaec
[FreeBSD/FreeBSD.git] / sys / dev / ixl / ixl_pf_qmgr.c
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