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