1 /****************************************************************************** 2 3 Copyright (c) 2013-2017, 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 = num; 87 qtag->num_active = alloc_size; 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 309