t4_main.c revision 227843
1218792Snp/*-
2218792Snp * Copyright (c) 2011 Chelsio Communications, Inc.
3218792Snp * All rights reserved.
4218792Snp * Written by: Navdeep Parhar <np@FreeBSD.org>
5218792Snp *
6218792Snp * Redistribution and use in source and binary forms, with or without
7218792Snp * modification, are permitted provided that the following conditions
8218792Snp * are met:
9218792Snp * 1. Redistributions of source code must retain the above copyright
10218792Snp *    notice, this list of conditions and the following disclaimer.
11218792Snp * 2. Redistributions in binary form must reproduce the above copyright
12218792Snp *    notice, this list of conditions and the following disclaimer in the
13218792Snp *    documentation and/or other materials provided with the distribution.
14218792Snp *
15218792Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16218792Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17218792Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18218792Snp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19218792Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20218792Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21218792Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22218792Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23218792Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24218792Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25218792Snp * SUCH DAMAGE.
26218792Snp */
27218792Snp
28218792Snp#include <sys/cdefs.h>
29218792Snp__FBSDID("$FreeBSD: head/sys/dev/cxgbe/t4_main.c 227843 2011-11-22 21:28:20Z marius $");
30218792Snp
31218792Snp#include "opt_inet.h"
32218792Snp
33218792Snp#include <sys/param.h>
34218792Snp#include <sys/conf.h>
35218792Snp#include <sys/priv.h>
36218792Snp#include <sys/kernel.h>
37218792Snp#include <sys/bus.h>
38218792Snp#include <sys/module.h>
39219286Snp#include <sys/malloc.h>
40219286Snp#include <sys/queue.h>
41219286Snp#include <sys/taskqueue.h>
42218792Snp#include <sys/pciio.h>
43218792Snp#include <dev/pci/pcireg.h>
44218792Snp#include <dev/pci/pcivar.h>
45218792Snp#include <dev/pci/pci_private.h>
46218792Snp#include <sys/firmware.h>
47219436Snp#include <sys/sbuf.h>
48218792Snp#include <sys/smp.h>
49218792Snp#include <sys/socket.h>
50218792Snp#include <sys/sockio.h>
51218792Snp#include <sys/sysctl.h>
52218792Snp#include <net/ethernet.h>
53218792Snp#include <net/if.h>
54218792Snp#include <net/if_types.h>
55218792Snp#include <net/if_dl.h>
56222003Snp#include <net/if_vlan_var.h>
57218792Snp
58218792Snp#include "common/t4_hw.h"
59218792Snp#include "common/common.h"
60221474Snp#include "common/t4_msg.h"
61218792Snp#include "common/t4_regs.h"
62218792Snp#include "common/t4_regs_values.h"
63218792Snp#include "common/t4fw_interface.h"
64218792Snp#include "t4_ioctl.h"
65222509Snp#include "t4_l2t.h"
66218792Snp
67218792Snp/* T4 bus driver interface */
68218792Snpstatic int t4_probe(device_t);
69218792Snpstatic int t4_attach(device_t);
70218792Snpstatic int t4_detach(device_t);
71218792Snpstatic device_method_t t4_methods[] = {
72218792Snp	DEVMETHOD(device_probe,		t4_probe),
73218792Snp	DEVMETHOD(device_attach,	t4_attach),
74218792Snp	DEVMETHOD(device_detach,	t4_detach),
75218792Snp
76227843Smarius	DEVMETHOD_END
77218792Snp};
78218792Snpstatic driver_t t4_driver = {
79218792Snp	"t4nex",
80218792Snp	t4_methods,
81218792Snp	sizeof(struct adapter)
82218792Snp};
83218792Snp
84218792Snp
85218792Snp/* T4 port (cxgbe) interface */
86218792Snpstatic int cxgbe_probe(device_t);
87218792Snpstatic int cxgbe_attach(device_t);
88218792Snpstatic int cxgbe_detach(device_t);
89218792Snpstatic device_method_t cxgbe_methods[] = {
90218792Snp	DEVMETHOD(device_probe,		cxgbe_probe),
91218792Snp	DEVMETHOD(device_attach,	cxgbe_attach),
92218792Snp	DEVMETHOD(device_detach,	cxgbe_detach),
93218792Snp	{ 0, 0 }
94218792Snp};
95218792Snpstatic driver_t cxgbe_driver = {
96218792Snp	"cxgbe",
97218792Snp	cxgbe_methods,
98218792Snp	sizeof(struct port_info)
99218792Snp};
100218792Snp
101218792Snpstatic d_ioctl_t t4_ioctl;
102218792Snpstatic d_open_t t4_open;
103218792Snpstatic d_close_t t4_close;
104218792Snp
105218792Snpstatic struct cdevsw t4_cdevsw = {
106218792Snp       .d_version = D_VERSION,
107218792Snp       .d_flags = 0,
108218792Snp       .d_open = t4_open,
109218792Snp       .d_close = t4_close,
110218792Snp       .d_ioctl = t4_ioctl,
111218792Snp       .d_name = "t4nex",
112218792Snp};
113218792Snp
114218792Snp/* ifnet + media interface */
115218792Snpstatic void cxgbe_init(void *);
116218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t);
117218792Snpstatic void cxgbe_start(struct ifnet *);
118218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *);
119218792Snpstatic void cxgbe_qflush(struct ifnet *);
120218792Snpstatic int cxgbe_media_change(struct ifnet *);
121218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *);
122218792Snp
123218792SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4 Ethernet driver and services");
124218792Snp
125218792Snp/*
126218792Snp * Tunables.
127218792Snp */
128227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, cxgbe, CTLFLAG_RD, 0,
129227309Sed    "cxgbe driver parameters");
130218792Snp
131218792Snpstatic int force_firmware_install = 0;
132218792SnpTUNABLE_INT("hw.cxgbe.force_firmware_install", &force_firmware_install);
133218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, force_firmware_install, CTLFLAG_RDTUN,
134218792Snp    &force_firmware_install, 0, "install firmware on every attach.");
135218792Snp
136218792Snp/*
137218792Snp * Holdoff timer and packet counter values.
138218792Snp */
139218792Snpstatic unsigned int intr_timer[SGE_NTIMERS] = {1, 5, 10, 50, 100, 200};
140218792Snpstatic unsigned int intr_pktcount[SGE_NCOUNTERS] = {1, 8, 16, 32}; /* 63 max */
141218792Snp
142218792Snp/*
143218792Snp * Max # of tx and rx queues to use for each 10G and 1G port.
144218792Snp */
145218792Snpstatic unsigned int max_ntxq_10g = 8;
146218792SnpTUNABLE_INT("hw.cxgbe.max_ntxq_10G_port", &max_ntxq_10g);
147218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_ntxq_10G_port, CTLFLAG_RDTUN,
148218792Snp    &max_ntxq_10g, 0, "maximum number of tx queues per 10G port.");
149218792Snp
150218792Snpstatic unsigned int max_nrxq_10g = 8;
151218792SnpTUNABLE_INT("hw.cxgbe.max_nrxq_10G_port", &max_nrxq_10g);
152218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_nrxq_10G_port, CTLFLAG_RDTUN,
153218792Snp    &max_nrxq_10g, 0, "maximum number of rxq's (per 10G port).");
154218792Snp
155218792Snpstatic unsigned int max_ntxq_1g = 2;
156218792SnpTUNABLE_INT("hw.cxgbe.max_ntxq_1G_port", &max_ntxq_1g);
157218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_ntxq_1G_port, CTLFLAG_RDTUN,
158218792Snp    &max_ntxq_1g, 0, "maximum number of tx queues per 1G port.");
159218792Snp
160218792Snpstatic unsigned int max_nrxq_1g = 2;
161218792SnpTUNABLE_INT("hw.cxgbe.max_nrxq_1G_port", &max_nrxq_1g);
162218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_nrxq_1G_port, CTLFLAG_RDTUN,
163218792Snp    &max_nrxq_1g, 0, "maximum number of rxq's (per 1G port).");
164218792Snp
165218792Snp/*
166218792Snp * Holdoff parameters for 10G and 1G ports.
167218792Snp */
168218792Snpstatic unsigned int tmr_idx_10g = 1;
169218792SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &tmr_idx_10g);
170218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_timer_idx_10G, CTLFLAG_RDTUN,
171218792Snp    &tmr_idx_10g, 0,
172218792Snp    "default timer index for interrupt holdoff (10G ports).");
173218792Snp
174218792Snpstatic int pktc_idx_10g = 2;
175218792SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &pktc_idx_10g);
176218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_pktc_idx_10G, CTLFLAG_RDTUN,
177218792Snp    &pktc_idx_10g, 0,
178218792Snp    "default pkt counter index for interrupt holdoff (10G ports).");
179218792Snp
180218792Snpstatic unsigned int tmr_idx_1g = 1;
181218792SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &tmr_idx_1g);
182218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_timer_idx_1G, CTLFLAG_RDTUN,
183218792Snp    &tmr_idx_1g, 0,
184218792Snp    "default timer index for interrupt holdoff (1G ports).");
185218792Snp
186218792Snpstatic int pktc_idx_1g = 2;
187218792SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &pktc_idx_1g);
188218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_pktc_idx_1G, CTLFLAG_RDTUN,
189218792Snp    &pktc_idx_1g, 0,
190218792Snp    "default pkt counter index for interrupt holdoff (1G ports).");
191218792Snp
192218792Snp/*
193218792Snp * Size (# of entries) of each tx and rx queue.
194218792Snp */
195218792Snpstatic unsigned int qsize_txq = TX_EQ_QSIZE;
196218792SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &qsize_txq);
197218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, qsize_txq, CTLFLAG_RDTUN,
198218792Snp    &qsize_txq, 0, "default queue size of NIC tx queues.");
199218792Snp
200218792Snpstatic unsigned int qsize_rxq = RX_IQ_QSIZE;
201218792SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &qsize_rxq);
202218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, qsize_rxq, CTLFLAG_RDTUN,
203218792Snp    &qsize_rxq, 0, "default queue size of NIC rx queues.");
204218792Snp
205218792Snp/*
206218792Snp * Interrupt types allowed.
207218792Snp */
208219944Snpstatic int intr_types = INTR_MSIX | INTR_MSI | INTR_INTX;
209218792SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &intr_types);
210218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_types, CTLFLAG_RDTUN, &intr_types, 0,
211218792Snp    "interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively)");
212218792Snp
213218792Snp/*
214222510Snp * Force the driver to use the same set of interrupts for all ports.
215218792Snp */
216222510Snpstatic int intr_shared = 0;
217222510SnpTUNABLE_INT("hw.cxgbe.interrupts_shared", &intr_shared);
218222510SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupts_shared, CTLFLAG_RDTUN,
219222510Snp    &intr_shared, 0, "interrupts shared between all ports");
220218792Snp
221221474Snpstatic unsigned int filter_mode = HW_TPL_FR_MT_PR_IV_P_FC;
222221474SnpTUNABLE_INT("hw.cxgbe.filter_mode", &filter_mode);
223221474SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, filter_mode, CTLFLAG_RDTUN,
224221474Snp    &filter_mode, 0, "default global filter mode.");
225221474Snp
226218792Snpstruct intrs_and_queues {
227219944Snp	int intr_type;		/* INTx, MSI, or MSI-X */
228218792Snp	int nirq;		/* Number of vectors */
229222510Snp	int intr_shared;	/* Interrupts shared between all ports */
230218792Snp	int ntxq10g;		/* # of NIC txq's for each 10G port */
231218792Snp	int nrxq10g;		/* # of NIC rxq's for each 10G port */
232218792Snp	int ntxq1g;		/* # of NIC txq's for each 1G port */
233218792Snp	int nrxq1g;		/* # of NIC rxq's for each 1G port */
234218792Snp};
235218792Snp
236221474Snpstruct filter_entry {
237221474Snp        uint32_t valid:1;	/* filter allocated and valid */
238221474Snp        uint32_t locked:1;	/* filter is administratively locked */
239221474Snp        uint32_t pending:1;	/* filter action is pending firmware reply */
240221474Snp	uint32_t smtidx:8;	/* Source MAC Table index for smac */
241222509Snp	struct l2t_entry *l2t;	/* Layer Two Table entry for dmac */
242221474Snp
243221474Snp        struct t4_filter_specification fs;
244221474Snp};
245221474Snp
246218792Snpenum {
247218792Snp	MEMWIN0_APERTURE = 2048,
248218792Snp	MEMWIN0_BASE     = 0x1b800,
249218792Snp	MEMWIN1_APERTURE = 32768,
250218792Snp	MEMWIN1_BASE     = 0x28000,
251218792Snp	MEMWIN2_APERTURE = 65536,
252218792Snp	MEMWIN2_BASE     = 0x30000,
253218792Snp};
254218792Snp
255218792Snpenum {
256218792Snp	XGMAC_MTU	= (1 << 0),
257218792Snp	XGMAC_PROMISC	= (1 << 1),
258218792Snp	XGMAC_ALLMULTI	= (1 << 2),
259218792Snp	XGMAC_VLANEX	= (1 << 3),
260218792Snp	XGMAC_UCADDR	= (1 << 4),
261218792Snp	XGMAC_MCADDRS	= (1 << 5),
262218792Snp
263218792Snp	XGMAC_ALL	= 0xffff
264218792Snp};
265218792Snp
266218792Snpstatic int map_bars(struct adapter *);
267218792Snpstatic void setup_memwin(struct adapter *);
268218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int,
269218792Snp    struct intrs_and_queues *);
270218792Snpstatic int prep_firmware(struct adapter *);
271222551Snpstatic int get_devlog_params(struct adapter *, struct devlog_params *);
272218792Snpstatic int get_capabilities(struct adapter *, struct fw_caps_config_cmd *);
273218792Snpstatic int get_params(struct adapter *, struct fw_caps_config_cmd *);
274218792Snpstatic void t4_set_desc(struct adapter *);
275218792Snpstatic void build_medialist(struct port_info *);
276218792Snpstatic int update_mac_settings(struct port_info *, int);
277218792Snpstatic int cxgbe_init_locked(struct port_info *);
278218792Snpstatic int cxgbe_init_synchronized(struct port_info *);
279218792Snpstatic int cxgbe_uninit_locked(struct port_info *);
280218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *);
281218792Snpstatic int first_port_up(struct adapter *);
282218792Snpstatic int last_port_down(struct adapter *);
283218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid,
284218792Snp    iq_intr_handler_t *, void *, char *);
285218792Snpstatic int t4_free_irq(struct adapter *, struct irq *);
286218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int,
287218792Snp    unsigned int);
288218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *);
289218792Snpstatic void cxgbe_tick(void *);
290218792Snpstatic int t4_sysctls(struct adapter *);
291218792Snpstatic int cxgbe_sysctls(struct port_info *);
292219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS);
293218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS);
294218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS);
295218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS);
296218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS);
297218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS);
298222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS);
299219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *);
300221474Snpstatic uint32_t fconf_to_mode(uint32_t);
301221474Snpstatic uint32_t mode_to_fconf(uint32_t);
302221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *);
303221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *);
304221474Snpstatic int set_filter_mode(struct adapter *, uint32_t);
305222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t);
306221474Snpstatic int get_filter(struct adapter *, struct t4_filter *);
307221474Snpstatic int set_filter(struct adapter *, struct t4_filter *);
308221474Snpstatic int del_filter(struct adapter *, struct t4_filter *);
309222509Snpstatic void clear_filter(struct filter_entry *);
310221474Snpstatic int set_filter_wr(struct adapter *, int);
311221474Snpstatic int del_filter_wr(struct adapter *, int);
312221474Snpvoid filter_rpl(struct adapter *, const struct cpl_set_tcb_rpl *);
313222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *);
314219392Snpstatic int t4_mod_event(module_t, int, void *);
315218792Snp
316218792Snpstruct t4_pciids {
317218792Snp	uint16_t device;
318218792Snp	uint8_t mpf;
319218792Snp	char *desc;
320218792Snp} t4_pciids[] = {
321218792Snp	{0xa000, 0, "Chelsio Terminator 4 FPGA"},
322218792Snp	{0x4400, 4, "Chelsio T440-dbg"},
323218792Snp	{0x4401, 4, "Chelsio T420-CR"},
324218792Snp	{0x4402, 4, "Chelsio T422-CR"},
325218792Snp	{0x4403, 4, "Chelsio T440-CR"},
326218792Snp	{0x4404, 4, "Chelsio T420-BCH"},
327218792Snp	{0x4405, 4, "Chelsio T440-BCH"},
328218792Snp	{0x4406, 4, "Chelsio T440-CH"},
329218792Snp	{0x4407, 4, "Chelsio T420-SO"},
330218792Snp	{0x4408, 4, "Chelsio T420-CX"},
331218792Snp	{0x4409, 4, "Chelsio T420-BT"},
332218792Snp	{0x440a, 4, "Chelsio T404-BT"},
333218792Snp};
334218792Snp
335218792Snpstatic int
336218792Snpt4_probe(device_t dev)
337218792Snp{
338218792Snp	int i;
339218792Snp	uint16_t v = pci_get_vendor(dev);
340218792Snp	uint16_t d = pci_get_device(dev);
341218792Snp
342218792Snp	if (v != PCI_VENDOR_ID_CHELSIO)
343218792Snp		return (ENXIO);
344218792Snp
345218792Snp	for (i = 0; i < ARRAY_SIZE(t4_pciids); i++) {
346218792Snp		if (d == t4_pciids[i].device &&
347218792Snp		    pci_get_function(dev) == t4_pciids[i].mpf) {
348218792Snp			device_set_desc(dev, t4_pciids[i].desc);
349218792Snp			return (BUS_PROBE_DEFAULT);
350218792Snp		}
351218792Snp	}
352218792Snp
353218792Snp	return (ENXIO);
354218792Snp}
355218792Snp
356218792Snpstatic int
357218792Snpt4_attach(device_t dev)
358218792Snp{
359218792Snp	struct adapter *sc;
360218792Snp	int rc = 0, i, n10g, n1g, rqidx, tqidx;
361218792Snp	struct fw_caps_config_cmd caps;
362218792Snp	uint32_t p, v;
363218792Snp	struct intrs_and_queues iaq;
364218792Snp	struct sge *s;
365218792Snp
366218792Snp	sc = device_get_softc(dev);
367218792Snp	sc->dev = dev;
368218792Snp	sc->pf = pci_get_function(dev);
369218792Snp	sc->mbox = sc->pf;
370218792Snp
371218792Snp	pci_enable_busmaster(dev);
372222085Snp	if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) {
373222085Snp		pci_set_max_read_req(dev, 4096);
374222085Snp		v = pci_read_config(dev, i + PCIR_EXPRESS_DEVICE_CTL, 2);
375222085Snp		v |= PCIM_EXP_CTL_RELAXED_ORD_ENABLE;
376222085Snp		pci_write_config(dev, i + PCIR_EXPRESS_DEVICE_CTL, v, 2);
377222085Snp	}
378222085Snp
379218792Snp	snprintf(sc->lockname, sizeof(sc->lockname), "%s",
380218792Snp	    device_get_nameunit(dev));
381218792Snp	mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF);
382218792Snp
383218792Snp	rc = map_bars(sc);
384218792Snp	if (rc != 0)
385218792Snp		goto done; /* error message displayed already */
386218792Snp
387218792Snp	memset(sc->chan_map, 0xff, sizeof(sc->chan_map));
388218792Snp
389218792Snp	/* Prepare the adapter for operation */
390218792Snp	rc = -t4_prep_adapter(sc);
391218792Snp	if (rc != 0) {
392218792Snp		device_printf(dev, "failed to prepare adapter: %d.\n", rc);
393218792Snp		goto done;
394218792Snp	}
395218792Snp
396218792Snp	/* Do this really early */
397218792Snp	sc->cdev = make_dev(&t4_cdevsw, device_get_unit(dev), UID_ROOT,
398218792Snp	    GID_WHEEL, 0600, "%s", device_get_nameunit(dev));
399218792Snp	sc->cdev->si_drv1 = sc;
400218792Snp
401218792Snp	/* Prepare the firmware for operation */
402218792Snp	rc = prep_firmware(sc);
403218792Snp	if (rc != 0)
404218792Snp		goto done; /* error message displayed already */
405218792Snp
406222551Snp	/* Read firmware devlog parameters */
407222551Snp	(void) get_devlog_params(sc, &sc->params.devlog);
408222551Snp
409218792Snp	/* Get device capabilities and select which ones we'll use */
410218792Snp	rc = get_capabilities(sc, &caps);
411218792Snp	if (rc != 0) {
412218792Snp		device_printf(dev,
413218792Snp		    "failed to initialize adapter capabilities: %d.\n", rc);
414218792Snp		goto done;
415218792Snp	}
416218792Snp
417218792Snp	/* Choose the global RSS mode. */
418218792Snp	rc = -t4_config_glbl_rss(sc, sc->mbox,
419218792Snp	    FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
420218792Snp	    F_FW_RSS_GLB_CONFIG_CMD_TNLMAPEN |
421220874Snp	    F_FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ |
422218792Snp	    F_FW_RSS_GLB_CONFIG_CMD_TNLALLLKP);
423218792Snp	if (rc != 0) {
424218792Snp		device_printf(dev,
425218792Snp		    "failed to select global RSS mode: %d.\n", rc);
426218792Snp		goto done;
427218792Snp	}
428218792Snp
429218792Snp	/* These are total (sum of all ports) limits for a bus driver */
430218792Snp	rc = -t4_cfg_pfvf(sc, sc->mbox, sc->pf, 0,
431221516Snp	    128,	/* max # of egress queues */
432218792Snp	    64,		/* max # of egress Ethernet or control queues */
433218792Snp	    64,		/* max # of ingress queues with fl/interrupt */
434218792Snp	    0,		/* max # of ingress queues without interrupt */
435218792Snp	    0,		/* PCIe traffic class */
436218792Snp	    4,		/* max # of virtual interfaces */
437218792Snp	    M_FW_PFVF_CMD_CMASK, M_FW_PFVF_CMD_PMASK, 16,
438218792Snp	    FW_CMD_CAP_PF, FW_CMD_CAP_PF);
439218792Snp	if (rc != 0) {
440218792Snp		device_printf(dev,
441218792Snp		    "failed to configure pf/vf resources: %d.\n", rc);
442218792Snp		goto done;
443218792Snp	}
444218792Snp
445218792Snp	/* Need this before sge_init */
446218792Snp	for (i = 0; i < SGE_NTIMERS; i++)
447218792Snp		sc->sge.timer_val[i] = min(intr_timer[i], 200U);
448218792Snp	for (i = 0; i < SGE_NCOUNTERS; i++)
449218792Snp		sc->sge.counter_val[i] = min(intr_pktcount[i], M_THRESHOLD_0);
450218792Snp
451218792Snp	/* Also need the cooked value of cclk before sge_init */
452218792Snp	p = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
453218792Snp	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK));
454218792Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &p, &v);
455218792Snp	if (rc != 0) {
456218792Snp		device_printf(sc->dev,
457218792Snp		    "failed to obtain core clock value: %d.\n", rc);
458218792Snp		goto done;
459218792Snp	}
460218792Snp	sc->params.vpd.cclk = v;
461218792Snp
462218792Snp	t4_sge_init(sc);
463218792Snp
464221474Snp	t4_set_filter_mode(sc, filter_mode);
465221474Snp	t4_set_reg_field(sc, A_TP_GLOBAL_CONFIG,
466221474Snp	    V_FIVETUPLELOOKUP(M_FIVETUPLELOOKUP),
467221474Snp	    V_FIVETUPLELOOKUP(M_FIVETUPLELOOKUP));
468221474Snp	t4_tp_wr_bits_indirect(sc, A_TP_INGRESS_CONFIG, F_CSUM_HAS_PSEUDO_HDR,
469221474Snp	    F_LOOKUPEVERYPKT);
470218792Snp
471218792Snp	/* get basic stuff going */
472218792Snp	rc = -t4_early_init(sc, sc->mbox);
473218792Snp	if (rc != 0) {
474218792Snp		device_printf(dev, "early init failed: %d.\n", rc);
475218792Snp		goto done;
476218792Snp	}
477218792Snp
478218792Snp	rc = get_params(sc, &caps);
479218792Snp	if (rc != 0)
480218792Snp		goto done; /* error message displayed already */
481218792Snp
482218792Snp	/* These are finalized by FW initialization, load their values now */
483218792Snp	v = t4_read_reg(sc, A_TP_TIMER_RESOLUTION);
484218792Snp	sc->params.tp.tre = G_TIMERRESOLUTION(v);
485218792Snp	sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v);
486218792Snp	t4_read_mtu_tbl(sc, sc->params.mtus, NULL);
487218792Snp
488218792Snp	/* tweak some settings */
489218792Snp	t4_write_reg(sc, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | V_RXTSHIFTMAXR1(4) |
490218792Snp	    V_RXTSHIFTMAXR2(15) | V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
491218792Snp	    V_KEEPALIVEMAXR1(4) | V_KEEPALIVEMAXR2(9));
492218792Snp	t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
493222703Snp	t4_set_reg_field(sc, A_TP_PARA_REG3, F_TUNNELCNGDROP0 |
494222703Snp	    F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | F_TUNNELCNGDROP3, 0);
495218792Snp
496218792Snp	setup_memwin(sc);
497218792Snp
498218792Snp	rc = t4_create_dma_tag(sc);
499218792Snp	if (rc != 0)
500218792Snp		goto done; /* error message displayed already */
501218792Snp
502218792Snp	/*
503218792Snp	 * First pass over all the ports - allocate VIs and initialize some
504218792Snp	 * basic parameters like mac address, port type, etc.  We also figure
505218792Snp	 * out whether a port is 10G or 1G and use that information when
506218792Snp	 * calculating how many interrupts to attempt to allocate.
507218792Snp	 */
508218792Snp	n10g = n1g = 0;
509218792Snp	for_each_port(sc, i) {
510218792Snp		struct port_info *pi;
511218792Snp
512218792Snp		pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK);
513218792Snp		sc->port[i] = pi;
514218792Snp
515218792Snp		/* These must be set before t4_port_init */
516218792Snp		pi->adapter = sc;
517218792Snp		pi->port_id = i;
518218792Snp
519218792Snp		/* Allocate the vi and initialize parameters like mac addr */
520218792Snp		rc = -t4_port_init(pi, sc->mbox, sc->pf, 0);
521218792Snp		if (rc != 0) {
522218792Snp			device_printf(dev, "unable to initialize port %d: %d\n",
523218792Snp			    i, rc);
524218792Snp			free(pi, M_CXGBE);
525222510Snp			sc->port[i] = NULL;
526222510Snp			goto done;
527218792Snp		}
528218792Snp
529218792Snp		snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d",
530218792Snp		    device_get_nameunit(dev), i);
531218792Snp		mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
532218792Snp
533218792Snp		if (is_10G_port(pi)) {
534218792Snp			n10g++;
535218792Snp			pi->tmr_idx = tmr_idx_10g;
536218792Snp			pi->pktc_idx = pktc_idx_10g;
537218792Snp		} else {
538218792Snp			n1g++;
539218792Snp			pi->tmr_idx = tmr_idx_1g;
540218792Snp			pi->pktc_idx = pktc_idx_1g;
541218792Snp		}
542218792Snp
543218792Snp		pi->xact_addr_filt = -1;
544218792Snp
545218792Snp		pi->qsize_rxq = max(qsize_rxq, 128);
546218792Snp		while (pi->qsize_rxq & 7)
547218792Snp			pi->qsize_rxq++;
548218792Snp		pi->qsize_txq = max(qsize_txq, 128);
549218792Snp
550218792Snp		if (pi->qsize_rxq != qsize_rxq) {
551218792Snp			device_printf(dev,
552218792Snp			    "using %d instead of %d as the rx queue size.\n",
553218792Snp			    pi->qsize_rxq, qsize_rxq);
554218792Snp		}
555218792Snp		if (pi->qsize_txq != qsize_txq) {
556218792Snp			device_printf(dev,
557218792Snp			    "using %d instead of %d as the tx queue size.\n",
558218792Snp			    pi->qsize_txq, qsize_txq);
559218792Snp		}
560218792Snp
561218792Snp		pi->dev = device_add_child(dev, "cxgbe", -1);
562218792Snp		if (pi->dev == NULL) {
563218792Snp			device_printf(dev,
564218792Snp			    "failed to add device for port %d.\n", i);
565218792Snp			rc = ENXIO;
566218792Snp			goto done;
567218792Snp		}
568218792Snp		device_set_softc(pi->dev, pi);
569218792Snp
570218792Snp		setbit(&sc->registered_device_map, i);
571218792Snp	}
572218792Snp
573218792Snp	if (sc->registered_device_map == 0) {
574218792Snp		device_printf(dev, "no usable ports\n");
575218792Snp		rc = ENXIO;
576218792Snp		goto done;
577218792Snp	}
578218792Snp
579218792Snp	/*
580218792Snp	 * Interrupt type, # of interrupts, # of rx/tx queues, etc.
581218792Snp	 */
582218792Snp	rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq);
583218792Snp	if (rc != 0)
584218792Snp		goto done; /* error message displayed already */
585218792Snp
586218792Snp	sc->intr_type = iaq.intr_type;
587218792Snp	sc->intr_count = iaq.nirq;
588218792Snp
589218792Snp	s = &sc->sge;
590218792Snp	s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g;
591218792Snp	s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g;
592220873Snp	s->neq = s->ntxq + s->nrxq;	/* the free list in an rxq is an eq */
593222510Snp	s->neq += sc->params.nports;	/* control queues, 1 per port */
594218792Snp	s->niq = s->nrxq + 1;		/* 1 extra for firmware event queue */
595222510Snp	if (iaq.intr_shared)
596222510Snp		sc->flags |= INTR_SHARED;
597222510Snp	s->niq += NINTRQ(sc);		/* interrupt queues */
598222510Snp
599222510Snp	s->intrq = malloc(NINTRQ(sc) * sizeof(struct sge_iq), M_CXGBE,
600220873Snp	    M_ZERO | M_WAITOK);
601222510Snp	s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_ctrlq), M_CXGBE,
602222510Snp	    M_ZERO | M_WAITOK);
603218792Snp	s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE,
604218792Snp	    M_ZERO | M_WAITOK);
605218792Snp	s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE,
606218792Snp	    M_ZERO | M_WAITOK);
607218792Snp	s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE,
608218792Snp	    M_ZERO | M_WAITOK);
609218792Snp	s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE,
610218792Snp	    M_ZERO | M_WAITOK);
611218792Snp
612218792Snp	sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE,
613218792Snp	    M_ZERO | M_WAITOK);
614218792Snp
615222509Snp	sc->l2t = t4_init_l2t(M_WAITOK);
616222509Snp
617218792Snp	t4_sysctls(sc);
618218792Snp
619218792Snp	/*
620218792Snp	 * Second pass over the ports.  This time we know the number of rx and
621218792Snp	 * tx queues that each port should get.
622218792Snp	 */
623218792Snp	rqidx = tqidx = 0;
624218792Snp	for_each_port(sc, i) {
625218792Snp		struct port_info *pi = sc->port[i];
626218792Snp
627218792Snp		if (pi == NULL)
628218792Snp			continue;
629218792Snp
630218792Snp		pi->first_rxq = rqidx;
631218792Snp		pi->nrxq = is_10G_port(pi) ? iaq.nrxq10g : iaq.nrxq1g;
632218792Snp
633218792Snp		pi->first_txq = tqidx;
634218792Snp		pi->ntxq = is_10G_port(pi) ? iaq.ntxq10g : iaq.ntxq1g;
635218792Snp
636218792Snp		rqidx += pi->nrxq;
637218792Snp		tqidx += pi->ntxq;
638218792Snp	}
639218792Snp
640218792Snp	rc = bus_generic_attach(dev);
641218792Snp	if (rc != 0) {
642218792Snp		device_printf(dev,
643218792Snp		    "failed to attach all child ports: %d\n", rc);
644218792Snp		goto done;
645218792Snp	}
646218792Snp
647218792Snp#ifdef INVARIANTS
648218792Snp	device_printf(dev,
649218792Snp	    "%p, %d ports (0x%x), %d intr_type, %d intr_count\n",
650218792Snp	    sc, sc->params.nports, sc->params.portvec,
651218792Snp	    sc->intr_type, sc->intr_count);
652218792Snp#endif
653218792Snp	t4_set_desc(sc);
654218792Snp
655218792Snpdone:
656218792Snp	if (rc != 0)
657218792Snp		t4_detach(dev);
658218792Snp
659218792Snp	return (rc);
660218792Snp}
661218792Snp
662218792Snp/*
663218792Snp * Idempotent
664218792Snp */
665218792Snpstatic int
666218792Snpt4_detach(device_t dev)
667218792Snp{
668218792Snp	struct adapter *sc;
669218792Snp	struct port_info *pi;
670218792Snp	int i;
671218792Snp
672218792Snp	sc = device_get_softc(dev);
673218792Snp
674218792Snp	if (sc->cdev)
675218792Snp		destroy_dev(sc->cdev);
676218792Snp
677218792Snp	bus_generic_detach(dev);
678218792Snp	for (i = 0; i < MAX_NPORTS; i++) {
679218792Snp		pi = sc->port[i];
680218792Snp		if (pi) {
681218792Snp			t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid);
682218792Snp			if (pi->dev)
683218792Snp				device_delete_child(dev, pi->dev);
684218792Snp
685218792Snp			mtx_destroy(&pi->pi_lock);
686218792Snp			free(pi, M_CXGBE);
687218792Snp		}
688218792Snp	}
689218792Snp
690218792Snp	if (sc->flags & FW_OK)
691218792Snp		t4_fw_bye(sc, sc->mbox);
692218792Snp
693219944Snp	if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX)
694218792Snp		pci_release_msi(dev);
695218792Snp
696218792Snp	if (sc->regs_res)
697218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid,
698218792Snp		    sc->regs_res);
699218792Snp
700218792Snp	if (sc->msix_res)
701218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid,
702218792Snp		    sc->msix_res);
703218792Snp
704222509Snp	if (sc->l2t)
705222509Snp		t4_free_l2t(sc->l2t);
706222509Snp
707218792Snp	free(sc->irq, M_CXGBE);
708218792Snp	free(sc->sge.rxq, M_CXGBE);
709218792Snp	free(sc->sge.txq, M_CXGBE);
710220873Snp	free(sc->sge.ctrlq, M_CXGBE);
711222510Snp	free(sc->sge.intrq, M_CXGBE);
712218792Snp	free(sc->sge.iqmap, M_CXGBE);
713218792Snp	free(sc->sge.eqmap, M_CXGBE);
714221474Snp	free(sc->tids.ftid_tab, M_CXGBE);
715218792Snp	t4_destroy_dma_tag(sc);
716218792Snp	mtx_destroy(&sc->sc_lock);
717218792Snp
718218792Snp	bzero(sc, sizeof(*sc));
719218792Snp
720218792Snp	return (0);
721218792Snp}
722218792Snp
723218792Snp
724218792Snpstatic int
725218792Snpcxgbe_probe(device_t dev)
726218792Snp{
727218792Snp	char buf[128];
728218792Snp	struct port_info *pi = device_get_softc(dev);
729218792Snp
730218792Snp	snprintf(buf, sizeof(buf), "Port %d", pi->port_id);
731218792Snp	device_set_desc_copy(dev, buf);
732218792Snp
733218792Snp	return (BUS_PROBE_DEFAULT);
734218792Snp}
735218792Snp
736218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \
737218792Snp    IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \
738218792Snp    IFCAP_VLAN_HWTSO)
739218792Snp#define T4_CAP_ENABLE (T4_CAP & ~IFCAP_TSO6)
740218792Snp
741218792Snpstatic int
742218792Snpcxgbe_attach(device_t dev)
743218792Snp{
744218792Snp	struct port_info *pi = device_get_softc(dev);
745218792Snp	struct ifnet *ifp;
746218792Snp
747218792Snp	/* Allocate an ifnet and set it up */
748218792Snp	ifp = if_alloc(IFT_ETHER);
749218792Snp	if (ifp == NULL) {
750218792Snp		device_printf(dev, "Cannot allocate ifnet\n");
751218792Snp		return (ENOMEM);
752218792Snp	}
753218792Snp	pi->ifp = ifp;
754218792Snp	ifp->if_softc = pi;
755218792Snp
756218792Snp	callout_init(&pi->tick, CALLOUT_MPSAFE);
757219286Snp	pi->tq = taskqueue_create("cxgbe_taskq", M_NOWAIT,
758219286Snp	    taskqueue_thread_enqueue, &pi->tq);
759219286Snp	if (pi->tq == NULL) {
760219286Snp		device_printf(dev, "failed to allocate port task queue\n");
761219286Snp		if_free(pi->ifp);
762219286Snp		return (ENOMEM);
763219286Snp	}
764219286Snp	taskqueue_start_threads(&pi->tq, 1, PI_NET, "%s taskq",
765219286Snp	    device_get_nameunit(dev));
766218792Snp
767218792Snp	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
768218792Snp	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
769218792Snp
770218792Snp	ifp->if_init = cxgbe_init;
771218792Snp	ifp->if_ioctl = cxgbe_ioctl;
772218792Snp	ifp->if_start = cxgbe_start;
773218792Snp	ifp->if_transmit = cxgbe_transmit;
774218792Snp	ifp->if_qflush = cxgbe_qflush;
775218792Snp
776218792Snp	ifp->if_snd.ifq_drv_maxlen = 1024;
777218792Snp	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
778218792Snp	IFQ_SET_READY(&ifp->if_snd);
779218792Snp
780218792Snp	ifp->if_capabilities = T4_CAP;
781218792Snp	ifp->if_capenable = T4_CAP_ENABLE;
782218792Snp	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO;
783218792Snp
784218792Snp	/* Initialize ifmedia for this port */
785218792Snp	ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change,
786218792Snp	    cxgbe_media_status);
787218792Snp	build_medialist(pi);
788218792Snp
789218792Snp	ether_ifattach(ifp, pi->hw_addr);
790218792Snp
791218792Snp#ifdef INVARIANTS
792218792Snp	device_printf(dev, "%p, %d txq, %d rxq\n", pi, pi->ntxq, pi->nrxq);
793218792Snp#endif
794218792Snp
795218792Snp	cxgbe_sysctls(pi);
796218792Snp
797218792Snp	return (0);
798218792Snp}
799218792Snp
800218792Snpstatic int
801218792Snpcxgbe_detach(device_t dev)
802218792Snp{
803218792Snp	struct port_info *pi = device_get_softc(dev);
804218792Snp	struct adapter *sc = pi->adapter;
805218792Snp	int rc;
806218792Snp
807218792Snp	/* Tell if_ioctl and if_init that the port is going away */
808218792Snp	ADAPTER_LOCK(sc);
809218792Snp	SET_DOOMED(pi);
810218792Snp	wakeup(&sc->flags);
811218792Snp	while (IS_BUSY(sc))
812218792Snp		mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0);
813218792Snp	SET_BUSY(sc);
814218792Snp	ADAPTER_UNLOCK(sc);
815218792Snp
816218792Snp	rc = cxgbe_uninit_synchronized(pi);
817218792Snp	if (rc != 0)
818218792Snp		device_printf(dev, "port uninit failed: %d.\n", rc);
819218792Snp
820219286Snp	taskqueue_free(pi->tq);
821219286Snp
822218792Snp	ifmedia_removeall(&pi->media);
823218792Snp	ether_ifdetach(pi->ifp);
824218792Snp	if_free(pi->ifp);
825218792Snp
826218792Snp	ADAPTER_LOCK(sc);
827218792Snp	CLR_BUSY(sc);
828218792Snp	wakeup_one(&sc->flags);
829218792Snp	ADAPTER_UNLOCK(sc);
830218792Snp
831218792Snp	return (0);
832218792Snp}
833218792Snp
834218792Snpstatic void
835218792Snpcxgbe_init(void *arg)
836218792Snp{
837218792Snp	struct port_info *pi = arg;
838218792Snp	struct adapter *sc = pi->adapter;
839218792Snp
840218792Snp	ADAPTER_LOCK(sc);
841218792Snp	cxgbe_init_locked(pi); /* releases adapter lock */
842218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
843218792Snp}
844218792Snp
845218792Snpstatic int
846218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
847218792Snp{
848218792Snp	int rc = 0, mtu, flags;
849218792Snp	struct port_info *pi = ifp->if_softc;
850218792Snp	struct adapter *sc = pi->adapter;
851218792Snp	struct ifreq *ifr = (struct ifreq *)data;
852218792Snp	uint32_t mask;
853218792Snp
854218792Snp	switch (cmd) {
855218792Snp	case SIOCSIFMTU:
856218792Snp		ADAPTER_LOCK(sc);
857218792Snp		rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
858218792Snp		if (rc) {
859218792Snpfail:
860218792Snp			ADAPTER_UNLOCK(sc);
861218792Snp			return (rc);
862218792Snp		}
863218792Snp
864218792Snp		mtu = ifr->ifr_mtu;
865218792Snp		if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) {
866218792Snp			rc = EINVAL;
867218792Snp		} else {
868218792Snp			ifp->if_mtu = mtu;
869218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
870218792Snp				t4_update_fl_bufsize(ifp);
871218792Snp				PORT_LOCK(pi);
872218792Snp				rc = update_mac_settings(pi, XGMAC_MTU);
873218792Snp				PORT_UNLOCK(pi);
874218792Snp			}
875218792Snp		}
876218792Snp		ADAPTER_UNLOCK(sc);
877218792Snp		break;
878218792Snp
879218792Snp	case SIOCSIFFLAGS:
880218792Snp		ADAPTER_LOCK(sc);
881218792Snp		if (IS_DOOMED(pi)) {
882218792Snp			rc = ENXIO;
883218792Snp			goto fail;
884218792Snp		}
885218792Snp		if (ifp->if_flags & IFF_UP) {
886218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
887218792Snp				flags = pi->if_flags;
888218792Snp				if ((ifp->if_flags ^ flags) &
889218792Snp				    (IFF_PROMISC | IFF_ALLMULTI)) {
890218792Snp					if (IS_BUSY(sc)) {
891218792Snp						rc = EBUSY;
892218792Snp						goto fail;
893218792Snp					}
894218792Snp					PORT_LOCK(pi);
895218792Snp					rc = update_mac_settings(pi,
896218792Snp					    XGMAC_PROMISC | XGMAC_ALLMULTI);
897218792Snp					PORT_UNLOCK(pi);
898218792Snp				}
899218792Snp				ADAPTER_UNLOCK(sc);
900218792Snp			} else
901218792Snp				rc = cxgbe_init_locked(pi);
902218792Snp			pi->if_flags = ifp->if_flags;
903218792Snp		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
904218792Snp			rc = cxgbe_uninit_locked(pi);
905218792Snp		else
906218792Snp			ADAPTER_UNLOCK(sc);
907218792Snp
908218792Snp		ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
909218792Snp		break;
910218792Snp
911218792Snp	case SIOCADDMULTI:
912218792Snp	case SIOCDELMULTI: /* these two can be called with a mutex held :-( */
913218792Snp		ADAPTER_LOCK(sc);
914218792Snp		rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
915218792Snp		if (rc)
916218792Snp			goto fail;
917218792Snp
918218792Snp		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
919218792Snp			PORT_LOCK(pi);
920218792Snp			rc = update_mac_settings(pi, XGMAC_MCADDRS);
921218792Snp			PORT_UNLOCK(pi);
922218792Snp		}
923218792Snp		ADAPTER_UNLOCK(sc);
924218792Snp		break;
925218792Snp
926218792Snp	case SIOCSIFCAP:
927218792Snp		ADAPTER_LOCK(sc);
928218792Snp		rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
929218792Snp		if (rc)
930218792Snp			goto fail;
931218792Snp
932218792Snp		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
933218792Snp		if (mask & IFCAP_TXCSUM) {
934218792Snp			ifp->if_capenable ^= IFCAP_TXCSUM;
935218792Snp			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
936218792Snp
937218792Snp			if (IFCAP_TSO & ifp->if_capenable &&
938218792Snp			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
939218792Snp				ifp->if_capenable &= ~IFCAP_TSO;
940218792Snp				ifp->if_hwassist &= ~CSUM_TSO;
941218792Snp				if_printf(ifp,
942218792Snp				    "tso disabled due to -txcsum.\n");
943218792Snp			}
944218792Snp		}
945218792Snp		if (mask & IFCAP_RXCSUM)
946218792Snp			ifp->if_capenable ^= IFCAP_RXCSUM;
947218792Snp		if (mask & IFCAP_TSO4) {
948218792Snp			ifp->if_capenable ^= IFCAP_TSO4;
949218792Snp
950218792Snp			if (IFCAP_TSO & ifp->if_capenable) {
951218792Snp				if (IFCAP_TXCSUM & ifp->if_capenable)
952218792Snp					ifp->if_hwassist |= CSUM_TSO;
953218792Snp				else {
954218792Snp					ifp->if_capenable &= ~IFCAP_TSO;
955218792Snp					ifp->if_hwassist &= ~CSUM_TSO;
956218792Snp					if_printf(ifp,
957218792Snp					    "enable txcsum first.\n");
958218792Snp					rc = EAGAIN;
959218792Snp				}
960218792Snp			} else
961218792Snp				ifp->if_hwassist &= ~CSUM_TSO;
962218792Snp		}
963218792Snp		if (mask & IFCAP_LRO) {
964218792Snp#ifdef INET
965218792Snp			int i;
966218792Snp			struct sge_rxq *rxq;
967218792Snp
968218792Snp			ifp->if_capenable ^= IFCAP_LRO;
969218792Snp			for_each_rxq(pi, i, rxq) {
970218792Snp				if (ifp->if_capenable & IFCAP_LRO)
971218792Snp					rxq->flags |= RXQ_LRO_ENABLED;
972218792Snp				else
973218792Snp					rxq->flags &= ~RXQ_LRO_ENABLED;
974218792Snp			}
975218792Snp#endif
976218792Snp		}
977218792Snp#ifndef TCP_OFFLOAD_DISABLE
978218792Snp		if (mask & IFCAP_TOE4) {
979218792Snp			rc = EOPNOTSUPP;
980218792Snp		}
981218792Snp#endif
982218792Snp		if (mask & IFCAP_VLAN_HWTAGGING) {
983218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
984218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
985218792Snp				PORT_LOCK(pi);
986218792Snp				rc = update_mac_settings(pi, XGMAC_VLANEX);
987218792Snp				PORT_UNLOCK(pi);
988218792Snp			}
989218792Snp		}
990218792Snp		if (mask & IFCAP_VLAN_MTU) {
991218792Snp			ifp->if_capenable ^= IFCAP_VLAN_MTU;
992218792Snp
993218792Snp			/* Need to find out how to disable auto-mtu-inflation */
994218792Snp		}
995218792Snp		if (mask & IFCAP_VLAN_HWTSO)
996218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
997218792Snp		if (mask & IFCAP_VLAN_HWCSUM)
998218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
999218792Snp
1000218792Snp#ifdef VLAN_CAPABILITIES
1001218792Snp		VLAN_CAPABILITIES(ifp);
1002218792Snp#endif
1003218792Snp		ADAPTER_UNLOCK(sc);
1004218792Snp		break;
1005218792Snp
1006218792Snp	case SIOCSIFMEDIA:
1007218792Snp	case SIOCGIFMEDIA:
1008218792Snp		ifmedia_ioctl(ifp, ifr, &pi->media, cmd);
1009218792Snp		break;
1010218792Snp
1011218792Snp	default:
1012218792Snp		rc = ether_ioctl(ifp, cmd, data);
1013218792Snp	}
1014218792Snp
1015218792Snp	return (rc);
1016218792Snp}
1017218792Snp
1018218792Snpstatic void
1019218792Snpcxgbe_start(struct ifnet *ifp)
1020218792Snp{
1021218792Snp	struct port_info *pi = ifp->if_softc;
1022218792Snp	struct sge_txq *txq;
1023218792Snp	int i;
1024218792Snp
1025218792Snp	for_each_txq(pi, i, txq) {
1026218792Snp		if (TXQ_TRYLOCK(txq)) {
1027219286Snp			txq_start(ifp, txq);
1028218792Snp			TXQ_UNLOCK(txq);
1029218792Snp		}
1030218792Snp	}
1031218792Snp}
1032218792Snp
1033218792Snpstatic int
1034218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m)
1035218792Snp{
1036218792Snp	struct port_info *pi = ifp->if_softc;
1037218792Snp	struct adapter *sc = pi->adapter;
1038218792Snp	struct sge_txq *txq = &sc->sge.txq[pi->first_txq];
1039218792Snp	struct buf_ring *br;
1040218792Snp	int rc;
1041218792Snp
1042218792Snp	M_ASSERTPKTHDR(m);
1043218792Snp
1044218792Snp	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1045218792Snp		m_freem(m);
1046218792Snp		return (0);
1047218792Snp	}
1048218792Snp
1049218792Snp	if (m->m_flags & M_FLOWID)
1050218792Snp		txq += (m->m_pkthdr.flowid % pi->ntxq);
1051220873Snp	br = txq->br;
1052218792Snp
1053218792Snp	if (TXQ_TRYLOCK(txq) == 0) {
1054218792Snp		/*
1055218792Snp		 * XXX: make sure that this packet really is sent out.  There is
1056218792Snp		 * a small race where t4_eth_tx may stop draining the drbr and
1057218792Snp		 * goes away, just before we enqueued this mbuf.
1058218792Snp		 */
1059218792Snp
1060218792Snp		return (drbr_enqueue(ifp, br, m));
1061218792Snp	}
1062218792Snp
1063218792Snp	/*
1064218792Snp	 * txq->m is the mbuf that is held up due to a temporary shortage of
1065218792Snp	 * resources and it should be put on the wire first.  Then what's in
1066218792Snp	 * drbr and finally the mbuf that was just passed in to us.
1067218792Snp	 *
1068218792Snp	 * Return code should indicate the fate of the mbuf that was passed in
1069218792Snp	 * this time.
1070218792Snp	 */
1071218792Snp
1072218792Snp	TXQ_LOCK_ASSERT_OWNED(txq);
1073218792Snp	if (drbr_needs_enqueue(ifp, br) || txq->m) {
1074218792Snp
1075218792Snp		/* Queued for transmission. */
1076218792Snp
1077218792Snp		rc = drbr_enqueue(ifp, br, m);
1078218792Snp		m = txq->m ? txq->m : drbr_dequeue(ifp, br);
1079218792Snp		(void) t4_eth_tx(ifp, txq, m);
1080218792Snp		TXQ_UNLOCK(txq);
1081218792Snp		return (rc);
1082218792Snp	}
1083218792Snp
1084218792Snp	/* Direct transmission. */
1085218792Snp	rc = t4_eth_tx(ifp, txq, m);
1086218792Snp	if (rc != 0 && txq->m)
1087218792Snp		rc = 0;	/* held, will be transmitted soon (hopefully) */
1088218792Snp
1089218792Snp	TXQ_UNLOCK(txq);
1090218792Snp	return (rc);
1091218792Snp}
1092218792Snp
1093218792Snpstatic void
1094218792Snpcxgbe_qflush(struct ifnet *ifp)
1095218792Snp{
1096218792Snp	struct port_info *pi = ifp->if_softc;
1097220649Snp	struct sge_txq *txq;
1098220649Snp	int i;
1099220649Snp	struct mbuf *m;
1100218792Snp
1101220649Snp	/* queues do not exist if !IFF_DRV_RUNNING. */
1102220649Snp	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1103220649Snp		for_each_txq(pi, i, txq) {
1104220649Snp			TXQ_LOCK(txq);
1105220649Snp			m_freem(txq->m);
1106220873Snp			while ((m = buf_ring_dequeue_sc(txq->br)) != NULL)
1107220649Snp				m_freem(m);
1108220649Snp			TXQ_UNLOCK(txq);
1109220649Snp		}
1110220649Snp	}
1111220649Snp	if_qflush(ifp);
1112218792Snp}
1113218792Snp
1114218792Snpstatic int
1115218792Snpcxgbe_media_change(struct ifnet *ifp)
1116218792Snp{
1117218792Snp	struct port_info *pi = ifp->if_softc;
1118218792Snp
1119218792Snp	device_printf(pi->dev, "%s unimplemented.\n", __func__);
1120218792Snp
1121218792Snp	return (EOPNOTSUPP);
1122218792Snp}
1123218792Snp
1124218792Snpstatic void
1125218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1126218792Snp{
1127218792Snp	struct port_info *pi = ifp->if_softc;
1128218792Snp	struct ifmedia_entry *cur = pi->media.ifm_cur;
1129218792Snp	int speed = pi->link_cfg.speed;
1130218792Snp	int data = (pi->port_type << 8) | pi->mod_type;
1131218792Snp
1132218792Snp	if (cur->ifm_data != data) {
1133218792Snp		build_medialist(pi);
1134218792Snp		cur = pi->media.ifm_cur;
1135218792Snp	}
1136218792Snp
1137218792Snp	ifmr->ifm_status = IFM_AVALID;
1138218792Snp	if (!pi->link_cfg.link_ok)
1139218792Snp		return;
1140218792Snp
1141218792Snp	ifmr->ifm_status |= IFM_ACTIVE;
1142218792Snp
1143218792Snp	/* active and current will differ iff current media is autoselect. */
1144218792Snp	if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
1145218792Snp		return;
1146218792Snp
1147218792Snp	ifmr->ifm_active = IFM_ETHER | IFM_FDX;
1148218792Snp	if (speed == SPEED_10000)
1149218792Snp		ifmr->ifm_active |= IFM_10G_T;
1150218792Snp	else if (speed == SPEED_1000)
1151218792Snp		ifmr->ifm_active |= IFM_1000_T;
1152218792Snp	else if (speed == SPEED_100)
1153218792Snp		ifmr->ifm_active |= IFM_100_TX;
1154218792Snp	else if (speed == SPEED_10)
1155218792Snp		ifmr->ifm_active |= IFM_10_T;
1156218792Snp	else
1157218792Snp		KASSERT(0, ("%s: link up but speed unknown (%u)", __func__,
1158218792Snp			    speed));
1159218792Snp}
1160218792Snp
1161218792Snpvoid
1162218792Snpt4_fatal_err(struct adapter *sc)
1163218792Snp{
1164218792Snp	t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0);
1165218792Snp	t4_intr_disable(sc);
1166218792Snp	log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n",
1167218792Snp	    device_get_nameunit(sc->dev));
1168218792Snp}
1169218792Snp
1170218792Snpstatic int
1171218792Snpmap_bars(struct adapter *sc)
1172218792Snp{
1173218792Snp	sc->regs_rid = PCIR_BAR(0);
1174218792Snp	sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1175218792Snp	    &sc->regs_rid, RF_ACTIVE);
1176218792Snp	if (sc->regs_res == NULL) {
1177218792Snp		device_printf(sc->dev, "cannot map registers.\n");
1178218792Snp		return (ENXIO);
1179218792Snp	}
1180218792Snp	sc->bt = rman_get_bustag(sc->regs_res);
1181218792Snp	sc->bh = rman_get_bushandle(sc->regs_res);
1182218792Snp	sc->mmio_len = rman_get_size(sc->regs_res);
1183218792Snp
1184218792Snp	sc->msix_rid = PCIR_BAR(4);
1185218792Snp	sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1186218792Snp	    &sc->msix_rid, RF_ACTIVE);
1187218792Snp	if (sc->msix_res == NULL) {
1188218792Snp		device_printf(sc->dev, "cannot map MSI-X BAR.\n");
1189218792Snp		return (ENXIO);
1190218792Snp	}
1191218792Snp
1192218792Snp	return (0);
1193218792Snp}
1194218792Snp
1195218792Snpstatic void
1196218792Snpsetup_memwin(struct adapter *sc)
1197218792Snp{
1198218792Snp	u_long bar0;
1199218792Snp
1200218792Snp	bar0 = rman_get_start(sc->regs_res);
1201218792Snp
1202218792Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0),
1203218792Snp	    	     (bar0 + MEMWIN0_BASE) | V_BIR(0) |
1204218792Snp		     V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10));
1205218792Snp
1206218792Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1),
1207218792Snp		     (bar0 + MEMWIN1_BASE) | V_BIR(0) |
1208218792Snp		     V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10));
1209218792Snp
1210218792Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2),
1211218792Snp		     (bar0 + MEMWIN2_BASE) | V_BIR(0) |
1212218792Snp		     V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10));
1213218792Snp}
1214218792Snp
1215218792Snpstatic int
1216218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g,
1217218792Snp    struct intrs_and_queues *iaq)
1218218792Snp{
1219218792Snp	int rc, itype, navail, nc, nrxq10g, nrxq1g;
1220218792Snp
1221218792Snp	bzero(iaq, sizeof(*iaq));
1222218792Snp	nc = mp_ncpus;	/* our snapshot of the number of CPUs */
1223218792Snp
1224219944Snp	for (itype = INTR_MSIX; itype; itype >>= 1) {
1225218792Snp
1226218792Snp		if ((itype & intr_types) == 0)
1227218792Snp			continue;	/* not allowed */
1228218792Snp
1229219944Snp		if (itype == INTR_MSIX)
1230218792Snp			navail = pci_msix_count(sc->dev);
1231219944Snp		else if (itype == INTR_MSI)
1232218792Snp			navail = pci_msi_count(sc->dev);
1233218792Snp		else
1234218792Snp			navail = 1;
1235218792Snp
1236218792Snp		if (navail == 0)
1237218792Snp			continue;
1238218792Snp
1239218792Snp		iaq->intr_type = itype;
1240218792Snp
1241218792Snp		iaq->ntxq10g = min(nc, max_ntxq_10g);
1242218792Snp		iaq->ntxq1g = min(nc, max_ntxq_1g);
1243218792Snp
1244218792Snp		nrxq10g = min(nc, max_nrxq_10g);
1245218792Snp		nrxq1g = min(nc, max_nrxq_1g);
1246218792Snp
1247222510Snp		iaq->nirq = n10g * nrxq10g + n1g * nrxq1g + T4_EXTRA_INTR;
1248222510Snp		if (iaq->nirq <= navail && intr_shared == 0) {
1249218792Snp
1250219944Snp			if (itype == INTR_MSI && !powerof2(iaq->nirq))
1251222510Snp				goto share;
1252219944Snp
1253218792Snp			/* One for err, one for fwq, and one for each rxq */
1254218792Snp
1255222510Snp			iaq->intr_shared = 0;
1256218792Snp			iaq->nrxq10g = nrxq10g;
1257218792Snp			iaq->nrxq1g = nrxq1g;
1258219944Snp
1259218792Snp		} else {
1260222510Snpshare:
1261222510Snp			iaq->intr_shared = 1;
1262218792Snp
1263222510Snp			if (navail >= nc + T4_EXTRA_INTR) {
1264219944Snp				if (itype == INTR_MSIX)
1265222510Snp					navail = nc + T4_EXTRA_INTR;
1266219944Snp
1267219944Snp				/* navail is and must remain a pow2 for MSI */
1268219944Snp				if (itype == INTR_MSI) {
1269219944Snp					KASSERT(powerof2(navail),
1270219944Snp					    ("%d not power of 2", navail));
1271219944Snp
1272222510Snp					while (navail / 2 >= nc + T4_EXTRA_INTR)
1273219944Snp						navail /= 2;
1274219944Snp				}
1275219944Snp			}
1276219944Snp			iaq->nirq = navail;	/* total # of interrupts */
1277219944Snp
1278218792Snp			/*
1279218792Snp			 * If we have multiple vectors available reserve one
1280218792Snp			 * exclusively for errors.  The rest will be shared by
1281218792Snp			 * the fwq and data.
1282218792Snp			 */
1283219944Snp			if (navail > 1)
1284218792Snp				navail--;
1285218792Snp			iaq->nrxq10g = min(nrxq10g, navail);
1286218792Snp			iaq->nrxq1g = min(nrxq1g, navail);
1287218792Snp		}
1288218792Snp
1289218792Snp		navail = iaq->nirq;
1290218792Snp		rc = 0;
1291219944Snp		if (itype == INTR_MSIX)
1292218792Snp			rc = pci_alloc_msix(sc->dev, &navail);
1293219944Snp		else if (itype == INTR_MSI)
1294218792Snp			rc = pci_alloc_msi(sc->dev, &navail);
1295218792Snp
1296218792Snp		if (rc == 0) {
1297218792Snp			if (navail == iaq->nirq)
1298218792Snp				return (0);
1299218792Snp
1300218792Snp			/*
1301218792Snp			 * Didn't get the number requested.  Use whatever number
1302218792Snp			 * the kernel is willing to allocate (it's in navail).
1303218792Snp			 */
1304218792Snp			pci_release_msi(sc->dev);
1305222510Snp			goto share;
1306218792Snp		}
1307218792Snp
1308218792Snp		device_printf(sc->dev,
1309218792Snp		    "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n",
1310218792Snp		    itype, rc, iaq->nirq, navail);
1311218792Snp	}
1312218792Snp
1313218792Snp	device_printf(sc->dev,
1314218792Snp	    "failed to find a usable interrupt type.  "
1315218792Snp	    "allowed=%d, msi-x=%d, msi=%d, intx=1", intr_types,
1316218792Snp	    pci_msix_count(sc->dev), pci_msi_count(sc->dev));
1317218792Snp
1318218792Snp	return (ENXIO);
1319218792Snp}
1320218792Snp
1321218792Snp/*
1322218792Snp * Install a compatible firmware (if required), establish contact with it,
1323218792Snp * become the master, and reset the device.
1324218792Snp */
1325218792Snpstatic int
1326218792Snpprep_firmware(struct adapter *sc)
1327218792Snp{
1328218792Snp	const struct firmware *fw;
1329218792Snp	int rc;
1330218792Snp	enum dev_state state;
1331218792Snp
1332218792Snp	/* Check firmware version and install a different one if necessary */
1333218792Snp	rc = t4_check_fw_version(sc);
1334218792Snp	if (rc != 0 || force_firmware_install) {
1335219287Snp		uint32_t v = 0;
1336218792Snp
1337218792Snp		fw = firmware_get(T4_FWNAME);
1338219287Snp		if (fw != NULL) {
1339219287Snp			const struct fw_hdr *hdr = (const void *)fw->data;
1340219287Snp
1341219287Snp			v = ntohl(hdr->fw_ver);
1342219287Snp
1343219287Snp			/*
1344219287Snp			 * The firmware module will not be used if it isn't the
1345219287Snp			 * same major version as what the driver was compiled
1346219287Snp			 * with.  This check trumps force_firmware_install.
1347219287Snp			 */
1348219287Snp			if (G_FW_HDR_FW_VER_MAJOR(v) != FW_VERSION_MAJOR) {
1349219287Snp				device_printf(sc->dev,
1350219287Snp				    "Found firmware image but version %d "
1351219287Snp				    "can not be used with this driver (%d)\n",
1352219287Snp				    G_FW_HDR_FW_VER_MAJOR(v), FW_VERSION_MAJOR);
1353219287Snp
1354219287Snp				firmware_put(fw, FIRMWARE_UNLOAD);
1355219287Snp				fw = NULL;
1356219287Snp			}
1357218792Snp		}
1358218792Snp
1359219287Snp		if (fw == NULL && (rc < 0 || force_firmware_install)) {
1360219287Snp			device_printf(sc->dev, "No usable firmware. "
1361219287Snp			    "card has %d.%d.%d, driver compiled with %d.%d.%d, "
1362219287Snp			    "force_firmware_install%s set",
1363219287Snp			    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
1364219287Snp			    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
1365219287Snp			    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
1366219287Snp			    FW_VERSION_MAJOR, FW_VERSION_MINOR,
1367219287Snp			    FW_VERSION_MICRO,
1368219287Snp			    force_firmware_install ? "" : " not");
1369219287Snp			return (EAGAIN);
1370219287Snp		}
1371219287Snp
1372219287Snp		/*
1373219287Snp		 * Always upgrade, even for minor/micro/build mismatches.
1374219287Snp		 * Downgrade only for a major version mismatch or if
1375219287Snp		 * force_firmware_install was specified.
1376219287Snp		 */
1377219287Snp		if (fw != NULL && (rc < 0 || force_firmware_install ||
1378219287Snp		    v > sc->params.fw_vers)) {
1379218792Snp			device_printf(sc->dev,
1380219287Snp			    "installing firmware %d.%d.%d.%d on card.\n",
1381219287Snp			    G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v),
1382219287Snp			    G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v));
1383219287Snp
1384219287Snp			rc = -t4_load_fw(sc, fw->data, fw->datasize);
1385219287Snp			if (rc != 0) {
1386219287Snp				device_printf(sc->dev,
1387219287Snp				    "failed to install firmware: %d\n", rc);
1388219287Snp				firmware_put(fw, FIRMWARE_UNLOAD);
1389219287Snp				return (rc);
1390219287Snp			} else {
1391219287Snp				/* refresh */
1392219287Snp				(void) t4_check_fw_version(sc);
1393219287Snp			}
1394218792Snp		}
1395218792Snp
1396219287Snp		if (fw != NULL)
1397219287Snp			firmware_put(fw, FIRMWARE_UNLOAD);
1398218792Snp	}
1399218792Snp
1400218792Snp	/* Contact firmware, request master */
1401218792Snp	rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MUST, &state);
1402218792Snp	if (rc < 0) {
1403218792Snp		rc = -rc;
1404218792Snp		device_printf(sc->dev,
1405218792Snp		    "failed to connect to the firmware: %d.\n", rc);
1406218792Snp		return (rc);
1407218792Snp	}
1408218792Snp
1409218792Snp	/* Reset device */
1410218792Snp	rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST);
1411218792Snp	if (rc != 0) {
1412218792Snp		device_printf(sc->dev, "firmware reset failed: %d.\n", rc);
1413218792Snp		if (rc != ETIMEDOUT && rc != EIO)
1414218792Snp			t4_fw_bye(sc, sc->mbox);
1415218792Snp		return (rc);
1416218792Snp	}
1417218792Snp
1418218792Snp	snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u",
1419218792Snp	    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
1420218792Snp	    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
1421218792Snp	    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
1422218792Snp	    G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers));
1423218792Snp	sc->flags |= FW_OK;
1424218792Snp
1425218792Snp	return (0);
1426218792Snp}
1427218792Snp
1428218792Snpstatic int
1429222551Snpget_devlog_params(struct adapter *sc, struct devlog_params *dlog)
1430222551Snp{
1431222551Snp	struct fw_devlog_cmd devlog_cmd;
1432222551Snp	uint32_t meminfo;
1433222551Snp	int rc;
1434222551Snp
1435222551Snp	bzero(&devlog_cmd, sizeof(devlog_cmd));
1436222551Snp	devlog_cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) |
1437222551Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
1438222551Snp	devlog_cmd.retval_len16 = htobe32(FW_LEN16(devlog_cmd));
1439222551Snp	rc = -t4_wr_mbox(sc, sc->mbox, &devlog_cmd, sizeof(devlog_cmd),
1440222551Snp	    &devlog_cmd);
1441222551Snp	if (rc != 0) {
1442222551Snp		device_printf(sc->dev,
1443222551Snp		    "failed to get devlog parameters: %d.\n", rc);
1444222551Snp		bzero(dlog, sizeof (*dlog));
1445222551Snp		return (rc);
1446222551Snp	}
1447222551Snp
1448222551Snp	meminfo = be32toh(devlog_cmd.memtype_devlog_memaddr16_devlog);
1449222551Snp	dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(meminfo);
1450222551Snp	dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(meminfo) << 4;
1451222551Snp	dlog->size = be32toh(devlog_cmd.memsize_devlog);
1452222551Snp
1453222551Snp	return (0);
1454222551Snp}
1455222551Snp
1456222551Snpstatic int
1457218792Snpget_capabilities(struct adapter *sc, struct fw_caps_config_cmd *caps)
1458218792Snp{
1459218792Snp	int rc;
1460218792Snp
1461218792Snp	bzero(caps, sizeof(*caps));
1462218792Snp	caps->op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
1463218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
1464218792Snp	caps->retval_len16 = htobe32(FW_LEN16(*caps));
1465218792Snp
1466218792Snp	rc = -t4_wr_mbox(sc, sc->mbox, caps, sizeof(*caps), caps);
1467218792Snp	if (rc != 0)
1468218792Snp		return (rc);
1469218792Snp
1470218792Snp	if (caps->niccaps & htobe16(FW_CAPS_CONFIG_NIC_VM))
1471218792Snp		caps->niccaps ^= htobe16(FW_CAPS_CONFIG_NIC_VM);
1472218792Snp
1473218792Snp	caps->op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
1474218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
1475218792Snp	rc = -t4_wr_mbox(sc, sc->mbox, caps, sizeof(*caps), NULL);
1476218792Snp
1477218792Snp	return (rc);
1478218792Snp}
1479218792Snp
1480218792Snpstatic int
1481218792Snpget_params(struct adapter *sc, struct fw_caps_config_cmd *caps)
1482218792Snp{
1483218792Snp	int rc;
1484218792Snp	uint32_t params[7], val[7];
1485218792Snp
1486218792Snp#define FW_PARAM_DEV(param) \
1487218792Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
1488218792Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
1489218792Snp#define FW_PARAM_PFVF(param) \
1490218792Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
1491218792Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param))
1492218792Snp
1493218792Snp	params[0] = FW_PARAM_DEV(PORTVEC);
1494218792Snp	params[1] = FW_PARAM_PFVF(IQFLINT_START);
1495218792Snp	params[2] = FW_PARAM_PFVF(EQ_START);
1496218792Snp	params[3] = FW_PARAM_PFVF(FILTER_START);
1497218792Snp	params[4] = FW_PARAM_PFVF(FILTER_END);
1498218792Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 5, params, val);
1499218792Snp	if (rc != 0) {
1500218792Snp		device_printf(sc->dev,
1501218792Snp		    "failed to query parameters: %d.\n", rc);
1502218792Snp		goto done;
1503218792Snp	}
1504218792Snp
1505218792Snp	sc->params.portvec = val[0];
1506218792Snp	sc->params.nports = 0;
1507218792Snp	while (val[0]) {
1508218792Snp		sc->params.nports++;
1509218792Snp		val[0] &= val[0] - 1;
1510218792Snp	}
1511218792Snp
1512218792Snp	sc->sge.iq_start = val[1];
1513218792Snp	sc->sge.eq_start = val[2];
1514218792Snp	sc->tids.ftid_base = val[3];
1515218792Snp	sc->tids.nftids = val[4] - val[3] + 1;
1516218792Snp
1517218792Snp	if (caps->toecaps) {
1518218792Snp		/* query offload-related parameters */
1519218792Snp		params[0] = FW_PARAM_DEV(NTID);
1520218792Snp		params[1] = FW_PARAM_PFVF(SERVER_START);
1521218792Snp		params[2] = FW_PARAM_PFVF(SERVER_END);
1522218792Snp		params[3] = FW_PARAM_PFVF(TDDP_START);
1523218792Snp		params[4] = FW_PARAM_PFVF(TDDP_END);
1524218792Snp		params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
1525218792Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, params, val);
1526218792Snp		if (rc != 0) {
1527218792Snp			device_printf(sc->dev,
1528218792Snp			    "failed to query TOE parameters: %d.\n", rc);
1529218792Snp			goto done;
1530218792Snp		}
1531218792Snp		sc->tids.ntids = val[0];
1532218792Snp		sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS);
1533218792Snp		sc->tids.stid_base = val[1];
1534218792Snp		sc->tids.nstids = val[2] - val[1] + 1;
1535218792Snp		sc->vres.ddp.start = val[3];
1536218792Snp		sc->vres.ddp.size = val[4] - val[3] + 1;
1537218792Snp		sc->params.ofldq_wr_cred = val[5];
1538218792Snp		sc->params.offload = 1;
1539218792Snp	}
1540218792Snp	if (caps->rdmacaps) {
1541218792Snp		params[0] = FW_PARAM_PFVF(STAG_START);
1542218792Snp		params[1] = FW_PARAM_PFVF(STAG_END);
1543218792Snp		params[2] = FW_PARAM_PFVF(RQ_START);
1544218792Snp		params[3] = FW_PARAM_PFVF(RQ_END);
1545218792Snp		params[4] = FW_PARAM_PFVF(PBL_START);
1546218792Snp		params[5] = FW_PARAM_PFVF(PBL_END);
1547218792Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, params, val);
1548218792Snp		if (rc != 0) {
1549218792Snp			device_printf(sc->dev,
1550218792Snp			    "failed to query RDMA parameters: %d.\n", rc);
1551218792Snp			goto done;
1552218792Snp		}
1553218792Snp		sc->vres.stag.start = val[0];
1554218792Snp		sc->vres.stag.size = val[1] - val[0] + 1;
1555218792Snp		sc->vres.rq.start = val[2];
1556218792Snp		sc->vres.rq.size = val[3] - val[2] + 1;
1557218792Snp		sc->vres.pbl.start = val[4];
1558218792Snp		sc->vres.pbl.size = val[5] - val[4] + 1;
1559218792Snp	}
1560218792Snp	if (caps->iscsicaps) {
1561218792Snp		params[0] = FW_PARAM_PFVF(ISCSI_START);
1562218792Snp		params[1] = FW_PARAM_PFVF(ISCSI_END);
1563218792Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, params, val);
1564218792Snp		if (rc != 0) {
1565218792Snp			device_printf(sc->dev,
1566218792Snp			    "failed to query iSCSI parameters: %d.\n", rc);
1567218792Snp			goto done;
1568218792Snp		}
1569218792Snp		sc->vres.iscsi.start = val[0];
1570218792Snp		sc->vres.iscsi.size = val[1] - val[0] + 1;
1571218792Snp	}
1572218792Snp#undef FW_PARAM_PFVF
1573218792Snp#undef FW_PARAM_DEV
1574218792Snp
1575218792Snpdone:
1576218792Snp	return (rc);
1577218792Snp}
1578218792Snp
1579218792Snpstatic void
1580218792Snpt4_set_desc(struct adapter *sc)
1581218792Snp{
1582218792Snp	char buf[128];
1583218792Snp	struct adapter_params *p = &sc->params;
1584218792Snp
1585218792Snp	snprintf(buf, sizeof(buf),
1586219944Snp	    "Chelsio %s (rev %d) %d port %sNIC PCIe-x%d %d %s, S/N:%s, E/C:%s",
1587218792Snp	    p->vpd.id, p->rev, p->nports, is_offload(sc) ? "R" : "",
1588219944Snp	    p->pci.width, sc->intr_count, sc->intr_type == INTR_MSIX ? "MSI-X" :
1589219944Snp	    (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), p->vpd.sn, p->vpd.ec);
1590218792Snp
1591218792Snp	device_set_desc_copy(sc->dev, buf);
1592218792Snp}
1593218792Snp
1594218792Snpstatic void
1595218792Snpbuild_medialist(struct port_info *pi)
1596218792Snp{
1597218792Snp	struct ifmedia *media = &pi->media;
1598218792Snp	int data, m;
1599218792Snp
1600218792Snp	PORT_LOCK(pi);
1601218792Snp
1602218792Snp	ifmedia_removeall(media);
1603218792Snp
1604218792Snp	m = IFM_ETHER | IFM_FDX;
1605218792Snp	data = (pi->port_type << 8) | pi->mod_type;
1606218792Snp
1607218792Snp	switch(pi->port_type) {
1608218792Snp	case FW_PORT_TYPE_BT_XFI:
1609218792Snp		ifmedia_add(media, m | IFM_10G_T, data, NULL);
1610218792Snp		break;
1611218792Snp
1612218792Snp	case FW_PORT_TYPE_BT_XAUI:
1613218792Snp		ifmedia_add(media, m | IFM_10G_T, data, NULL);
1614218792Snp		/* fall through */
1615218792Snp
1616218792Snp	case FW_PORT_TYPE_BT_SGMII:
1617218792Snp		ifmedia_add(media, m | IFM_1000_T, data, NULL);
1618218792Snp		ifmedia_add(media, m | IFM_100_TX, data, NULL);
1619218792Snp		ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL);
1620218792Snp		ifmedia_set(media, IFM_ETHER | IFM_AUTO);
1621218792Snp		break;
1622218792Snp
1623218792Snp	case FW_PORT_TYPE_CX4:
1624218792Snp		ifmedia_add(media, m | IFM_10G_CX4, data, NULL);
1625218792Snp		ifmedia_set(media, m | IFM_10G_CX4);
1626218792Snp		break;
1627218792Snp
1628218792Snp	case FW_PORT_TYPE_SFP:
1629218792Snp	case FW_PORT_TYPE_FIBER_XFI:
1630218792Snp	case FW_PORT_TYPE_FIBER_XAUI:
1631218792Snp		switch (pi->mod_type) {
1632218792Snp
1633218792Snp		case FW_PORT_MOD_TYPE_LR:
1634218792Snp			ifmedia_add(media, m | IFM_10G_LR, data, NULL);
1635218792Snp			ifmedia_set(media, m | IFM_10G_LR);
1636218792Snp			break;
1637218792Snp
1638218792Snp		case FW_PORT_MOD_TYPE_SR:
1639218792Snp			ifmedia_add(media, m | IFM_10G_SR, data, NULL);
1640218792Snp			ifmedia_set(media, m | IFM_10G_SR);
1641218792Snp			break;
1642218792Snp
1643218792Snp		case FW_PORT_MOD_TYPE_LRM:
1644218792Snp			ifmedia_add(media, m | IFM_10G_LRM, data, NULL);
1645218792Snp			ifmedia_set(media, m | IFM_10G_LRM);
1646218792Snp			break;
1647218792Snp
1648218792Snp		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
1649218792Snp		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
1650218792Snp			ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL);
1651218792Snp			ifmedia_set(media, m | IFM_10G_TWINAX);
1652218792Snp			break;
1653218792Snp
1654218792Snp		case FW_PORT_MOD_TYPE_NONE:
1655218792Snp			m &= ~IFM_FDX;
1656218792Snp			ifmedia_add(media, m | IFM_NONE, data, NULL);
1657218792Snp			ifmedia_set(media, m | IFM_NONE);
1658218792Snp			break;
1659218792Snp
1660218792Snp		case FW_PORT_MOD_TYPE_NA:
1661218792Snp		case FW_PORT_MOD_TYPE_ER:
1662218792Snp		default:
1663218792Snp			ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
1664218792Snp			ifmedia_set(media, m | IFM_UNKNOWN);
1665218792Snp			break;
1666218792Snp		}
1667218792Snp		break;
1668218792Snp
1669218792Snp	case FW_PORT_TYPE_KX4:
1670218792Snp	case FW_PORT_TYPE_KX:
1671218792Snp	case FW_PORT_TYPE_KR:
1672218792Snp	default:
1673218792Snp		ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
1674218792Snp		ifmedia_set(media, m | IFM_UNKNOWN);
1675218792Snp		break;
1676218792Snp	}
1677218792Snp
1678218792Snp	PORT_UNLOCK(pi);
1679218792Snp}
1680218792Snp
1681218792Snp/*
1682218792Snp * Program the port's XGMAC based on parameters in ifnet.  The caller also
1683218792Snp * indicates which parameters should be programmed (the rest are left alone).
1684218792Snp */
1685218792Snpstatic int
1686218792Snpupdate_mac_settings(struct port_info *pi, int flags)
1687218792Snp{
1688218792Snp	int rc;
1689218792Snp	struct ifnet *ifp = pi->ifp;
1690218792Snp	struct adapter *sc = pi->adapter;
1691218792Snp	int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1;
1692218792Snp
1693218792Snp	PORT_LOCK_ASSERT_OWNED(pi);
1694218792Snp	KASSERT(flags, ("%s: not told what to update.", __func__));
1695218792Snp
1696218792Snp	if (flags & XGMAC_MTU)
1697218792Snp		mtu = ifp->if_mtu;
1698218792Snp
1699218792Snp	if (flags & XGMAC_PROMISC)
1700218792Snp		promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0;
1701218792Snp
1702218792Snp	if (flags & XGMAC_ALLMULTI)
1703218792Snp		allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0;
1704218792Snp
1705218792Snp	if (flags & XGMAC_VLANEX)
1706218792Snp		vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0;
1707218792Snp
1708218792Snp	rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1,
1709218792Snp	    vlanex, false);
1710218792Snp	if (rc) {
1711218792Snp		if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc);
1712218792Snp		return (rc);
1713218792Snp	}
1714218792Snp
1715218792Snp	if (flags & XGMAC_UCADDR) {
1716218792Snp		uint8_t ucaddr[ETHER_ADDR_LEN];
1717218792Snp
1718218792Snp		bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr));
1719218792Snp		rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt,
1720218792Snp		    ucaddr, true, true);
1721218792Snp		if (rc < 0) {
1722218792Snp			rc = -rc;
1723218792Snp			if_printf(ifp, "change_mac failed: %d\n", rc);
1724218792Snp			return (rc);
1725218792Snp		} else {
1726218792Snp			pi->xact_addr_filt = rc;
1727218792Snp			rc = 0;
1728218792Snp		}
1729218792Snp	}
1730218792Snp
1731218792Snp	if (flags & XGMAC_MCADDRS) {
1732218792Snp		const uint8_t *mcaddr;
1733218792Snp		int del = 1;
1734218792Snp		uint64_t hash = 0;
1735218792Snp		struct ifmultiaddr *ifma;
1736218792Snp
1737218792Snp		if_maddr_rlock(ifp);
1738218792Snp		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1739218792Snp			if (ifma->ifma_addr->sa_family != AF_LINK)
1740218792Snp				continue;
1741218792Snp			mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
1742218792Snp
1743218792Snp			rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, del, 1,
1744218792Snp			    &mcaddr, NULL, &hash, 0);
1745218792Snp			if (rc < 0) {
1746218792Snp				rc = -rc;
1747218792Snp				if_printf(ifp, "failed to add mc address"
1748218792Snp				    " %02x:%02x:%02x:%02x:%02x:%02x rc=%d\n",
1749218792Snp				    mcaddr[0], mcaddr[1], mcaddr[2], mcaddr[3],
1750218792Snp				    mcaddr[4], mcaddr[5], rc);
1751218792Snp				goto mcfail;
1752218792Snp			}
1753218792Snp			del = 0;
1754218792Snp		}
1755218792Snp
1756218792Snp		rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0);
1757218792Snp		if (rc != 0)
1758218792Snp			if_printf(ifp, "failed to set mc address hash: %d", rc);
1759218792Snpmcfail:
1760218792Snp		if_maddr_runlock(ifp);
1761218792Snp	}
1762218792Snp
1763218792Snp	return (rc);
1764218792Snp}
1765218792Snp
1766218792Snpstatic int
1767218792Snpcxgbe_init_locked(struct port_info *pi)
1768218792Snp{
1769218792Snp	struct adapter *sc = pi->adapter;
1770218792Snp	int rc = 0;
1771218792Snp
1772218792Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
1773218792Snp
1774218792Snp	while (!IS_DOOMED(pi) && IS_BUSY(sc)) {
1775218792Snp		if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4init", 0)) {
1776218792Snp			rc = EINTR;
1777218792Snp			goto done;
1778218792Snp		}
1779218792Snp	}
1780218792Snp	if (IS_DOOMED(pi)) {
1781218792Snp		rc = ENXIO;
1782218792Snp		goto done;
1783218792Snp	}
1784218792Snp	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
1785218792Snp
1786218792Snp	/* Give up the adapter lock, port init code can sleep. */
1787218792Snp	SET_BUSY(sc);
1788218792Snp	ADAPTER_UNLOCK(sc);
1789218792Snp
1790218792Snp	rc = cxgbe_init_synchronized(pi);
1791218792Snp
1792218792Snpdone:
1793218792Snp	ADAPTER_LOCK(sc);
1794218792Snp	KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
1795218792Snp	CLR_BUSY(sc);
1796218792Snp	wakeup_one(&sc->flags);
1797218792Snp	ADAPTER_UNLOCK(sc);
1798218792Snp	return (rc);
1799218792Snp}
1800218792Snp
1801218792Snpstatic int
1802218792Snpcxgbe_init_synchronized(struct port_info *pi)
1803218792Snp{
1804218792Snp	struct adapter *sc = pi->adapter;
1805218792Snp	struct ifnet *ifp = pi->ifp;
1806218792Snp	int rc = 0, i;
1807218792Snp	uint16_t *rss;
1808218792Snp	struct sge_rxq *rxq;
1809218792Snp
1810218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1811218792Snp
1812218792Snp	if (isset(&sc->open_device_map, pi->port_id)) {
1813218792Snp		KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING,
1814218792Snp		    ("mismatch between open_device_map and if_drv_flags"));
1815218792Snp		return (0);	/* already running */
1816218792Snp	}
1817218792Snp
1818218792Snp	if (sc->open_device_map == 0 && ((rc = first_port_up(sc)) != 0))
1819218792Snp		return (rc);	/* error message displayed already */
1820218792Snp
1821218792Snp	/*
1822218792Snp	 * Allocate tx/rx/fl queues for this port.
1823218792Snp	 */
1824218792Snp	rc = t4_setup_eth_queues(pi);
1825218792Snp	if (rc != 0)
1826218792Snp		goto done;	/* error message displayed already */
1827218792Snp
1828218792Snp	/*
1829218792Snp	 * Setup RSS for this port.
1830218792Snp	 */
1831218792Snp	rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK);
1832218792Snp	for_each_rxq(pi, i, rxq) {
1833218792Snp		rss[i] = rxq->iq.abs_id;
1834218792Snp	}
1835218792Snp	rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, pi->rss_size, rss,
1836218792Snp	    pi->nrxq);
1837218792Snp	free(rss, M_CXGBE);
1838218792Snp	if (rc != 0) {
1839218792Snp		if_printf(ifp, "rss_config failed: %d\n", rc);
1840218792Snp		goto done;
1841218792Snp	}
1842218792Snp
1843218792Snp	PORT_LOCK(pi);
1844218792Snp	rc = update_mac_settings(pi, XGMAC_ALL);
1845218792Snp	PORT_UNLOCK(pi);
1846218792Snp	if (rc)
1847218792Snp		goto done;	/* error message displayed already */
1848218792Snp
1849218792Snp	rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg);
1850218792Snp	if (rc != 0) {
1851218792Snp		if_printf(ifp, "start_link failed: %d\n", rc);
1852218792Snp		goto done;
1853218792Snp	}
1854218792Snp
1855218792Snp	rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true);
1856218792Snp	if (rc != 0) {
1857218792Snp		if_printf(ifp, "enable_vi failed: %d\n", rc);
1858218792Snp		goto done;
1859218792Snp	}
1860218792Snp	pi->flags |= VI_ENABLED;
1861218792Snp
1862218792Snp	/* all ok */
1863218792Snp	setbit(&sc->open_device_map, pi->port_id);
1864218792Snp	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1865218792Snp	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1866218792Snp
1867218792Snp	callout_reset(&pi->tick, hz, cxgbe_tick, pi);
1868218792Snpdone:
1869218792Snp	if (rc != 0)
1870218792Snp		cxgbe_uninit_synchronized(pi);
1871218792Snp
1872218792Snp	return (rc);
1873218792Snp}
1874218792Snp
1875218792Snpstatic int
1876218792Snpcxgbe_uninit_locked(struct port_info *pi)
1877218792Snp{
1878218792Snp	struct adapter *sc = pi->adapter;
1879218792Snp	int rc;
1880218792Snp
1881218792Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
1882218792Snp
1883218792Snp	while (!IS_DOOMED(pi) && IS_BUSY(sc)) {
1884218792Snp		if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4uninit", 0)) {
1885218792Snp			rc = EINTR;
1886218792Snp			goto done;
1887218792Snp		}
1888218792Snp	}
1889218792Snp	if (IS_DOOMED(pi)) {
1890218792Snp		rc = ENXIO;
1891218792Snp		goto done;
1892218792Snp	}
1893218792Snp	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
1894218792Snp	SET_BUSY(sc);
1895218792Snp	ADAPTER_UNLOCK(sc);
1896218792Snp
1897218792Snp	rc = cxgbe_uninit_synchronized(pi);
1898218792Snp
1899218792Snp	ADAPTER_LOCK(sc);
1900218792Snp	KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
1901218792Snp	CLR_BUSY(sc);
1902218792Snp	wakeup_one(&sc->flags);
1903218792Snpdone:
1904218792Snp	ADAPTER_UNLOCK(sc);
1905218792Snp	return (rc);
1906218792Snp}
1907218792Snp
1908218792Snp/*
1909218792Snp * Idempotent.
1910218792Snp */
1911218792Snpstatic int
1912218792Snpcxgbe_uninit_synchronized(struct port_info *pi)
1913218792Snp{
1914218792Snp	struct adapter *sc = pi->adapter;
1915218792Snp	struct ifnet *ifp = pi->ifp;
1916218792Snp	int rc;
1917218792Snp
1918218792Snp	/*
1919218792Snp	 * taskqueue_drain may cause a deadlock if the adapter lock is held.
1920218792Snp	 */
1921218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1922218792Snp
1923218792Snp	/*
1924218792Snp	 * Clear this port's bit from the open device map, and then drain
1925218792Snp	 * tasks and callouts.
1926218792Snp	 */
1927218792Snp	clrbit(&sc->open_device_map, pi->port_id);
1928218792Snp
1929218792Snp	PORT_LOCK(pi);
1930218792Snp	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1931218792Snp	callout_stop(&pi->tick);
1932218792Snp	PORT_UNLOCK(pi);
1933218792Snp	callout_drain(&pi->tick);
1934218792Snp
1935218792Snp	/*
1936218792Snp	 * Stop and then free the queues' resources, including the queues
1937218792Snp	 * themselves.
1938218792Snp	 *
1939218792Snp	 * XXX: we could just stop the queues here (on ifconfig down) and free
1940218792Snp	 * them later (on port detach), but having up/down go through the entire
1941218792Snp	 * allocate/activate/deactivate/free sequence is a good way to find
1942218792Snp	 * leaks and bugs.
1943218792Snp	 */
1944218792Snp	rc = t4_teardown_eth_queues(pi);
1945218792Snp	if (rc != 0)
1946218792Snp		if_printf(ifp, "teardown failed: %d\n", rc);
1947218792Snp
1948218792Snp	if (pi->flags & VI_ENABLED) {
1949218792Snp		rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false);
1950218792Snp		if (rc)
1951218792Snp			if_printf(ifp, "disable_vi failed: %d\n", rc);
1952218792Snp		else
1953218792Snp			pi->flags &= ~VI_ENABLED;
1954218792Snp	}
1955218792Snp
1956218792Snp	pi->link_cfg.link_ok = 0;
1957218792Snp	pi->link_cfg.speed = 0;
1958218792Snp	t4_os_link_changed(sc, pi->port_id, 0);
1959218792Snp
1960218792Snp	if (sc->open_device_map == 0)
1961218792Snp		last_port_down(sc);
1962218792Snp
1963218792Snp	return (0);
1964218792Snp}
1965218792Snp
1966222510Snp#define T4_ALLOC_IRQ(sc, irq, rid, handler, arg, name) do { \
1967222510Snp	rc = t4_alloc_irq(sc, irq, rid, handler, arg, name); \
1968218792Snp	if (rc != 0) \
1969218792Snp		goto done; \
1970218792Snp} while (0)
1971218792Snpstatic int
1972218792Snpfirst_port_up(struct adapter *sc)
1973218792Snp{
1974222510Snp	int rc, i, rid, p, q;
1975222510Snp	char s[8];
1976222510Snp	struct irq *irq;
1977222510Snp	struct sge_iq *intrq;
1978218792Snp
1979218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1980218792Snp
1981218792Snp	/*
1982220873Snp	 * queues that belong to the adapter (not any particular port).
1983218792Snp	 */
1984220873Snp	rc = t4_setup_adapter_queues(sc);
1985218792Snp	if (rc != 0)
1986218792Snp		goto done;
1987218792Snp
1988218792Snp	/*
1989218792Snp	 * Setup interrupts.
1990218792Snp	 */
1991222510Snp	irq = &sc->irq[0];
1992222510Snp	rid = sc->intr_type == INTR_INTX ? 0 : 1;
1993218792Snp	if (sc->intr_count == 1) {
1994222510Snp		KASSERT(sc->flags & INTR_SHARED,
1995222510Snp		    ("%s: single interrupt but not shared?", __func__));
1996222510Snp
1997222510Snp		T4_ALLOC_IRQ(sc, irq, rid, t4_intr_all, sc, "all");
1998218792Snp	} else {
1999218792Snp		/* Multiple interrupts.  The first one is always error intr */
2000222510Snp		T4_ALLOC_IRQ(sc, irq, rid, t4_intr_err, sc, "err");
2001222510Snp		irq++;
2002222510Snp		rid++;
2003218792Snp
2004222510Snp		/* Firmware event queue normally has an interrupt of its own */
2005222510Snp		if (sc->intr_count > T4_EXTRA_INTR) {
2006222510Snp			T4_ALLOC_IRQ(sc, irq, rid, t4_intr_evt, &sc->sge.fwq,
2007222510Snp			    "evt");
2008222510Snp			irq++;
2009222510Snp			rid++;
2010222510Snp		}
2011222510Snp
2012222510Snp		intrq = &sc->sge.intrq[0];
2013222510Snp		if (sc->flags & INTR_SHARED) {
2014222510Snp
2015222510Snp			/* All ports share these interrupt queues */
2016222510Snp
2017222510Snp			for (i = 0; i < NINTRQ(sc); i++) {
2018222510Snp				snprintf(s, sizeof(s), "*.%d", i);
2019222510Snp				T4_ALLOC_IRQ(sc, irq, rid, t4_intr, intrq, s);
2020222510Snp				irq++;
2021222510Snp				rid++;
2022222510Snp				intrq++;
2023218792Snp			}
2024218792Snp		} else {
2025218792Snp
2026222510Snp			/* Each port has its own set of interrupt queues */
2027218792Snp
2028222510Snp			for (p = 0; p < sc->params.nports; p++) {
2029222510Snp				for (q = 0; q < sc->port[p]->nrxq; q++) {
2030222510Snp					snprintf(s, sizeof(s), "%d.%d", p, q);
2031222510Snp					T4_ALLOC_IRQ(sc, irq, rid, t4_intr,
2032222510Snp					    intrq, s);
2033222510Snp					irq++;
2034222510Snp					rid++;
2035222510Snp					intrq++;
2036218792Snp				}
2037218792Snp			}
2038218792Snp		}
2039218792Snp	}
2040218792Snp
2041218792Snp	t4_intr_enable(sc);
2042218792Snp	sc->flags |= FULL_INIT_DONE;
2043218792Snp
2044218792Snpdone:
2045218792Snp	if (rc != 0)
2046218792Snp		last_port_down(sc);
2047218792Snp
2048218792Snp	return (rc);
2049218792Snp}
2050218792Snp#undef T4_ALLOC_IRQ
2051218792Snp
2052218792Snp/*
2053218792Snp * Idempotent.
2054218792Snp */
2055218792Snpstatic int
2056218792Snplast_port_down(struct adapter *sc)
2057218792Snp{
2058218792Snp	int i;
2059218792Snp
2060218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
2061218792Snp
2062218792Snp	t4_intr_disable(sc);
2063218792Snp
2064220873Snp	t4_teardown_adapter_queues(sc);
2065218792Snp
2066218792Snp	for (i = 0; i < sc->intr_count; i++)
2067218792Snp		t4_free_irq(sc, &sc->irq[i]);
2068218792Snp
2069218792Snp	sc->flags &= ~FULL_INIT_DONE;
2070218792Snp
2071218792Snp	return (0);
2072218792Snp}
2073218792Snp
2074218792Snpstatic int
2075218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid,
2076218792Snp    iq_intr_handler_t *handler, void *arg, char *name)
2077218792Snp{
2078218792Snp	int rc;
2079218792Snp
2080218792Snp	irq->rid = rid;
2081218792Snp	irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid,
2082218792Snp	    RF_SHAREABLE | RF_ACTIVE);
2083218792Snp	if (irq->res == NULL) {
2084218792Snp		device_printf(sc->dev,
2085218792Snp		    "failed to allocate IRQ for rid %d, name %s.\n", rid, name);
2086218792Snp		return (ENOMEM);
2087218792Snp	}
2088218792Snp
2089218792Snp	rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET,
2090218792Snp	    NULL, handler, arg, &irq->tag);
2091218792Snp	if (rc != 0) {
2092218792Snp		device_printf(sc->dev,
2093218792Snp		    "failed to setup interrupt for rid %d, name %s: %d\n",
2094218792Snp		    rid, name, rc);
2095218792Snp	} else if (name)
2096218792Snp		bus_describe_intr(sc->dev, irq->res, irq->tag, name);
2097218792Snp
2098218792Snp	return (rc);
2099218792Snp}
2100218792Snp
2101218792Snpstatic int
2102218792Snpt4_free_irq(struct adapter *sc, struct irq *irq)
2103218792Snp{
2104218792Snp	if (irq->tag)
2105218792Snp		bus_teardown_intr(sc->dev, irq->res, irq->tag);
2106218792Snp	if (irq->res)
2107218792Snp		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res);
2108218792Snp
2109218792Snp	bzero(irq, sizeof(*irq));
2110218792Snp
2111218792Snp	return (0);
2112218792Snp}
2113218792Snp
2114218792Snpstatic void
2115218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start,
2116218792Snp    unsigned int end)
2117218792Snp{
2118218792Snp	uint32_t *p = (uint32_t *)(buf + start);
2119218792Snp
2120218792Snp	for ( ; start <= end; start += sizeof(uint32_t))
2121218792Snp		*p++ = t4_read_reg(sc, start);
2122218792Snp}
2123218792Snp
2124218792Snpstatic void
2125218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf)
2126218792Snp{
2127218792Snp	int i;
2128218792Snp	static const unsigned int reg_ranges[] = {
2129218792Snp		0x1008, 0x1108,
2130218792Snp		0x1180, 0x11b4,
2131218792Snp		0x11fc, 0x123c,
2132218792Snp		0x1300, 0x173c,
2133218792Snp		0x1800, 0x18fc,
2134218792Snp		0x3000, 0x30d8,
2135218792Snp		0x30e0, 0x5924,
2136218792Snp		0x5960, 0x59d4,
2137218792Snp		0x5a00, 0x5af8,
2138218792Snp		0x6000, 0x6098,
2139218792Snp		0x6100, 0x6150,
2140218792Snp		0x6200, 0x6208,
2141218792Snp		0x6240, 0x6248,
2142218792Snp		0x6280, 0x6338,
2143218792Snp		0x6370, 0x638c,
2144218792Snp		0x6400, 0x643c,
2145218792Snp		0x6500, 0x6524,
2146218792Snp		0x6a00, 0x6a38,
2147218792Snp		0x6a60, 0x6a78,
2148218792Snp		0x6b00, 0x6b84,
2149218792Snp		0x6bf0, 0x6c84,
2150218792Snp		0x6cf0, 0x6d84,
2151218792Snp		0x6df0, 0x6e84,
2152218792Snp		0x6ef0, 0x6f84,
2153218792Snp		0x6ff0, 0x7084,
2154218792Snp		0x70f0, 0x7184,
2155218792Snp		0x71f0, 0x7284,
2156218792Snp		0x72f0, 0x7384,
2157218792Snp		0x73f0, 0x7450,
2158218792Snp		0x7500, 0x7530,
2159218792Snp		0x7600, 0x761c,
2160218792Snp		0x7680, 0x76cc,
2161218792Snp		0x7700, 0x7798,
2162218792Snp		0x77c0, 0x77fc,
2163218792Snp		0x7900, 0x79fc,
2164218792Snp		0x7b00, 0x7c38,
2165218792Snp		0x7d00, 0x7efc,
2166218792Snp		0x8dc0, 0x8e1c,
2167218792Snp		0x8e30, 0x8e78,
2168218792Snp		0x8ea0, 0x8f6c,
2169218792Snp		0x8fc0, 0x9074,
2170218792Snp		0x90fc, 0x90fc,
2171218792Snp		0x9400, 0x9458,
2172218792Snp		0x9600, 0x96bc,
2173218792Snp		0x9800, 0x9808,
2174218792Snp		0x9820, 0x983c,
2175218792Snp		0x9850, 0x9864,
2176218792Snp		0x9c00, 0x9c6c,
2177218792Snp		0x9c80, 0x9cec,
2178218792Snp		0x9d00, 0x9d6c,
2179218792Snp		0x9d80, 0x9dec,
2180218792Snp		0x9e00, 0x9e6c,
2181218792Snp		0x9e80, 0x9eec,
2182218792Snp		0x9f00, 0x9f6c,
2183218792Snp		0x9f80, 0x9fec,
2184218792Snp		0xd004, 0xd03c,
2185218792Snp		0xdfc0, 0xdfe0,
2186218792Snp		0xe000, 0xea7c,
2187218792Snp		0xf000, 0x11190,
2188218792Snp		0x19040, 0x19124,
2189218792Snp		0x19150, 0x191b0,
2190218792Snp		0x191d0, 0x191e8,
2191218792Snp		0x19238, 0x1924c,
2192218792Snp		0x193f8, 0x19474,
2193218792Snp		0x19490, 0x194f8,
2194218792Snp		0x19800, 0x19f30,
2195218792Snp		0x1a000, 0x1a06c,
2196218792Snp		0x1a0b0, 0x1a120,
2197218792Snp		0x1a128, 0x1a138,
2198218792Snp		0x1a190, 0x1a1c4,
2199218792Snp		0x1a1fc, 0x1a1fc,
2200218792Snp		0x1e040, 0x1e04c,
2201218792Snp		0x1e240, 0x1e28c,
2202218792Snp		0x1e2c0, 0x1e2c0,
2203218792Snp		0x1e2e0, 0x1e2e0,
2204218792Snp		0x1e300, 0x1e384,
2205218792Snp		0x1e3c0, 0x1e3c8,
2206218792Snp		0x1e440, 0x1e44c,
2207218792Snp		0x1e640, 0x1e68c,
2208218792Snp		0x1e6c0, 0x1e6c0,
2209218792Snp		0x1e6e0, 0x1e6e0,
2210218792Snp		0x1e700, 0x1e784,
2211218792Snp		0x1e7c0, 0x1e7c8,
2212218792Snp		0x1e840, 0x1e84c,
2213218792Snp		0x1ea40, 0x1ea8c,
2214218792Snp		0x1eac0, 0x1eac0,
2215218792Snp		0x1eae0, 0x1eae0,
2216218792Snp		0x1eb00, 0x1eb84,
2217218792Snp		0x1ebc0, 0x1ebc8,
2218218792Snp		0x1ec40, 0x1ec4c,
2219218792Snp		0x1ee40, 0x1ee8c,
2220218792Snp		0x1eec0, 0x1eec0,
2221218792Snp		0x1eee0, 0x1eee0,
2222218792Snp		0x1ef00, 0x1ef84,
2223218792Snp		0x1efc0, 0x1efc8,
2224218792Snp		0x1f040, 0x1f04c,
2225218792Snp		0x1f240, 0x1f28c,
2226218792Snp		0x1f2c0, 0x1f2c0,
2227218792Snp		0x1f2e0, 0x1f2e0,
2228218792Snp		0x1f300, 0x1f384,
2229218792Snp		0x1f3c0, 0x1f3c8,
2230218792Snp		0x1f440, 0x1f44c,
2231218792Snp		0x1f640, 0x1f68c,
2232218792Snp		0x1f6c0, 0x1f6c0,
2233218792Snp		0x1f6e0, 0x1f6e0,
2234218792Snp		0x1f700, 0x1f784,
2235218792Snp		0x1f7c0, 0x1f7c8,
2236218792Snp		0x1f840, 0x1f84c,
2237218792Snp		0x1fa40, 0x1fa8c,
2238218792Snp		0x1fac0, 0x1fac0,
2239218792Snp		0x1fae0, 0x1fae0,
2240218792Snp		0x1fb00, 0x1fb84,
2241218792Snp		0x1fbc0, 0x1fbc8,
2242218792Snp		0x1fc40, 0x1fc4c,
2243218792Snp		0x1fe40, 0x1fe8c,
2244218792Snp		0x1fec0, 0x1fec0,
2245218792Snp		0x1fee0, 0x1fee0,
2246218792Snp		0x1ff00, 0x1ff84,
2247218792Snp		0x1ffc0, 0x1ffc8,
2248218792Snp		0x20000, 0x2002c,
2249218792Snp		0x20100, 0x2013c,
2250218792Snp		0x20190, 0x201c8,
2251218792Snp		0x20200, 0x20318,
2252218792Snp		0x20400, 0x20528,
2253218792Snp		0x20540, 0x20614,
2254218792Snp		0x21000, 0x21040,
2255218792Snp		0x2104c, 0x21060,
2256218792Snp		0x210c0, 0x210ec,
2257218792Snp		0x21200, 0x21268,
2258218792Snp		0x21270, 0x21284,
2259218792Snp		0x212fc, 0x21388,
2260218792Snp		0x21400, 0x21404,
2261218792Snp		0x21500, 0x21518,
2262218792Snp		0x2152c, 0x2153c,
2263218792Snp		0x21550, 0x21554,
2264218792Snp		0x21600, 0x21600,
2265218792Snp		0x21608, 0x21628,
2266218792Snp		0x21630, 0x2163c,
2267218792Snp		0x21700, 0x2171c,
2268218792Snp		0x21780, 0x2178c,
2269218792Snp		0x21800, 0x21c38,
2270218792Snp		0x21c80, 0x21d7c,
2271218792Snp		0x21e00, 0x21e04,
2272218792Snp		0x22000, 0x2202c,
2273218792Snp		0x22100, 0x2213c,
2274218792Snp		0x22190, 0x221c8,
2275218792Snp		0x22200, 0x22318,
2276218792Snp		0x22400, 0x22528,
2277218792Snp		0x22540, 0x22614,
2278218792Snp		0x23000, 0x23040,
2279218792Snp		0x2304c, 0x23060,
2280218792Snp		0x230c0, 0x230ec,
2281218792Snp		0x23200, 0x23268,
2282218792Snp		0x23270, 0x23284,
2283218792Snp		0x232fc, 0x23388,
2284218792Snp		0x23400, 0x23404,
2285218792Snp		0x23500, 0x23518,
2286218792Snp		0x2352c, 0x2353c,
2287218792Snp		0x23550, 0x23554,
2288218792Snp		0x23600, 0x23600,
2289218792Snp		0x23608, 0x23628,
2290218792Snp		0x23630, 0x2363c,
2291218792Snp		0x23700, 0x2371c,
2292218792Snp		0x23780, 0x2378c,
2293218792Snp		0x23800, 0x23c38,
2294218792Snp		0x23c80, 0x23d7c,
2295218792Snp		0x23e00, 0x23e04,
2296218792Snp		0x24000, 0x2402c,
2297218792Snp		0x24100, 0x2413c,
2298218792Snp		0x24190, 0x241c8,
2299218792Snp		0x24200, 0x24318,
2300218792Snp		0x24400, 0x24528,
2301218792Snp		0x24540, 0x24614,
2302218792Snp		0x25000, 0x25040,
2303218792Snp		0x2504c, 0x25060,
2304218792Snp		0x250c0, 0x250ec,
2305218792Snp		0x25200, 0x25268,
2306218792Snp		0x25270, 0x25284,
2307218792Snp		0x252fc, 0x25388,
2308218792Snp		0x25400, 0x25404,
2309218792Snp		0x25500, 0x25518,
2310218792Snp		0x2552c, 0x2553c,
2311218792Snp		0x25550, 0x25554,
2312218792Snp		0x25600, 0x25600,
2313218792Snp		0x25608, 0x25628,
2314218792Snp		0x25630, 0x2563c,
2315218792Snp		0x25700, 0x2571c,
2316218792Snp		0x25780, 0x2578c,
2317218792Snp		0x25800, 0x25c38,
2318218792Snp		0x25c80, 0x25d7c,
2319218792Snp		0x25e00, 0x25e04,
2320218792Snp		0x26000, 0x2602c,
2321218792Snp		0x26100, 0x2613c,
2322218792Snp		0x26190, 0x261c8,
2323218792Snp		0x26200, 0x26318,
2324218792Snp		0x26400, 0x26528,
2325218792Snp		0x26540, 0x26614,
2326218792Snp		0x27000, 0x27040,
2327218792Snp		0x2704c, 0x27060,
2328218792Snp		0x270c0, 0x270ec,
2329218792Snp		0x27200, 0x27268,
2330218792Snp		0x27270, 0x27284,
2331218792Snp		0x272fc, 0x27388,
2332218792Snp		0x27400, 0x27404,
2333218792Snp		0x27500, 0x27518,
2334218792Snp		0x2752c, 0x2753c,
2335218792Snp		0x27550, 0x27554,
2336218792Snp		0x27600, 0x27600,
2337218792Snp		0x27608, 0x27628,
2338218792Snp		0x27630, 0x2763c,
2339218792Snp		0x27700, 0x2771c,
2340218792Snp		0x27780, 0x2778c,
2341218792Snp		0x27800, 0x27c38,
2342218792Snp		0x27c80, 0x27d7c,
2343218792Snp		0x27e00, 0x27e04
2344218792Snp	};
2345218792Snp
2346218792Snp	regs->version = 4 | (sc->params.rev << 10);
2347218792Snp	for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2)
2348218792Snp		reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]);
2349218792Snp}
2350218792Snp
2351218792Snpstatic void
2352218792Snpcxgbe_tick(void *arg)
2353218792Snp{
2354218792Snp	struct port_info *pi = arg;
2355218792Snp	struct ifnet *ifp = pi->ifp;
2356218792Snp	struct sge_txq *txq;
2357218792Snp	int i, drops;
2358218792Snp	struct port_stats *s = &pi->stats;
2359218792Snp
2360218792Snp	PORT_LOCK(pi);
2361218792Snp	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2362218792Snp		PORT_UNLOCK(pi);
2363218792Snp		return;	/* without scheduling another callout */
2364218792Snp	}
2365218792Snp
2366218792Snp	t4_get_port_stats(pi->adapter, pi->tx_chan, s);
2367218792Snp
2368218792Snp	ifp->if_opackets = s->tx_frames;
2369218792Snp	ifp->if_ipackets = s->rx_frames;
2370218792Snp	ifp->if_obytes = s->tx_octets;
2371218792Snp	ifp->if_ibytes = s->rx_octets;
2372218792Snp	ifp->if_omcasts = s->tx_mcast_frames;
2373218792Snp	ifp->if_imcasts = s->rx_mcast_frames;
2374218792Snp	ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 +
2375218792Snp	    s->rx_ovflow3;
2376218792Snp
2377218792Snp	drops = s->tx_drop;
2378218792Snp	for_each_txq(pi, i, txq)
2379220873Snp		drops += txq->br->br_drops;
2380218792Snp	ifp->if_snd.ifq_drops = drops;
2381218792Snp
2382218792Snp	ifp->if_oerrors = s->tx_error_frames;
2383218792Snp	ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long +
2384218792Snp	    s->rx_fcs_err + s->rx_len_err;
2385218792Snp
2386218792Snp	callout_schedule(&pi->tick, hz);
2387218792Snp	PORT_UNLOCK(pi);
2388218792Snp}
2389218792Snp
2390218792Snpstatic int
2391218792Snpt4_sysctls(struct adapter *sc)
2392218792Snp{
2393218792Snp	struct sysctl_ctx_list *ctx;
2394218792Snp	struct sysctl_oid *oid;
2395218792Snp	struct sysctl_oid_list *children;
2396218792Snp
2397218792Snp	ctx = device_get_sysctl_ctx(sc->dev);
2398218792Snp	oid = device_get_sysctl_tree(sc->dev);
2399218792Snp	children = SYSCTL_CHILDREN(oid);
2400218792Snp
2401218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD,
2402218792Snp	    &sc->params.nports, 0, "# of ports");
2403218792Snp
2404218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD,
2405218792Snp	    &sc->params.rev, 0, "chip hardware revision");
2406218792Snp
2407218792Snp	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version",
2408218792Snp	    CTLFLAG_RD, &sc->fw_version, 0, "firmware version");
2409218792Snp
2410218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "TOE", CTLFLAG_RD,
2411218792Snp	    &sc->params.offload, 0, "hardware is capable of TCP offload");
2412218792Snp
2413218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD,
2414218792Snp	    &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)");
2415218792Snp
2416219436Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers",
2417219436Snp	    CTLTYPE_STRING | CTLFLAG_RD, &intr_timer, sizeof(intr_timer),
2418219436Snp	    sysctl_int_array, "A", "interrupt holdoff timer values (us)");
2419218792Snp
2420219436Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts",
2421219436Snp	    CTLTYPE_STRING | CTLFLAG_RD, &intr_pktcount, sizeof(intr_pktcount),
2422219436Snp	    sysctl_int_array, "A", "interrupt holdoff packet counter values");
2423218792Snp
2424222551Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog",
2425222551Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
2426222551Snp	    sysctl_devlog, "A", "device log");
2427222551Snp
2428218792Snp	return (0);
2429218792Snp}
2430218792Snp
2431218792Snpstatic int
2432218792Snpcxgbe_sysctls(struct port_info *pi)
2433218792Snp{
2434218792Snp	struct sysctl_ctx_list *ctx;
2435218792Snp	struct sysctl_oid *oid;
2436218792Snp	struct sysctl_oid_list *children;
2437218792Snp
2438218792Snp	ctx = device_get_sysctl_ctx(pi->dev);
2439218792Snp
2440218792Snp	/*
2441218792Snp	 * dev.cxgbe.X.
2442218792Snp	 */
2443218792Snp	oid = device_get_sysctl_tree(pi->dev);
2444218792Snp	children = SYSCTL_CHILDREN(oid);
2445218792Snp
2446218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD,
2447218792Snp	    &pi->nrxq, 0, "# of rx queues");
2448218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD,
2449218792Snp	    &pi->ntxq, 0, "# of tx queues");
2450218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD,
2451218792Snp	    &pi->first_rxq, 0, "index of first rx queue");
2452218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD,
2453218792Snp	    &pi->first_txq, 0, "index of first tx queue");
2454218792Snp
2455218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx",
2456218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I",
2457218792Snp	    "holdoff timer index");
2458218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx",
2459218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I",
2460218792Snp	    "holdoff packet counter index");
2461218792Snp
2462218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq",
2463218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I",
2464218792Snp	    "rx queue size");
2465218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq",
2466218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I",
2467218792Snp	    "tx queue size");
2468218792Snp
2469218792Snp	/*
2470218792Snp	 * dev.cxgbe.X.stats.
2471218792Snp	 */
2472218792Snp	oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD,
2473218792Snp	    NULL, "port statistics");
2474218792Snp	children = SYSCTL_CHILDREN(oid);
2475218792Snp
2476218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \
2477218792Snp	SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \
2478218792Snp	    CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \
2479218792Snp	    sysctl_handle_t4_reg64, "QU", desc)
2480218792Snp
2481218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames",
2482218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L));
2483218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames",
2484218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L));
2485218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames",
2486218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L));
2487218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames",
2488218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L));
2489218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames",
2490218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L));
2491218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames",
2492218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L));
2493218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_64",
2494218792Snp	    "# of tx frames in this range",
2495218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L));
2496218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127",
2497218792Snp	    "# of tx frames in this range",
2498218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L));
2499218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255",
2500218792Snp	    "# of tx frames in this range",
2501218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L));
2502218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511",
2503218792Snp	    "# of tx frames in this range",
2504218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L));
2505218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023",
2506218792Snp	    "# of tx frames in this range",
2507218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L));
2508218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518",
2509218792Snp	    "# of tx frames in this range",
2510218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L));
2511218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max",
2512218792Snp	    "# of tx frames in this range",
2513218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L));
2514218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames",
2515218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L));
2516218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted",
2517218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L));
2518218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted",
2519218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L));
2520218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted",
2521218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L));
2522218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted",
2523218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L));
2524218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted",
2525218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L));
2526218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted",
2527218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L));
2528218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted",
2529218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L));
2530218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted",
2531218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L));
2532218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted",
2533218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L));
2534218792Snp
2535218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames",
2536218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L));
2537218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames",
2538218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L));
2539218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames",
2540218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L));
2541218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames",
2542218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L));
2543218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames",
2544218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L));
2545218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU",
2546218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L));
2547218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames",
2548218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L));
2549218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err",
2550218792Snp	    "# of frames received with bad FCS",
2551218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L));
2552218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_len_err",
2553218792Snp	    "# of frames received with length error",
2554218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L));
2555218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors",
2556218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L));
2557218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received",
2558218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L));
2559218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_64",
2560218792Snp	    "# of rx frames in this range",
2561218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L));
2562218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127",
2563218792Snp	    "# of rx frames in this range",
2564218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L));
2565218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255",
2566218792Snp	    "# of rx frames in this range",
2567218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L));
2568218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511",
2569218792Snp	    "# of rx frames in this range",
2570218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L));
2571218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023",
2572218792Snp	    "# of rx frames in this range",
2573218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L));
2574218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518",
2575218792Snp	    "# of rx frames in this range",
2576218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L));
2577218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max",
2578218792Snp	    "# of rx frames in this range",
2579218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L));
2580218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received",
2581218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L));
2582218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received",
2583218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L));
2584218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received",
2585218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L));
2586218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received",
2587218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L));
2588218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received",
2589218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L));
2590218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received",
2591218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L));
2592218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received",
2593218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L));
2594218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received",
2595218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L));
2596218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received",
2597218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L));
2598218792Snp
2599218792Snp#undef SYSCTL_ADD_T4_REG64
2600218792Snp
2601218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \
2602218792Snp	SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \
2603218792Snp	    &pi->stats.name, desc)
2604218792Snp
2605218792Snp	/* We get these from port_stats and they may be stale by upto 1s */
2606218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0,
2607218792Snp	    "# drops due to buffer-group 0 overflows");
2608218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1,
2609218792Snp	    "# drops due to buffer-group 1 overflows");
2610218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2,
2611218792Snp	    "# drops due to buffer-group 2 overflows");
2612218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3,
2613218792Snp	    "# drops due to buffer-group 3 overflows");
2614218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc0,
2615218792Snp	    "# of buffer-group 0 truncated packets");
2616218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc1,
2617218792Snp	    "# of buffer-group 1 truncated packets");
2618218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc2,
2619218792Snp	    "# of buffer-group 2 truncated packets");
2620218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc3,
2621218792Snp	    "# of buffer-group 3 truncated packets");
2622218792Snp
2623218792Snp#undef SYSCTL_ADD_T4_PORTSTAT
2624218792Snp
2625218792Snp	return (0);
2626218792Snp}
2627218792Snp
2628218792Snpstatic int
2629219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS)
2630219436Snp{
2631219436Snp	int rc, *i;
2632219436Snp	struct sbuf sb;
2633219436Snp
2634219436Snp	sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND);
2635219436Snp	for (i = arg1; arg2; arg2 -= sizeof(int), i++)
2636219436Snp		sbuf_printf(&sb, "%d ", *i);
2637219436Snp	sbuf_trim(&sb);
2638219436Snp	sbuf_finish(&sb);
2639219436Snp	rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
2640219436Snp	sbuf_delete(&sb);
2641219436Snp	return (rc);
2642219436Snp}
2643219436Snp
2644219436Snpstatic int
2645218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS)
2646218792Snp{
2647218792Snp	struct port_info *pi = arg1;
2648218792Snp	struct adapter *sc = pi->adapter;
2649218792Snp	struct sge_rxq *rxq;
2650218792Snp	int idx, rc, i;
2651218792Snp
2652218792Snp	idx = pi->tmr_idx;
2653218792Snp
2654218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
2655218792Snp	if (rc != 0 || req->newptr == NULL)
2656218792Snp		return (rc);
2657218792Snp
2658218792Snp	if (idx < 0 || idx >= SGE_NTIMERS)
2659218792Snp		return (EINVAL);
2660218792Snp
2661218792Snp	ADAPTER_LOCK(sc);
2662218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
2663218792Snp	if (rc == 0) {
2664218792Snp		for_each_rxq(pi, i, rxq) {
2665218792Snp			rxq->iq.intr_params = V_QINTR_TIMER_IDX(idx) |
2666218792Snp			    V_QINTR_CNT_EN(pi->pktc_idx != -1);
2667218792Snp		}
2668218792Snp		pi->tmr_idx = idx;
2669218792Snp	}
2670218792Snp
2671218792Snp	ADAPTER_UNLOCK(sc);
2672218792Snp	return (rc);
2673218792Snp}
2674218792Snp
2675218792Snpstatic int
2676218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS)
2677218792Snp{
2678218792Snp	struct port_info *pi = arg1;
2679218792Snp	struct adapter *sc = pi->adapter;
2680218792Snp	int idx, rc;
2681218792Snp
2682218792Snp	idx = pi->pktc_idx;
2683218792Snp
2684218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
2685218792Snp	if (rc != 0 || req->newptr == NULL)
2686218792Snp		return (rc);
2687218792Snp
2688218792Snp	if (idx < -1 || idx >= SGE_NCOUNTERS)
2689218792Snp		return (EINVAL);
2690218792Snp
2691218792Snp	ADAPTER_LOCK(sc);
2692218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
2693218792Snp	if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING)
2694218792Snp		rc = EBUSY; /* can be changed only when port is down */
2695218792Snp
2696218792Snp	if (rc == 0)
2697218792Snp		pi->pktc_idx = idx;
2698218792Snp
2699218792Snp	ADAPTER_UNLOCK(sc);
2700218792Snp	return (rc);
2701218792Snp}
2702218792Snp
2703218792Snpstatic int
2704218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS)
2705218792Snp{
2706218792Snp	struct port_info *pi = arg1;
2707218792Snp	struct adapter *sc = pi->adapter;
2708218792Snp	int qsize, rc;
2709218792Snp
2710218792Snp	qsize = pi->qsize_rxq;
2711218792Snp
2712218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
2713218792Snp	if (rc != 0 || req->newptr == NULL)
2714218792Snp		return (rc);
2715218792Snp
2716218792Snp	if (qsize < 128 || (qsize & 7))
2717218792Snp		return (EINVAL);
2718218792Snp
2719218792Snp	ADAPTER_LOCK(sc);
2720218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
2721218792Snp	if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING)
2722218792Snp		rc = EBUSY; /* can be changed only when port is down */
2723218792Snp
2724218792Snp	if (rc == 0)
2725218792Snp		pi->qsize_rxq = qsize;
2726218792Snp
2727218792Snp	ADAPTER_UNLOCK(sc);
2728218792Snp	return (rc);
2729218792Snp}
2730218792Snp
2731218792Snpstatic int
2732218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS)
2733218792Snp{
2734218792Snp	struct port_info *pi = arg1;
2735218792Snp	struct adapter *sc = pi->adapter;
2736218792Snp	int qsize, rc;
2737218792Snp
2738218792Snp	qsize = pi->qsize_txq;
2739218792Snp
2740218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
2741218792Snp	if (rc != 0 || req->newptr == NULL)
2742218792Snp		return (rc);
2743218792Snp
2744218792Snp	if (qsize < 128)
2745218792Snp		return (EINVAL);
2746218792Snp
2747218792Snp	ADAPTER_LOCK(sc);
2748218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
2749218792Snp	if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING)
2750218792Snp		rc = EBUSY; /* can be changed only when port is down */
2751218792Snp
2752218792Snp	if (rc == 0)
2753218792Snp		pi->qsize_txq = qsize;
2754218792Snp
2755218792Snp	ADAPTER_UNLOCK(sc);
2756218792Snp	return (rc);
2757218792Snp}
2758218792Snp
2759218792Snpstatic int
2760218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS)
2761218792Snp{
2762218792Snp	struct adapter *sc = arg1;
2763218792Snp	int reg = arg2;
2764218792Snp	uint64_t val;
2765218792Snp
2766218792Snp	val = t4_read_reg64(sc, reg);
2767218792Snp
2768218792Snp	return (sysctl_handle_64(oidp, &val, 0, req));
2769218792Snp}
2770218792Snp
2771222551Snpconst char *devlog_level_strings[] = {
2772222551Snp	[FW_DEVLOG_LEVEL_EMERG]		= "EMERG",
2773222551Snp	[FW_DEVLOG_LEVEL_CRIT]		= "CRIT",
2774222551Snp	[FW_DEVLOG_LEVEL_ERR]		= "ERR",
2775222551Snp	[FW_DEVLOG_LEVEL_NOTICE]	= "NOTICE",
2776222551Snp	[FW_DEVLOG_LEVEL_INFO]		= "INFO",
2777222551Snp	[FW_DEVLOG_LEVEL_DEBUG]		= "DEBUG"
2778222551Snp};
2779222551Snp
2780222551Snpconst char *devlog_facility_strings[] = {
2781222551Snp	[FW_DEVLOG_FACILITY_CORE]	= "CORE",
2782222551Snp	[FW_DEVLOG_FACILITY_SCHED]	= "SCHED",
2783222551Snp	[FW_DEVLOG_FACILITY_TIMER]	= "TIMER",
2784222551Snp	[FW_DEVLOG_FACILITY_RES]	= "RES",
2785222551Snp	[FW_DEVLOG_FACILITY_HW]		= "HW",
2786222551Snp	[FW_DEVLOG_FACILITY_FLR]	= "FLR",
2787222551Snp	[FW_DEVLOG_FACILITY_DMAQ]	= "DMAQ",
2788222551Snp	[FW_DEVLOG_FACILITY_PHY]	= "PHY",
2789222551Snp	[FW_DEVLOG_FACILITY_MAC]	= "MAC",
2790222551Snp	[FW_DEVLOG_FACILITY_PORT]	= "PORT",
2791222551Snp	[FW_DEVLOG_FACILITY_VI]		= "VI",
2792222551Snp	[FW_DEVLOG_FACILITY_FILTER]	= "FILTER",
2793222551Snp	[FW_DEVLOG_FACILITY_ACL]	= "ACL",
2794222551Snp	[FW_DEVLOG_FACILITY_TM]		= "TM",
2795222551Snp	[FW_DEVLOG_FACILITY_QFC]	= "QFC",
2796222551Snp	[FW_DEVLOG_FACILITY_DCB]	= "DCB",
2797222551Snp	[FW_DEVLOG_FACILITY_ETH]	= "ETH",
2798222551Snp	[FW_DEVLOG_FACILITY_OFLD]	= "OFLD",
2799222551Snp	[FW_DEVLOG_FACILITY_RI]		= "RI",
2800222551Snp	[FW_DEVLOG_FACILITY_ISCSI]	= "ISCSI",
2801222551Snp	[FW_DEVLOG_FACILITY_FCOE]	= "FCOE",
2802222551Snp	[FW_DEVLOG_FACILITY_FOISCSI]	= "FOISCSI",
2803222551Snp	[FW_DEVLOG_FACILITY_FOFCOE]	= "FOFCOE"
2804222551Snp};
2805222551Snp
2806222551Snpstatic int
2807222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS)
2808222551Snp{
2809222551Snp	struct adapter *sc = arg1;
2810222551Snp	struct devlog_params *dparams = &sc->params.devlog;
2811222551Snp	struct fw_devlog_e *buf, *e;
2812222551Snp	int i, j, rc, nentries, first = 0;
2813222551Snp	struct sbuf *sb;
2814222551Snp	uint64_t ftstamp = UINT64_MAX;
2815222551Snp
2816222551Snp	if (dparams->start == 0)
2817222551Snp		return (ENXIO);
2818222551Snp
2819222551Snp	nentries = dparams->size / sizeof(struct fw_devlog_e);
2820222551Snp
2821222551Snp	buf = malloc(dparams->size, M_CXGBE, M_NOWAIT);
2822222551Snp	if (buf == NULL)
2823222551Snp		return (ENOMEM);
2824222551Snp
2825222551Snp	rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size,
2826222551Snp	    (void *)buf);
2827222551Snp	if (rc != 0)
2828222551Snp		goto done;
2829222551Snp
2830222551Snp	for (i = 0; i < nentries; i++) {
2831222551Snp		e = &buf[i];
2832222551Snp
2833222551Snp		if (e->timestamp == 0)
2834222551Snp			break;	/* end */
2835222551Snp
2836222551Snp		e->timestamp = be64toh(e->timestamp);
2837222551Snp		e->seqno = be32toh(e->seqno);
2838222551Snp		for (j = 0; j < 8; j++)
2839222551Snp			e->params[j] = be32toh(e->params[j]);
2840222551Snp
2841222551Snp		if (e->timestamp < ftstamp) {
2842222551Snp			ftstamp = e->timestamp;
2843222551Snp			first = i;
2844222551Snp		}
2845222551Snp	}
2846222551Snp
2847222551Snp	if (buf[first].timestamp == 0)
2848222551Snp		goto done;	/* nothing in the log */
2849222551Snp
2850222551Snp	rc = sysctl_wire_old_buffer(req, 0);
2851222551Snp	if (rc != 0)
2852222551Snp		goto done;
2853222551Snp
2854222551Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
2855222551Snp	sbuf_printf(sb, "\n%10s  %15s  %8s  %8s  %s\n",
2856222551Snp	    "Seq#", "Tstamp", "Level", "Facility", "Message");
2857222551Snp
2858222551Snp	i = first;
2859222551Snp	do {
2860222551Snp		e = &buf[i];
2861222551Snp		if (e->timestamp == 0)
2862222551Snp			break;	/* end */
2863222551Snp
2864222551Snp		sbuf_printf(sb, "%10d  %15ju  %8s  %8s  ",
2865222551Snp		    e->seqno, e->timestamp,
2866222551Snp		    (e->level < ARRAY_SIZE(devlog_level_strings) ?
2867222551Snp			devlog_level_strings[e->level] : "UNKNOWN"),
2868222551Snp		    (e->facility < ARRAY_SIZE(devlog_facility_strings) ?
2869222551Snp			devlog_facility_strings[e->facility] : "UNKNOWN"));
2870222551Snp		sbuf_printf(sb, e->fmt, e->params[0], e->params[1],
2871222551Snp		    e->params[2], e->params[3], e->params[4],
2872222551Snp		    e->params[5], e->params[6], e->params[7]);
2873222551Snp
2874222551Snp		if (++i == nentries)
2875222551Snp			i = 0;
2876222551Snp	} while (i != first);
2877222551Snp
2878222551Snp	rc = sbuf_finish(sb);
2879222551Snp	sbuf_delete(sb);
2880222551Snpdone:
2881222551Snp	free(buf, M_CXGBE);
2882222551Snp	return (rc);
2883222551Snp}
2884222551Snp
2885219286Snpstatic inline void
2886219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq)
2887219286Snp{
2888219286Snp	struct buf_ring *br;
2889219286Snp	struct mbuf *m;
2890219286Snp
2891219286Snp	TXQ_LOCK_ASSERT_OWNED(txq);
2892219286Snp
2893220873Snp	br = txq->br;
2894219286Snp	m = txq->m ? txq->m : drbr_dequeue(ifp, br);
2895219286Snp	if (m)
2896219286Snp		t4_eth_tx(ifp, txq, m);
2897219286Snp}
2898219286Snp
2899219286Snpvoid
2900219286Snpcxgbe_txq_start(void *arg, int count)
2901219286Snp{
2902219286Snp	struct sge_txq *txq = arg;
2903219286Snp
2904219286Snp	TXQ_LOCK(txq);
2905220649Snp	if (txq->eq.flags & EQ_CRFLUSHED) {
2906220649Snp		txq->eq.flags &= ~EQ_CRFLUSHED;
2907220649Snp		txq_start(txq->ifp, txq);
2908220649Snp	} else
2909220649Snp		wakeup_one(txq);	/* txq is going away, wakeup free_txq */
2910219286Snp	TXQ_UNLOCK(txq);
2911219286Snp}
2912219286Snp
2913221474Snpstatic uint32_t
2914221474Snpfconf_to_mode(uint32_t fconf)
2915221474Snp{
2916221474Snp	uint32_t mode;
2917221474Snp
2918221474Snp	mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR |
2919221474Snp	    T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT;
2920221474Snp
2921221474Snp	if (fconf & F_FRAGMENTATION)
2922221474Snp		mode |= T4_FILTER_IP_FRAGMENT;
2923221474Snp
2924221474Snp	if (fconf & F_MPSHITTYPE)
2925221474Snp		mode |= T4_FILTER_MPS_HIT_TYPE;
2926221474Snp
2927221474Snp	if (fconf & F_MACMATCH)
2928221474Snp		mode |= T4_FILTER_MAC_IDX;
2929221474Snp
2930221474Snp	if (fconf & F_ETHERTYPE)
2931221474Snp		mode |= T4_FILTER_ETH_TYPE;
2932221474Snp
2933221474Snp	if (fconf & F_PROTOCOL)
2934221474Snp		mode |= T4_FILTER_IP_PROTO;
2935221474Snp
2936221474Snp	if (fconf & F_TOS)
2937221474Snp		mode |= T4_FILTER_IP_TOS;
2938221474Snp
2939221474Snp	if (fconf & F_VLAN)
2940221474Snp		mode |= T4_FILTER_IVLAN;
2941221474Snp
2942221474Snp	if (fconf & F_VNIC_ID)
2943221474Snp		mode |= T4_FILTER_OVLAN;
2944221474Snp
2945221474Snp	if (fconf & F_PORT)
2946221474Snp		mode |= T4_FILTER_PORT;
2947221474Snp
2948221474Snp	if (fconf & F_FCOE)
2949221474Snp		mode |= T4_FILTER_FCoE;
2950221474Snp
2951221474Snp	return (mode);
2952221474Snp}
2953221474Snp
2954221474Snpstatic uint32_t
2955221474Snpmode_to_fconf(uint32_t mode)
2956221474Snp{
2957221474Snp	uint32_t fconf = 0;
2958221474Snp
2959221474Snp	if (mode & T4_FILTER_IP_FRAGMENT)
2960221474Snp		fconf |= F_FRAGMENTATION;
2961221474Snp
2962221474Snp	if (mode & T4_FILTER_MPS_HIT_TYPE)
2963221474Snp		fconf |= F_MPSHITTYPE;
2964221474Snp
2965221474Snp	if (mode & T4_FILTER_MAC_IDX)
2966221474Snp		fconf |= F_MACMATCH;
2967221474Snp
2968221474Snp	if (mode & T4_FILTER_ETH_TYPE)
2969221474Snp		fconf |= F_ETHERTYPE;
2970221474Snp
2971221474Snp	if (mode & T4_FILTER_IP_PROTO)
2972221474Snp		fconf |= F_PROTOCOL;
2973221474Snp
2974221474Snp	if (mode & T4_FILTER_IP_TOS)
2975221474Snp		fconf |= F_TOS;
2976221474Snp
2977221474Snp	if (mode & T4_FILTER_IVLAN)
2978221474Snp		fconf |= F_VLAN;
2979221474Snp
2980221474Snp	if (mode & T4_FILTER_OVLAN)
2981221474Snp		fconf |= F_VNIC_ID;
2982221474Snp
2983221474Snp	if (mode & T4_FILTER_PORT)
2984221474Snp		fconf |= F_PORT;
2985221474Snp
2986221474Snp	if (mode & T4_FILTER_FCoE)
2987221474Snp		fconf |= F_FCOE;
2988221474Snp
2989221474Snp	return (fconf);
2990221474Snp}
2991221474Snp
2992221474Snpstatic uint32_t
2993221474Snpfspec_to_fconf(struct t4_filter_specification *fs)
2994221474Snp{
2995221474Snp	uint32_t fconf = 0;
2996221474Snp
2997221474Snp	if (fs->val.frag || fs->mask.frag)
2998221474Snp		fconf |= F_FRAGMENTATION;
2999221474Snp
3000221474Snp	if (fs->val.matchtype || fs->mask.matchtype)
3001221474Snp		fconf |= F_MPSHITTYPE;
3002221474Snp
3003221474Snp	if (fs->val.macidx || fs->mask.macidx)
3004221474Snp		fconf |= F_MACMATCH;
3005221474Snp
3006221474Snp	if (fs->val.ethtype || fs->mask.ethtype)
3007221474Snp		fconf |= F_ETHERTYPE;
3008221474Snp
3009221474Snp	if (fs->val.proto || fs->mask.proto)
3010221474Snp		fconf |= F_PROTOCOL;
3011221474Snp
3012221474Snp	if (fs->val.tos || fs->mask.tos)
3013221474Snp		fconf |= F_TOS;
3014221474Snp
3015221474Snp	if (fs->val.ivlan_vld || fs->mask.ivlan_vld)
3016221474Snp		fconf |= F_VLAN;
3017221474Snp
3018221474Snp	if (fs->val.ovlan_vld || fs->mask.ovlan_vld)
3019221474Snp		fconf |= F_VNIC_ID;
3020221474Snp
3021221474Snp	if (fs->val.iport || fs->mask.iport)
3022221474Snp		fconf |= F_PORT;
3023221474Snp
3024221474Snp	if (fs->val.fcoe || fs->mask.fcoe)
3025221474Snp		fconf |= F_FCOE;
3026221474Snp
3027221474Snp	return (fconf);
3028221474Snp}
3029221474Snp
3030221474Snpstatic int
3031221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode)
3032221474Snp{
3033221474Snp	uint32_t fconf;
3034221474Snp
3035221474Snp	t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1,
3036221474Snp	    A_TP_VLAN_PRI_MAP);
3037221474Snp
3038221474Snp	*mode = fconf_to_mode(fconf);
3039221474Snp
3040221474Snp	return (0);
3041221474Snp}
3042221474Snp
3043221474Snpstatic int
3044221474Snpset_filter_mode(struct adapter *sc, uint32_t mode)
3045221474Snp{
3046221474Snp	uint32_t fconf;
3047221474Snp	int rc;
3048221474Snp
3049221474Snp	fconf = mode_to_fconf(mode);
3050221474Snp
3051221474Snp	ADAPTER_LOCK(sc);
3052221474Snp	if (IS_BUSY(sc)) {
3053221474Snp		rc = EAGAIN;
3054221474Snp		goto done;
3055221474Snp	}
3056221474Snp
3057221474Snp	if (sc->tids.ftids_in_use > 0) {
3058221474Snp		rc = EBUSY;
3059221474Snp		goto done;
3060221474Snp	}
3061221474Snp
3062221474Snp	rc = -t4_set_filter_mode(sc, fconf);
3063221474Snpdone:
3064221474Snp	ADAPTER_UNLOCK(sc);
3065221474Snp	return (rc);
3066221474Snp}
3067221474Snp
3068222552Snpstatic inline uint64_t
3069222552Snpget_filter_hits(struct adapter *sc, uint32_t fid)
3070222552Snp{
3071222552Snp	uint32_t tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE);
3072222552Snp	uint64_t hits;
3073222552Snp
3074222552Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0),
3075222552Snp	    tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE);
3076222552Snp	t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0));
3077222552Snp	hits = t4_read_reg64(sc, MEMWIN0_BASE + 16);
3078222552Snp
3079222552Snp	return (be64toh(hits));
3080222552Snp}
3081222552Snp
3082221474Snpstatic int
3083221474Snpget_filter(struct adapter *sc, struct t4_filter *t)
3084221474Snp{
3085221474Snp	int i, nfilters = sc->tids.nftids;
3086221474Snp	struct filter_entry *f;
3087221474Snp
3088221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
3089221474Snp
3090221474Snp	if (IS_BUSY(sc))
3091221474Snp		return (EAGAIN);
3092221474Snp
3093221474Snp	if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL ||
3094221474Snp	    t->idx >= nfilters) {
3095221474Snp		t->idx = 0xffffffff;
3096221474Snp		return (0);
3097221474Snp	}
3098221474Snp
3099221474Snp	f = &sc->tids.ftid_tab[t->idx];
3100221474Snp	for (i = t->idx; i < nfilters; i++, f++) {
3101221474Snp		if (f->valid) {
3102221474Snp			t->idx = i;
3103222509Snp			t->l2tidx = f->l2t ? f->l2t->idx : 0;
3104222509Snp			t->smtidx = f->smtidx;
3105222552Snp			if (f->fs.hitcnts)
3106222552Snp				t->hits = get_filter_hits(sc, t->idx);
3107222552Snp			else
3108222552Snp				t->hits = UINT64_MAX;
3109221474Snp			t->fs = f->fs;
3110221474Snp
3111221474Snp			return (0);
3112221474Snp		}
3113221474Snp	}
3114221474Snp
3115221474Snp	t->idx = 0xffffffff;
3116221474Snp	return (0);
3117221474Snp}
3118221474Snp
3119221474Snpstatic int
3120221474Snpset_filter(struct adapter *sc, struct t4_filter *t)
3121221474Snp{
3122221474Snp	uint32_t fconf;
3123221474Snp	unsigned int nfilters, nports;
3124221474Snp	struct filter_entry *f;
3125221474Snp	int i;
3126221474Snp
3127221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
3128221474Snp
3129221474Snp	nfilters = sc->tids.nftids;
3130221474Snp	nports = sc->params.nports;
3131221474Snp
3132221474Snp	if (nfilters == 0)
3133221474Snp		return (ENOTSUP);
3134221474Snp
3135221474Snp	if (!(sc->flags & FULL_INIT_DONE))
3136221474Snp		return (EAGAIN);
3137221474Snp
3138221474Snp	if (t->idx >= nfilters)
3139221474Snp		return (EINVAL);
3140221474Snp
3141221474Snp	/* Validate against the global filter mode */
3142221474Snp	t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1,
3143221474Snp	    A_TP_VLAN_PRI_MAP);
3144221474Snp	if ((fconf | fspec_to_fconf(&t->fs)) != fconf)
3145221474Snp		return (E2BIG);
3146221474Snp
3147221474Snp	if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports)
3148221474Snp		return (EINVAL);
3149221474Snp
3150221474Snp	if (t->fs.val.iport >= nports)
3151221474Snp		return (EINVAL);
3152221474Snp
3153221474Snp	/* Can't specify an iq if not steering to it */
3154221474Snp	if (!t->fs.dirsteer && t->fs.iq)
3155221474Snp		return (EINVAL);
3156221474Snp
3157221474Snp	/* IPv6 filter idx must be 4 aligned */
3158221474Snp	if (t->fs.type == 1 &&
3159221474Snp	    ((t->idx & 0x3) || t->idx + 4 >= nfilters))
3160221474Snp		return (EINVAL);
3161221474Snp
3162221474Snp	if (sc->tids.ftid_tab == NULL) {
3163221474Snp		KASSERT(sc->tids.ftids_in_use == 0,
3164221474Snp		    ("%s: no memory allocated but filters_in_use > 0",
3165221474Snp		    __func__));
3166221474Snp
3167221474Snp		sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) *
3168221474Snp		    nfilters, M_CXGBE, M_NOWAIT | M_ZERO);
3169221474Snp		if (sc->tids.ftid_tab == NULL)
3170221474Snp			return (ENOMEM);
3171221474Snp	}
3172221474Snp
3173221474Snp	for (i = 0; i < 4; i++) {
3174221474Snp		f = &sc->tids.ftid_tab[t->idx + i];
3175221474Snp
3176221474Snp		if (f->pending || f->valid)
3177221474Snp			return (EBUSY);
3178221474Snp		if (f->locked)
3179221474Snp			return (EPERM);
3180221474Snp
3181221474Snp		if (t->fs.type == 0)
3182221474Snp			break;
3183221474Snp	}
3184221474Snp
3185221474Snp	f = &sc->tids.ftid_tab[t->idx];
3186221474Snp	f->fs = t->fs;
3187221474Snp
3188221474Snp	return set_filter_wr(sc, t->idx);
3189221474Snp}
3190221474Snp
3191221474Snpstatic int
3192221474Snpdel_filter(struct adapter *sc, struct t4_filter *t)
3193221474Snp{
3194221474Snp	unsigned int nfilters;
3195221474Snp	struct filter_entry *f;
3196221474Snp
3197221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
3198221474Snp
3199221474Snp	if (IS_BUSY(sc))
3200221474Snp		return (EAGAIN);
3201221474Snp
3202221474Snp	nfilters = sc->tids.nftids;
3203221474Snp
3204221474Snp	if (nfilters == 0)
3205221474Snp		return (ENOTSUP);
3206221474Snp
3207221474Snp	if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 ||
3208221474Snp	    t->idx >= nfilters)
3209221474Snp		return (EINVAL);
3210221474Snp
3211221474Snp	if (!(sc->flags & FULL_INIT_DONE))
3212221474Snp		return (EAGAIN);
3213221474Snp
3214221474Snp	f = &sc->tids.ftid_tab[t->idx];
3215221474Snp
3216221474Snp	if (f->pending)
3217221474Snp		return (EBUSY);
3218221474Snp	if (f->locked)
3219221474Snp		return (EPERM);
3220221474Snp
3221221474Snp	if (f->valid) {
3222221474Snp		t->fs = f->fs;	/* extra info for the caller */
3223221474Snp		return del_filter_wr(sc, t->idx);
3224221474Snp	}
3225221474Snp
3226221474Snp	return (0);
3227221474Snp}
3228221474Snp
3229221474Snpstatic void
3230222509Snpclear_filter(struct filter_entry *f)
3231221474Snp{
3232222509Snp	if (f->l2t)
3233222509Snp		t4_l2t_release(f->l2t);
3234222509Snp
3235221474Snp	bzero(f, sizeof (*f));
3236221474Snp}
3237221474Snp
3238221474Snpstatic int
3239221474Snpset_filter_wr(struct adapter *sc, int fidx)
3240221474Snp{
3241221474Snp	int rc;
3242221474Snp	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
3243221474Snp	struct mbuf *m;
3244221474Snp	struct fw_filter_wr *fwr;
3245221474Snp	unsigned int ftid;
3246221474Snp
3247221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
3248221474Snp
3249222509Snp	if (f->fs.newdmac || f->fs.newvlan) {
3250222509Snp		/* This filter needs an L2T entry; allocate one. */
3251222509Snp		f->l2t = t4_l2t_alloc_switching(sc->l2t);
3252222509Snp		if (f->l2t == NULL)
3253222509Snp			return (EAGAIN);
3254222509Snp		if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport,
3255222509Snp		    f->fs.dmac)) {
3256222509Snp			t4_l2t_release(f->l2t);
3257222509Snp			f->l2t = NULL;
3258222509Snp			return (ENOMEM);
3259222509Snp		}
3260222509Snp	}
3261221474Snp
3262221474Snp	ftid = sc->tids.ftid_base + fidx;
3263221474Snp
3264221474Snp	m = m_gethdr(M_NOWAIT, MT_DATA);
3265221474Snp	if (m == NULL)
3266221474Snp		return (ENOMEM);
3267221474Snp
3268221474Snp	fwr = mtod(m, struct fw_filter_wr *);
3269221474Snp	m->m_len = m->m_pkthdr.len = sizeof(*fwr);
3270221474Snp	bzero(fwr, sizeof (*fwr));
3271221474Snp
3272221474Snp	fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR));
3273221474Snp	fwr->len16_pkd = htobe32(FW_LEN16(*fwr));
3274221474Snp	fwr->tid_to_iq =
3275221474Snp	    htobe32(V_FW_FILTER_WR_TID(ftid) |
3276221474Snp		V_FW_FILTER_WR_RQTYPE(f->fs.type) |
3277221474Snp		V_FW_FILTER_WR_NOREPLY(0) |
3278221474Snp		V_FW_FILTER_WR_IQ(f->fs.iq));
3279221474Snp	fwr->del_filter_to_l2tix =
3280221474Snp	    htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) |
3281221474Snp		V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) |
3282221474Snp		V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) |
3283221474Snp		V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) |
3284221474Snp		V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) |
3285221474Snp		V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) |
3286221474Snp		V_FW_FILTER_WR_DMAC(f->fs.newdmac) |
3287221474Snp		V_FW_FILTER_WR_SMAC(f->fs.newsmac) |
3288221474Snp		V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT ||
3289221474Snp		    f->fs.newvlan == VLAN_REWRITE) |
3290221474Snp		V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE ||
3291221474Snp		    f->fs.newvlan == VLAN_REWRITE) |
3292221474Snp		V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) |
3293221474Snp		V_FW_FILTER_WR_TXCHAN(f->fs.eport) |
3294221474Snp		V_FW_FILTER_WR_PRIO(f->fs.prio) |
3295222509Snp		V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0));
3296221474Snp	fwr->ethtype = htobe16(f->fs.val.ethtype);
3297221474Snp	fwr->ethtypem = htobe16(f->fs.mask.ethtype);
3298221474Snp	fwr->frag_to_ovlan_vldm =
3299221474Snp	    (V_FW_FILTER_WR_FRAG(f->fs.val.frag) |
3300221474Snp		V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) |
3301221474Snp		V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.ivlan_vld) |
3302221474Snp		V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.ovlan_vld) |
3303221474Snp		V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.ivlan_vld) |
3304221474Snp		V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.ovlan_vld));
3305221474Snp	fwr->smac_sel = 0;
3306221474Snp	fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) |
3307222510Snp	    V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.intrq[0].abs_id));
3308221474Snp	fwr->maci_to_matchtypem =
3309221474Snp	    htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) |
3310221474Snp		V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) |
3311221474Snp		V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) |
3312221474Snp		V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) |
3313221474Snp		V_FW_FILTER_WR_PORT(f->fs.val.iport) |
3314221474Snp		V_FW_FILTER_WR_PORTM(f->fs.mask.iport) |
3315221474Snp		V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) |
3316221474Snp		V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype));
3317221474Snp	fwr->ptcl = f->fs.val.proto;
3318221474Snp	fwr->ptclm = f->fs.mask.proto;
3319221474Snp	fwr->ttyp = f->fs.val.tos;
3320221474Snp	fwr->ttypm = f->fs.mask.tos;
3321221474Snp	fwr->ivlan = htobe16(f->fs.val.ivlan);
3322221474Snp	fwr->ivlanm = htobe16(f->fs.mask.ivlan);
3323221474Snp	fwr->ovlan = htobe16(f->fs.val.ovlan);
3324221474Snp	fwr->ovlanm = htobe16(f->fs.mask.ovlan);
3325221474Snp	bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip));
3326221474Snp	bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm));
3327221474Snp	bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip));
3328221474Snp	bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm));
3329221474Snp	fwr->lp = htobe16(f->fs.val.dport);
3330221474Snp	fwr->lpm = htobe16(f->fs.mask.dport);
3331221474Snp	fwr->fp = htobe16(f->fs.val.sport);
3332221474Snp	fwr->fpm = htobe16(f->fs.mask.sport);
3333221474Snp	if (f->fs.newsmac)
3334221474Snp		bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma));
3335221474Snp
3336221474Snp	f->pending = 1;
3337221474Snp	sc->tids.ftids_in_use++;
3338221474Snp	rc = t4_mgmt_tx(sc, m);
3339221474Snp	if (rc != 0) {
3340221474Snp		sc->tids.ftids_in_use--;
3341221474Snp		m_freem(m);
3342222509Snp		clear_filter(f);
3343221474Snp	}
3344221474Snp	return (rc);
3345221474Snp}
3346221474Snp
3347221474Snpstatic int
3348221474Snpdel_filter_wr(struct adapter *sc, int fidx)
3349221474Snp{
3350221474Snp	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
3351221474Snp	struct mbuf *m;
3352221474Snp	struct fw_filter_wr *fwr;
3353221474Snp	unsigned int rc, ftid;
3354221474Snp
3355221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
3356221474Snp
3357221474Snp	ftid = sc->tids.ftid_base + fidx;
3358221474Snp
3359221474Snp	m = m_gethdr(M_NOWAIT, MT_DATA);
3360221474Snp	if (m == NULL)
3361221474Snp		return (ENOMEM);
3362221474Snp
3363221474Snp	fwr = mtod(m, struct fw_filter_wr *);
3364221474Snp	m->m_len = m->m_pkthdr.len = sizeof(*fwr);
3365221474Snp	bzero(fwr, sizeof (*fwr));
3366221474Snp
3367222510Snp	t4_mk_filtdelwr(ftid, fwr, sc->sge.intrq[0].abs_id);
3368221474Snp
3369221474Snp	f->pending = 1;
3370221474Snp	rc = t4_mgmt_tx(sc, m);
3371221474Snp	if (rc != 0) {
3372221474Snp		f->pending = 0;
3373221474Snp		m_freem(m);
3374221474Snp	}
3375221474Snp	return (rc);
3376221474Snp}
3377221474Snp
3378221474Snp/* XXX move intr handlers to main.c and make this static */
3379221474Snpvoid
3380221474Snpfilter_rpl(struct adapter *sc, const struct cpl_set_tcb_rpl *rpl)
3381221474Snp{
3382221474Snp	unsigned int idx = GET_TID(rpl);
3383221474Snp
3384221474Snp	if (idx >= sc->tids.ftid_base &&
3385221474Snp	    (idx -= sc->tids.ftid_base) < sc->tids.nftids) {
3386221474Snp		unsigned int rc = G_COOKIE(rpl->cookie);
3387221474Snp		struct filter_entry *f = &sc->tids.ftid_tab[idx];
3388221474Snp
3389221474Snp		if (rc == FW_FILTER_WR_FLT_DELETED) {
3390221474Snp			/*
3391221474Snp			 * Clear the filter when we get confirmation from the
3392221474Snp			 * hardware that the filter has been deleted.
3393221474Snp			 */
3394222509Snp			clear_filter(f);
3395221474Snp			sc->tids.ftids_in_use--;
3396221474Snp		} else if (rc == FW_FILTER_WR_SMT_TBL_FULL) {
3397221474Snp			device_printf(sc->dev,
3398221474Snp			    "filter %u setup failed due to full SMT\n", idx);
3399222509Snp			clear_filter(f);
3400221474Snp			sc->tids.ftids_in_use--;
3401221474Snp		} else if (rc == FW_FILTER_WR_FLT_ADDED) {
3402221474Snp			f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff;
3403221474Snp			f->pending = 0;  /* asynchronous setup completed */
3404221474Snp			f->valid = 1;
3405221474Snp		} else {
3406221474Snp			/*
3407221474Snp			 * Something went wrong.  Issue a warning about the
3408221474Snp			 * problem and clear everything out.
3409221474Snp			 */
3410221474Snp			device_printf(sc->dev,
3411221474Snp			    "filter %u setup failed with error %u\n", idx, rc);
3412222509Snp			clear_filter(f);
3413221474Snp			sc->tids.ftids_in_use--;
3414221474Snp		}
3415221474Snp	}
3416221474Snp}
3417221474Snp
3418222973Snpstatic int
3419222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt)
3420222973Snp{
3421222973Snp	int rc = EINVAL;
3422222973Snp
3423222973Snp	if (cntxt->cid > M_CTXTQID)
3424222973Snp		return (rc);
3425222973Snp
3426222973Snp	if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS &&
3427222973Snp	    cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM)
3428222973Snp		return (rc);
3429222973Snp
3430222973Snp	if (sc->flags & FW_OK) {
3431222973Snp		ADAPTER_LOCK(sc);	/* Avoid parallel t4_wr_mbox */
3432222973Snp		rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id,
3433222973Snp		    &cntxt->data[0]);
3434222973Snp		ADAPTER_UNLOCK(sc);
3435222973Snp	}
3436222973Snp
3437222973Snp	if (rc != 0) {
3438222973Snp		/* Read via firmware failed or wasn't even attempted */
3439222973Snp
3440222973Snp		rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id,
3441222973Snp		    &cntxt->data[0]);
3442222973Snp	}
3443222973Snp
3444222973Snp	return (rc);
3445222973Snp}
3446222973Snp
3447218792Snpint
3448218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap)
3449218792Snp{
3450222102Snp	int i;
3451218792Snp
3452222102Snp	return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0);
3453218792Snp}
3454218792Snp
3455218792Snpint
3456218792Snpt4_os_pci_save_state(struct adapter *sc)
3457218792Snp{
3458218792Snp	device_t dev;
3459218792Snp	struct pci_devinfo *dinfo;
3460218792Snp
3461218792Snp	dev = sc->dev;
3462218792Snp	dinfo = device_get_ivars(dev);
3463218792Snp
3464218792Snp	pci_cfg_save(dev, dinfo, 0);
3465218792Snp	return (0);
3466218792Snp}
3467218792Snp
3468218792Snpint
3469218792Snpt4_os_pci_restore_state(struct adapter *sc)
3470218792Snp{
3471218792Snp	device_t dev;
3472218792Snp	struct pci_devinfo *dinfo;
3473218792Snp
3474218792Snp	dev = sc->dev;
3475218792Snp	dinfo = device_get_ivars(dev);
3476218792Snp
3477218792Snp	pci_cfg_restore(dev, dinfo);
3478218792Snp	return (0);
3479218792Snp}
3480219299Snp
3481218792Snpvoid
3482218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx)
3483218792Snp{
3484218792Snp	struct port_info *pi = sc->port[idx];
3485218792Snp	static const char *mod_str[] = {
3486220232Snp		NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
3487218792Snp	};
3488218792Snp
3489218792Snp	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
3490218792Snp		if_printf(pi->ifp, "transceiver unplugged.\n");
3491220232Snp	else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
3492220232Snp		if_printf(pi->ifp, "unknown transceiver inserted.\n");
3493220232Snp	else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
3494220232Snp		if_printf(pi->ifp, "unsupported transceiver inserted.\n");
3495219299Snp	else if (pi->mod_type > 0 && pi->mod_type < ARRAY_SIZE(mod_str)) {
3496218792Snp		if_printf(pi->ifp, "%s transceiver inserted.\n",
3497218792Snp		    mod_str[pi->mod_type]);
3498219299Snp	} else {
3499219299Snp		if_printf(pi->ifp, "transceiver (type %d) inserted.\n",
3500219299Snp		    pi->mod_type);
3501219299Snp	}
3502218792Snp}
3503218792Snp
3504218792Snpvoid
3505218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat)
3506218792Snp{
3507218792Snp	struct port_info *pi = sc->port[idx];
3508218792Snp	struct ifnet *ifp = pi->ifp;
3509218792Snp
3510218792Snp	if (link_stat) {
3511218792Snp		ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed);
3512218792Snp		if_link_state_change(ifp, LINK_STATE_UP);
3513218792Snp	} else
3514218792Snp		if_link_state_change(ifp, LINK_STATE_DOWN);
3515218792Snp}
3516218792Snp
3517218792Snpstatic int
3518218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td)
3519218792Snp{
3520218792Snp       return (0);
3521218792Snp}
3522218792Snp
3523218792Snpstatic int
3524218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td)
3525218792Snp{
3526218792Snp       return (0);
3527218792Snp}
3528218792Snp
3529218792Snpstatic int
3530218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag,
3531218792Snp    struct thread *td)
3532218792Snp{
3533218792Snp	int rc;
3534218792Snp	struct adapter *sc = dev->si_drv1;
3535218792Snp
3536218792Snp	rc = priv_check(td, PRIV_DRIVER);
3537218792Snp	if (rc != 0)
3538218792Snp		return (rc);
3539218792Snp
3540218792Snp	switch (cmd) {
3541220410Snp	case CHELSIO_T4_GETREG: {
3542220410Snp		struct t4_reg *edata = (struct t4_reg *)data;
3543220410Snp
3544218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
3545218792Snp			return (EFAULT);
3546220410Snp
3547220410Snp		if (edata->size == 4)
3548220410Snp			edata->val = t4_read_reg(sc, edata->addr);
3549220410Snp		else if (edata->size == 8)
3550220410Snp			edata->val = t4_read_reg64(sc, edata->addr);
3551220410Snp		else
3552220410Snp			return (EINVAL);
3553220410Snp
3554218792Snp		break;
3555218792Snp	}
3556220410Snp	case CHELSIO_T4_SETREG: {
3557220410Snp		struct t4_reg *edata = (struct t4_reg *)data;
3558220410Snp
3559218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
3560218792Snp			return (EFAULT);
3561220410Snp
3562220410Snp		if (edata->size == 4) {
3563220410Snp			if (edata->val & 0xffffffff00000000)
3564220410Snp				return (EINVAL);
3565220410Snp			t4_write_reg(sc, edata->addr, (uint32_t) edata->val);
3566220410Snp		} else if (edata->size == 8)
3567220410Snp			t4_write_reg64(sc, edata->addr, edata->val);
3568220410Snp		else
3569220410Snp			return (EINVAL);
3570218792Snp		break;
3571218792Snp	}
3572218792Snp	case CHELSIO_T4_REGDUMP: {
3573218792Snp		struct t4_regdump *regs = (struct t4_regdump *)data;
3574218792Snp		int reglen = T4_REGDUMP_SIZE;
3575218792Snp		uint8_t *buf;
3576218792Snp
3577218792Snp		if (regs->len < reglen) {
3578218792Snp			regs->len = reglen; /* hint to the caller */
3579218792Snp			return (ENOBUFS);
3580218792Snp		}
3581218792Snp
3582218792Snp		regs->len = reglen;
3583218792Snp		buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO);
3584218792Snp		t4_get_regs(sc, regs, buf);
3585218792Snp		rc = copyout(buf, regs->data, reglen);
3586218792Snp		free(buf, M_CXGBE);
3587218792Snp		break;
3588218792Snp	}
3589221474Snp	case CHELSIO_T4_GET_FILTER_MODE:
3590221474Snp		rc = get_filter_mode(sc, (uint32_t *)data);
3591221474Snp		break;
3592221474Snp	case CHELSIO_T4_SET_FILTER_MODE:
3593221474Snp		rc = set_filter_mode(sc, *(uint32_t *)data);
3594221474Snp		break;
3595221474Snp	case CHELSIO_T4_GET_FILTER:
3596221474Snp		ADAPTER_LOCK(sc);
3597221474Snp		rc = get_filter(sc, (struct t4_filter *)data);
3598221474Snp		ADAPTER_UNLOCK(sc);
3599221474Snp		break;
3600221474Snp	case CHELSIO_T4_SET_FILTER:
3601221474Snp		ADAPTER_LOCK(sc);
3602221474Snp		rc = set_filter(sc, (struct t4_filter *)data);
3603221474Snp		ADAPTER_UNLOCK(sc);
3604221474Snp		break;
3605221474Snp	case CHELSIO_T4_DEL_FILTER:
3606221474Snp		ADAPTER_LOCK(sc);
3607221474Snp		rc = del_filter(sc, (struct t4_filter *)data);
3608221474Snp		ADAPTER_UNLOCK(sc);
3609221474Snp		break;
3610222973Snp	case CHELSIO_T4_GET_SGE_CONTEXT:
3611222973Snp		rc = get_sge_context(sc, (struct t4_sge_context *)data);
3612222973Snp		break;
3613218792Snp	default:
3614218792Snp		rc = EINVAL;
3615218792Snp	}
3616218792Snp
3617218792Snp	return (rc);
3618218792Snp}
3619218792Snp
3620219392Snpstatic int
3621219392Snpt4_mod_event(module_t mod, int cmd, void *arg)
3622219392Snp{
3623219392Snp
3624219392Snp	if (cmd == MOD_LOAD)
3625219392Snp		t4_sge_modload();
3626219392Snp
3627219392Snp	return (0);
3628219392Snp}
3629219392Snp
3630218792Snpstatic devclass_t t4_devclass;
3631218792Snpstatic devclass_t cxgbe_devclass;
3632218792Snp
3633219392SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0);
3634218792SnpMODULE_VERSION(t4nex, 1);
3635218792Snp
3636218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0);
3637218792SnpMODULE_VERSION(cxgbe, 1);
3638