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