sfxge_intr.c revision 284555
185152Sbde/*- 285120Smdodd * Copyright (c) 2010-2015 Solarflare Communications Inc. 31590Srgrimes * All rights reserved. 4213099Smarius * 5213075Smarius * This software was developed in part by Philip Paeps under contract for 6213075Smarius * Solarflare Communications, Inc. 7213075Smarius * 8213075Smarius * Redistribution and use in source and binary forms, with or without 9213075Smarius * modification, are permitted provided that the following conditions are met: 1085152Sbde * 1185120Smdodd * 1. Redistributions of source code must retain the above copyright notice, 121590Srgrimes * this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * The views and conclusions contained in the software and documentation are 30 * those of the authors and should not be interpreted as representing official 31 * policies, either expressed or implied, of the FreeBSD Project. 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/sfxge_intr.c 284555 2015-06-18 15:46:39Z arybchik $"); 36 37#include <sys/param.h> 38#include <sys/bus.h> 39#include <sys/rman.h> 40#include <sys/syslog.h> 41 42#include <machine/bus.h> 43#include <machine/resource.h> 44 45#include <dev/pci/pcireg.h> 46#include <dev/pci/pcivar.h> 47 48#include "common/efx.h" 49 50#include "sfxge.h" 51 52static int 53sfxge_intr_line_filter(void *arg) 54{ 55 struct sfxge_evq *evq; 56 struct sfxge_softc *sc; 57 efx_nic_t *enp; 58 struct sfxge_intr *intr; 59 boolean_t fatal; 60 uint32_t qmask; 61 62 evq = (struct sfxge_evq *)arg; 63 sc = evq->sc; 64 enp = sc->enp; 65 intr = &sc->intr; 66 67 KASSERT(intr != NULL, ("intr == NULL")); 68 KASSERT(intr->type == EFX_INTR_LINE, 69 ("intr->type != EFX_INTR_LINE")); 70 71 if (intr->state != SFXGE_INTR_STARTED) 72 return (FILTER_STRAY); 73 74 (void)efx_intr_status_line(enp, &fatal, &qmask); 75 76 if (fatal) { 77 (void) efx_intr_disable(enp); 78 (void) efx_intr_fatal(enp); 79 return (FILTER_HANDLED); 80 } 81 82 if (qmask != 0) { 83 intr->zero_count = 0; 84 return (FILTER_SCHEDULE_THREAD); 85 } 86 87 /* SF bug 15783: If the function is not asserting its IRQ and 88 * we read the queue mask on the cycle before a flag is added 89 * to the mask, this inhibits the function from asserting the 90 * IRQ even though we don't see the flag set. To work around 91 * this, we must re-prime all event queues and report the IRQ 92 * as handled when we see a mask of zero. To allow for shared 93 * IRQs, we don't repeat this if we see a mask of zero twice 94 * or more in a row. 95 */ 96 if (intr->zero_count++ == 0) { 97 if (evq->init_state == SFXGE_EVQ_STARTED) { 98 if (efx_ev_qpending(evq->common, evq->read_ptr)) 99 return (FILTER_SCHEDULE_THREAD); 100 efx_ev_qprime(evq->common, evq->read_ptr); 101 return (FILTER_HANDLED); 102 } 103 } 104 105 return (FILTER_STRAY); 106} 107 108static void 109sfxge_intr_line(void *arg) 110{ 111 struct sfxge_evq *evq = arg; 112 113 (void)sfxge_ev_qpoll(evq); 114} 115 116static void 117sfxge_intr_message(void *arg) 118{ 119 struct sfxge_evq *evq; 120 struct sfxge_softc *sc; 121 efx_nic_t *enp; 122 struct sfxge_intr *intr; 123 unsigned int index; 124 boolean_t fatal; 125 126 evq = (struct sfxge_evq *)arg; 127 sc = evq->sc; 128 enp = sc->enp; 129 intr = &sc->intr; 130 index = evq->index; 131 132 KASSERT(intr != NULL, ("intr == NULL")); 133 KASSERT(intr->type == EFX_INTR_MESSAGE, 134 ("intr->type != EFX_INTR_MESSAGE")); 135 136 if (__predict_false(intr->state != SFXGE_INTR_STARTED)) 137 return; 138 139 (void)efx_intr_status_message(enp, index, &fatal); 140 141 if (fatal) { 142 (void)efx_intr_disable(enp); 143 (void)efx_intr_fatal(enp); 144 return; 145 } 146 147 (void)sfxge_ev_qpoll(evq); 148} 149 150static int 151sfxge_intr_bus_enable(struct sfxge_softc *sc) 152{ 153 struct sfxge_intr *intr; 154 struct sfxge_intr_hdl *table; 155 driver_filter_t *filter; 156 driver_intr_t *handler; 157 int index; 158 int err; 159 160 intr = &sc->intr; 161 table = intr->table; 162 163 switch (intr->type) { 164 case EFX_INTR_MESSAGE: 165 filter = NULL; /* not shared */ 166 handler = sfxge_intr_message; 167 break; 168 169 case EFX_INTR_LINE: 170 filter = sfxge_intr_line_filter; 171 handler = sfxge_intr_line; 172 break; 173 174 default: 175 KASSERT(0, ("Invalid interrupt type")); 176 return (EINVAL); 177 } 178 179 /* Try to add the handlers */ 180 for (index = 0; index < intr->n_alloc; index++) { 181 if ((err = bus_setup_intr(sc->dev, table[index].eih_res, 182 INTR_MPSAFE|INTR_TYPE_NET, filter, handler, 183 sc->evq[index], &table[index].eih_tag)) != 0) { 184 goto fail; 185 } 186#ifdef SFXGE_HAVE_DESCRIBE_INTR 187 if (intr->n_alloc > 1) 188 bus_describe_intr(sc->dev, table[index].eih_res, 189 table[index].eih_tag, "%d", index); 190#endif 191 bus_bind_intr(sc->dev, table[index].eih_res, index); 192 193 } 194 195 return (0); 196 197fail: 198 /* Remove remaining handlers */ 199 while (--index >= 0) 200 bus_teardown_intr(sc->dev, table[index].eih_res, 201 table[index].eih_tag); 202 203 return (err); 204} 205 206static void 207sfxge_intr_bus_disable(struct sfxge_softc *sc) 208{ 209 struct sfxge_intr *intr; 210 struct sfxge_intr_hdl *table; 211 int i; 212 213 intr = &sc->intr; 214 table = intr->table; 215 216 /* Remove all handlers */ 217 for (i = 0; i < intr->n_alloc; i++) 218 bus_teardown_intr(sc->dev, table[i].eih_res, 219 table[i].eih_tag); 220} 221 222static int 223sfxge_intr_alloc(struct sfxge_softc *sc, int count) 224{ 225 device_t dev; 226 struct sfxge_intr_hdl *table; 227 struct sfxge_intr *intr; 228 struct resource *res; 229 int rid; 230 int error; 231 int i; 232 233 dev = sc->dev; 234 intr = &sc->intr; 235 error = 0; 236 237 table = malloc(count * sizeof(struct sfxge_intr_hdl), 238 M_SFXGE, M_WAITOK); 239 intr->table = table; 240 241 for (i = 0; i < count; i++) { 242 rid = i + 1; 243 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 244 RF_SHAREABLE | RF_ACTIVE); 245 if (res == NULL) { 246 device_printf(dev, "Couldn't allocate interrupts for " 247 "message %d\n", rid); 248 error = ENOMEM; 249 break; 250 } 251 table[i].eih_rid = rid; 252 table[i].eih_res = res; 253 } 254 255 if (error != 0) { 256 count = i - 1; 257 for (i = 0; i < count; i++) 258 bus_release_resource(dev, SYS_RES_IRQ, 259 table[i].eih_rid, table[i].eih_res); 260 } 261 262 return (error); 263} 264 265static void 266sfxge_intr_teardown_msix(struct sfxge_softc *sc) 267{ 268 device_t dev; 269 struct resource *resp; 270 int rid; 271 272 dev = sc->dev; 273 resp = sc->intr.msix_res; 274 275 rid = rman_get_rid(resp); 276 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp); 277} 278 279static int 280sfxge_intr_setup_msix(struct sfxge_softc *sc) 281{ 282 struct sfxge_intr *intr; 283 struct resource *resp; 284 device_t dev; 285 int count; 286 int rid; 287 288 dev = sc->dev; 289 intr = &sc->intr; 290 291 /* Check if MSI-X is available. */ 292 count = pci_msix_count(dev); 293 if (count == 0) 294 return (EINVAL); 295 296 /* Do not try to allocate more than already estimated EVQ maximum */ 297 KASSERT(sc->evq_max > 0, ("evq_max is zero")); 298 count = MIN(count, sc->evq_max); 299 300 rid = PCIR_BAR(4); 301 resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 302 if (resp == NULL) 303 return (ENOMEM); 304 305 if (pci_alloc_msix(dev, &count) != 0) { 306 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp); 307 return (ENOMEM); 308 } 309 310 /* Allocate interrupt handlers. */ 311 if (sfxge_intr_alloc(sc, count) != 0) { 312 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp); 313 pci_release_msi(dev); 314 return (ENOMEM); 315 } 316 317 intr->type = EFX_INTR_MESSAGE; 318 intr->n_alloc = count; 319 intr->msix_res = resp; 320 321 return (0); 322} 323 324static int 325sfxge_intr_setup_msi(struct sfxge_softc *sc) 326{ 327 struct sfxge_intr_hdl *table; 328 struct sfxge_intr *intr; 329 device_t dev; 330 int count; 331 int error; 332 333 dev = sc->dev; 334 intr = &sc->intr; 335 table = intr->table; 336 337 /* 338 * Check if MSI is available. All messages must be written to 339 * the same address and on x86 this means the IRQs have the 340 * same CPU affinity. So we only ever allocate 1. 341 */ 342 count = pci_msi_count(dev) ? 1 : 0; 343 if (count == 0) 344 return (EINVAL); 345 346 if ((error = pci_alloc_msi(dev, &count)) != 0) 347 return (ENOMEM); 348 349 /* Allocate interrupt handler. */ 350 if (sfxge_intr_alloc(sc, count) != 0) { 351 pci_release_msi(dev); 352 return (ENOMEM); 353 } 354 355 intr->type = EFX_INTR_MESSAGE; 356 intr->n_alloc = count; 357 358 return (0); 359} 360 361static int 362sfxge_intr_setup_fixed(struct sfxge_softc *sc) 363{ 364 struct sfxge_intr_hdl *table; 365 struct sfxge_intr *intr; 366 struct resource *res; 367 device_t dev; 368 int rid; 369 370 dev = sc->dev; 371 intr = &sc->intr; 372 373 rid = 0; 374 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 375 RF_SHAREABLE | RF_ACTIVE); 376 if (res == NULL) 377 return (ENOMEM); 378 379 table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK); 380 table[0].eih_rid = rid; 381 table[0].eih_res = res; 382 383 intr->type = EFX_INTR_LINE; 384 intr->n_alloc = 1; 385 intr->table = table; 386 387 return (0); 388} 389 390static const char *const __sfxge_err[] = { 391 "", 392 "SRAM out-of-bounds", 393 "Buffer ID out-of-bounds", 394 "Internal memory parity", 395 "Receive buffer ownership", 396 "Transmit buffer ownership", 397 "Receive descriptor ownership", 398 "Transmit descriptor ownership", 399 "Event queue ownership", 400 "Event queue FIFO overflow", 401 "Illegal address", 402 "SRAM parity" 403}; 404 405void 406sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0, 407 uint32_t dword1) 408{ 409 struct sfxge_softc *sc = (struct sfxge_softc *)arg; 410 device_t dev = sc->dev; 411 412 log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)", 413 device_get_name(dev), device_get_unit(dev), 414 __sfxge_err[code], dword1, dword0); 415} 416 417void 418sfxge_intr_stop(struct sfxge_softc *sc) 419{ 420 struct sfxge_intr *intr; 421 422 intr = &sc->intr; 423 424 KASSERT(intr->state == SFXGE_INTR_STARTED, 425 ("Interrupts not started")); 426 427 intr->state = SFXGE_INTR_INITIALIZED; 428 429 /* Disable interrupts at the NIC */ 430 efx_intr_disable(sc->enp); 431 432 /* Disable interrupts at the bus */ 433 sfxge_intr_bus_disable(sc); 434 435 /* Tear down common code interrupt bits. */ 436 efx_intr_fini(sc->enp); 437} 438 439int 440sfxge_intr_start(struct sfxge_softc *sc) 441{ 442 struct sfxge_intr *intr; 443 efsys_mem_t *esmp; 444 int rc; 445 446 intr = &sc->intr; 447 esmp = &intr->status; 448 449 KASSERT(intr->state == SFXGE_INTR_INITIALIZED, 450 ("Interrupts not initialized")); 451 452 /* Zero the memory. */ 453 (void)memset(esmp->esm_base, 0, EFX_INTR_SIZE); 454 455 /* Initialize common code interrupt bits. */ 456 (void)efx_intr_init(sc->enp, intr->type, esmp); 457 458 /* Enable interrupts at the bus */ 459 if ((rc = sfxge_intr_bus_enable(sc)) != 0) 460 goto fail; 461 462 intr->state = SFXGE_INTR_STARTED; 463 464 /* Enable interrupts at the NIC */ 465 efx_intr_enable(sc->enp); 466 467 return (0); 468 469fail: 470 /* Tear down common code interrupt bits. */ 471 efx_intr_fini(sc->enp); 472 473 intr->state = SFXGE_INTR_INITIALIZED; 474 475 return (rc); 476} 477 478void 479sfxge_intr_fini(struct sfxge_softc *sc) 480{ 481 struct sfxge_intr_hdl *table; 482 struct sfxge_intr *intr; 483 efsys_mem_t *esmp; 484 device_t dev; 485 int i; 486 487 dev = sc->dev; 488 intr = &sc->intr; 489 esmp = &intr->status; 490 table = intr->table; 491 492 KASSERT(intr->state == SFXGE_INTR_INITIALIZED, 493 ("intr->state != SFXGE_INTR_INITIALIZED")); 494 495 /* Free DMA memory. */ 496 sfxge_dma_free(esmp); 497 498 /* Free interrupt handles. */ 499 for (i = 0; i < intr->n_alloc; i++) 500 bus_release_resource(dev, SYS_RES_IRQ, 501 table[i].eih_rid, table[i].eih_res); 502 503 if (table[0].eih_rid != 0) 504 pci_release_msi(dev); 505 506 if (intr->msix_res != NULL) 507 sfxge_intr_teardown_msix(sc); 508 509 /* Free the handle table */ 510 free(table, M_SFXGE); 511 intr->table = NULL; 512 intr->n_alloc = 0; 513 514 /* Clear the interrupt type */ 515 intr->type = EFX_INTR_INVALID; 516 517 intr->state = SFXGE_INTR_UNINITIALIZED; 518} 519 520int 521sfxge_intr_init(struct sfxge_softc *sc) 522{ 523 device_t dev; 524 struct sfxge_intr *intr; 525 efsys_mem_t *esmp; 526 int rc; 527 528 dev = sc->dev; 529 intr = &sc->intr; 530 esmp = &intr->status; 531 532 KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED, 533 ("Interrupts already initialized")); 534 535 /* Try to setup MSI-X or MSI interrupts if available. */ 536 if ((rc = sfxge_intr_setup_msix(sc)) == 0) 537 device_printf(dev, "Using MSI-X interrupts\n"); 538 else if ((rc = sfxge_intr_setup_msi(sc)) == 0) 539 device_printf(dev, "Using MSI interrupts\n"); 540 else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) { 541 device_printf(dev, "Using fixed interrupts\n"); 542 } else { 543 device_printf(dev, "Couldn't setup interrupts\n"); 544 return (ENOMEM); 545 } 546 547 /* Set up DMA for interrupts. */ 548 if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0) 549 return (ENOMEM); 550 551 intr->state = SFXGE_INTR_INITIALIZED; 552 553 return (0); 554} 555