1227569Sphilip/*- 2227569Sphilip * Copyright (c) 2010-2011 Solarflare Communications, Inc. 3227569Sphilip * All rights reserved. 4227569Sphilip * 5227569Sphilip * This software was developed in part by Philip Paeps under contract for 6227569Sphilip * Solarflare Communications, Inc. 7227569Sphilip * 8227569Sphilip * Redistribution and use in source and binary forms, with or without 9227569Sphilip * modification, are permitted provided that the following conditions 10227569Sphilip * are met: 11227569Sphilip * 1. Redistributions of source code must retain the above copyright 12227569Sphilip * notice, this list of conditions and the following disclaimer. 13227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright 14227569Sphilip * notice, this list of conditions and the following disclaimer in the 15227569Sphilip * documentation and/or other materials provided with the distribution. 16227569Sphilip * 17227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20227569Sphilip * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27227569Sphilip * SUCH DAMAGE. 28227569Sphilip */ 29227569Sphilip 30227569Sphilip#include <sys/cdefs.h> 31227569Sphilip__FBSDID("$FreeBSD$"); 32227569Sphilip 33227569Sphilip#include <sys/param.h> 34227569Sphilip#include <sys/bus.h> 35227569Sphilip#include <sys/rman.h> 36227569Sphilip#include <sys/smp.h> 37227569Sphilip#include <sys/syslog.h> 38227569Sphilip 39227569Sphilip#include <machine/bus.h> 40227569Sphilip#include <machine/resource.h> 41227569Sphilip 42227569Sphilip#include <dev/pci/pcireg.h> 43227569Sphilip#include <dev/pci/pcivar.h> 44227569Sphilip 45227569Sphilip#include "common/efx.h" 46227569Sphilip 47227569Sphilip#include "sfxge.h" 48227569Sphilip 49227569Sphilipstatic int 50227569Sphilipsfxge_intr_line_filter(void *arg) 51227569Sphilip{ 52227569Sphilip struct sfxge_evq *evq; 53227569Sphilip struct sfxge_softc *sc; 54227569Sphilip efx_nic_t *enp; 55227569Sphilip struct sfxge_intr *intr; 56227569Sphilip boolean_t fatal; 57227569Sphilip uint32_t qmask; 58227569Sphilip 59227569Sphilip evq = (struct sfxge_evq *)arg; 60227569Sphilip sc = evq->sc; 61227569Sphilip enp = sc->enp; 62227569Sphilip intr = &sc->intr; 63227569Sphilip 64227569Sphilip KASSERT(intr != NULL, ("intr == NULL")); 65227569Sphilip KASSERT(intr->type == EFX_INTR_LINE, 66227569Sphilip ("intr->type != EFX_INTR_LINE")); 67227569Sphilip 68228100Sphilip if (intr->state != SFXGE_INTR_STARTED) 69227569Sphilip return FILTER_STRAY; 70227569Sphilip 71227569Sphilip (void)efx_intr_status_line(enp, &fatal, &qmask); 72227569Sphilip 73227569Sphilip if (fatal) { 74227569Sphilip (void) efx_intr_disable(enp); 75227569Sphilip (void) efx_intr_fatal(enp); 76227569Sphilip return FILTER_HANDLED; 77227569Sphilip } 78227569Sphilip 79227569Sphilip if (qmask != 0) { 80227569Sphilip intr->zero_count = 0; 81227569Sphilip return FILTER_SCHEDULE_THREAD; 82227569Sphilip } 83227569Sphilip 84227569Sphilip /* SF bug 15783: If the function is not asserting its IRQ and 85227569Sphilip * we read the queue mask on the cycle before a flag is added 86227569Sphilip * to the mask, this inhibits the function from asserting the 87227569Sphilip * IRQ even though we don't see the flag set. To work around 88227569Sphilip * this, we must re-prime all event queues and report the IRQ 89227569Sphilip * as handled when we see a mask of zero. To allow for shared 90227569Sphilip * IRQs, we don't repeat this if we see a mask of zero twice 91227569Sphilip * or more in a row. 92227569Sphilip */ 93227569Sphilip if (intr->zero_count++ == 0) { 94227569Sphilip if (evq->init_state == SFXGE_EVQ_STARTED) { 95227569Sphilip if (efx_ev_qpending(evq->common, evq->read_ptr)) 96227569Sphilip return FILTER_SCHEDULE_THREAD; 97227569Sphilip efx_ev_qprime(evq->common, evq->read_ptr); 98227569Sphilip return FILTER_HANDLED; 99227569Sphilip } 100227569Sphilip } 101227569Sphilip 102227569Sphilip return FILTER_STRAY; 103227569Sphilip} 104227569Sphilip 105227569Sphilipstatic void 106227569Sphilipsfxge_intr_line(void *arg) 107227569Sphilip{ 108227569Sphilip struct sfxge_evq *evq = arg; 109227569Sphilip struct sfxge_softc *sc = evq->sc; 110227569Sphilip 111227569Sphilip (void)sfxge_ev_qpoll(sc, 0); 112227569Sphilip} 113227569Sphilip 114227569Sphilipstatic void 115227569Sphilipsfxge_intr_message(void *arg) 116227569Sphilip{ 117227569Sphilip struct sfxge_evq *evq; 118227569Sphilip struct sfxge_softc *sc; 119227569Sphilip efx_nic_t *enp; 120227569Sphilip struct sfxge_intr *intr; 121227569Sphilip unsigned int index; 122227569Sphilip boolean_t fatal; 123227569Sphilip 124227569Sphilip evq = (struct sfxge_evq *)arg; 125227569Sphilip sc = evq->sc; 126227569Sphilip enp = sc->enp; 127227569Sphilip intr = &sc->intr; 128227569Sphilip index = evq->index; 129227569Sphilip 130227569Sphilip KASSERT(intr != NULL, ("intr == NULL")); 131227569Sphilip KASSERT(intr->type == EFX_INTR_MESSAGE, 132227569Sphilip ("intr->type != EFX_INTR_MESSAGE")); 133227569Sphilip 134228100Sphilip if (intr->state != SFXGE_INTR_STARTED) 135227569Sphilip return; 136227569Sphilip 137227569Sphilip (void)efx_intr_status_message(enp, index, &fatal); 138227569Sphilip 139227569Sphilip if (fatal) { 140227569Sphilip (void)efx_intr_disable(enp); 141227569Sphilip (void)efx_intr_fatal(enp); 142227569Sphilip return; 143227569Sphilip } 144227569Sphilip 145227569Sphilip (void)sfxge_ev_qpoll(sc, index); 146227569Sphilip} 147227569Sphilip 148227569Sphilipstatic int 149227569Sphilipsfxge_intr_bus_enable(struct sfxge_softc *sc) 150227569Sphilip{ 151227569Sphilip struct sfxge_intr *intr; 152227569Sphilip struct sfxge_intr_hdl *table; 153227569Sphilip driver_filter_t *filter; 154227569Sphilip driver_intr_t *handler; 155227569Sphilip int index; 156227569Sphilip int err; 157227569Sphilip 158227569Sphilip intr = &sc->intr; 159227569Sphilip table = intr->table; 160227569Sphilip 161227569Sphilip switch (intr->type) { 162227569Sphilip case EFX_INTR_MESSAGE: 163227569Sphilip filter = NULL; /* not shared */ 164227569Sphilip handler = sfxge_intr_message; 165227569Sphilip break; 166227569Sphilip 167227569Sphilip case EFX_INTR_LINE: 168227569Sphilip filter = sfxge_intr_line_filter; 169227569Sphilip handler = sfxge_intr_line; 170227569Sphilip break; 171227569Sphilip 172227569Sphilip default: 173227569Sphilip KASSERT(0, ("Invalid interrupt type")); 174227569Sphilip return EINVAL; 175227569Sphilip } 176227569Sphilip 177227569Sphilip /* Try to add the handlers */ 178227569Sphilip for (index = 0; index < intr->n_alloc; index++) { 179227569Sphilip if ((err = bus_setup_intr(sc->dev, table[index].eih_res, 180227569Sphilip INTR_MPSAFE|INTR_TYPE_NET, filter, handler, 181227569Sphilip sc->evq[index], &table[index].eih_tag)) != 0) { 182227569Sphilip goto fail; 183227569Sphilip } 184227569Sphilip#ifdef SFXGE_HAVE_DESCRIBE_INTR 185227569Sphilip if (intr->n_alloc > 1) 186227569Sphilip bus_describe_intr(sc->dev, table[index].eih_res, 187227569Sphilip table[index].eih_tag, "%d", index); 188227569Sphilip#endif 189227569Sphilip bus_bind_intr(sc->dev, table[index].eih_res, index); 190227569Sphilip 191227569Sphilip } 192227569Sphilip 193227569Sphilip return (0); 194227569Sphilip 195227569Sphilipfail: 196227569Sphilip /* Remove remaining handlers */ 197227569Sphilip while (--index >= 0) 198227569Sphilip bus_teardown_intr(sc->dev, table[index].eih_res, 199227569Sphilip table[index].eih_tag); 200227569Sphilip 201227569Sphilip return (err); 202227569Sphilip} 203227569Sphilip 204227569Sphilipstatic void 205227569Sphilipsfxge_intr_bus_disable(struct sfxge_softc *sc) 206227569Sphilip{ 207227569Sphilip struct sfxge_intr *intr; 208227569Sphilip struct sfxge_intr_hdl *table; 209227569Sphilip int i; 210227569Sphilip 211227569Sphilip intr = &sc->intr; 212227569Sphilip table = intr->table; 213227569Sphilip 214227569Sphilip /* Remove all handlers */ 215227569Sphilip for (i = 0; i < intr->n_alloc; i++) 216227569Sphilip bus_teardown_intr(sc->dev, table[i].eih_res, 217227569Sphilip table[i].eih_tag); 218227569Sphilip} 219227569Sphilip 220227569Sphilipstatic int 221227569Sphilipsfxge_intr_alloc(struct sfxge_softc *sc, int count) 222227569Sphilip{ 223227569Sphilip device_t dev; 224227569Sphilip struct sfxge_intr_hdl *table; 225227569Sphilip struct sfxge_intr *intr; 226227569Sphilip struct resource *res; 227227569Sphilip int rid; 228227569Sphilip int error; 229227569Sphilip int i; 230227569Sphilip 231227569Sphilip dev = sc->dev; 232227569Sphilip intr = &sc->intr; 233227569Sphilip error = 0; 234227569Sphilip 235227569Sphilip table = malloc(count * sizeof(struct sfxge_intr_hdl), 236227569Sphilip M_SFXGE, M_WAITOK); 237227569Sphilip intr->table = table; 238227569Sphilip 239227569Sphilip for (i = 0; i < count; i++) { 240227569Sphilip rid = i + 1; 241227569Sphilip res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 242227569Sphilip RF_SHAREABLE | RF_ACTIVE); 243227569Sphilip if (res == NULL) { 244227569Sphilip device_printf(dev, "Couldn't allocate interrupts for " 245227569Sphilip "message %d\n", rid); 246227569Sphilip error = ENOMEM; 247227569Sphilip break; 248227569Sphilip } 249227569Sphilip table[i].eih_rid = rid; 250227569Sphilip table[i].eih_res = res; 251227569Sphilip } 252227569Sphilip 253227569Sphilip if (error) { 254227569Sphilip count = i - 1; 255227569Sphilip for (i = 0; i < count; i++) 256227569Sphilip bus_release_resource(dev, SYS_RES_IRQ, 257227569Sphilip table[i].eih_rid, table[i].eih_res); 258227569Sphilip } 259227569Sphilip 260227569Sphilip return (error); 261227569Sphilip} 262227569Sphilip 263227569Sphilipstatic void 264227569Sphilipsfxge_intr_teardown_msix(struct sfxge_softc *sc) 265227569Sphilip{ 266227569Sphilip device_t dev; 267227569Sphilip struct resource *resp; 268227569Sphilip int rid; 269227569Sphilip 270227569Sphilip dev = sc->dev; 271227569Sphilip resp = sc->intr.msix_res; 272227569Sphilip 273227569Sphilip rid = rman_get_rid(resp); 274227569Sphilip bus_release_resource(dev, SYS_RES_MEMORY, rid, resp); 275227569Sphilip} 276227569Sphilip 277227569Sphilipstatic int 278227569Sphilipsfxge_intr_setup_msix(struct sfxge_softc *sc) 279227569Sphilip{ 280227569Sphilip struct sfxge_intr *intr; 281227569Sphilip struct resource *resp; 282227569Sphilip device_t dev; 283227569Sphilip int count; 284227569Sphilip int rid; 285227569Sphilip 286227569Sphilip dev = sc->dev; 287227569Sphilip intr = &sc->intr; 288227569Sphilip 289227569Sphilip /* Check if MSI-X is available. */ 290227569Sphilip count = pci_msix_count(dev); 291227569Sphilip if (count == 0) 292227569Sphilip return (EINVAL); 293227569Sphilip 294227569Sphilip /* Limit the number of interrupts to the number of CPUs. */ 295227569Sphilip if (count > mp_ncpus) 296227569Sphilip count = mp_ncpus; 297227569Sphilip 298227569Sphilip /* Not very likely these days... */ 299227569Sphilip if (count > EFX_MAXRSS) 300227569Sphilip count = EFX_MAXRSS; 301227569Sphilip 302227569Sphilip rid = PCIR_BAR(4); 303227569Sphilip resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 304227569Sphilip if (resp == NULL) 305227569Sphilip return (ENOMEM); 306227569Sphilip 307227569Sphilip if (pci_alloc_msix(dev, &count) != 0) { 308227569Sphilip bus_release_resource(dev, SYS_RES_MEMORY, rid, resp); 309227569Sphilip return (ENOMEM); 310227569Sphilip } 311227569Sphilip 312227569Sphilip /* Allocate interrupt handlers. */ 313227569Sphilip if (sfxge_intr_alloc(sc, count) != 0) { 314227569Sphilip bus_release_resource(dev, SYS_RES_MEMORY, rid, resp); 315227569Sphilip pci_release_msi(dev); 316227569Sphilip return (ENOMEM); 317227569Sphilip } 318227569Sphilip 319227569Sphilip intr->type = EFX_INTR_MESSAGE; 320227569Sphilip intr->n_alloc = count; 321227569Sphilip intr->msix_res = resp; 322227569Sphilip 323227569Sphilip return (0); 324227569Sphilip} 325227569Sphilip 326227569Sphilipstatic int 327227569Sphilipsfxge_intr_setup_msi(struct sfxge_softc *sc) 328227569Sphilip{ 329227569Sphilip struct sfxge_intr_hdl *table; 330227569Sphilip struct sfxge_intr *intr; 331227569Sphilip device_t dev; 332227569Sphilip int count; 333227569Sphilip int error; 334227569Sphilip 335227569Sphilip dev = sc->dev; 336227569Sphilip intr = &sc->intr; 337227569Sphilip table = intr->table; 338227569Sphilip 339227569Sphilip /* 340227569Sphilip * Check if MSI is available. All messages must be written to 341227569Sphilip * the same address and on x86 this means the IRQs have the 342227569Sphilip * same CPU affinity. So we only ever allocate 1. 343227569Sphilip */ 344227569Sphilip count = pci_msi_count(dev) ? 1 : 0; 345227569Sphilip if (count == 0) 346227569Sphilip return (EINVAL); 347227569Sphilip 348227569Sphilip if ((error = pci_alloc_msi(dev, &count)) != 0) 349227569Sphilip return (ENOMEM); 350227569Sphilip 351227569Sphilip /* Allocate interrupt handler. */ 352227569Sphilip if (sfxge_intr_alloc(sc, count) != 0) { 353227569Sphilip pci_release_msi(dev); 354227569Sphilip return (ENOMEM); 355227569Sphilip } 356227569Sphilip 357227569Sphilip intr->type = EFX_INTR_MESSAGE; 358227569Sphilip intr->n_alloc = count; 359227569Sphilip 360227569Sphilip return (0); 361227569Sphilip} 362227569Sphilip 363227569Sphilipstatic int 364227569Sphilipsfxge_intr_setup_fixed(struct sfxge_softc *sc) 365227569Sphilip{ 366227569Sphilip struct sfxge_intr_hdl *table; 367227569Sphilip struct sfxge_intr *intr; 368227569Sphilip struct resource *res; 369227569Sphilip device_t dev; 370227569Sphilip int rid; 371227569Sphilip 372227569Sphilip dev = sc->dev; 373227569Sphilip intr = &sc->intr; 374227569Sphilip 375227569Sphilip rid = 0; 376227569Sphilip res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 377227569Sphilip RF_SHAREABLE | RF_ACTIVE); 378227569Sphilip if (res == NULL) 379227569Sphilip return (ENOMEM); 380227569Sphilip 381227569Sphilip table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK); 382227569Sphilip table[0].eih_rid = rid; 383227569Sphilip table[0].eih_res = res; 384227569Sphilip 385227569Sphilip intr->type = EFX_INTR_LINE; 386227569Sphilip intr->n_alloc = 1; 387227569Sphilip intr->table = table; 388227569Sphilip 389227569Sphilip return (0); 390227569Sphilip} 391227569Sphilip 392227569Sphilipstatic const char *const __sfxge_err[] = { 393227569Sphilip "", 394227569Sphilip "SRAM out-of-bounds", 395227569Sphilip "Buffer ID out-of-bounds", 396227569Sphilip "Internal memory parity", 397227569Sphilip "Receive buffer ownership", 398227569Sphilip "Transmit buffer ownership", 399227569Sphilip "Receive descriptor ownership", 400227569Sphilip "Transmit descriptor ownership", 401227569Sphilip "Event queue ownership", 402227569Sphilip "Event queue FIFO overflow", 403227569Sphilip "Illegal address", 404227569Sphilip "SRAM parity" 405227569Sphilip}; 406227569Sphilip 407227569Sphilipvoid 408227569Sphilipsfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0, 409227569Sphilip uint32_t dword1) 410227569Sphilip{ 411227569Sphilip struct sfxge_softc *sc = (struct sfxge_softc *)arg; 412227569Sphilip device_t dev = sc->dev; 413227569Sphilip 414227569Sphilip log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)", 415227569Sphilip device_get_name(dev), device_get_unit(dev), 416227569Sphilip __sfxge_err[code], dword1, dword0); 417227569Sphilip} 418227569Sphilip 419227569Sphilipvoid 420227569Sphilipsfxge_intr_stop(struct sfxge_softc *sc) 421227569Sphilip{ 422227569Sphilip struct sfxge_intr *intr; 423227569Sphilip 424227569Sphilip intr = &sc->intr; 425227569Sphilip 426227569Sphilip KASSERT(intr->state == SFXGE_INTR_STARTED, 427227569Sphilip ("Interrupts not started")); 428227569Sphilip 429227569Sphilip intr->state = SFXGE_INTR_INITIALIZED; 430227569Sphilip 431227569Sphilip /* Disable interrupts at the NIC */ 432227569Sphilip efx_intr_disable(sc->enp); 433227569Sphilip 434227569Sphilip /* Disable interrupts at the bus */ 435227569Sphilip sfxge_intr_bus_disable(sc); 436227569Sphilip 437227569Sphilip /* Tear down common code interrupt bits. */ 438227569Sphilip efx_intr_fini(sc->enp); 439227569Sphilip} 440227569Sphilip 441227569Sphilipint 442227569Sphilipsfxge_intr_start(struct sfxge_softc *sc) 443227569Sphilip{ 444227569Sphilip struct sfxge_intr *intr; 445227569Sphilip efsys_mem_t *esmp; 446227569Sphilip int rc; 447227569Sphilip 448227569Sphilip intr = &sc->intr; 449227569Sphilip esmp = &intr->status; 450227569Sphilip 451227569Sphilip KASSERT(intr->state == SFXGE_INTR_INITIALIZED, 452227569Sphilip ("Interrupts not initialized")); 453227569Sphilip 454227569Sphilip /* Zero the memory. */ 455227569Sphilip (void)memset(esmp->esm_base, 0, EFX_INTR_SIZE); 456227569Sphilip 457227569Sphilip /* Initialize common code interrupt bits. */ 458227569Sphilip (void)efx_intr_init(sc->enp, intr->type, esmp); 459227569Sphilip 460227569Sphilip /* Enable interrupts at the bus */ 461227569Sphilip if ((rc = sfxge_intr_bus_enable(sc)) != 0) 462227569Sphilip goto fail; 463227569Sphilip 464228100Sphilip intr->state = SFXGE_INTR_STARTED; 465227569Sphilip 466227569Sphilip /* Enable interrupts at the NIC */ 467227569Sphilip efx_intr_enable(sc->enp); 468227569Sphilip 469227569Sphilip return (0); 470227569Sphilip 471227569Sphilipfail: 472227569Sphilip /* Tear down common code interrupt bits. */ 473227569Sphilip efx_intr_fini(sc->enp); 474227569Sphilip 475227569Sphilip intr->state = SFXGE_INTR_INITIALIZED; 476227569Sphilip 477227569Sphilip return (rc); 478227569Sphilip} 479227569Sphilip 480227569Sphilipvoid 481227569Sphilipsfxge_intr_fini(struct sfxge_softc *sc) 482227569Sphilip{ 483227569Sphilip struct sfxge_intr_hdl *table; 484227569Sphilip struct sfxge_intr *intr; 485227569Sphilip efsys_mem_t *esmp; 486227569Sphilip device_t dev; 487227569Sphilip int i; 488227569Sphilip 489227569Sphilip dev = sc->dev; 490227569Sphilip intr = &sc->intr; 491227569Sphilip esmp = &intr->status; 492227569Sphilip table = intr->table; 493227569Sphilip 494227569Sphilip KASSERT(intr->state == SFXGE_INTR_INITIALIZED, 495227569Sphilip ("intr->state != SFXGE_INTR_INITIALIZED")); 496227569Sphilip 497227569Sphilip /* Free DMA memory. */ 498227569Sphilip sfxge_dma_free(esmp); 499227569Sphilip 500227569Sphilip /* Free interrupt handles. */ 501227569Sphilip for (i = 0; i < intr->n_alloc; i++) 502227569Sphilip bus_release_resource(dev, SYS_RES_IRQ, 503227569Sphilip table[i].eih_rid, table[i].eih_res); 504227569Sphilip 505227569Sphilip if (table[0].eih_rid != 0) 506227569Sphilip pci_release_msi(dev); 507227569Sphilip 508227569Sphilip if (intr->msix_res != NULL) 509227569Sphilip sfxge_intr_teardown_msix(sc); 510227569Sphilip 511227569Sphilip /* Free the handle table */ 512227569Sphilip free(table, M_SFXGE); 513227569Sphilip intr->table = NULL; 514227569Sphilip intr->n_alloc = 0; 515227569Sphilip 516227569Sphilip /* Clear the interrupt type */ 517227569Sphilip intr->type = EFX_INTR_INVALID; 518227569Sphilip 519227569Sphilip intr->state = SFXGE_INTR_UNINITIALIZED; 520227569Sphilip} 521227569Sphilip 522227569Sphilipint 523227569Sphilipsfxge_intr_init(struct sfxge_softc *sc) 524227569Sphilip{ 525227569Sphilip device_t dev; 526227569Sphilip struct sfxge_intr *intr; 527227569Sphilip efsys_mem_t *esmp; 528227569Sphilip int rc; 529227569Sphilip 530227569Sphilip dev = sc->dev; 531227569Sphilip intr = &sc->intr; 532227569Sphilip esmp = &intr->status; 533227569Sphilip 534227569Sphilip KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED, 535227569Sphilip ("Interrupts already initialized")); 536227569Sphilip 537227569Sphilip /* Try to setup MSI-X or MSI interrupts if available. */ 538227569Sphilip if ((rc = sfxge_intr_setup_msix(sc)) == 0) 539227569Sphilip device_printf(dev, "Using MSI-X interrupts\n"); 540227569Sphilip else if ((rc = sfxge_intr_setup_msi(sc)) == 0) 541227569Sphilip device_printf(dev, "Using MSI interrupts\n"); 542227569Sphilip else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) { 543227569Sphilip device_printf(dev, "Using fixed interrupts\n"); 544227569Sphilip } else { 545227569Sphilip device_printf(dev, "Couldn't setup interrupts\n"); 546227569Sphilip return (ENOMEM); 547227569Sphilip } 548227569Sphilip 549227569Sphilip /* Set up DMA for interrupts. */ 550227569Sphilip if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0) 551227569Sphilip return (ENOMEM); 552227569Sphilip 553227569Sphilip intr->state = SFXGE_INTR_INITIALIZED; 554227569Sphilip 555227569Sphilip return (0); 556227569Sphilip} 557