]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ixl/ixl_pf_qmgr.c
MFV r336948: 9112 Improve allocation performance on high-end systems
[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 /*$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_WAITOK);
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 u16
270 ixl_pf_qidx_from_vsi_qidx(struct ixl_pf_qtag *qtag, u16 index)
271 {
272         MPASS(index < qtag->num_allocated);
273
274         if (qtag->type == IXL_PF_QALLOC_CONTIGUOUS)
275                 return qtag->qidx[0] + index;
276         else
277                 return qtag->qidx[index];
278 }
279
280 /* Static Functions */
281
282 static int
283 ixl_pf_qmgr_find_free_contiguous_block(struct ixl_pf_qmgr *qmgr, int num)
284 {
285         int i;
286         int count = 0;
287         bool block_started = false;
288         int possible_start;
289
290         for (i = 0; i < qmgr->num_queues; i++) {
291                 if (!qmgr->qinfo[i].allocated) {
292                         if (!block_started) {
293                                 block_started = true;
294                                 possible_start = i;
295                         }
296                         count++;
297                         if (count == num)
298                                 return (possible_start);
299                 } else { /* this queue is already allocated */
300                         block_started = false;
301                         count = 0;
302                 }
303         }
304
305         /* Can't find a contiguous block of the requested size */
306         return (-1);
307 }
308