cxgb_main.c revision 167514
1167514Skmacy/**************************************************************************
2167514Skmacy
3167514SkmacyCopyright (c) 2007, Chelsio Inc.
4167514SkmacyAll rights reserved.
5167514Skmacy
6167514SkmacyRedistribution and use in source and binary forms, with or without
7167514Skmacymodification, are permitted provided that the following conditions are met:
8167514Skmacy
9167514Skmacy 1. Redistributions of source code must retain the above copyright notice,
10167514Skmacy    this list of conditions and the following disclaimer.
11167514Skmacy
12167514Skmacy 2. Redistributions in binary form must reproduce the above copyright
13167514Skmacy    notice, this list of conditions and the following disclaimer in the
14167514Skmacy    documentation and/or other materials provided with the distribution.
15167514Skmacy
16167514Skmacy 3. Neither the name of the Chelsio Corporation nor the names of its
17167514Skmacy    contributors may be used to endorse or promote products derived from
18167514Skmacy    this software without specific prior written permission.
19167514Skmacy
20167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30167514SkmacyPOSSIBILITY OF SUCH DAMAGE.
31167514Skmacy
32167514Skmacy***************************************************************************/
33167514Skmacy
34167514Skmacy#include <sys/cdefs.h>
35167514Skmacy__FBSDID("$FreeBSD: head/sys/dev/cxgb/cxgb_main.c 167514 2007-03-14 02:37:44Z kmacy $");
36167514Skmacy
37167514Skmacy#include <sys/param.h>
38167514Skmacy#include <sys/systm.h>
39167514Skmacy#include <sys/kernel.h>
40167514Skmacy#include <sys/bus.h>
41167514Skmacy#include <sys/module.h>
42167514Skmacy#include <sys/pciio.h>
43167514Skmacy#include <sys/conf.h>
44167514Skmacy#include <machine/bus.h>
45167514Skmacy#include <machine/resource.h>
46167514Skmacy#include <sys/bus_dma.h>
47167514Skmacy#include <sys/rman.h>
48167514Skmacy#include <sys/ioccom.h>
49167514Skmacy#include <sys/mbuf.h>
50167514Skmacy#include <sys/linker.h>
51167514Skmacy#include <sys/firmware.h>
52167514Skmacy#include <sys/socket.h>
53167514Skmacy#include <sys/sockio.h>
54167514Skmacy#include <sys/smp.h>
55167514Skmacy#include <sys/sysctl.h>
56167514Skmacy#include <sys/queue.h>
57167514Skmacy#include <sys/taskqueue.h>
58167514Skmacy
59167514Skmacy
60167514Skmacy
61167514Skmacy#include <net/bpf.h>
62167514Skmacy#include <net/ethernet.h>
63167514Skmacy#include <net/if.h>
64167514Skmacy#include <net/if_arp.h>
65167514Skmacy#include <net/if_dl.h>
66167514Skmacy#include <net/if_media.h>
67167514Skmacy#include <net/if_types.h>
68167514Skmacy
69167514Skmacy#include <netinet/in_systm.h>
70167514Skmacy#include <netinet/in.h>
71167514Skmacy#include <netinet/if_ether.h>
72167514Skmacy#include <netinet/ip.h>
73167514Skmacy#include <netinet/ip.h>
74167514Skmacy#include <netinet/tcp.h>
75167514Skmacy#include <netinet/udp.h>
76167514Skmacy
77167514Skmacy#include <dev/pci/pcireg.h>
78167514Skmacy#include <dev/pci/pcivar.h>
79167514Skmacy#include <dev/pci/pci_private.h>
80167514Skmacy
81167514Skmacy#include <dev/cxgb/cxgb_osdep.h>
82167514Skmacy#include <dev/cxgb/common/cxgb_common.h>
83167514Skmacy#include <dev/cxgb/cxgb_ioctl.h>
84167514Skmacy#include <dev/cxgb/common/cxgb_regs.h>
85167514Skmacy#include <dev/cxgb/common/cxgb_t3_cpl.h>
86167514Skmacy#include <dev/cxgb/common/cxgb_firmware_exports.h>
87167514Skmacy
88167514Skmacy
89167514Skmacy#ifdef PRIV_SUPPORTED
90167514Skmacy#include <sys/priv.h>
91167514Skmacy#endif
92167514Skmacy
93167514Skmacystatic int cxgb_setup_msix(adapter_t *, int);
94167514Skmacystatic void cxgb_init(void *);
95167514Skmacystatic void cxgb_init_locked(struct port_info *);
96167514Skmacystatic void cxgb_stop(struct port_info *);
97167514Skmacystatic void cxgb_set_rxmode(struct port_info *);
98167514Skmacystatic int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t);
99167514Skmacystatic void cxgb_start(struct ifnet *);
100167514Skmacystatic void cxgb_start_proc(void *, int ncount);
101167514Skmacystatic int cxgb_media_change(struct ifnet *);
102167514Skmacystatic void cxgb_media_status(struct ifnet *, struct ifmediareq *);
103167514Skmacystatic int setup_sge_qsets(adapter_t *);
104167514Skmacystatic void cxgb_async_intr(void *);
105167514Skmacystatic void cxgb_ext_intr_handler(void *, int);
106167514Skmacystatic void cxgb_tick(void *);
107167514Skmacystatic void check_link_status(adapter_t *sc);
108167514Skmacystatic void setup_rss(adapter_t *sc);
109167514Skmacy
110167514Skmacy/* Attachment glue for the PCI controller end of the device.  Each port of
111167514Skmacy * the device is attached separately, as defined later.
112167514Skmacy */
113167514Skmacystatic int cxgb_controller_probe(device_t);
114167514Skmacystatic int cxgb_controller_attach(device_t);
115167514Skmacystatic int cxgb_controller_detach(device_t);
116167514Skmacystatic void cxgb_free(struct adapter *);
117167514Skmacystatic __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
118167514Skmacy    unsigned int end);
119167514Skmacystatic void cxgb_get_regs(adapter_t *sc, struct ifconf_regs *regs, uint8_t *buf);
120167514Skmacystatic int cxgb_get_regs_len(void);
121167514Skmacy
122167514Skmacystatic device_method_t cxgb_controller_methods[] = {
123167514Skmacy	DEVMETHOD(device_probe,		cxgb_controller_probe),
124167514Skmacy	DEVMETHOD(device_attach,	cxgb_controller_attach),
125167514Skmacy	DEVMETHOD(device_detach,	cxgb_controller_detach),
126167514Skmacy
127167514Skmacy	/* bus interface */
128167514Skmacy	DEVMETHOD(bus_print_child,	bus_generic_print_child),
129167514Skmacy	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
130167514Skmacy
131167514Skmacy	{ 0, 0 }
132167514Skmacy};
133167514Skmacy
134167514Skmacystatic driver_t cxgb_controller_driver = {
135167514Skmacy	"cxgbc",
136167514Skmacy	cxgb_controller_methods,
137167514Skmacy	sizeof(struct adapter)
138167514Skmacy};
139167514Skmacy
140167514Skmacystatic devclass_t	cxgb_controller_devclass;
141167514SkmacyDRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgb_controller_devclass, 0, 0);
142167514Skmacy
143167514Skmacy/*
144167514Skmacy * Attachment glue for the ports.  Attachment is done directly to the
145167514Skmacy * controller device.
146167514Skmacy */
147167514Skmacystatic int cxgb_port_probe(device_t);
148167514Skmacystatic int cxgb_port_attach(device_t);
149167514Skmacystatic int cxgb_port_detach(device_t);
150167514Skmacy
151167514Skmacystatic device_method_t cxgb_port_methods[] = {
152167514Skmacy	DEVMETHOD(device_probe,		cxgb_port_probe),
153167514Skmacy	DEVMETHOD(device_attach,	cxgb_port_attach),
154167514Skmacy	DEVMETHOD(device_detach,	cxgb_port_detach),
155167514Skmacy	{ 0, 0 }
156167514Skmacy};
157167514Skmacy
158167514Skmacystatic driver_t cxgb_port_driver = {
159167514Skmacy	"cxgb",
160167514Skmacy	cxgb_port_methods,
161167514Skmacy	0
162167514Skmacy};
163167514Skmacy
164167514Skmacystatic d_ioctl_t cxgb_extension_ioctl;
165167514Skmacy
166167514Skmacystatic devclass_t	cxgb_port_devclass;
167167514SkmacyDRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0);
168167514Skmacy
169167514Skmacy#define SGE_MSIX_COUNT (SGE_QSETS + 1)
170167514Skmacy
171167514Skmacy/*
172167514Skmacy * The driver uses the best interrupt scheme available on a platform in the
173167514Skmacy * order MSI-X, MSI, legacy pin interrupts.  This parameter determines which
174167514Skmacy * of these schemes the driver may consider as follows:
175167514Skmacy *
176167514Skmacy * msi = 2: choose from among all three options
177167514Skmacy * msi = 1 : only consider MSI and pin interrupts
178167514Skmacy * msi = 0: force pin interrupts
179167514Skmacy */
180167514Skmacystatic int msi_allowed = 0;
181167514SkmacyTUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed);
182167514Skmacy
183167514SkmacySYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters");
184167514SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0,
185167514Skmacy    "MSI-X, MSI, INTx selector");
186167514Skmacy
187167514Skmacyenum {
188167514Skmacy	MAX_TXQ_ENTRIES      = 16384,
189167514Skmacy	MAX_CTRL_TXQ_ENTRIES = 1024,
190167514Skmacy	MAX_RSPQ_ENTRIES     = 16384,
191167514Skmacy	MAX_RX_BUFFERS       = 16384,
192167514Skmacy	MAX_RX_JUMBO_BUFFERS = 16384,
193167514Skmacy	MIN_TXQ_ENTRIES      = 4,
194167514Skmacy	MIN_CTRL_TXQ_ENTRIES = 4,
195167514Skmacy	MIN_RSPQ_ENTRIES     = 32,
196167514Skmacy	MIN_FL_ENTRIES       = 32
197167514Skmacy};
198167514Skmacy
199167514Skmacy#define PORT_MASK ((1 << MAX_NPORTS) - 1)
200167514Skmacy
201167514Skmacy/* Table for probing the cards.  The desc field isn't actually used */
202167514Skmacystruct cxgb_ident {
203167514Skmacy	uint16_t	vendor;
204167514Skmacy	uint16_t	device;
205167514Skmacy	int		index;
206167514Skmacy	char		*desc;
207167514Skmacy} cxgb_identifiers[] = {
208167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"},
209167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"},
210167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"},
211167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"},
212167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"},
213167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"},
214167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"},
215167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"},
216167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"},
217167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"},
218167514Skmacy	{0, 0, 0, NULL}
219167514Skmacy};
220167514Skmacy
221167514Skmacystatic struct cxgb_ident *
222167514Skmacycxgb_get_ident(device_t dev)
223167514Skmacy{
224167514Skmacy	struct cxgb_ident *id;
225167514Skmacy
226167514Skmacy	for (id = cxgb_identifiers; id->desc != NULL; id++) {
227167514Skmacy		if ((id->vendor == pci_get_vendor(dev)) &&
228167514Skmacy		    (id->device == pci_get_device(dev))) {
229167514Skmacy			return (id);
230167514Skmacy		}
231167514Skmacy	}
232167514Skmacy	return (NULL);
233167514Skmacy}
234167514Skmacy
235167514Skmacystatic const struct adapter_info *
236167514Skmacycxgb_get_adapter_info(device_t dev)
237167514Skmacy{
238167514Skmacy	struct cxgb_ident *id;
239167514Skmacy	const struct adapter_info *ai;
240167514Skmacy
241167514Skmacy	id = cxgb_get_ident(dev);
242167514Skmacy	if (id == NULL)
243167514Skmacy		return (NULL);
244167514Skmacy
245167514Skmacy	ai = t3_get_adapter_info(id->index);
246167514Skmacy
247167514Skmacy	return (ai);
248167514Skmacy}
249167514Skmacy
250167514Skmacystatic int
251167514Skmacycxgb_controller_probe(device_t dev)
252167514Skmacy{
253167514Skmacy	const struct adapter_info *ai;
254167514Skmacy	char *ports, buf[80];
255167514Skmacy
256167514Skmacy	ai = cxgb_get_adapter_info(dev);
257167514Skmacy	if (ai == NULL)
258167514Skmacy		return (ENXIO);
259167514Skmacy
260167514Skmacy	if (ai->nports == 1)
261167514Skmacy		ports = "port";
262167514Skmacy	else
263167514Skmacy		ports = "ports";
264167514Skmacy
265167514Skmacy	snprintf(buf, sizeof(buf), "%s RNIC, %d %s", ai->desc, ai->nports, ports);
266167514Skmacy	device_set_desc_copy(dev, buf);
267167514Skmacy	return (BUS_PROBE_DEFAULT);
268167514Skmacy}
269167514Skmacy
270167514Skmacystatic int
271167514Skmacycxgb_fw_download(adapter_t *sc, device_t dev)
272167514Skmacy{
273167514Skmacy	char buf[32];
274167514Skmacy#ifdef FIRMWARE_LATEST
275167514Skmacy	const struct firmware *fw;
276167514Skmacy#else
277167514Skmacy	struct firmware *fw;
278167514Skmacy#endif
279167514Skmacy	int status;
280167514Skmacy
281167514Skmacy	snprintf(&buf[0], sizeof(buf), "t3fw%d%d", CHELSIO_FW_MAJOR, CHELSIO_FW_MINOR);
282167514Skmacy
283167514Skmacy	fw = firmware_get(buf);
284167514Skmacy
285167514Skmacy
286167514Skmacy	if (fw == NULL) {
287167514Skmacy		device_printf(dev, "Could not find firmware image %s\n", buf);
288167514Skmacy		return ENOENT;
289167514Skmacy	}
290167514Skmacy
291167514Skmacy	status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize);
292167514Skmacy
293167514Skmacy	firmware_put(fw, FIRMWARE_UNLOAD);
294167514Skmacy
295167514Skmacy	return (status);
296167514Skmacy}
297167514Skmacy
298167514Skmacy
299167514Skmacystatic int
300167514Skmacycxgb_controller_attach(device_t dev)
301167514Skmacy{
302167514Skmacy	driver_intr_t *cxgb_intr = NULL;
303167514Skmacy	device_t child;
304167514Skmacy	const struct adapter_info *ai;
305167514Skmacy	struct adapter *sc;
306167514Skmacy	int i, msi_count = 0, error = 0;
307167514Skmacy	uint32_t vers;
308167514Skmacy
309167514Skmacy	sc = device_get_softc(dev);
310167514Skmacy	sc->dev = dev;
311167514Skmacy
312167514Skmacy	pci_enable_busmaster(dev);
313167514Skmacy
314167514Skmacy	/*
315167514Skmacy	 * Allocate the registers and make them available to the driver.
316167514Skmacy	 * The registers that we care about for NIC mode are in BAR 0
317167514Skmacy	 */
318167514Skmacy	sc->regs_rid = PCIR_BAR(0);
319167514Skmacy	if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
320167514Skmacy	    &sc->regs_rid, RF_ACTIVE)) == NULL) {
321167514Skmacy		device_printf(dev, "Cannot allocate BAR\n");
322167514Skmacy		return (ENXIO);
323167514Skmacy	}
324167514Skmacy
325167514Skmacy	mtx_init(&sc->sge.reg_lock, "SGE reg lock", NULL, MTX_DEF);
326167514Skmacy	mtx_init(&sc->lock, "cxgb controller lock", NULL, MTX_DEF);
327167514Skmacy	mtx_init(&sc->mdio_lock, "cxgb mdio", NULL, MTX_DEF);
328167514Skmacy
329167514Skmacy	sc->bt = rman_get_bustag(sc->regs_res);
330167514Skmacy	sc->bh = rman_get_bushandle(sc->regs_res);
331167514Skmacy	sc->mmio_len = rman_get_size(sc->regs_res);
332167514Skmacy
333167514Skmacy	/* Allocate the BAR for doing MSI-X.  If it succeeds, try to allocate
334167514Skmacy	 * enough messages for the queue sets.  If that fails, try falling
335167514Skmacy	 * back to MSI.  If that fails, then try falling back to the legacy
336167514Skmacy	 * interrupt pin model.
337167514Skmacy	 */
338167514Skmacy#ifdef MSI_SUPPORTED
339167514Skmacy	sc->msix_regs_rid = 0x20;
340167514Skmacy	if ((msi_allowed >= 2) &&
341167514Skmacy	    (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
342167514Skmacy	    &sc->msix_regs_rid, RF_ACTIVE)) != NULL) {
343167514Skmacy
344167514Skmacy		msi_count = SGE_MSIX_COUNT;
345167514Skmacy		if ((pci_alloc_msix(dev, &msi_count) != 0) ||
346167514Skmacy		    (msi_count != SGE_MSIX_COUNT)) {
347167514Skmacy			msi_count = 0;
348167514Skmacy			pci_release_msi(dev);
349167514Skmacy			bus_release_resource(dev, SYS_RES_MEMORY,
350167514Skmacy			    sc->msix_regs_rid, sc->msix_regs_res);
351167514Skmacy			sc->msix_regs_res = NULL;
352167514Skmacy		} else {
353167514Skmacy			sc->flags |= USING_MSIX;
354167514Skmacy			cxgb_intr = t3_intr_msix;
355167514Skmacy		}
356167514Skmacy
357167514Skmacy		printf("allocated %d msix intrs\n", msi_count);
358167514Skmacy	}
359167514Skmacy
360167514Skmacy	if ((msi_allowed >= 1) && (msi_count == 0)) {
361167514Skmacy		msi_count = 1;
362167514Skmacy		if (pci_alloc_msi(dev, &msi_count)) {
363167514Skmacy			device_printf(dev, "alloc msi failed\n");
364167514Skmacy			msi_count = 0;
365167514Skmacy			pci_release_msi(dev);
366167514Skmacy		} else {
367167514Skmacy			sc->flags |= USING_MSI;
368167514Skmacy			sc->irq_rid = 1;
369167514Skmacy			cxgb_intr = t3_intr_msi;
370167514Skmacy		}
371167514Skmacy	}
372167514Skmacy#endif
373167514Skmacy	if (msi_count == 0) {
374167514Skmacy		sc->irq_rid = 0;
375167514Skmacy		cxgb_intr = t3b_intr;
376167514Skmacy	}
377167514Skmacy
378167514Skmacy
379167514Skmacy	/* Create a private taskqueue thread for handling driver events */
380167514Skmacy#ifdef TASKQUEUE_CURRENT
381167514Skmacy	sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT,
382167514Skmacy	    taskqueue_thread_enqueue, &sc->tq);
383167514Skmacy#else
384167514Skmacy	sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT,
385167514Skmacy	    taskqueue_thread_enqueue, &sc->tq);
386167514Skmacy#endif
387167514Skmacy	if (sc->tq == NULL) {
388167514Skmacy		device_printf(dev, "failed to allocate controller task queue\n");
389167514Skmacy		goto out;
390167514Skmacy	}
391167514Skmacy
392167514Skmacy	taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
393167514Skmacy	    device_get_nameunit(dev));
394167514Skmacy	TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc);
395167514Skmacy
396167514Skmacy
397167514Skmacy	/* Create a periodic callout for checking adapter status */
398167514Skmacy	callout_init_mtx(&sc->cxgb_tick_ch, &sc->lock, 0);
399167514Skmacy
400167514Skmacy	ai = cxgb_get_adapter_info(dev);
401167514Skmacy	if (t3_prep_adapter(sc, ai, 1) < 0) {
402167514Skmacy		error = ENODEV;
403167514Skmacy		goto out;
404167514Skmacy	}
405167514Skmacy	if (t3_check_fw_version(sc) != 0) {
406167514Skmacy		/*
407167514Skmacy		 * Warn user that a firmware update will be attempted in init.
408167514Skmacy		 */
409167514Skmacy		device_printf(dev, "firmware needs to be updated to version %d.%d\n",
410167514Skmacy		    CHELSIO_FW_MAJOR, CHELSIO_FW_MINOR);
411167514Skmacy		sc->flags &= ~FW_UPTODATE;
412167514Skmacy	} else {
413167514Skmacy		sc->flags |= FW_UPTODATE;
414167514Skmacy	}
415167514Skmacy
416167514Skmacy	if (t3_init_hw(sc, 0) != 0) {
417167514Skmacy		device_printf(dev, "hw initialization failed\n");
418167514Skmacy		error = ENXIO;
419167514Skmacy		goto out;
420167514Skmacy	}
421167514Skmacy	t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
422167514Skmacy
423167514Skmacy	/*
424167514Skmacy	 * Create a child device for each MAC.  The ethernet attachment
425167514Skmacy	 * will be done in these children.
426167514Skmacy	 */
427167514Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
428167514Skmacy		if ((child = device_add_child(dev, "cxgb", -1)) == NULL) {
429167514Skmacy			device_printf(dev, "failed to add child port\n");
430167514Skmacy			error = EINVAL;
431167514Skmacy			goto out;
432167514Skmacy		}
433167514Skmacy		sc->portdev[i] = child;
434167514Skmacy		sc->port[i].adapter = sc;
435167514Skmacy#ifdef MULTIQ
436167514Skmacy		sc->port[i].nqsets = mp_ncpus;
437167514Skmacy#else
438167514Skmacy		sc->port[i].nqsets = 1;
439167514Skmacy#endif
440167514Skmacy		sc->port[i].first_qset = i;
441167514Skmacy		sc->port[i].port = i;
442167514Skmacy		device_set_softc(child, &sc->port[i]);
443167514Skmacy	}
444167514Skmacy	if ((error = bus_generic_attach(dev)) != 0)
445167514Skmacy		goto out;;
446167514Skmacy
447167514Skmacy	if ((error = setup_sge_qsets(sc)) != 0)
448167514Skmacy		goto out;
449167514Skmacy
450167514Skmacy	setup_rss(sc);
451167514Skmacy
452167514Skmacy	/* If it's MSI or INTx, allocate a single interrupt for everything */
453167514Skmacy	if ((sc->flags & USING_MSIX) == 0) {
454167514Skmacy		if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
455167514Skmacy		   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
456167514Skmacy			device_printf(dev, "Cannot allocate interrupt rid=%d\n", sc->irq_rid);
457167514Skmacy			error = EINVAL;
458167514Skmacy			goto out;
459167514Skmacy		}
460167514Skmacy		device_printf(dev, "allocated irq_res=%p\n", sc->irq_res);
461167514Skmacy
462167514Skmacy		if (bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
463167514Skmacy#ifdef INTR_FILTERS
464167514Skmacy			NULL,
465167514Skmacy#endif
466167514Skmacy			cxgb_intr, sc, &sc->intr_tag)) {
467167514Skmacy			device_printf(dev, "Cannot set up interrupt\n");
468167514Skmacy			error = EINVAL;
469167514Skmacy			goto out;
470167514Skmacy		}
471167514Skmacy	} else {
472167514Skmacy		cxgb_setup_msix(sc, msi_count);
473167514Skmacy	}
474167514Skmacy
475167514Skmacy	sc->params.stats_update_period = 1;
476167514Skmacy
477167514Skmacy	/* initialize sge private state */
478167514Skmacy	t3_sge_init_sw(sc);
479167514Skmacy
480167514Skmacy	t3_led_ready(sc);
481167514Skmacy
482167514Skmacy	error = t3_get_fw_version(sc, &vers);
483167514Skmacy	if (error)
484167514Skmacy		goto out;
485167514Skmacy
486167514Skmacy	snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d", G_FW_VERSION_MAJOR(vers),
487167514Skmacy	    G_FW_VERSION_MINOR(vers));
488167514Skmacy
489167514Skmacy	t3_add_sysctls(sc);
490167514Skmacy
491167514Skmacyout:
492167514Skmacy	if (error)
493167514Skmacy		cxgb_free(sc);
494167514Skmacy
495167514Skmacy	return (error);
496167514Skmacy}
497167514Skmacy
498167514Skmacystatic int
499167514Skmacycxgb_controller_detach(device_t dev)
500167514Skmacy{
501167514Skmacy	struct adapter *sc;
502167514Skmacy
503167514Skmacy	sc = device_get_softc(dev);
504167514Skmacy
505167514Skmacy	cxgb_free(sc);
506167514Skmacy
507167514Skmacy	return (0);
508167514Skmacy}
509167514Skmacy
510167514Skmacystatic void
511167514Skmacycxgb_free(struct adapter *sc)
512167514Skmacy{
513167514Skmacy	int i;
514167514Skmacy
515167514Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
516167514Skmacy		if (sc->portdev[i] != NULL)
517167514Skmacy			device_delete_child(sc->dev, sc->portdev[i]);
518167514Skmacy	}
519167514Skmacy
520167514Skmacy	t3_sge_deinit_sw(sc);
521167514Skmacy
522167514Skmacy	if (sc->tq != NULL) {
523167514Skmacy		taskqueue_drain(sc->tq, &sc->ext_intr_task);
524167514Skmacy		taskqueue_free(sc->tq);
525167514Skmacy	}
526167514Skmacy
527167514Skmacy	callout_drain(&sc->cxgb_tick_ch);
528167514Skmacy
529167514Skmacy	bus_generic_detach(sc->dev);
530167514Skmacy
531167514Skmacy	t3_free_sge_resources(sc);
532167514Skmacy	t3_sge_free(sc);
533167514Skmacy
534167514Skmacy	for (i = 0; i < SGE_QSETS; i++) {
535167514Skmacy		if (sc->msix_intr_tag[i] != NULL) {
536167514Skmacy			bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
537167514Skmacy			    sc->msix_intr_tag[i]);
538167514Skmacy		}
539167514Skmacy		if (sc->msix_irq_res[i] != NULL) {
540167514Skmacy			bus_release_resource(sc->dev, SYS_RES_IRQ,
541167514Skmacy			    sc->msix_irq_rid[i], sc->msix_irq_res[i]);
542167514Skmacy		}
543167514Skmacy	}
544167514Skmacy
545167514Skmacy	if (sc->intr_tag != NULL) {
546167514Skmacy		bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
547167514Skmacy	}
548167514Skmacy
549167514Skmacy	if (sc->irq_res != NULL) {
550167514Skmacy		device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n",
551167514Skmacy		    sc->irq_rid, sc->irq_res);
552167514Skmacy		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
553167514Skmacy		    sc->irq_res);
554167514Skmacy	}
555167514Skmacy#ifdef MSI_SUPPORTED
556167514Skmacy	if (sc->flags & (USING_MSI | USING_MSIX)) {
557167514Skmacy		device_printf(sc->dev, "releasing msi message(s)\n");
558167514Skmacy		pci_release_msi(sc->dev);
559167514Skmacy	}
560167514Skmacy#endif
561167514Skmacy	if (sc->msix_regs_res != NULL) {
562167514Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
563167514Skmacy		    sc->msix_regs_res);
564167514Skmacy	}
565167514Skmacy
566167514Skmacy	if (sc->regs_res != NULL)
567167514Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid,
568167514Skmacy		    sc->regs_res);
569167514Skmacy
570167514Skmacy	mtx_destroy(&sc->mdio_lock);
571167514Skmacy	mtx_destroy(&sc->sge.reg_lock);
572167514Skmacy	mtx_destroy(&sc->lock);
573167514Skmacy
574167514Skmacy	return;
575167514Skmacy}
576167514Skmacy
577167514Skmacy/**
578167514Skmacy *	setup_sge_qsets - configure SGE Tx/Rx/response queues
579167514Skmacy *	@sc: the controller softc
580167514Skmacy *
581167514Skmacy *	Determines how many sets of SGE queues to use and initializes them.
582167514Skmacy *	We support multiple queue sets per port if we have MSI-X, otherwise
583167514Skmacy *	just one queue set per port.
584167514Skmacy */
585167514Skmacystatic int
586167514Skmacysetup_sge_qsets(adapter_t *sc)
587167514Skmacy{
588167514Skmacy	int i, j, err, irq_idx, qset_idx;
589167514Skmacy	u_int ntxq = 3;
590167514Skmacy
591167514Skmacy	if ((err = t3_sge_alloc(sc)) != 0) {
592167514Skmacy		printf("t3_sge_alloc returned %d\n", err);
593167514Skmacy		return (err);
594167514Skmacy	}
595167514Skmacy
596167514Skmacy	if (sc->params.rev > 0 && !(sc->flags & USING_MSI))
597167514Skmacy		irq_idx = -1;
598167514Skmacy	else
599167514Skmacy		irq_idx = 0;
600167514Skmacy
601167514Skmacy	for (qset_idx = 0, i = 0; i < (sc)->params.nports; ++i) {
602167514Skmacy		struct port_info *pi = &sc->port[i];
603167514Skmacy
604167514Skmacy		for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
605167514Skmacy			err = t3_sge_alloc_qset(sc, qset_idx, 1,
606167514Skmacy			    (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx,
607167514Skmacy			    &sc->params.sge.qset[qset_idx], ntxq, pi);
608167514Skmacy			if (err) {
609167514Skmacy				t3_free_sge_resources(sc);
610167514Skmacy				printf("t3_sge_alloc_qset failed with %d\n", err);
611167514Skmacy				return (err);
612167514Skmacy			}
613167514Skmacy		}
614167514Skmacy	}
615167514Skmacy
616167514Skmacy	return (0);
617167514Skmacy}
618167514Skmacy
619167514Skmacystatic int
620167514Skmacycxgb_setup_msix(adapter_t *sc, int msix_count)
621167514Skmacy{
622167514Skmacy	int i, j, k, nqsets, rid;
623167514Skmacy
624167514Skmacy	/* The first message indicates link changes and error conditions */
625167514Skmacy	sc->irq_rid = 1;
626167514Skmacy	if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
627167514Skmacy	   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
628167514Skmacy		device_printf(sc->dev, "Cannot allocate msix interrupt\n");
629167514Skmacy		return (EINVAL);
630167514Skmacy	}
631167514Skmacy	if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
632167514Skmacy#ifdef INTR_FILTERS
633167514Skmacy			NULL,
634167514Skmacy#endif
635167514Skmacy		cxgb_async_intr, sc, &sc->intr_tag)) {
636167514Skmacy		device_printf(sc->dev, "Cannot set up interrupt\n");
637167514Skmacy		return (EINVAL);
638167514Skmacy	}
639167514Skmacy
640167514Skmacy	for (i = 0, k = 0; i < (sc)->params.nports; ++i) {
641167514Skmacy		nqsets = sc->port[i].nqsets;
642167514Skmacy		for (j = 0; j < nqsets; ++j, k++) {
643167514Skmacy			struct sge_qset *qs = &sc->sge.qs[k];
644167514Skmacy
645167514Skmacy			rid = k + 2;
646167514Skmacy			if (cxgb_debug)
647167514Skmacy				printf("rid=%d ", rid);
648167514Skmacy			if ((sc->msix_irq_res[k] = bus_alloc_resource_any(
649167514Skmacy			    sc->dev, SYS_RES_IRQ, &rid,
650167514Skmacy			    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
651167514Skmacy				device_printf(sc->dev, "Cannot allocate "
652167514Skmacy				    "interrupt for message %d\n", rid);
653167514Skmacy				return (EINVAL);
654167514Skmacy			}
655167514Skmacy			sc->msix_irq_rid[k] = rid;
656167514Skmacy			if (bus_setup_intr(sc->dev, sc->msix_irq_res[j],
657167514Skmacy			    INTR_MPSAFE|INTR_TYPE_NET,
658167514Skmacy#ifdef INTR_FILTERS
659167514Skmacy			NULL,
660167514Skmacy#endif
661167514Skmacy				t3_intr_msix, qs, &sc->msix_intr_tag[k])) {
662167514Skmacy				device_printf(sc->dev, "Cannot set up "
663167514Skmacy				    "interrupt for message %d\n", rid);
664167514Skmacy				return (EINVAL);
665167514Skmacy			}
666167514Skmacy		}
667167514Skmacy	}
668167514Skmacy	return (0);
669167514Skmacy}
670167514Skmacy
671167514Skmacystatic int
672167514Skmacycxgb_port_probe(device_t dev)
673167514Skmacy{
674167514Skmacy	struct port_info *p;
675167514Skmacy	char buf[80];
676167514Skmacy
677167514Skmacy	p = device_get_softc(dev);
678167514Skmacy
679167514Skmacy	snprintf(buf, sizeof(buf), "Port %d %s", p->port, p->port_type->desc);
680167514Skmacy	device_set_desc_copy(dev, buf);
681167514Skmacy	return (0);
682167514Skmacy}
683167514Skmacy
684167514Skmacy
685167514Skmacystatic int
686167514Skmacycxgb_makedev(struct port_info *pi)
687167514Skmacy{
688167514Skmacy	struct cdevsw *cxgb_cdevsw;
689167514Skmacy
690167514Skmacy	if ((cxgb_cdevsw = malloc(sizeof(struct cdevsw), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
691167514Skmacy		return (ENOMEM);
692167514Skmacy
693167514Skmacy	cxgb_cdevsw->d_version = D_VERSION;
694167514Skmacy	cxgb_cdevsw->d_name = strdup(pi->ifp->if_xname, M_DEVBUF);
695167514Skmacy	cxgb_cdevsw->d_ioctl = cxgb_extension_ioctl;
696167514Skmacy
697167514Skmacy	pi->port_cdev = make_dev(cxgb_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
698167514Skmacy	    pi->ifp->if_xname);
699167514Skmacy
700167514Skmacy	if (pi->port_cdev == NULL)
701167514Skmacy		return (ENOMEM);
702167514Skmacy
703167514Skmacy	pi->port_cdev->si_drv1 = (void *)pi;
704167514Skmacy
705167514Skmacy	return (0);
706167514Skmacy}
707167514Skmacy
708167514Skmacy
709167514Skmacy#ifdef TSO_SUPPORTED
710167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU)
711167514Skmacy/* Don't enable TSO6 yet */
712167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU)
713167514Skmacy#else
714167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU)
715167514Skmacy/* Don't enable TSO6 yet */
716167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM |  IFCAP_JUMBO_MTU)
717167514Skmacy#define IFCAP_TSO4 0x0
718167514Skmacy#define CSUM_TSO   0x0
719167514Skmacy#endif
720167514Skmacy
721167514Skmacy
722167514Skmacystatic int
723167514Skmacycxgb_port_attach(device_t dev)
724167514Skmacy{
725167514Skmacy	struct port_info *p;
726167514Skmacy	struct ifnet *ifp;
727167514Skmacy	int media_flags;
728167514Skmacy	int err;
729167514Skmacy	char buf[64];
730167514Skmacy
731167514Skmacy	p = device_get_softc(dev);
732167514Skmacy
733167514Skmacy	snprintf(buf, sizeof(buf), "cxgb port %d", p->port);
734167514Skmacy	mtx_init(&p->lock, buf, 0, MTX_DEF);
735167514Skmacy
736167514Skmacy	/* Allocate an ifnet object and set it up */
737167514Skmacy	ifp = p->ifp = if_alloc(IFT_ETHER);
738167514Skmacy	if (ifp == NULL) {
739167514Skmacy		device_printf(dev, "Cannot allocate ifnet\n");
740167514Skmacy		return (ENOMEM);
741167514Skmacy	}
742167514Skmacy
743167514Skmacy	/*
744167514Skmacy	 * Note that there is currently no watchdog timer.
745167514Skmacy	 */
746167514Skmacy	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
747167514Skmacy	ifp->if_init = cxgb_init;
748167514Skmacy	ifp->if_softc = p;
749167514Skmacy	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
750167514Skmacy	ifp->if_ioctl = cxgb_ioctl;
751167514Skmacy	ifp->if_start = cxgb_start;
752167514Skmacy	ifp->if_timer = 0;	/* Disable ifnet watchdog */
753167514Skmacy	ifp->if_watchdog = NULL;
754167514Skmacy
755167514Skmacy	ifp->if_snd.ifq_drv_maxlen = TX_ETH_Q_SIZE;
756167514Skmacy	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
757167514Skmacy	IFQ_SET_READY(&ifp->if_snd);
758167514Skmacy
759167514Skmacy	ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0;
760167514Skmacy	ifp->if_capabilities |= CXGB_CAP;
761167514Skmacy	ifp->if_capenable |= CXGB_CAP_ENABLE;
762167514Skmacy	ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO);
763167514Skmacy	ifp->if_baudrate = 100000000;
764167514Skmacy
765167514Skmacy	ether_ifattach(ifp, p->hw_addr);
766167514Skmacy#ifdef DEFAULT_JUMBO
767167514Skmacy	ifp->if_mtu = 9000;
768167514Skmacy#endif
769167514Skmacy	if ((err = cxgb_makedev(p)) != 0) {
770167514Skmacy		printf("makedev failed %d\n", err);
771167514Skmacy		return (err);
772167514Skmacy	}
773167514Skmacy	ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change,
774167514Skmacy	    cxgb_media_status);
775167514Skmacy
776167514Skmacy	if (!strcmp(p->port_type->desc, "10GBASE-CX4"))
777167514Skmacy	        media_flags = IFM_ETHER | IFM_10G_CX4;
778167514Skmacy	else if (!strcmp(p->port_type->desc, "10GBASE-SR"))
779167514Skmacy	        media_flags = IFM_ETHER | IFM_10G_SR;
780167514Skmacy	else if (!strcmp(p->port_type->desc, "10GBASE-XR"))
781167514Skmacy	        media_flags = IFM_ETHER | IFM_10G_LR;
782167514Skmacy	else {
783167514Skmacy	        printf("unsupported media type %s\n", p->port_type->desc);
784167514Skmacy		return (ENXIO);
785167514Skmacy	}
786167514Skmacy
787167514Skmacy	ifmedia_add(&p->media, media_flags, 0, NULL);
788167514Skmacy	ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL);
789167514Skmacy	ifmedia_set(&p->media, media_flags);
790167514Skmacy
791167514Skmacy	snprintf(buf, sizeof(buf), "cxgb_port_taskq%d", p->port);
792167514Skmacy#ifdef TASKQUEUE_CURRENT
793167514Skmacy	/* Create a port for handling TX without starvation */
794167514Skmacy	p->tq = taskqueue_create(buf, M_NOWAIT,
795167514Skmacy	    taskqueue_thread_enqueue, &p->tq);
796167514Skmacy#else
797167514Skmacy	/* Create a port for handling TX without starvation */
798167514Skmacy	p->tq = taskqueue_create_fast(buf, M_NOWAIT,
799167514Skmacy	    taskqueue_thread_enqueue, &p->tq);
800167514Skmacy#endif
801167514Skmacy
802167514Skmacy
803167514Skmacy	if (p->tq == NULL) {
804167514Skmacy		device_printf(dev, "failed to allocate port task queue\n");
805167514Skmacy		return (ENOMEM);
806167514Skmacy	}
807167514Skmacy	taskqueue_start_threads(&p->tq, 1, PI_NET, "%s taskq",
808167514Skmacy	    device_get_nameunit(dev));
809167514Skmacy	TASK_INIT(&p->start_task, 0, cxgb_start_proc, ifp);
810167514Skmacy
811167514Skmacy
812167514Skmacy	return (0);
813167514Skmacy}
814167514Skmacy
815167514Skmacystatic int
816167514Skmacycxgb_port_detach(device_t dev)
817167514Skmacy{
818167514Skmacy	struct port_info *p;
819167514Skmacy
820167514Skmacy	p = device_get_softc(dev);
821167514Skmacy	mtx_destroy(&p->lock);
822167514Skmacy	if (p->tq != NULL) {
823167514Skmacy		taskqueue_drain(p->tq, &p->start_task);
824167514Skmacy		taskqueue_free(p->tq);
825167514Skmacy		p->tq = NULL;
826167514Skmacy	}
827167514Skmacy
828167514Skmacy	ether_ifdetach(p->ifp);
829167514Skmacy	if_free(p->ifp);
830167514Skmacy
831167514Skmacy	destroy_dev(p->port_cdev);
832167514Skmacy
833167514Skmacy
834167514Skmacy	return (0);
835167514Skmacy}
836167514Skmacy
837167514Skmacyvoid
838167514Skmacyt3_fatal_err(struct adapter *sc)
839167514Skmacy{
840167514Skmacy	u_int fw_status[4];
841167514Skmacy
842167514Skmacy	device_printf(sc->dev,"encountered fatal error, operation suspended\n");
843167514Skmacy	if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status))
844167514Skmacy		device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n",
845167514Skmacy		    fw_status[0], fw_status[1], fw_status[2], fw_status[3]);
846167514Skmacy}
847167514Skmacy
848167514Skmacyint
849167514Skmacyt3_os_find_pci_capability(adapter_t *sc, int cap)
850167514Skmacy{
851167514Skmacy	device_t dev;
852167514Skmacy	struct pci_devinfo *dinfo;
853167514Skmacy	pcicfgregs *cfg;
854167514Skmacy	uint32_t status;
855167514Skmacy	uint8_t ptr;
856167514Skmacy
857167514Skmacy	dev = sc->dev;
858167514Skmacy	dinfo = device_get_ivars(dev);
859167514Skmacy	cfg = &dinfo->cfg;
860167514Skmacy
861167514Skmacy	status = pci_read_config(dev, PCIR_STATUS, 2);
862167514Skmacy	if (!(status & PCIM_STATUS_CAPPRESENT))
863167514Skmacy		return (0);
864167514Skmacy
865167514Skmacy	switch (cfg->hdrtype & PCIM_HDRTYPE) {
866167514Skmacy	case 0:
867167514Skmacy	case 1:
868167514Skmacy		ptr = PCIR_CAP_PTR;
869167514Skmacy		break;
870167514Skmacy	case 2:
871167514Skmacy		ptr = PCIR_CAP_PTR_2;
872167514Skmacy		break;
873167514Skmacy	default:
874167514Skmacy		return (0);
875167514Skmacy		break;
876167514Skmacy	}
877167514Skmacy	ptr = pci_read_config(dev, ptr, 1);
878167514Skmacy
879167514Skmacy	while (ptr != 0) {
880167514Skmacy		if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap)
881167514Skmacy			return (ptr);
882167514Skmacy		ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1);
883167514Skmacy	}
884167514Skmacy
885167514Skmacy	return (0);
886167514Skmacy}
887167514Skmacy
888167514Skmacyint
889167514Skmacyt3_os_pci_save_state(struct adapter *sc)
890167514Skmacy{
891167514Skmacy	device_t dev;
892167514Skmacy	struct pci_devinfo *dinfo;
893167514Skmacy
894167514Skmacy	dev = sc->dev;
895167514Skmacy	dinfo = device_get_ivars(dev);
896167514Skmacy
897167514Skmacy	pci_cfg_save(dev, dinfo, 0);
898167514Skmacy	return (0);
899167514Skmacy}
900167514Skmacy
901167514Skmacyint
902167514Skmacyt3_os_pci_restore_state(struct adapter *sc)
903167514Skmacy{
904167514Skmacy	device_t dev;
905167514Skmacy	struct pci_devinfo *dinfo;
906167514Skmacy
907167514Skmacy	dev = sc->dev;
908167514Skmacy	dinfo = device_get_ivars(dev);
909167514Skmacy
910167514Skmacy	pci_cfg_restore(dev, dinfo);
911167514Skmacy	return (0);
912167514Skmacy}
913167514Skmacy
914167514Skmacy/**
915167514Skmacy *	t3_os_link_changed - handle link status changes
916167514Skmacy *	@adapter: the adapter associated with the link change
917167514Skmacy *	@port_id: the port index whose limk status has changed
918167514Skmacy *	@link_stat: the new status of the link
919167514Skmacy *	@speed: the new speed setting
920167514Skmacy *	@duplex: the new duplex setting
921167514Skmacy *	@fc: the new flow-control setting
922167514Skmacy *
923167514Skmacy *	This is the OS-dependent handler for link status changes.  The OS
924167514Skmacy *	neutral handler takes care of most of the processing for these events,
925167514Skmacy *	then calls this handler for any OS-specific processing.
926167514Skmacy */
927167514Skmacyvoid
928167514Skmacyt3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
929167514Skmacy     int duplex, int fc)
930167514Skmacy{
931167514Skmacy	struct port_info *pi = &adapter->port[port_id];
932167514Skmacy
933167514Skmacy	if ((pi->ifp->if_flags & IFF_UP) == 0)
934167514Skmacy		return;
935167514Skmacy
936167514Skmacy	if (link_status)
937167514Skmacy		if_link_state_change(pi->ifp, LINK_STATE_UP);
938167514Skmacy	else
939167514Skmacy		if_link_state_change(pi->ifp, LINK_STATE_DOWN);
940167514Skmacy
941167514Skmacy}
942167514Skmacy
943167514Skmacy
944167514Skmacy/*
945167514Skmacy * Interrupt-context handler for external (PHY) interrupts.
946167514Skmacy */
947167514Skmacyvoid
948167514Skmacyt3_os_ext_intr_handler(adapter_t *sc)
949167514Skmacy{
950167514Skmacy	if (cxgb_debug)
951167514Skmacy		printf("t3_os_ext_intr_handler\n");
952167514Skmacy	/*
953167514Skmacy	 * Schedule a task to handle external interrupts as they may be slow
954167514Skmacy	 * and we use a mutex to protect MDIO registers.  We disable PHY
955167514Skmacy	 * interrupts in the meantime and let the task reenable them when
956167514Skmacy	 * it's done.
957167514Skmacy	 */
958167514Skmacy	if (sc->slow_intr_mask) {
959167514Skmacy		sc->slow_intr_mask &= ~F_T3DBG;
960167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
961167514Skmacy		taskqueue_enqueue(sc->tq, &sc->ext_intr_task);
962167514Skmacy	}
963167514Skmacy}
964167514Skmacy
965167514Skmacyvoid
966167514Skmacyt3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
967167514Skmacy{
968167514Skmacy
969167514Skmacy	/*
970167514Skmacy	 * The ifnet might not be allocated before this gets called,
971167514Skmacy	 * as this is called early on in attach by t3_prep_adapter
972167514Skmacy	 * save the address off in the port structure
973167514Skmacy	 */
974167514Skmacy	if (cxgb_debug)
975167514Skmacy		printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":");
976167514Skmacy	bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN);
977167514Skmacy}
978167514Skmacy
979167514Skmacy/**
980167514Skmacy *	link_start - enable a port
981167514Skmacy *	@p: the port to enable
982167514Skmacy *
983167514Skmacy *	Performs the MAC and PHY actions needed to enable a port.
984167514Skmacy */
985167514Skmacystatic void
986167514Skmacycxgb_link_start(struct port_info *p)
987167514Skmacy{
988167514Skmacy	struct ifnet *ifp;
989167514Skmacy	struct t3_rx_mode rm;
990167514Skmacy	struct cmac *mac = &p->mac;
991167514Skmacy
992167514Skmacy	ifp = p->ifp;
993167514Skmacy
994167514Skmacy	t3_init_rx_mode(&rm, p);
995167514Skmacy	t3_mac_reset(mac);
996167514Skmacy	t3_mac_set_mtu(mac, ifp->if_mtu);
997167514Skmacy	t3_mac_set_address(mac, 0, p->hw_addr);
998167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
999167514Skmacy	t3_link_start(&p->phy, mac, &p->link_config);
1000167514Skmacy	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1001167514Skmacy}
1002167514Skmacy
1003167514Skmacy/**
1004167514Skmacy *	setup_rss - configure Receive Side Steering (per-queue connection demux)
1005167514Skmacy *	@adap: the adapter
1006167514Skmacy *
1007167514Skmacy *	Sets up RSS to distribute packets to multiple receive queues.  We
1008167514Skmacy *	configure the RSS CPU lookup table to distribute to the number of HW
1009167514Skmacy *	receive queues, and the response queue lookup table to narrow that
1010167514Skmacy *	down to the response queues actually configured for each port.
1011167514Skmacy *	We always configure the RSS mapping for two ports since the mapping
1012167514Skmacy *	table has plenty of entries.
1013167514Skmacy */
1014167514Skmacystatic void
1015167514Skmacysetup_rss(adapter_t *adap)
1016167514Skmacy{
1017167514Skmacy	int i;
1018167514Skmacy	u_int nq0 = adap->port[0].nqsets;
1019167514Skmacy	u_int nq1 = max((u_int)adap->port[1].nqsets, 1U);
1020167514Skmacy	uint8_t cpus[SGE_QSETS + 1];
1021167514Skmacy	uint16_t rspq_map[RSS_TABLE_SIZE];
1022167514Skmacy
1023167514Skmacy	for (i = 0; i < SGE_QSETS; ++i)
1024167514Skmacy		cpus[i] = i;
1025167514Skmacy	cpus[SGE_QSETS] = 0xff;
1026167514Skmacy
1027167514Skmacy	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
1028167514Skmacy		rspq_map[i] = i % nq0;
1029167514Skmacy		rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
1030167514Skmacy	}
1031167514Skmacy
1032167514Skmacy	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
1033167514Skmacy	    F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
1034167514Skmacy	    V_RRCPLCPUSIZE(6), cpus, rspq_map);
1035167514Skmacy}
1036167514Skmacy
1037167514Skmacystatic void
1038167514Skmacysend_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
1039167514Skmacy			      int hi, int port)
1040167514Skmacy{
1041167514Skmacy	struct mbuf *m;
1042167514Skmacy	struct mngt_pktsched_wr *req;
1043167514Skmacy
1044167514Skmacy	m = m_gethdr(M_NOWAIT, MT_DATA);
1045167514Skmacy	req = (struct mngt_pktsched_wr *)m->m_data;
1046167514Skmacy	req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
1047167514Skmacy	req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
1048167514Skmacy	req->sched = sched;
1049167514Skmacy	req->idx = qidx;
1050167514Skmacy	req->min = lo;
1051167514Skmacy	req->max = hi;
1052167514Skmacy	req->binding = port;
1053167514Skmacy	m->m_len = m->m_pkthdr.len = sizeof(*req);
1054167514Skmacy	t3_mgmt_tx(adap, m);
1055167514Skmacy}
1056167514Skmacy
1057167514Skmacystatic void
1058167514Skmacybind_qsets(adapter_t *sc)
1059167514Skmacy{
1060167514Skmacy	int i, j;
1061167514Skmacy
1062167514Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
1063167514Skmacy		const struct port_info *pi = adap2pinfo(sc, i);
1064167514Skmacy
1065167514Skmacy		for (j = 0; j < pi->nqsets; ++j)
1066167514Skmacy			send_pktsched_cmd(sc, 1, pi->first_qset + j, -1,
1067167514Skmacy					  -1, i);
1068167514Skmacy	}
1069167514Skmacy}
1070167514Skmacy
1071167514Skmacystatic void
1072167514Skmacycxgb_init(void *arg)
1073167514Skmacy{
1074167514Skmacy	struct port_info *p = arg;
1075167514Skmacy
1076167514Skmacy	PORT_LOCK(p);
1077167514Skmacy	cxgb_init_locked(p);
1078167514Skmacy	PORT_UNLOCK(p);
1079167514Skmacy}
1080167514Skmacy
1081167514Skmacystatic void
1082167514Skmacycxgb_init_locked(struct port_info *p)
1083167514Skmacy{
1084167514Skmacy	struct ifnet *ifp;
1085167514Skmacy	adapter_t *sc = p->adapter;
1086167514Skmacy	int error;
1087167514Skmacy
1088167514Skmacy	mtx_assert(&p->lock, MA_OWNED);
1089167514Skmacy
1090167514Skmacy	ifp = p->ifp;
1091167514Skmacy	if ((sc->flags & FW_UPTODATE) == 0) {
1092167514Skmacy		device_printf(sc->dev, "updating firmware to version %d.%d\n",
1093167514Skmacy		    CHELSIO_FW_MAJOR, CHELSIO_FW_MINOR);
1094167514Skmacy		if ((error = cxgb_fw_download(sc, sc->dev)) != 0) {
1095167514Skmacy			device_printf(sc->dev, "firmware download failed err: %d"
1096167514Skmacy			    "interface will be unavailable\n", error);
1097167514Skmacy			return;
1098167514Skmacy		}
1099167514Skmacy		sc->flags |= FW_UPTODATE;
1100167514Skmacy	}
1101167514Skmacy
1102167514Skmacy	cxgb_link_start(p);
1103167514Skmacy	ADAPTER_LOCK(p->adapter);
1104167514Skmacy	if (p->adapter->open_device_map == 0)
1105167514Skmacy		t3_intr_clear(sc);
1106167514Skmacy	t3_sge_start(sc);
1107167514Skmacy
1108167514Skmacy	p->adapter->open_device_map |= (1 << p->port);
1109167514Skmacy	ADAPTER_UNLOCK(p->adapter);
1110167514Skmacy	t3_intr_enable(sc);
1111167514Skmacy	t3_port_intr_enable(sc, p->port);
1112167514Skmacy	if ((p->adapter->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
1113167514Skmacy		bind_qsets(sc);
1114167514Skmacy	p->adapter->flags |= QUEUES_BOUND;
1115167514Skmacy	callout_reset(&sc->cxgb_tick_ch, sc->params.stats_update_period * hz,
1116167514Skmacy	    cxgb_tick, sc);
1117167514Skmacy
1118167514Skmacy
1119167514Skmacy	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1120167514Skmacy	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1121167514Skmacy}
1122167514Skmacy
1123167514Skmacystatic void
1124167514Skmacycxgb_set_rxmode(struct port_info *p)
1125167514Skmacy{
1126167514Skmacy	struct t3_rx_mode rm;
1127167514Skmacy	struct cmac *mac = &p->mac;
1128167514Skmacy
1129167514Skmacy	t3_init_rx_mode(&rm, p);
1130167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
1131167514Skmacy}
1132167514Skmacy
1133167514Skmacystatic void
1134167514Skmacycxgb_stop(struct port_info *p)
1135167514Skmacy{
1136167514Skmacy	struct ifnet *ifp;
1137167514Skmacy
1138167514Skmacy	callout_drain(&p->adapter->cxgb_tick_ch);
1139167514Skmacy	ifp = p->ifp;
1140167514Skmacy
1141167514Skmacy	PORT_LOCK(p);
1142167514Skmacy	ADAPTER_LOCK(p->adapter);
1143167514Skmacy	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1144167514Skmacy	p->adapter->open_device_map &= ~(1 << p->port);
1145167514Skmacy	if (p->adapter->open_device_map == 0)
1146167514Skmacy		t3_intr_disable(p->adapter);
1147167514Skmacy	ADAPTER_UNLOCK(p->adapter);
1148167514Skmacy	t3_port_intr_disable(p->adapter, p->port);
1149167514Skmacy	t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
1150167514Skmacy	PORT_UNLOCK(p);
1151167514Skmacy
1152167514Skmacy}
1153167514Skmacy
1154167514Skmacystatic int
1155167514Skmacycxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
1156167514Skmacy{
1157167514Skmacy	struct port_info *p = ifp->if_softc;
1158167514Skmacy	struct ifaddr *ifa = (struct ifaddr *)data;
1159167514Skmacy	struct ifreq *ifr = (struct ifreq *)data;
1160167514Skmacy	int flags, error = 0;
1161167514Skmacy	uint32_t mask;
1162167514Skmacy
1163167514Skmacy	switch (command) {
1164167514Skmacy	case SIOCSIFMTU:
1165167514Skmacy		if ((ifr->ifr_mtu < ETHERMIN) ||
1166167514Skmacy		    (ifr->ifr_mtu > ETHER_MAX_LEN_JUMBO))
1167167514Skmacy			error = EINVAL;
1168167514Skmacy		else if (ifp->if_mtu != ifr->ifr_mtu) {
1169167514Skmacy			PORT_LOCK(p);
1170167514Skmacy			ifp->if_mtu = ifr->ifr_mtu;
1171167514Skmacy			t3_mac_set_mtu(&p->mac, ifp->if_mtu);
1172167514Skmacy			PORT_UNLOCK(p);
1173167514Skmacy		}
1174167514Skmacy		break;
1175167514Skmacy	case SIOCSIFADDR:
1176167514Skmacy	case SIOCGIFADDR:
1177167514Skmacy		if (ifa->ifa_addr->sa_family == AF_INET) {
1178167514Skmacy			ifp->if_flags |= IFF_UP;
1179167514Skmacy			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1180167514Skmacy				cxgb_init(p);
1181167514Skmacy			}
1182167514Skmacy			arp_ifinit(ifp, ifa);
1183167514Skmacy		} else
1184167514Skmacy			error = ether_ioctl(ifp, command, data);
1185167514Skmacy		break;
1186167514Skmacy	case SIOCSIFFLAGS:
1187167514Skmacy		PORT_LOCK(p);
1188167514Skmacy		if (ifp->if_flags & IFF_UP) {
1189167514Skmacy			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1190167514Skmacy				flags = p->if_flags;
1191167514Skmacy				if (((ifp->if_flags ^ flags) & IFF_PROMISC) ||
1192167514Skmacy				    ((ifp->if_flags ^ flags) & IFF_ALLMULTI))
1193167514Skmacy					cxgb_set_rxmode(p);
1194167514Skmacy
1195167514Skmacy			} else
1196167514Skmacy				cxgb_init_locked(p);
1197167514Skmacy		} else {
1198167514Skmacy			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1199167514Skmacy				cxgb_stop(p);
1200167514Skmacy			}
1201167514Skmacy		}
1202167514Skmacy		p->if_flags = ifp->if_flags;
1203167514Skmacy		PORT_UNLOCK(p);
1204167514Skmacy		break;
1205167514Skmacy	case SIOCSIFMEDIA:
1206167514Skmacy	case SIOCGIFMEDIA:
1207167514Skmacy		error = ifmedia_ioctl(ifp, ifr, &p->media, command);
1208167514Skmacy		break;
1209167514Skmacy	case SIOCSIFCAP:
1210167514Skmacy		PORT_LOCK(p);
1211167514Skmacy		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1212167514Skmacy		if (mask & IFCAP_TXCSUM) {
1213167514Skmacy			if (IFCAP_TXCSUM & ifp->if_capenable) {
1214167514Skmacy				ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
1215167514Skmacy				ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP
1216167514Skmacy				    | CSUM_TSO);
1217167514Skmacy			} else {
1218167514Skmacy				ifp->if_capenable |= IFCAP_TXCSUM;
1219167514Skmacy				ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
1220167514Skmacy			}
1221167514Skmacy		} else if (mask & IFCAP_RXCSUM) {
1222167514Skmacy			if (IFCAP_RXCSUM & ifp->if_capenable) {
1223167514Skmacy				ifp->if_capenable &= ~IFCAP_RXCSUM;
1224167514Skmacy			} else {
1225167514Skmacy				ifp->if_capenable |= IFCAP_RXCSUM;
1226167514Skmacy			}
1227167514Skmacy		}
1228167514Skmacy		if (mask & IFCAP_TSO4) {
1229167514Skmacy			if (IFCAP_TSO4 & ifp->if_capenable) {
1230167514Skmacy				ifp->if_capenable &= ~IFCAP_TSO4;
1231167514Skmacy				ifp->if_hwassist &= ~CSUM_TSO;
1232167514Skmacy			} else if (IFCAP_TXCSUM & ifp->if_capenable) {
1233167514Skmacy				ifp->if_capenable |= IFCAP_TSO4;
1234167514Skmacy				ifp->if_hwassist |= CSUM_TSO;
1235167514Skmacy			} else {
1236167514Skmacy				if (cxgb_debug)
1237167514Skmacy					printf("cxgb requires tx checksum offload"
1238167514Skmacy					    " be enabled to use TSO\n");
1239167514Skmacy				error = EINVAL;
1240167514Skmacy			}
1241167514Skmacy		}
1242167514Skmacy		PORT_UNLOCK(p);
1243167514Skmacy		break;
1244167514Skmacy	default:
1245167514Skmacy		error = ether_ioctl(ifp, command, data);
1246167514Skmacy		break;
1247167514Skmacy	}
1248167514Skmacy
1249167514Skmacy	return (error);
1250167514Skmacy}
1251167514Skmacy
1252167514Skmacystatic int
1253167514Skmacycxgb_start_tx(struct ifnet *ifp, uint32_t txmax)
1254167514Skmacy{
1255167514Skmacy	struct sge_qset *qs;
1256167514Skmacy	struct sge_txq *txq;
1257167514Skmacy	struct port_info *p = ifp->if_softc;
1258167514Skmacy	struct mbuf *m = NULL;
1259167514Skmacy	int err, in_use_init;
1260167514Skmacy
1261167514Skmacy
1262167514Skmacy	if (!p->link_config.link_ok)
1263167514Skmacy		return (ENXIO);
1264167514Skmacy
1265167514Skmacy	if (IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1266167514Skmacy		return (ENOBUFS);
1267167514Skmacy
1268167514Skmacy	qs = &p->adapter->sge.qs[p->first_qset];
1269167514Skmacy	txq = &qs->txq[TXQ_ETH];
1270167514Skmacy	err = 0;
1271167514Skmacy
1272167514Skmacy	mtx_lock(&txq->lock);
1273167514Skmacy	in_use_init = txq->in_use;
1274167514Skmacy	while ((txq->in_use - in_use_init < txmax) &&
1275167514Skmacy	    (txq->size > txq->in_use + TX_MAX_DESC)) {
1276167514Skmacy		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
1277167514Skmacy		if (m == NULL)
1278167514Skmacy			break;
1279167514Skmacy		if ((err = t3_encap(p, &m)) != 0)
1280167514Skmacy			break;
1281167514Skmacy		BPF_MTAP(ifp, m);
1282167514Skmacy	}
1283167514Skmacy	mtx_unlock(&txq->lock);
1284167514Skmacy
1285167514Skmacy	if (__predict_false(err)) {
1286167514Skmacy		if (cxgb_debug)
1287167514Skmacy			printf("would set OFLAGS\n");
1288167514Skmacy		if (err == ENOMEM) {
1289167514Skmacy			IFQ_LOCK(&ifp->if_snd);
1290167514Skmacy			IFQ_DRV_PREPEND(&ifp->if_snd, m);
1291167514Skmacy			IFQ_UNLOCK(&ifp->if_snd);
1292167514Skmacy		}
1293167514Skmacy	}
1294167514Skmacy	if (err == 0 && m == NULL)
1295167514Skmacy		err = ENOBUFS;
1296167514Skmacy
1297167514Skmacy	return (err);
1298167514Skmacy}
1299167514Skmacy
1300167514Skmacystatic void
1301167514Skmacycxgb_start_proc(void *arg, int ncount)
1302167514Skmacy{
1303167514Skmacy	struct ifnet *ifp = arg;
1304167514Skmacy	struct port_info *pi = ifp->if_softc;
1305167514Skmacy	struct sge_qset *qs;
1306167514Skmacy	struct sge_txq *txq;
1307167514Skmacy	int error = 0;
1308167514Skmacy
1309167514Skmacy	qs = &pi->adapter->sge.qs[pi->first_qset];
1310167514Skmacy	txq = &qs->txq[TXQ_ETH];
1311167514Skmacy
1312167514Skmacy	while (error == 0) {
1313167514Skmacy		if (desc_reclaimable(txq) > TX_START_MAX_DESC)
1314167514Skmacy			taskqueue_enqueue(pi->adapter->tq, &pi->adapter->timer_reclaim_task);
1315167514Skmacy
1316167514Skmacy		error = cxgb_start_tx(ifp, TX_MAX_DESC + 1);
1317167514Skmacy	}
1318167514Skmacy}
1319167514Skmacy
1320167514Skmacystatic void
1321167514Skmacycxgb_start(struct ifnet *ifp)
1322167514Skmacy{
1323167514Skmacy	struct port_info *pi = ifp->if_softc;
1324167514Skmacy	struct sge_qset *qs;
1325167514Skmacy	struct sge_txq *txq;
1326167514Skmacy	int err;
1327167514Skmacy
1328167514Skmacy	qs = &pi->adapter->sge.qs[pi->first_qset];
1329167514Skmacy	txq = &qs->txq[TXQ_ETH];
1330167514Skmacy
1331167514Skmacy	if (desc_reclaimable(txq) > TX_START_MAX_DESC)
1332167514Skmacy		taskqueue_enqueue(pi->adapter->tq, &pi->adapter->timer_reclaim_task);
1333167514Skmacy
1334167514Skmacy	err = cxgb_start_tx(ifp, TX_START_MAX_DESC);
1335167514Skmacy
1336167514Skmacy	if (err == 0)
1337167514Skmacy		taskqueue_enqueue(pi->tq, &pi->start_task);
1338167514Skmacy}
1339167514Skmacy
1340167514Skmacy
1341167514Skmacystatic int
1342167514Skmacycxgb_media_change(struct ifnet *ifp)
1343167514Skmacy{
1344167514Skmacy	if_printf(ifp, "media change not supported\n");
1345167514Skmacy	return (ENXIO);
1346167514Skmacy}
1347167514Skmacy
1348167514Skmacystatic void
1349167514Skmacycxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1350167514Skmacy{
1351167514Skmacy	struct port_info *p = ifp->if_softc;
1352167514Skmacy
1353167514Skmacy	ifmr->ifm_status = IFM_AVALID;
1354167514Skmacy	ifmr->ifm_active = IFM_ETHER;
1355167514Skmacy
1356167514Skmacy	if (!p->link_config.link_ok)
1357167514Skmacy		return;
1358167514Skmacy
1359167514Skmacy	ifmr->ifm_status |= IFM_ACTIVE;
1360167514Skmacy
1361167514Skmacy	if (p->link_config.duplex)
1362167514Skmacy		ifmr->ifm_active |= IFM_FDX;
1363167514Skmacy	else
1364167514Skmacy		ifmr->ifm_active |= IFM_HDX;
1365167514Skmacy}
1366167514Skmacy
1367167514Skmacystatic void
1368167514Skmacycxgb_async_intr(void *data)
1369167514Skmacy{
1370167514Skmacy	if (cxgb_debug)
1371167514Skmacy		printf("cxgb_async_intr\n");
1372167514Skmacy}
1373167514Skmacy
1374167514Skmacystatic void
1375167514Skmacycxgb_ext_intr_handler(void *arg, int count)
1376167514Skmacy{
1377167514Skmacy	adapter_t *sc = (adapter_t *)arg;
1378167514Skmacy
1379167514Skmacy	if (cxgb_debug)
1380167514Skmacy		printf("cxgb_ext_intr_handler\n");
1381167514Skmacy
1382167514Skmacy	t3_phy_intr_handler(sc);
1383167514Skmacy
1384167514Skmacy	/* Now reenable external interrupts */
1385167514Skmacy	if (sc->slow_intr_mask) {
1386167514Skmacy		sc->slow_intr_mask |= F_T3DBG;
1387167514Skmacy		t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG);
1388167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
1389167514Skmacy	}
1390167514Skmacy}
1391167514Skmacy
1392167514Skmacystatic void
1393167514Skmacycxgb_tick(void *arg)
1394167514Skmacy{
1395167514Skmacy	adapter_t *sc = (adapter_t *)arg;
1396167514Skmacy	const struct adapter_params *p = &sc->params;
1397167514Skmacy
1398167514Skmacy	if (p->linkpoll_period)
1399167514Skmacy		check_link_status(sc);
1400167514Skmacy
1401167514Skmacy	callout_reset(&sc->cxgb_tick_ch, sc->params.stats_update_period * hz,
1402167514Skmacy	    cxgb_tick, sc);
1403167514Skmacy}
1404167514Skmacy
1405167514Skmacystatic void
1406167514Skmacycheck_link_status(adapter_t *sc)
1407167514Skmacy{
1408167514Skmacy	int i;
1409167514Skmacy
1410167514Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
1411167514Skmacy		struct port_info *p = &sc->port[i];
1412167514Skmacy
1413167514Skmacy		if (!(p->port_type->caps & SUPPORTED_IRQ))
1414167514Skmacy			t3_link_changed(sc, i);
1415167514Skmacy	}
1416167514Skmacy}
1417167514Skmacy
1418167514Skmacystatic int
1419167514Skmacyin_range(int val, int lo, int hi)
1420167514Skmacy{
1421167514Skmacy	return val < 0 || (val <= hi && val >= lo);
1422167514Skmacy}
1423167514Skmacy
1424167514Skmacystatic int
1425167514Skmacycxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
1426167514Skmacy    int fflag, struct thread *td)
1427167514Skmacy{
1428167514Skmacy	int mmd, error = 0;
1429167514Skmacy	struct port_info *pi = dev->si_drv1;
1430167514Skmacy	adapter_t *sc = pi->adapter;
1431167514Skmacy
1432167514Skmacy#ifdef PRIV_SUPPORTED
1433167514Skmacy	if (priv_check(td, PRIV_DRIVER)) {
1434167514Skmacy		if (cxgb_debug)
1435167514Skmacy			printf("user does not have access to privileged ioctls\n");
1436167514Skmacy		return (EPERM);
1437167514Skmacy	}
1438167514Skmacy#else
1439167514Skmacy	if (suser(td)) {
1440167514Skmacy		if (cxgb_debug)
1441167514Skmacy			printf("user does not have access to privileged ioctls\n");
1442167514Skmacy		return (EPERM);
1443167514Skmacy	}
1444167514Skmacy#endif
1445167514Skmacy
1446167514Skmacy	switch (cmd) {
1447167514Skmacy	case SIOCGMIIREG: {
1448167514Skmacy		uint32_t val;
1449167514Skmacy		struct cphy *phy = &pi->phy;
1450167514Skmacy		struct mii_data *mid = (struct mii_data *)data;
1451167514Skmacy
1452167514Skmacy		if (!phy->mdio_read)
1453167514Skmacy			return (EOPNOTSUPP);
1454167514Skmacy		if (is_10G(sc)) {
1455167514Skmacy			mmd = mid->phy_id >> 8;
1456167514Skmacy			if (!mmd)
1457167514Skmacy				mmd = MDIO_DEV_PCS;
1458167514Skmacy			else if (mmd > MDIO_DEV_XGXS)
1459167514Skmacy				return -EINVAL;
1460167514Skmacy
1461167514Skmacy			error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd,
1462167514Skmacy					     mid->reg_num, &val);
1463167514Skmacy		} else
1464167514Skmacy		        error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0,
1465167514Skmacy					     mid->reg_num & 0x1f, &val);
1466167514Skmacy		if (error == 0)
1467167514Skmacy			mid->val_out = val;
1468167514Skmacy		break;
1469167514Skmacy	}
1470167514Skmacy	case SIOCSMIIREG: {
1471167514Skmacy		struct cphy *phy = &pi->phy;
1472167514Skmacy		struct mii_data *mid = (struct mii_data *)data;
1473167514Skmacy
1474167514Skmacy		if (!phy->mdio_write)
1475167514Skmacy			return (EOPNOTSUPP);
1476167514Skmacy		if (is_10G(sc)) {
1477167514Skmacy			mmd = mid->phy_id >> 8;
1478167514Skmacy			if (!mmd)
1479167514Skmacy				mmd = MDIO_DEV_PCS;
1480167514Skmacy			else if (mmd > MDIO_DEV_XGXS)
1481167514Skmacy				return (EINVAL);
1482167514Skmacy
1483167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f,
1484167514Skmacy					      mmd, mid->reg_num, mid->val_in);
1485167514Skmacy		} else
1486167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0,
1487167514Skmacy					      mid->reg_num & 0x1f,
1488167514Skmacy					      mid->val_in);
1489167514Skmacy		break;
1490167514Skmacy	}
1491167514Skmacy	case CHELSIO_SETREG: {
1492167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
1493167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
1494167514Skmacy			return (EFAULT);
1495167514Skmacy		t3_write_reg(sc, edata->addr, edata->val);
1496167514Skmacy		break;
1497167514Skmacy	}
1498167514Skmacy	case CHELSIO_GETREG: {
1499167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
1500167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
1501167514Skmacy			return (EFAULT);
1502167514Skmacy		edata->val = t3_read_reg(sc, edata->addr);
1503167514Skmacy		break;
1504167514Skmacy	}
1505167514Skmacy	case CHELSIO_GET_SGE_CONTEXT: {
1506167514Skmacy		struct ch_cntxt *ecntxt = (struct ch_cntxt *)data;
1507167514Skmacy		mtx_lock(&sc->sge.reg_lock);
1508167514Skmacy		switch (ecntxt->cntxt_type) {
1509167514Skmacy		case CNTXT_TYPE_EGRESS:
1510167514Skmacy			error = t3_sge_read_ecntxt(sc, ecntxt->cntxt_id,
1511167514Skmacy			    ecntxt->data);
1512167514Skmacy			break;
1513167514Skmacy		case CNTXT_TYPE_FL:
1514167514Skmacy			error = t3_sge_read_fl(sc, ecntxt->cntxt_id,
1515167514Skmacy			    ecntxt->data);
1516167514Skmacy			break;
1517167514Skmacy		case CNTXT_TYPE_RSP:
1518167514Skmacy			error = t3_sge_read_rspq(sc, ecntxt->cntxt_id,
1519167514Skmacy			    ecntxt->data);
1520167514Skmacy			break;
1521167514Skmacy		case CNTXT_TYPE_CQ:
1522167514Skmacy			error = t3_sge_read_cq(sc, ecntxt->cntxt_id,
1523167514Skmacy			    ecntxt->data);
1524167514Skmacy			break;
1525167514Skmacy		default:
1526167514Skmacy			error = EINVAL;
1527167514Skmacy			break;
1528167514Skmacy		}
1529167514Skmacy		mtx_unlock(&sc->sge.reg_lock);
1530167514Skmacy		break;
1531167514Skmacy	}
1532167514Skmacy	case CHELSIO_GET_SGE_DESC: {
1533167514Skmacy		struct ch_desc *edesc = (struct ch_desc *)data;
1534167514Skmacy		int ret;
1535167514Skmacy		if (edesc->queue_num >= SGE_QSETS * 6)
1536167514Skmacy			return (EINVAL);
1537167514Skmacy		ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6],
1538167514Skmacy		    edesc->queue_num % 6, edesc->idx, edesc->data);
1539167514Skmacy		if (ret < 0)
1540167514Skmacy			return (EINVAL);
1541167514Skmacy		edesc->size = ret;
1542167514Skmacy		break;
1543167514Skmacy	}
1544167514Skmacy	case CHELSIO_SET_QSET_PARAMS: {
1545167514Skmacy		struct qset_params *q;
1546167514Skmacy		struct ch_qset_params *t = (struct ch_qset_params *)data;
1547167514Skmacy
1548167514Skmacy		if (t->qset_idx >= SGE_QSETS)
1549167514Skmacy			return -EINVAL;
1550167514Skmacy		if (!in_range(t->intr_lat, 0, M_NEWTIMER) ||
1551167514Skmacy		    !in_range(t->cong_thres, 0, 255) ||
1552167514Skmacy		    !in_range(t->txq_size[0], MIN_TXQ_ENTRIES,
1553167514Skmacy			      MAX_TXQ_ENTRIES) ||
1554167514Skmacy		    !in_range(t->txq_size[1], MIN_TXQ_ENTRIES,
1555167514Skmacy			      MAX_TXQ_ENTRIES) ||
1556167514Skmacy		    !in_range(t->txq_size[2], MIN_CTRL_TXQ_ENTRIES,
1557167514Skmacy			      MAX_CTRL_TXQ_ENTRIES) ||
1558167514Skmacy		    !in_range(t->fl_size[0], MIN_FL_ENTRIES, MAX_RX_BUFFERS) ||
1559167514Skmacy		    !in_range(t->fl_size[1], MIN_FL_ENTRIES,
1560167514Skmacy			      MAX_RX_JUMBO_BUFFERS) ||
1561167514Skmacy		    !in_range(t->rspq_size, MIN_RSPQ_ENTRIES, MAX_RSPQ_ENTRIES))
1562167514Skmacy		       return -EINVAL;
1563167514Skmacy		if ((sc->flags & FULL_INIT_DONE) &&
1564167514Skmacy		    (t->rspq_size >= 0 || t->fl_size[0] >= 0 ||
1565167514Skmacy		     t->fl_size[1] >= 0 || t->txq_size[0] >= 0 ||
1566167514Skmacy		     t->txq_size[1] >= 0 || t->txq_size[2] >= 0 ||
1567167514Skmacy		     t->polling >= 0 || t->cong_thres >= 0))
1568167514Skmacy			return -EBUSY;
1569167514Skmacy
1570167514Skmacy		q = &sc->params.sge.qset[t->qset_idx];
1571167514Skmacy
1572167514Skmacy		if (t->rspq_size >= 0)
1573167514Skmacy			q->rspq_size = t->rspq_size;
1574167514Skmacy		if (t->fl_size[0] >= 0)
1575167514Skmacy			q->fl_size = t->fl_size[0];
1576167514Skmacy		if (t->fl_size[1] >= 0)
1577167514Skmacy			q->jumbo_size = t->fl_size[1];
1578167514Skmacy		if (t->txq_size[0] >= 0)
1579167514Skmacy			q->txq_size[0] = t->txq_size[0];
1580167514Skmacy		if (t->txq_size[1] >= 0)
1581167514Skmacy			q->txq_size[1] = t->txq_size[1];
1582167514Skmacy		if (t->txq_size[2] >= 0)
1583167514Skmacy			q->txq_size[2] = t->txq_size[2];
1584167514Skmacy		if (t->cong_thres >= 0)
1585167514Skmacy			q->cong_thres = t->cong_thres;
1586167514Skmacy		if (t->intr_lat >= 0) {
1587167514Skmacy			struct sge_qset *qs = &sc->sge.qs[t->qset_idx];
1588167514Skmacy
1589167514Skmacy			q->coalesce_nsecs = t->intr_lat*1000;
1590167514Skmacy			t3_update_qset_coalesce(qs, q);
1591167514Skmacy		}
1592167514Skmacy		break;
1593167514Skmacy	}
1594167514Skmacy	case CHELSIO_GET_QSET_PARAMS: {
1595167514Skmacy		struct qset_params *q;
1596167514Skmacy		struct ch_qset_params *t = (struct ch_qset_params *)data;
1597167514Skmacy
1598167514Skmacy		if (t->qset_idx >= SGE_QSETS)
1599167514Skmacy			return (EINVAL);
1600167514Skmacy
1601167514Skmacy		q = &(sc)->params.sge.qset[t->qset_idx];
1602167514Skmacy		t->rspq_size   = q->rspq_size;
1603167514Skmacy		t->txq_size[0] = q->txq_size[0];
1604167514Skmacy		t->txq_size[1] = q->txq_size[1];
1605167514Skmacy		t->txq_size[2] = q->txq_size[2];
1606167514Skmacy		t->fl_size[0]  = q->fl_size;
1607167514Skmacy		t->fl_size[1]  = q->jumbo_size;
1608167514Skmacy		t->polling     = q->polling;
1609167514Skmacy		t->intr_lat    = q->coalesce_nsecs / 1000;
1610167514Skmacy		t->cong_thres  = q->cong_thres;
1611167514Skmacy		break;
1612167514Skmacy	}
1613167514Skmacy	case CHELSIO_SET_QSET_NUM: {
1614167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
1615167514Skmacy		unsigned int port_idx = pi->port;
1616167514Skmacy
1617167514Skmacy		if (sc->flags & FULL_INIT_DONE)
1618167514Skmacy			return (EBUSY);
1619167514Skmacy		if (edata->val < 1 ||
1620167514Skmacy		    (edata->val > 1 && !(sc->flags & USING_MSIX)))
1621167514Skmacy			return (EINVAL);
1622167514Skmacy		if (edata->val + sc->port[!port_idx].nqsets > SGE_QSETS)
1623167514Skmacy			return (EINVAL);
1624167514Skmacy		sc->port[port_idx].nqsets = edata->val;
1625167514Skmacy		/*
1626167514Skmacy		 * XXX we're hardcoding ourselves to 2 ports
1627167514Skmacy		 * just like the LEENUX
1628167514Skmacy		 */
1629167514Skmacy		sc->port[1].first_qset = sc->port[0].nqsets;
1630167514Skmacy		break;
1631167514Skmacy	}
1632167514Skmacy	case CHELSIO_GET_QSET_NUM: {
1633167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
1634167514Skmacy		edata->val = pi->nqsets;
1635167514Skmacy		break;
1636167514Skmacy	}
1637167514Skmacy#ifdef notyet
1638167514Skmacy		/*
1639167514Skmacy		 * XXX FreeBSD driver does not currently support any
1640167514Skmacy		 * offload functionality
1641167514Skmacy		 */
1642167514Skmacy	case CHELSIO_LOAD_FW:
1643167514Skmacy	case CHELSIO_DEVUP:
1644167514Skmacy	case CHELSIO_SETMTUTAB:
1645167514Skmacy	case CHELSIO_GET_PM:
1646167514Skmacy	case CHELSIO_SET_PM:
1647167514Skmacy	case CHELSIO_READ_TCAM_WORD:
1648167514Skmacy		return (EOPNOTSUPP);
1649167514Skmacy		break;
1650167514Skmacy#endif
1651167514Skmacy	case CHELSIO_GET_MEM: {
1652167514Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
1653167514Skmacy		struct mc7 *mem;
1654167514Skmacy		uint8_t *useraddr;
1655167514Skmacy		u64 buf[32];
1656167514Skmacy
1657167514Skmacy		if (!is_offload(sc))
1658167514Skmacy			return (EOPNOTSUPP);
1659167514Skmacy		if (!(sc->flags & FULL_INIT_DONE))
1660167514Skmacy			return (EIO);         /* need the memory controllers */
1661167514Skmacy		if ((t->addr & 0x7) || (t->len & 0x7))
1662167514Skmacy			return (EINVAL);
1663167514Skmacy		if (t->mem_id == MEM_CM)
1664167514Skmacy			mem = &sc->cm;
1665167514Skmacy		else if (t->mem_id == MEM_PMRX)
1666167514Skmacy			mem = &sc->pmrx;
1667167514Skmacy		else if (t->mem_id == MEM_PMTX)
1668167514Skmacy			mem = &sc->pmtx;
1669167514Skmacy		else
1670167514Skmacy			return (EINVAL);
1671167514Skmacy
1672167514Skmacy		/*
1673167514Skmacy		 * Version scheme:
1674167514Skmacy		 * bits 0..9: chip version
1675167514Skmacy		 * bits 10..15: chip revision
1676167514Skmacy		 */
1677167514Skmacy		t->version = 3 | (sc->params.rev << 10);
1678167514Skmacy
1679167514Skmacy		/*
1680167514Skmacy		 * Read 256 bytes at a time as len can be large and we don't
1681167514Skmacy		 * want to use huge intermediate buffers.
1682167514Skmacy		 */
1683167514Skmacy		useraddr = (uint8_t *)(t + 1);   /* advance to start of buffer */
1684167514Skmacy		while (t->len) {
1685167514Skmacy			unsigned int chunk = min(t->len, sizeof(buf));
1686167514Skmacy
1687167514Skmacy			error = t3_mc7_bd_read(mem, t->addr / 8, chunk / 8, buf);
1688167514Skmacy			if (error)
1689167514Skmacy				return (-error);
1690167514Skmacy			if (copyout(buf, useraddr, chunk))
1691167514Skmacy				return (EFAULT);
1692167514Skmacy			useraddr += chunk;
1693167514Skmacy			t->addr += chunk;
1694167514Skmacy			t->len -= chunk;
1695167514Skmacy		}
1696167514Skmacy		break;
1697167514Skmacy	}
1698167514Skmacy	case CHELSIO_SET_TRACE_FILTER: {
1699167514Skmacy		struct ch_trace *t = (struct ch_trace *)data;
1700167514Skmacy		const struct trace_params *tp;
1701167514Skmacy
1702167514Skmacy		tp = (const struct trace_params *)&t->sip;
1703167514Skmacy		if (t->config_tx)
1704167514Skmacy			t3_config_trace_filter(sc, tp, 0, t->invert_match,
1705167514Skmacy					       t->trace_tx);
1706167514Skmacy		if (t->config_rx)
1707167514Skmacy			t3_config_trace_filter(sc, tp, 1, t->invert_match,
1708167514Skmacy					       t->trace_rx);
1709167514Skmacy		break;
1710167514Skmacy	}
1711167514Skmacy	case CHELSIO_SET_PKTSCHED: {
1712167514Skmacy		struct ch_pktsched_params *p = (struct ch_pktsched_params *)data;
1713167514Skmacy		if (sc->open_device_map == 0)
1714167514Skmacy			return (EAGAIN);
1715167514Skmacy		send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max,
1716167514Skmacy		    p->binding);
1717167514Skmacy		break;
1718167514Skmacy	}
1719167514Skmacy	case CHELSIO_IFCONF_GETREGS: {
1720167514Skmacy		struct ifconf_regs *regs = (struct ifconf_regs *)data;
1721167514Skmacy		int reglen = cxgb_get_regs_len();
1722167514Skmacy		uint8_t *buf = malloc(REGDUMP_SIZE, M_DEVBUF, M_NOWAIT);
1723167514Skmacy		if (buf == NULL) {
1724167514Skmacy			return (ENOMEM);
1725167514Skmacy		} if (regs->len > reglen)
1726167514Skmacy			regs->len = reglen;
1727167514Skmacy		else if (regs->len < reglen) {
1728167514Skmacy			error = E2BIG;
1729167514Skmacy			goto done;
1730167514Skmacy		}
1731167514Skmacy		cxgb_get_regs(sc, regs, buf);
1732167514Skmacy		error = copyout(buf, regs->data, reglen);
1733167514Skmacy
1734167514Skmacy		done:
1735167514Skmacy		free(buf, M_DEVBUF);
1736167514Skmacy
1737167514Skmacy		break;
1738167514Skmacy	}
1739167514Skmacy	default:
1740167514Skmacy		return (EOPNOTSUPP);
1741167514Skmacy		break;
1742167514Skmacy	}
1743167514Skmacy
1744167514Skmacy	return (error);
1745167514Skmacy}
1746167514Skmacy
1747167514Skmacystatic __inline void
1748167514Skmacyreg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
1749167514Skmacy    unsigned int end)
1750167514Skmacy{
1751167514Skmacy	uint32_t *p = (uint32_t *)buf + start;
1752167514Skmacy
1753167514Skmacy	for ( ; start <= end; start += sizeof(uint32_t))
1754167514Skmacy		*p++ = t3_read_reg(ap, start);
1755167514Skmacy}
1756167514Skmacy
1757167514Skmacy#define T3_REGMAP_SIZE (3 * 1024)
1758167514Skmacystatic int
1759167514Skmacycxgb_get_regs_len(void)
1760167514Skmacy{
1761167514Skmacy	return T3_REGMAP_SIZE;
1762167514Skmacy}
1763167514Skmacy#undef T3_REGMAP_SIZE
1764167514Skmacy
1765167514Skmacystatic void
1766167514Skmacycxgb_get_regs(adapter_t *sc, struct ifconf_regs *regs, uint8_t *buf)
1767167514Skmacy{
1768167514Skmacy
1769167514Skmacy	/*
1770167514Skmacy	 * Version scheme:
1771167514Skmacy	 * bits 0..9: chip version
1772167514Skmacy	 * bits 10..15: chip revision
1773167514Skmacy	 * bit 31: set for PCIe cards
1774167514Skmacy	 */
1775167514Skmacy	regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31);
1776167514Skmacy
1777167514Skmacy	/*
1778167514Skmacy	 * We skip the MAC statistics registers because they are clear-on-read.
1779167514Skmacy	 * Also reading multi-register stats would need to synchronize with the
1780167514Skmacy	 * periodic mac stats accumulation.  Hard to justify the complexity.
1781167514Skmacy	 */
1782167514Skmacy	memset(buf, 0, REGDUMP_SIZE);
1783167514Skmacy	reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
1784167514Skmacy	reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
1785167514Skmacy	reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
1786167514Skmacy	reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
1787167514Skmacy	reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
1788167514Skmacy	reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0,
1789167514Skmacy		       XGM_REG(A_XGM_SERDES_STAT3, 1));
1790167514Skmacy	reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
1791167514Skmacy		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
1792167514Skmacy}
1793