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