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