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 #include "ixl.h" 36 #include "ixl_pf.h" 37 #include "ixl_iw.h" 38 #include "ixl_iw_int.h" 39 40 #ifdef IXL_IW 41 42 #define IXL_IW_VEC_BASE(pf) ((pf)->msix - (pf)->iw_msix) 43 #define IXL_IW_VEC_COUNT(pf) ((pf)->iw_msix) 44 #define IXL_IW_VEC_LIMIT(pf) ((pf)->msix) 45 46 extern int ixl_enable_iwarp; 47 48 static struct ixl_iw_state ixl_iw; 49 static int ixl_iw_ref_cnt; 50 51 static void 52 ixl_iw_pf_msix_reset(struct ixl_pf *pf) 53 { 54 struct i40e_hw *hw = &pf->hw; 55 u32 reg; 56 int vec; 57 58 for (vec = IXL_IW_VEC_BASE(pf); vec < IXL_IW_VEC_LIMIT(pf); vec++) { 59 reg = I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK; 60 wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg); 61 } 62 63 return; 64 } 65 66 static void 67 ixl_iw_invoke_op(void *context, int pending) 68 { 69 struct ixl_iw_pf_entry *pf_entry = (struct ixl_iw_pf_entry *)context; 70 struct ixl_iw_pf info; 71 bool initialize; 72 int err; 73 74 INIT_DEBUGOUT("begin"); 75 76 mtx_lock(&ixl_iw.mtx); 77 if ((pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) && 78 (pf_entry->state.iw_current == IXL_IW_PF_STATE_OFF)) 79 initialize = true; 80 else if ((pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_OFF) && 81 (pf_entry->state.iw_current == IXL_IW_PF_STATE_ON)) 82 initialize = false; 83 else { 84 /* nothing to be done, so finish here */ 85 mtx_unlock(&ixl_iw.mtx); 86 return; 87 } 88 info = pf_entry->pf_info; 89 mtx_unlock(&ixl_iw.mtx); 90 91 if (initialize) { 92 err = ixl_iw.ops->init(&info); 93 if (err) 94 device_printf(pf_entry->pf->dev, 95 "%s: failed to initialize iwarp (err %d)\n", 96 __func__, err); 97 else 98 pf_entry->state.iw_current = IXL_IW_PF_STATE_ON; 99 } else { 100 err = ixl_iw.ops->stop(&info); 101 if (err) 102 device_printf(pf_entry->pf->dev, 103 "%s: failed to stop iwarp (err %d)\n", 104 __func__, err); 105 else { 106 ixl_iw_pf_msix_reset(pf_entry->pf); 107 pf_entry->state.iw_current = IXL_IW_PF_STATE_OFF; 108 } 109 } 110 return; 111 } 112 113 static void 114 ixl_iw_uninit(void) 115 { 116 INIT_DEBUGOUT("begin"); 117 118 mtx_destroy(&ixl_iw.mtx); 119 120 return; 121 } 122 123 static void 124 ixl_iw_init(void) 125 { 126 INIT_DEBUGOUT("begin"); 127 128 LIST_INIT(&ixl_iw.pfs); 129 mtx_init(&ixl_iw.mtx, "ixl_iw_pfs", NULL, MTX_DEF); 130 ixl_iw.registered = false; 131 132 return; 133 } 134 135 /****************************************************************************** 136 * if_ixl internal API 137 *****************************************************************************/ 138 139 int 140 ixl_iw_pf_init(struct ixl_pf *pf) 141 { 142 struct ixl_iw_pf_entry *pf_entry; 143 struct ixl_iw_pf *pf_info; 144 int err = 0; 145 146 INIT_DEBUGOUT("begin"); 147 148 mtx_lock(&ixl_iw.mtx); 149 150 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node) 151 if (pf_entry->pf == pf) 152 break; 153 if (pf_entry == NULL) { 154 /* attempt to initialize PF not yet attached - sth is wrong */ 155 device_printf(pf->dev, "%s: PF not found\n", __func__); 156 err = ENOENT; 157 goto out; 158 } 159 160 pf_info = &pf_entry->pf_info; 161 162 pf_info->handle = (void *)pf; 163 164 pf_info->ifp = pf->vsi.ifp; 165 pf_info->dev = pf->dev; 166 pf_info->pci_mem = pf->pci_mem; 167 pf_info->pf_id = pf->hw.pf_id; 168 pf_info->mtu = pf->vsi.ifp->if_mtu; 169 170 pf_info->iw_msix.count = IXL_IW_VEC_COUNT(pf); 171 pf_info->iw_msix.base = IXL_IW_VEC_BASE(pf); 172 173 for (int i = 0; i < IXL_IW_MAX_USER_PRIORITY; i++) 174 pf_info->qs_handle[i] = le16_to_cpu(pf->vsi.info.qs_handle[0]); 175 176 pf_entry->state.pf = IXL_IW_PF_STATE_ON; 177 if (ixl_iw.registered) { 178 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_ON; 179 taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task); 180 } 181 182 out: 183 mtx_unlock(&ixl_iw.mtx); 184 185 return (err); 186 } 187 188 void 189 ixl_iw_pf_stop(struct ixl_pf *pf) 190 { 191 struct ixl_iw_pf_entry *pf_entry; 192 193 INIT_DEBUGOUT("begin"); 194 195 mtx_lock(&ixl_iw.mtx); 196 197 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node) 198 if (pf_entry->pf == pf) 199 break; 200 if (pf_entry == NULL) { 201 /* attempt to stop PF which has not been attached - sth is wrong */ 202 device_printf(pf->dev, "%s: PF not found\n", __func__); 203 goto out; 204 } 205 206 pf_entry->state.pf = IXL_IW_PF_STATE_OFF; 207 if (pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) { 208 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF; 209 if (ixl_iw.registered) 210 taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task); 211 } 212 213 out: 214 mtx_unlock(&ixl_iw.mtx); 215 216 return; 217 } 218 219 int 220 ixl_iw_pf_attach(struct ixl_pf *pf) 221 { 222 struct ixl_iw_pf_entry *pf_entry; 223 int err = 0; 224 225 INIT_DEBUGOUT("begin"); 226 227 if (ixl_iw_ref_cnt == 0) 228 ixl_iw_init(); 229 230 mtx_lock(&ixl_iw.mtx); 231 232 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node) 233 if (pf_entry->pf == pf) { 234 device_printf(pf->dev, "%s: PF already exists\n", 235 __func__); 236 err = EEXIST; 237 goto out; 238 } 239 240 pf_entry = malloc(sizeof(struct ixl_iw_pf_entry), 241 M_IXL, M_NOWAIT | M_ZERO); 242 if (pf_entry == NULL) { 243 device_printf(pf->dev, 244 "%s: failed to allocate memory to attach new PF\n", 245 __func__); 246 err = ENOMEM; 247 goto out; 248 } 249 pf_entry->pf = pf; 250 pf_entry->state.pf = IXL_IW_PF_STATE_OFF; 251 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF; 252 pf_entry->state.iw_current = IXL_IW_PF_STATE_OFF; 253 254 LIST_INSERT_HEAD(&ixl_iw.pfs, pf_entry, node); 255 ixl_iw_ref_cnt++; 256 257 TASK_INIT(&pf_entry->iw_task, 0, ixl_iw_invoke_op, pf_entry); 258 out: 259 mtx_unlock(&ixl_iw.mtx); 260 261 return (err); 262 } 263 264 int 265 ixl_iw_pf_detach(struct ixl_pf *pf) 266 { 267 struct ixl_iw_pf_entry *pf_entry; 268 int err = 0; 269 270 INIT_DEBUGOUT("begin"); 271 272 mtx_lock(&ixl_iw.mtx); 273 274 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node) 275 if (pf_entry->pf == pf) 276 break; 277 if (pf_entry == NULL) { 278 /* attempt to stop PF which has not been attached - sth is wrong */ 279 device_printf(pf->dev, "%s: PF not found\n", __func__); 280 err = ENOENT; 281 goto out; 282 } 283 284 if (pf_entry->state.pf != IXL_IW_PF_STATE_OFF) { 285 /* attempt to detach PF which has not yet been stopped - sth is wrong */ 286 device_printf(pf->dev, "%s: failed - PF is still active\n", 287 __func__); 288 err = EBUSY; 289 goto out; 290 } 291 LIST_REMOVE(pf_entry, node); 292 free(pf_entry, M_IXL); 293 ixl_iw_ref_cnt--; 294 295 out: 296 mtx_unlock(&ixl_iw.mtx); 297 298 if (ixl_iw_ref_cnt == 0) 299 ixl_iw_uninit(); 300 301 return (err); 302 } 303 304 305 /****************************************************************************** 306 * API exposed to iw_ixl module 307 *****************************************************************************/ 308 309 int 310 ixl_iw_pf_reset(void *pf_handle) 311 { 312 struct ixl_pf *pf = (struct ixl_pf *)pf_handle; 313 314 INIT_DEBUGOUT("begin"); 315 316 IXL_PF_LOCK(pf); 317 ixl_init_locked(pf); 318 IXL_PF_UNLOCK(pf); 319 320 return (0); 321 } 322 323 int 324 ixl_iw_pf_msix_init(void *pf_handle, 325 struct ixl_iw_msix_mapping *msix_info) 326 { 327 struct ixl_pf *pf = (struct ixl_pf *)pf_handle; 328 struct i40e_hw *hw = &pf->hw; 329 u32 reg; 330 int vec, i; 331 332 INIT_DEBUGOUT("begin"); 333 334 if ((msix_info->aeq_vector < IXL_IW_VEC_BASE(pf)) || 335 (msix_info->aeq_vector >= IXL_IW_VEC_LIMIT(pf))) { 336 printf("%s: invalid MSI-X vector (%i) for AEQ\n", 337 __func__, msix_info->aeq_vector); 338 return (EINVAL); 339 } 340 reg = I40E_PFINT_AEQCTL_CAUSE_ENA_MASK | 341 (msix_info->aeq_vector << I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) | 342 (msix_info->itr_indx << I40E_PFINT_AEQCTL_ITR_INDX_SHIFT); 343 wr32(hw, I40E_PFINT_AEQCTL, reg); 344 345 for (vec = IXL_IW_VEC_BASE(pf); vec < IXL_IW_VEC_LIMIT(pf); vec++) { 346 for (i = 0; i < msix_info->ceq_cnt; i++) 347 if (msix_info->ceq_vector[i] == vec) 348 break; 349 if (i == msix_info->ceq_cnt) { 350 /* this vector has no CEQ mapped */ 351 reg = I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK; 352 wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg); 353 } else { 354 reg = (i & I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK) | 355 (I40E_QUEUE_TYPE_PE_CEQ << 356 I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT); 357 wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg); 358 359 reg = I40E_PFINT_CEQCTL_CAUSE_ENA_MASK | 360 (vec << I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) | 361 (msix_info->itr_indx << 362 I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) | 363 (IXL_QUEUE_EOL << 364 I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT); 365 wr32(hw, I40E_PFINT_CEQCTL(i), reg); 366 } 367 } 368 369 return (0); 370 } 371 372 int 373 ixl_iw_register(struct ixl_iw_ops *ops) 374 { 375 struct ixl_iw_pf_entry *pf_entry; 376 int err = 0; 377 int iwarp_cap_on_pfs = 0; 378 379 INIT_DEBUGOUT("begin"); 380 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node) 381 iwarp_cap_on_pfs += pf_entry->pf->hw.func_caps.iwarp; 382 if (!iwarp_cap_on_pfs && ixl_enable_iwarp) { 383 printf("%s: the device is not iwarp-capable, registering dropped\n", 384 __func__); 385 return (ENODEV); 386 } 387 if (ixl_enable_iwarp == 0) { 388 printf("%s: enable_iwarp is off, registering dropped\n", 389 __func__); 390 return (EACCES); 391 } 392 393 if ((ops->init == NULL) || (ops->stop == NULL)) { 394 printf("%s: invalid iwarp driver ops\n", __func__); 395 return (EINVAL); 396 } 397 398 mtx_lock(&ixl_iw.mtx); 399 if (ixl_iw.registered) { 400 printf("%s: iwarp driver already registered\n", __func__); 401 err = (EBUSY); 402 goto out; 403 } 404 ixl_iw.registered = true; 405 mtx_unlock(&ixl_iw.mtx); 406 407 ixl_iw.tq = taskqueue_create("ixl_iw", M_NOWAIT, 408 taskqueue_thread_enqueue, &ixl_iw.tq); 409 if (ixl_iw.tq == NULL) { 410 printf("%s: failed to create queue\n", __func__); 411 ixl_iw.registered = false; 412 return (ENOMEM); 413 } 414 taskqueue_start_threads(&ixl_iw.tq, 1, PI_NET, "ixl iw"); 415 416 ixl_iw.ops = malloc(sizeof(struct ixl_iw_ops), 417 M_IXL, M_NOWAIT | M_ZERO); 418 if (ixl_iw.ops == NULL) { 419 printf("%s: failed to allocate memory\n", __func__); 420 taskqueue_free(ixl_iw.tq); 421 ixl_iw.registered = false; 422 return (ENOMEM); 423 } 424 425 ixl_iw.ops->init = ops->init; 426 ixl_iw.ops->stop = ops->stop; 427 428 mtx_lock(&ixl_iw.mtx); 429 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node) 430 if (pf_entry->state.pf == IXL_IW_PF_STATE_ON) { 431 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_ON; 432 taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task); 433 } 434 out: 435 mtx_unlock(&ixl_iw.mtx); 436 437 return (err); 438 } 439 440 int 441 ixl_iw_unregister(void) 442 { 443 struct ixl_iw_pf_entry *pf_entry; 444 int iwarp_cap_on_pfs = 0; 445 446 INIT_DEBUGOUT("begin"); 447 448 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node) 449 iwarp_cap_on_pfs += pf_entry->pf->hw.func_caps.iwarp; 450 if (!iwarp_cap_on_pfs && ixl_enable_iwarp) { 451 printf("%s: attempt to unregister driver when no iwarp-capable device present\n", 452 __func__); 453 return (ENODEV); 454 } 455 456 if (ixl_enable_iwarp == 0) { 457 printf("%s: attempt to unregister driver when enable_iwarp is off\n", 458 __func__); 459 return (ENODEV); 460 } 461 mtx_lock(&ixl_iw.mtx); 462 463 if (!ixl_iw.registered) { 464 printf("%s: failed - iwarp driver has not been registered\n", 465 __func__); 466 mtx_unlock(&ixl_iw.mtx); 467 return (ENOENT); 468 } 469 470 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node) 471 if (pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) { 472 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF; 473 taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task); 474 } 475 476 ixl_iw.registered = false; 477 478 mtx_unlock(&ixl_iw.mtx); 479 480 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node) 481 taskqueue_drain(ixl_iw.tq, &pf_entry->iw_task); 482 taskqueue_free(ixl_iw.tq); 483 ixl_iw.tq = NULL; 484 free(ixl_iw.ops, M_IXL); 485 ixl_iw.ops = NULL; 486 487 return (0); 488 } 489 490 #endif /* IXL_IW */ 491