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