t4_main.c revision 218792
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 218792 2011-02-18 08:00:26Z np $");
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>
39218792Snp#include <sys/pciio.h>
40218792Snp#include <dev/pci/pcireg.h>
41218792Snp#include <dev/pci/pcivar.h>
42218792Snp#include <dev/pci/pci_private.h>
43218792Snp#include <sys/firmware.h>
44218792Snp#include <sys/smp.h>
45218792Snp#include <sys/socket.h>
46218792Snp#include <sys/sockio.h>
47218792Snp#include <sys/sysctl.h>
48218792Snp#include <net/ethernet.h>
49218792Snp#include <net/if.h>
50218792Snp#include <net/if_types.h>
51218792Snp#include <net/if_dl.h>
52218792Snp
53218792Snp#include "common/t4_hw.h"
54218792Snp#include "common/common.h"
55218792Snp#include "common/t4_regs.h"
56218792Snp#include "common/t4_regs_values.h"
57218792Snp#include "common/t4fw_interface.h"
58218792Snp#include "t4_ioctl.h"
59218792Snp
60218792Snp/* T4 bus driver interface */
61218792Snpstatic int t4_probe(device_t);
62218792Snpstatic int t4_attach(device_t);
63218792Snpstatic int t4_detach(device_t);
64218792Snpstatic device_method_t t4_methods[] = {
65218792Snp	DEVMETHOD(device_probe,		t4_probe),
66218792Snp	DEVMETHOD(device_attach,	t4_attach),
67218792Snp	DEVMETHOD(device_detach,	t4_detach),
68218792Snp
69218792Snp	/* bus interface */
70218792Snp	DEVMETHOD(bus_print_child,	bus_generic_print_child),
71218792Snp	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
72218792Snp
73218792Snp	{ 0, 0 }
74218792Snp};
75218792Snpstatic driver_t t4_driver = {
76218792Snp	"t4nex",
77218792Snp	t4_methods,
78218792Snp	sizeof(struct adapter)
79218792Snp};
80218792Snp
81218792Snp
82218792Snp/* T4 port (cxgbe) interface */
83218792Snpstatic int cxgbe_probe(device_t);
84218792Snpstatic int cxgbe_attach(device_t);
85218792Snpstatic int cxgbe_detach(device_t);
86218792Snpstatic device_method_t cxgbe_methods[] = {
87218792Snp	DEVMETHOD(device_probe,		cxgbe_probe),
88218792Snp	DEVMETHOD(device_attach,	cxgbe_attach),
89218792Snp	DEVMETHOD(device_detach,	cxgbe_detach),
90218792Snp	{ 0, 0 }
91218792Snp};
92218792Snpstatic driver_t cxgbe_driver = {
93218792Snp	"cxgbe",
94218792Snp	cxgbe_methods,
95218792Snp	sizeof(struct port_info)
96218792Snp};
97218792Snp
98218792Snpstatic d_ioctl_t t4_ioctl;
99218792Snpstatic d_open_t t4_open;
100218792Snpstatic d_close_t t4_close;
101218792Snp
102218792Snpstatic struct cdevsw t4_cdevsw = {
103218792Snp       .d_version = D_VERSION,
104218792Snp       .d_flags = 0,
105218792Snp       .d_open = t4_open,
106218792Snp       .d_close = t4_close,
107218792Snp       .d_ioctl = t4_ioctl,
108218792Snp       .d_name = "t4nex",
109218792Snp};
110218792Snp
111218792Snp/* ifnet + media interface */
112218792Snpstatic void cxgbe_init(void *);
113218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t);
114218792Snpstatic void cxgbe_start(struct ifnet *);
115218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *);
116218792Snpstatic void cxgbe_qflush(struct ifnet *);
117218792Snpstatic int cxgbe_media_change(struct ifnet *);
118218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *);
119218792Snp
120218792SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4 Ethernet driver and services");
121218792Snp
122218792Snp/*
123218792Snp * Tunables.
124218792Snp */
125218792SnpSYSCTL_NODE(_hw, OID_AUTO, cxgbe, CTLFLAG_RD, 0, "cxgbe driver parameters");
126218792Snp
127218792Snpstatic int force_firmware_install = 0;
128218792SnpTUNABLE_INT("hw.cxgbe.force_firmware_install", &force_firmware_install);
129218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, force_firmware_install, CTLFLAG_RDTUN,
130218792Snp    &force_firmware_install, 0, "install firmware on every attach.");
131218792Snp
132218792Snp/*
133218792Snp * Holdoff timer and packet counter values.
134218792Snp */
135218792Snpstatic unsigned int intr_timer[SGE_NTIMERS] = {1, 5, 10, 50, 100, 200};
136218792Snpstatic unsigned int intr_pktcount[SGE_NCOUNTERS] = {1, 8, 16, 32}; /* 63 max */
137218792Snp
138218792Snp/*
139218792Snp * Max # of tx and rx queues to use for each 10G and 1G port.
140218792Snp */
141218792Snpstatic unsigned int max_ntxq_10g = 8;
142218792SnpTUNABLE_INT("hw.cxgbe.max_ntxq_10G_port", &max_ntxq_10g);
143218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_ntxq_10G_port, CTLFLAG_RDTUN,
144218792Snp    &max_ntxq_10g, 0, "maximum number of tx queues per 10G port.");
145218792Snp
146218792Snpstatic unsigned int max_nrxq_10g = 8;
147218792SnpTUNABLE_INT("hw.cxgbe.max_nrxq_10G_port", &max_nrxq_10g);
148218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_nrxq_10G_port, CTLFLAG_RDTUN,
149218792Snp    &max_nrxq_10g, 0, "maximum number of rxq's (per 10G port).");
150218792Snp
151218792Snpstatic unsigned int max_ntxq_1g = 2;
152218792SnpTUNABLE_INT("hw.cxgbe.max_ntxq_1G_port", &max_ntxq_1g);
153218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_ntxq_1G_port, CTLFLAG_RDTUN,
154218792Snp    &max_ntxq_1g, 0, "maximum number of tx queues per 1G port.");
155218792Snp
156218792Snpstatic unsigned int max_nrxq_1g = 2;
157218792SnpTUNABLE_INT("hw.cxgbe.max_nrxq_1G_port", &max_nrxq_1g);
158218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_nrxq_1G_port, CTLFLAG_RDTUN,
159218792Snp    &max_nrxq_1g, 0, "maximum number of rxq's (per 1G port).");
160218792Snp
161218792Snp/*
162218792Snp * Holdoff parameters for 10G and 1G ports.
163218792Snp */
164218792Snpstatic unsigned int tmr_idx_10g = 1;
165218792SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &tmr_idx_10g);
166218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_timer_idx_10G, CTLFLAG_RDTUN,
167218792Snp    &tmr_idx_10g, 0,
168218792Snp    "default timer index for interrupt holdoff (10G ports).");
169218792Snp
170218792Snpstatic int pktc_idx_10g = 2;
171218792SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &pktc_idx_10g);
172218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_pktc_idx_10G, CTLFLAG_RDTUN,
173218792Snp    &pktc_idx_10g, 0,
174218792Snp    "default pkt counter index for interrupt holdoff (10G ports).");
175218792Snp
176218792Snpstatic unsigned int tmr_idx_1g = 1;
177218792SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &tmr_idx_1g);
178218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_timer_idx_1G, CTLFLAG_RDTUN,
179218792Snp    &tmr_idx_1g, 0,
180218792Snp    "default timer index for interrupt holdoff (1G ports).");
181218792Snp
182218792Snpstatic int pktc_idx_1g = 2;
183218792SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &pktc_idx_1g);
184218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_pktc_idx_1G, CTLFLAG_RDTUN,
185218792Snp    &pktc_idx_1g, 0,
186218792Snp    "default pkt counter index for interrupt holdoff (1G ports).");
187218792Snp
188218792Snp/*
189218792Snp * Size (# of entries) of each tx and rx queue.
190218792Snp */
191218792Snpstatic unsigned int qsize_txq = TX_EQ_QSIZE;
192218792SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &qsize_txq);
193218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, qsize_txq, CTLFLAG_RDTUN,
194218792Snp    &qsize_txq, 0, "default queue size of NIC tx queues.");
195218792Snp
196218792Snpstatic unsigned int qsize_rxq = RX_IQ_QSIZE;
197218792SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &qsize_rxq);
198218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, qsize_rxq, CTLFLAG_RDTUN,
199218792Snp    &qsize_rxq, 0, "default queue size of NIC rx queues.");
200218792Snp
201218792Snp/*
202218792Snp * Interrupt types allowed.
203218792Snp */
204218792Snpstatic int intr_types = 7;
205218792SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &intr_types);
206218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_types, CTLFLAG_RDTUN, &intr_types, 0,
207218792Snp    "interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively)");
208218792Snp
209218792Snp/*
210218792Snp * Force the driver to use interrupt forwarding.
211218792Snp */
212218792Snpstatic int intr_fwd = 0;
213218792SnpTUNABLE_INT("hw.cxgbe.interrupt_forwarding", &intr_fwd);
214218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_forwarding, CTLFLAG_RDTUN,
215218792Snp    &intr_fwd, 0, "always use forwarded interrupts");
216218792Snp
217218792Snpstruct intrs_and_queues {
218218792Snp	int intr_type;		/* 1, 2, or 4 for INTx, MSI, or MSI-X */
219218792Snp	int nirq;		/* Number of vectors */
220218792Snp	int intr_fwd;		/* Interrupts forwarded */
221218792Snp	int ntxq10g;		/* # of NIC txq's for each 10G port */
222218792Snp	int nrxq10g;		/* # of NIC rxq's for each 10G port */
223218792Snp	int ntxq1g;		/* # of NIC txq's for each 1G port */
224218792Snp	int nrxq1g;		/* # of NIC rxq's for each 1G port */
225218792Snp};
226218792Snp
227218792Snpenum {
228218792Snp	MEMWIN0_APERTURE = 2048,
229218792Snp	MEMWIN0_BASE     = 0x1b800,
230218792Snp	MEMWIN1_APERTURE = 32768,
231218792Snp	MEMWIN1_BASE     = 0x28000,
232218792Snp	MEMWIN2_APERTURE = 65536,
233218792Snp	MEMWIN2_BASE     = 0x30000,
234218792Snp};
235218792Snp
236218792Snpenum {
237218792Snp	XGMAC_MTU	= (1 << 0),
238218792Snp	XGMAC_PROMISC	= (1 << 1),
239218792Snp	XGMAC_ALLMULTI	= (1 << 2),
240218792Snp	XGMAC_VLANEX	= (1 << 3),
241218792Snp	XGMAC_UCADDR	= (1 << 4),
242218792Snp	XGMAC_MCADDRS	= (1 << 5),
243218792Snp
244218792Snp	XGMAC_ALL	= 0xffff
245218792Snp};
246218792Snp
247218792Snpstatic int map_bars(struct adapter *);
248218792Snpstatic void setup_memwin(struct adapter *);
249218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int,
250218792Snp    struct intrs_and_queues *);
251218792Snpstatic int prep_firmware(struct adapter *);
252218792Snpstatic int get_capabilities(struct adapter *, struct fw_caps_config_cmd *);
253218792Snpstatic int get_params(struct adapter *, struct fw_caps_config_cmd *);
254218792Snpstatic void t4_set_desc(struct adapter *);
255218792Snpstatic void build_medialist(struct port_info *);
256218792Snpstatic int update_mac_settings(struct port_info *, int);
257218792Snpstatic int cxgbe_init_locked(struct port_info *);
258218792Snpstatic int cxgbe_init_synchronized(struct port_info *);
259218792Snpstatic int cxgbe_uninit_locked(struct port_info *);
260218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *);
261218792Snpstatic int first_port_up(struct adapter *);
262218792Snpstatic int last_port_down(struct adapter *);
263218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid,
264218792Snp    iq_intr_handler_t *, void *, char *);
265218792Snpstatic int t4_free_irq(struct adapter *, struct irq *);
266218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int,
267218792Snp    unsigned int);
268218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *);
269218792Snpstatic void cxgbe_tick(void *);
270218792Snpstatic int t4_sysctls(struct adapter *);
271218792Snpstatic int cxgbe_sysctls(struct port_info *);
272218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS);
273218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS);
274218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS);
275218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS);
276218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS);
277218792Snp
278218792Snp
279218792Snpstruct t4_pciids {
280218792Snp	uint16_t device;
281218792Snp	uint8_t mpf;
282218792Snp	char *desc;
283218792Snp} t4_pciids[] = {
284218792Snp	{0xa000, 0, "Chelsio Terminator 4 FPGA"},
285218792Snp	{0x4400, 4, "Chelsio T440-dbg"},
286218792Snp	{0x4401, 4, "Chelsio T420-CR"},
287218792Snp	{0x4402, 4, "Chelsio T422-CR"},
288218792Snp	{0x4403, 4, "Chelsio T440-CR"},
289218792Snp	{0x4404, 4, "Chelsio T420-BCH"},
290218792Snp	{0x4405, 4, "Chelsio T440-BCH"},
291218792Snp	{0x4406, 4, "Chelsio T440-CH"},
292218792Snp	{0x4407, 4, "Chelsio T420-SO"},
293218792Snp	{0x4408, 4, "Chelsio T420-CX"},
294218792Snp	{0x4409, 4, "Chelsio T420-BT"},
295218792Snp	{0x440a, 4, "Chelsio T404-BT"},
296218792Snp};
297218792Snp
298218792Snpstatic int
299218792Snpt4_probe(device_t dev)
300218792Snp{
301218792Snp	int i;
302218792Snp	uint16_t v = pci_get_vendor(dev);
303218792Snp	uint16_t d = pci_get_device(dev);
304218792Snp
305218792Snp	if (v != PCI_VENDOR_ID_CHELSIO)
306218792Snp		return (ENXIO);
307218792Snp
308218792Snp	for (i = 0; i < ARRAY_SIZE(t4_pciids); i++) {
309218792Snp		if (d == t4_pciids[i].device &&
310218792Snp		    pci_get_function(dev) == t4_pciids[i].mpf) {
311218792Snp			device_set_desc(dev, t4_pciids[i].desc);
312218792Snp			return (BUS_PROBE_DEFAULT);
313218792Snp		}
314218792Snp	}
315218792Snp
316218792Snp	return (ENXIO);
317218792Snp}
318218792Snp
319218792Snpstatic int
320218792Snpt4_attach(device_t dev)
321218792Snp{
322218792Snp	struct adapter *sc;
323218792Snp	int rc = 0, i, n10g, n1g, rqidx, tqidx;
324218792Snp	struct fw_caps_config_cmd caps;
325218792Snp	uint32_t p, v;
326218792Snp	struct intrs_and_queues iaq;
327218792Snp	struct sge *s;
328218792Snp
329218792Snp	sc = device_get_softc(dev);
330218792Snp	sc->dev = dev;
331218792Snp	sc->pf = pci_get_function(dev);
332218792Snp	sc->mbox = sc->pf;
333218792Snp
334218792Snp	pci_enable_busmaster(dev);
335218792Snp	pci_set_max_read_req(dev, 4096);
336218792Snp	snprintf(sc->lockname, sizeof(sc->lockname), "%s",
337218792Snp	    device_get_nameunit(dev));
338218792Snp	mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF);
339218792Snp
340218792Snp	rc = map_bars(sc);
341218792Snp	if (rc != 0)
342218792Snp		goto done; /* error message displayed already */
343218792Snp
344218792Snp	memset(sc->chan_map, 0xff, sizeof(sc->chan_map));
345218792Snp
346218792Snp	/* Prepare the adapter for operation */
347218792Snp	rc = -t4_prep_adapter(sc);
348218792Snp	if (rc != 0) {
349218792Snp		device_printf(dev, "failed to prepare adapter: %d.\n", rc);
350218792Snp		goto done;
351218792Snp	}
352218792Snp
353218792Snp	/* Do this really early */
354218792Snp	sc->cdev = make_dev(&t4_cdevsw, device_get_unit(dev), UID_ROOT,
355218792Snp	    GID_WHEEL, 0600, "%s", device_get_nameunit(dev));
356218792Snp	sc->cdev->si_drv1 = sc;
357218792Snp
358218792Snp	/* Prepare the firmware for operation */
359218792Snp	rc = prep_firmware(sc);
360218792Snp	if (rc != 0)
361218792Snp		goto done; /* error message displayed already */
362218792Snp
363218792Snp	/* Get device capabilities and select which ones we'll use */
364218792Snp	rc = get_capabilities(sc, &caps);
365218792Snp	if (rc != 0) {
366218792Snp		device_printf(dev,
367218792Snp		    "failed to initialize adapter capabilities: %d.\n", rc);
368218792Snp		goto done;
369218792Snp	}
370218792Snp
371218792Snp	/* Choose the global RSS mode. */
372218792Snp	rc = -t4_config_glbl_rss(sc, sc->mbox,
373218792Snp	    FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
374218792Snp	    F_FW_RSS_GLB_CONFIG_CMD_TNLMAPEN |
375218792Snp	    F_FW_RSS_GLB_CONFIG_CMD_TNLALLLKP);
376218792Snp	if (rc != 0) {
377218792Snp		device_printf(dev,
378218792Snp		    "failed to select global RSS mode: %d.\n", rc);
379218792Snp		goto done;
380218792Snp	}
381218792Snp
382218792Snp	/* These are total (sum of all ports) limits for a bus driver */
383218792Snp	rc = -t4_cfg_pfvf(sc, sc->mbox, sc->pf, 0,
384218792Snp	    64,		/* max # of egress queues */
385218792Snp	    64,		/* max # of egress Ethernet or control queues */
386218792Snp	    64,		/* max # of ingress queues with fl/interrupt */
387218792Snp	    0,		/* max # of ingress queues without interrupt */
388218792Snp	    0,		/* PCIe traffic class */
389218792Snp	    4,		/* max # of virtual interfaces */
390218792Snp	    M_FW_PFVF_CMD_CMASK, M_FW_PFVF_CMD_PMASK, 16,
391218792Snp	    FW_CMD_CAP_PF, FW_CMD_CAP_PF);
392218792Snp	if (rc != 0) {
393218792Snp		device_printf(dev,
394218792Snp		    "failed to configure pf/vf resources: %d.\n", rc);
395218792Snp		goto done;
396218792Snp	}
397218792Snp
398218792Snp	/* Need this before sge_init */
399218792Snp	for (i = 0; i < SGE_NTIMERS; i++)
400218792Snp		sc->sge.timer_val[i] = min(intr_timer[i], 200U);
401218792Snp	for (i = 0; i < SGE_NCOUNTERS; i++)
402218792Snp		sc->sge.counter_val[i] = min(intr_pktcount[i], M_THRESHOLD_0);
403218792Snp
404218792Snp	/* Also need the cooked value of cclk before sge_init */
405218792Snp	p = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
406218792Snp	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK));
407218792Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &p, &v);
408218792Snp	if (rc != 0) {
409218792Snp		device_printf(sc->dev,
410218792Snp		    "failed to obtain core clock value: %d.\n", rc);
411218792Snp		goto done;
412218792Snp	}
413218792Snp	sc->params.vpd.cclk = v;
414218792Snp
415218792Snp	t4_sge_init(sc);
416218792Snp
417218792Snp	/*
418218792Snp	 * XXX: This is the place to call t4_set_filter_mode()
419218792Snp	 */
420218792Snp
421218792Snp	/* get basic stuff going */
422218792Snp	rc = -t4_early_init(sc, sc->mbox);
423218792Snp	if (rc != 0) {
424218792Snp		device_printf(dev, "early init failed: %d.\n", rc);
425218792Snp		goto done;
426218792Snp	}
427218792Snp
428218792Snp	rc = get_params(sc, &caps);
429218792Snp	if (rc != 0)
430218792Snp		goto done; /* error message displayed already */
431218792Snp
432218792Snp	/* These are finalized by FW initialization, load their values now */
433218792Snp	v = t4_read_reg(sc, A_TP_TIMER_RESOLUTION);
434218792Snp	sc->params.tp.tre = G_TIMERRESOLUTION(v);
435218792Snp	sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v);
436218792Snp	t4_read_mtu_tbl(sc, sc->params.mtus, NULL);
437218792Snp
438218792Snp	/* tweak some settings */
439218792Snp	t4_write_reg(sc, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | V_RXTSHIFTMAXR1(4) |
440218792Snp	    V_RXTSHIFTMAXR2(15) | V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
441218792Snp	    V_KEEPALIVEMAXR1(4) | V_KEEPALIVEMAXR2(9));
442218792Snp	t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
443218792Snp
444218792Snp	setup_memwin(sc);
445218792Snp
446218792Snp	rc = t4_create_dma_tag(sc);
447218792Snp	if (rc != 0)
448218792Snp		goto done; /* error message displayed already */
449218792Snp
450218792Snp	/*
451218792Snp	 * First pass over all the ports - allocate VIs and initialize some
452218792Snp	 * basic parameters like mac address, port type, etc.  We also figure
453218792Snp	 * out whether a port is 10G or 1G and use that information when
454218792Snp	 * calculating how many interrupts to attempt to allocate.
455218792Snp	 */
456218792Snp	n10g = n1g = 0;
457218792Snp	for_each_port(sc, i) {
458218792Snp		struct port_info *pi;
459218792Snp
460218792Snp		pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK);
461218792Snp		sc->port[i] = pi;
462218792Snp
463218792Snp		/* These must be set before t4_port_init */
464218792Snp		pi->adapter = sc;
465218792Snp		pi->port_id = i;
466218792Snp
467218792Snp		/* Allocate the vi and initialize parameters like mac addr */
468218792Snp		rc = -t4_port_init(pi, sc->mbox, sc->pf, 0);
469218792Snp		if (rc != 0) {
470218792Snp			device_printf(dev, "unable to initialize port %d: %d\n",
471218792Snp			    i, rc);
472218792Snp			free(pi, M_CXGBE);
473218792Snp			sc->port[i] = NULL;	/* indicates init failed */
474218792Snp			continue;
475218792Snp		}
476218792Snp
477218792Snp		snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d",
478218792Snp		    device_get_nameunit(dev), i);
479218792Snp		mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
480218792Snp
481218792Snp		if (is_10G_port(pi)) {
482218792Snp			n10g++;
483218792Snp			pi->tmr_idx = tmr_idx_10g;
484218792Snp			pi->pktc_idx = pktc_idx_10g;
485218792Snp		} else {
486218792Snp			n1g++;
487218792Snp			pi->tmr_idx = tmr_idx_1g;
488218792Snp			pi->pktc_idx = pktc_idx_1g;
489218792Snp		}
490218792Snp
491218792Snp		pi->xact_addr_filt = -1;
492218792Snp
493218792Snp		pi->qsize_rxq = max(qsize_rxq, 128);
494218792Snp		while (pi->qsize_rxq & 7)
495218792Snp			pi->qsize_rxq++;
496218792Snp		pi->qsize_txq = max(qsize_txq, 128);
497218792Snp
498218792Snp		if (pi->qsize_rxq != qsize_rxq) {
499218792Snp			device_printf(dev,
500218792Snp			    "using %d instead of %d as the rx queue size.\n",
501218792Snp			    pi->qsize_rxq, qsize_rxq);
502218792Snp		}
503218792Snp		if (pi->qsize_txq != qsize_txq) {
504218792Snp			device_printf(dev,
505218792Snp			    "using %d instead of %d as the tx queue size.\n",
506218792Snp			    pi->qsize_txq, qsize_txq);
507218792Snp		}
508218792Snp
509218792Snp		pi->dev = device_add_child(dev, "cxgbe", -1);
510218792Snp		if (pi->dev == NULL) {
511218792Snp			device_printf(dev,
512218792Snp			    "failed to add device for port %d.\n", i);
513218792Snp			rc = ENXIO;
514218792Snp			goto done;
515218792Snp		}
516218792Snp		device_set_softc(pi->dev, pi);
517218792Snp
518218792Snp		setbit(&sc->registered_device_map, i);
519218792Snp	}
520218792Snp
521218792Snp	if (sc->registered_device_map == 0) {
522218792Snp		device_printf(dev, "no usable ports\n");
523218792Snp		rc = ENXIO;
524218792Snp		goto done;
525218792Snp	}
526218792Snp
527218792Snp	/*
528218792Snp	 * Interrupt type, # of interrupts, # of rx/tx queues, etc.
529218792Snp	 */
530218792Snp	rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq);
531218792Snp	if (rc != 0)
532218792Snp		goto done; /* error message displayed already */
533218792Snp
534218792Snp	sc->intr_type = iaq.intr_type;
535218792Snp	sc->intr_count = iaq.nirq;
536218792Snp
537218792Snp	s = &sc->sge;
538218792Snp	s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g;
539218792Snp	s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g;
540218792Snp	s->neq = s->ntxq + s->nrxq;	/* the fl in an rxq is an eq */
541218792Snp	s->niq = s->nrxq + 1;		/* 1 extra for firmware event queue */
542218792Snp	if (iaq.intr_fwd) {
543218792Snp		sc->flags |= INTR_FWD;
544218792Snp		s->niq += NFIQ(sc);		/* forwarded interrupt queues */
545218792Snp		s->fiq = malloc(NFIQ(sc) * sizeof(struct sge_iq), M_CXGBE,
546218792Snp		    M_ZERO | M_WAITOK);
547218792Snp	}
548218792Snp	s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE,
549218792Snp	    M_ZERO | M_WAITOK);
550218792Snp	s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE,
551218792Snp	    M_ZERO | M_WAITOK);
552218792Snp	s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE,
553218792Snp	    M_ZERO | M_WAITOK);
554218792Snp	s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE,
555218792Snp	    M_ZERO | M_WAITOK);
556218792Snp
557218792Snp	sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE,
558218792Snp	    M_ZERO | M_WAITOK);
559218792Snp
560218792Snp	t4_sysctls(sc);
561218792Snp
562218792Snp	/*
563218792Snp	 * Second pass over the ports.  This time we know the number of rx and
564218792Snp	 * tx queues that each port should get.
565218792Snp	 */
566218792Snp	rqidx = tqidx = 0;
567218792Snp	for_each_port(sc, i) {
568218792Snp		struct port_info *pi = sc->port[i];
569218792Snp
570218792Snp		if (pi == NULL)
571218792Snp			continue;
572218792Snp
573218792Snp		pi->first_rxq = rqidx;
574218792Snp		pi->nrxq = is_10G_port(pi) ? iaq.nrxq10g : iaq.nrxq1g;
575218792Snp
576218792Snp		pi->first_txq = tqidx;
577218792Snp		pi->ntxq = is_10G_port(pi) ? iaq.ntxq10g : iaq.ntxq1g;
578218792Snp
579218792Snp		rqidx += pi->nrxq;
580218792Snp		tqidx += pi->ntxq;
581218792Snp	}
582218792Snp
583218792Snp	rc = bus_generic_attach(dev);
584218792Snp	if (rc != 0) {
585218792Snp		device_printf(dev,
586218792Snp		    "failed to attach all child ports: %d\n", rc);
587218792Snp		goto done;
588218792Snp	}
589218792Snp
590218792Snp#ifdef INVARIANTS
591218792Snp	device_printf(dev,
592218792Snp	    "%p, %d ports (0x%x), %d intr_type, %d intr_count\n",
593218792Snp	    sc, sc->params.nports, sc->params.portvec,
594218792Snp	    sc->intr_type, sc->intr_count);
595218792Snp#endif
596218792Snp	t4_set_desc(sc);
597218792Snp
598218792Snpdone:
599218792Snp	if (rc != 0)
600218792Snp		t4_detach(dev);
601218792Snp
602218792Snp	return (rc);
603218792Snp}
604218792Snp
605218792Snp/*
606218792Snp * Idempotent
607218792Snp */
608218792Snpstatic int
609218792Snpt4_detach(device_t dev)
610218792Snp{
611218792Snp	struct adapter *sc;
612218792Snp	struct port_info *pi;
613218792Snp	int i;
614218792Snp
615218792Snp	sc = device_get_softc(dev);
616218792Snp
617218792Snp	if (sc->cdev)
618218792Snp		destroy_dev(sc->cdev);
619218792Snp
620218792Snp	bus_generic_detach(dev);
621218792Snp	for (i = 0; i < MAX_NPORTS; i++) {
622218792Snp		pi = sc->port[i];
623218792Snp		if (pi) {
624218792Snp			t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid);
625218792Snp			if (pi->dev)
626218792Snp				device_delete_child(dev, pi->dev);
627218792Snp
628218792Snp			mtx_destroy(&pi->pi_lock);
629218792Snp			free(pi, M_CXGBE);
630218792Snp		}
631218792Snp	}
632218792Snp
633218792Snp	if (sc->flags & FW_OK)
634218792Snp		t4_fw_bye(sc, sc->mbox);
635218792Snp
636218792Snp	if (sc->intr_type == 2 || sc->intr_type == 4)
637218792Snp		pci_release_msi(dev);
638218792Snp
639218792Snp	if (sc->regs_res)
640218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid,
641218792Snp		    sc->regs_res);
642218792Snp
643218792Snp	if (sc->msix_res)
644218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid,
645218792Snp		    sc->msix_res);
646218792Snp
647218792Snp	free(sc->irq, M_CXGBE);
648218792Snp	free(sc->sge.rxq, M_CXGBE);
649218792Snp	free(sc->sge.txq, M_CXGBE);
650218792Snp	free(sc->sge.fiq, M_CXGBE);
651218792Snp	free(sc->sge.iqmap, M_CXGBE);
652218792Snp	free(sc->sge.eqmap, M_CXGBE);
653218792Snp	t4_destroy_dma_tag(sc);
654218792Snp	mtx_destroy(&sc->sc_lock);
655218792Snp
656218792Snp	bzero(sc, sizeof(*sc));
657218792Snp
658218792Snp	return (0);
659218792Snp}
660218792Snp
661218792Snp
662218792Snpstatic int
663218792Snpcxgbe_probe(device_t dev)
664218792Snp{
665218792Snp	char buf[128];
666218792Snp	struct port_info *pi = device_get_softc(dev);
667218792Snp
668218792Snp	snprintf(buf, sizeof(buf), "Port %d", pi->port_id);
669218792Snp	device_set_desc_copy(dev, buf);
670218792Snp
671218792Snp	return (BUS_PROBE_DEFAULT);
672218792Snp}
673218792Snp
674218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \
675218792Snp    IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \
676218792Snp    IFCAP_VLAN_HWTSO)
677218792Snp#define T4_CAP_ENABLE (T4_CAP & ~IFCAP_TSO6)
678218792Snp
679218792Snpstatic int
680218792Snpcxgbe_attach(device_t dev)
681218792Snp{
682218792Snp	struct port_info *pi = device_get_softc(dev);
683218792Snp	struct ifnet *ifp;
684218792Snp
685218792Snp	/* Allocate an ifnet and set it up */
686218792Snp	ifp = if_alloc(IFT_ETHER);
687218792Snp	if (ifp == NULL) {
688218792Snp		device_printf(dev, "Cannot allocate ifnet\n");
689218792Snp		return (ENOMEM);
690218792Snp	}
691218792Snp	pi->ifp = ifp;
692218792Snp	ifp->if_softc = pi;
693218792Snp
694218792Snp	callout_init(&pi->tick, CALLOUT_MPSAFE);
695218792Snp
696218792Snp	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
697218792Snp	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
698218792Snp
699218792Snp	ifp->if_init = cxgbe_init;
700218792Snp	ifp->if_ioctl = cxgbe_ioctl;
701218792Snp	ifp->if_start = cxgbe_start;
702218792Snp	ifp->if_transmit = cxgbe_transmit;
703218792Snp	ifp->if_qflush = cxgbe_qflush;
704218792Snp
705218792Snp	ifp->if_snd.ifq_drv_maxlen = 1024;
706218792Snp	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
707218792Snp	IFQ_SET_READY(&ifp->if_snd);
708218792Snp
709218792Snp	ifp->if_capabilities = T4_CAP;
710218792Snp	ifp->if_capenable = T4_CAP_ENABLE;
711218792Snp	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO;
712218792Snp
713218792Snp	/* Initialize ifmedia for this port */
714218792Snp	ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change,
715218792Snp	    cxgbe_media_status);
716218792Snp	build_medialist(pi);
717218792Snp
718218792Snp	ether_ifattach(ifp, pi->hw_addr);
719218792Snp
720218792Snp#ifdef INVARIANTS
721218792Snp	device_printf(dev, "%p, %d txq, %d rxq\n", pi, pi->ntxq, pi->nrxq);
722218792Snp#endif
723218792Snp
724218792Snp	cxgbe_sysctls(pi);
725218792Snp
726218792Snp	return (0);
727218792Snp}
728218792Snp
729218792Snpstatic int
730218792Snpcxgbe_detach(device_t dev)
731218792Snp{
732218792Snp	struct port_info *pi = device_get_softc(dev);
733218792Snp	struct adapter *sc = pi->adapter;
734218792Snp	int rc;
735218792Snp
736218792Snp	/* Tell if_ioctl and if_init that the port is going away */
737218792Snp	ADAPTER_LOCK(sc);
738218792Snp	SET_DOOMED(pi);
739218792Snp	wakeup(&sc->flags);
740218792Snp	while (IS_BUSY(sc))
741218792Snp		mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0);
742218792Snp	SET_BUSY(sc);
743218792Snp	ADAPTER_UNLOCK(sc);
744218792Snp
745218792Snp	rc = cxgbe_uninit_synchronized(pi);
746218792Snp	if (rc != 0)
747218792Snp		device_printf(dev, "port uninit failed: %d.\n", rc);
748218792Snp
749218792Snp	ifmedia_removeall(&pi->media);
750218792Snp	ether_ifdetach(pi->ifp);
751218792Snp	if_free(pi->ifp);
752218792Snp
753218792Snp	ADAPTER_LOCK(sc);
754218792Snp	CLR_BUSY(sc);
755218792Snp	wakeup_one(&sc->flags);
756218792Snp	ADAPTER_UNLOCK(sc);
757218792Snp
758218792Snp	return (0);
759218792Snp}
760218792Snp
761218792Snpstatic void
762218792Snpcxgbe_init(void *arg)
763218792Snp{
764218792Snp	struct port_info *pi = arg;
765218792Snp	struct adapter *sc = pi->adapter;
766218792Snp
767218792Snp	ADAPTER_LOCK(sc);
768218792Snp	cxgbe_init_locked(pi); /* releases adapter lock */
769218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
770218792Snp}
771218792Snp
772218792Snpstatic int
773218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
774218792Snp{
775218792Snp	int rc = 0, mtu, flags;
776218792Snp	struct port_info *pi = ifp->if_softc;
777218792Snp	struct adapter *sc = pi->adapter;
778218792Snp	struct ifreq *ifr = (struct ifreq *)data;
779218792Snp	uint32_t mask;
780218792Snp
781218792Snp	switch (cmd) {
782218792Snp	case SIOCSIFMTU:
783218792Snp		ADAPTER_LOCK(sc);
784218792Snp		rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
785218792Snp		if (rc) {
786218792Snpfail:
787218792Snp			ADAPTER_UNLOCK(sc);
788218792Snp			return (rc);
789218792Snp		}
790218792Snp
791218792Snp		mtu = ifr->ifr_mtu;
792218792Snp		if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) {
793218792Snp			rc = EINVAL;
794218792Snp		} else {
795218792Snp			ifp->if_mtu = mtu;
796218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
797218792Snp				t4_update_fl_bufsize(ifp);
798218792Snp				PORT_LOCK(pi);
799218792Snp				rc = update_mac_settings(pi, XGMAC_MTU);
800218792Snp				PORT_UNLOCK(pi);
801218792Snp			}
802218792Snp		}
803218792Snp		ADAPTER_UNLOCK(sc);
804218792Snp		break;
805218792Snp
806218792Snp	case SIOCSIFFLAGS:
807218792Snp		ADAPTER_LOCK(sc);
808218792Snp		if (IS_DOOMED(pi)) {
809218792Snp			rc = ENXIO;
810218792Snp			goto fail;
811218792Snp		}
812218792Snp		if (ifp->if_flags & IFF_UP) {
813218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
814218792Snp				flags = pi->if_flags;
815218792Snp				if ((ifp->if_flags ^ flags) &
816218792Snp				    (IFF_PROMISC | IFF_ALLMULTI)) {
817218792Snp					if (IS_BUSY(sc)) {
818218792Snp						rc = EBUSY;
819218792Snp						goto fail;
820218792Snp					}
821218792Snp					PORT_LOCK(pi);
822218792Snp					rc = update_mac_settings(pi,
823218792Snp					    XGMAC_PROMISC | XGMAC_ALLMULTI);
824218792Snp					PORT_UNLOCK(pi);
825218792Snp				}
826218792Snp				ADAPTER_UNLOCK(sc);
827218792Snp			} else
828218792Snp				rc = cxgbe_init_locked(pi);
829218792Snp			pi->if_flags = ifp->if_flags;
830218792Snp		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
831218792Snp			rc = cxgbe_uninit_locked(pi);
832218792Snp		else
833218792Snp			ADAPTER_UNLOCK(sc);
834218792Snp
835218792Snp		ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
836218792Snp		break;
837218792Snp
838218792Snp	case SIOCADDMULTI:
839218792Snp	case SIOCDELMULTI: /* these two can be called with a mutex held :-( */
840218792Snp		ADAPTER_LOCK(sc);
841218792Snp		rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
842218792Snp		if (rc)
843218792Snp			goto fail;
844218792Snp
845218792Snp		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
846218792Snp			PORT_LOCK(pi);
847218792Snp			rc = update_mac_settings(pi, XGMAC_MCADDRS);
848218792Snp			PORT_UNLOCK(pi);
849218792Snp		}
850218792Snp		ADAPTER_UNLOCK(sc);
851218792Snp		break;
852218792Snp
853218792Snp	case SIOCSIFCAP:
854218792Snp		ADAPTER_LOCK(sc);
855218792Snp		rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
856218792Snp		if (rc)
857218792Snp			goto fail;
858218792Snp
859218792Snp		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
860218792Snp		if (mask & IFCAP_TXCSUM) {
861218792Snp			ifp->if_capenable ^= IFCAP_TXCSUM;
862218792Snp			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
863218792Snp
864218792Snp			if (IFCAP_TSO & ifp->if_capenable &&
865218792Snp			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
866218792Snp				ifp->if_capenable &= ~IFCAP_TSO;
867218792Snp				ifp->if_hwassist &= ~CSUM_TSO;
868218792Snp				if_printf(ifp,
869218792Snp				    "tso disabled due to -txcsum.\n");
870218792Snp			}
871218792Snp		}
872218792Snp		if (mask & IFCAP_RXCSUM)
873218792Snp			ifp->if_capenable ^= IFCAP_RXCSUM;
874218792Snp		if (mask & IFCAP_TSO4) {
875218792Snp			ifp->if_capenable ^= IFCAP_TSO4;
876218792Snp
877218792Snp			if (IFCAP_TSO & ifp->if_capenable) {
878218792Snp				if (IFCAP_TXCSUM & ifp->if_capenable)
879218792Snp					ifp->if_hwassist |= CSUM_TSO;
880218792Snp				else {
881218792Snp					ifp->if_capenable &= ~IFCAP_TSO;
882218792Snp					ifp->if_hwassist &= ~CSUM_TSO;
883218792Snp					if_printf(ifp,
884218792Snp					    "enable txcsum first.\n");
885218792Snp					rc = EAGAIN;
886218792Snp				}
887218792Snp			} else
888218792Snp				ifp->if_hwassist &= ~CSUM_TSO;
889218792Snp		}
890218792Snp		if (mask & IFCAP_LRO) {
891218792Snp#ifdef INET
892218792Snp			int i;
893218792Snp			struct sge_rxq *rxq;
894218792Snp
895218792Snp			ifp->if_capenable ^= IFCAP_LRO;
896218792Snp			for_each_rxq(pi, i, rxq) {
897218792Snp				if (ifp->if_capenable & IFCAP_LRO)
898218792Snp					rxq->flags |= RXQ_LRO_ENABLED;
899218792Snp				else
900218792Snp					rxq->flags &= ~RXQ_LRO_ENABLED;
901218792Snp			}
902218792Snp#endif
903218792Snp		}
904218792Snp#ifndef TCP_OFFLOAD_DISABLE
905218792Snp		if (mask & IFCAP_TOE4) {
906218792Snp			rc = EOPNOTSUPP;
907218792Snp		}
908218792Snp#endif
909218792Snp		if (mask & IFCAP_VLAN_HWTAGGING) {
910218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
911218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
912218792Snp				PORT_LOCK(pi);
913218792Snp				rc = update_mac_settings(pi, XGMAC_VLANEX);
914218792Snp				PORT_UNLOCK(pi);
915218792Snp			}
916218792Snp		}
917218792Snp		if (mask & IFCAP_VLAN_MTU) {
918218792Snp			ifp->if_capenable ^= IFCAP_VLAN_MTU;
919218792Snp
920218792Snp			/* Need to find out how to disable auto-mtu-inflation */
921218792Snp		}
922218792Snp		if (mask & IFCAP_VLAN_HWTSO)
923218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
924218792Snp		if (mask & IFCAP_VLAN_HWCSUM)
925218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
926218792Snp
927218792Snp#ifdef VLAN_CAPABILITIES
928218792Snp		VLAN_CAPABILITIES(ifp);
929218792Snp#endif
930218792Snp		ADAPTER_UNLOCK(sc);
931218792Snp		break;
932218792Snp
933218792Snp	case SIOCSIFMEDIA:
934218792Snp	case SIOCGIFMEDIA:
935218792Snp		ifmedia_ioctl(ifp, ifr, &pi->media, cmd);
936218792Snp		break;
937218792Snp
938218792Snp	default:
939218792Snp		rc = ether_ioctl(ifp, cmd, data);
940218792Snp	}
941218792Snp
942218792Snp	return (rc);
943218792Snp}
944218792Snp
945218792Snpstatic void
946218792Snpcxgbe_start(struct ifnet *ifp)
947218792Snp{
948218792Snp	struct port_info *pi = ifp->if_softc;
949218792Snp	struct sge_txq *txq;
950218792Snp	int i;
951218792Snp
952218792Snp	for_each_txq(pi, i, txq) {
953218792Snp		if (TXQ_TRYLOCK(txq)) {
954218792Snp			struct buf_ring *br = txq->eq.br;
955218792Snp			struct mbuf *m;
956218792Snp
957218792Snp			m = txq->m ? txq->m : drbr_dequeue(ifp, br);
958218792Snp			if (m)
959218792Snp				t4_eth_tx(ifp, txq, m);
960218792Snp
961218792Snp			TXQ_UNLOCK(txq);
962218792Snp		}
963218792Snp	}
964218792Snp}
965218792Snp
966218792Snpstatic int
967218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m)
968218792Snp{
969218792Snp	struct port_info *pi = ifp->if_softc;
970218792Snp	struct adapter *sc = pi->adapter;
971218792Snp	struct sge_txq *txq = &sc->sge.txq[pi->first_txq];
972218792Snp	struct buf_ring *br;
973218792Snp	int rc;
974218792Snp
975218792Snp	M_ASSERTPKTHDR(m);
976218792Snp
977218792Snp	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
978218792Snp		m_freem(m);
979218792Snp		return (0);
980218792Snp	}
981218792Snp
982218792Snp	if (m->m_flags & M_FLOWID)
983218792Snp		txq += (m->m_pkthdr.flowid % pi->ntxq);
984218792Snp	br = txq->eq.br;
985218792Snp
986218792Snp	if (TXQ_TRYLOCK(txq) == 0) {
987218792Snp		/*
988218792Snp		 * XXX: make sure that this packet really is sent out.  There is
989218792Snp		 * a small race where t4_eth_tx may stop draining the drbr and
990218792Snp		 * goes away, just before we enqueued this mbuf.
991218792Snp		 */
992218792Snp
993218792Snp		return (drbr_enqueue(ifp, br, m));
994218792Snp	}
995218792Snp
996218792Snp	/*
997218792Snp	 * txq->m is the mbuf that is held up due to a temporary shortage of
998218792Snp	 * resources and it should be put on the wire first.  Then what's in
999218792Snp	 * drbr and finally the mbuf that was just passed in to us.
1000218792Snp	 *
1001218792Snp	 * Return code should indicate the fate of the mbuf that was passed in
1002218792Snp	 * this time.
1003218792Snp	 */
1004218792Snp
1005218792Snp	TXQ_LOCK_ASSERT_OWNED(txq);
1006218792Snp	if (drbr_needs_enqueue(ifp, br) || txq->m) {
1007218792Snp
1008218792Snp		/* Queued for transmission. */
1009218792Snp
1010218792Snp		rc = drbr_enqueue(ifp, br, m);
1011218792Snp		m = txq->m ? txq->m : drbr_dequeue(ifp, br);
1012218792Snp		(void) t4_eth_tx(ifp, txq, m);
1013218792Snp		TXQ_UNLOCK(txq);
1014218792Snp		return (rc);
1015218792Snp	}
1016218792Snp
1017218792Snp	/* Direct transmission. */
1018218792Snp	rc = t4_eth_tx(ifp, txq, m);
1019218792Snp	if (rc != 0 && txq->m)
1020218792Snp		rc = 0;	/* held, will be transmitted soon (hopefully) */
1021218792Snp
1022218792Snp	TXQ_UNLOCK(txq);
1023218792Snp	return (rc);
1024218792Snp}
1025218792Snp
1026218792Snpstatic void
1027218792Snpcxgbe_qflush(struct ifnet *ifp)
1028218792Snp{
1029218792Snp	struct port_info *pi = ifp->if_softc;
1030218792Snp
1031218792Snp	device_printf(pi->dev, "%s unimplemented.\n", __func__);
1032218792Snp}
1033218792Snp
1034218792Snpstatic int
1035218792Snpcxgbe_media_change(struct ifnet *ifp)
1036218792Snp{
1037218792Snp	struct port_info *pi = ifp->if_softc;
1038218792Snp
1039218792Snp	device_printf(pi->dev, "%s unimplemented.\n", __func__);
1040218792Snp
1041218792Snp	return (EOPNOTSUPP);
1042218792Snp}
1043218792Snp
1044218792Snpstatic void
1045218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1046218792Snp{
1047218792Snp	struct port_info *pi = ifp->if_softc;
1048218792Snp	struct ifmedia_entry *cur = pi->media.ifm_cur;
1049218792Snp	int speed = pi->link_cfg.speed;
1050218792Snp	int data = (pi->port_type << 8) | pi->mod_type;
1051218792Snp
1052218792Snp	if (cur->ifm_data != data) {
1053218792Snp		build_medialist(pi);
1054218792Snp		cur = pi->media.ifm_cur;
1055218792Snp	}
1056218792Snp
1057218792Snp	ifmr->ifm_status = IFM_AVALID;
1058218792Snp	if (!pi->link_cfg.link_ok)
1059218792Snp		return;
1060218792Snp
1061218792Snp	ifmr->ifm_status |= IFM_ACTIVE;
1062218792Snp
1063218792Snp	/* active and current will differ iff current media is autoselect. */
1064218792Snp	if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
1065218792Snp		return;
1066218792Snp
1067218792Snp	ifmr->ifm_active = IFM_ETHER | IFM_FDX;
1068218792Snp	if (speed == SPEED_10000)
1069218792Snp		ifmr->ifm_active |= IFM_10G_T;
1070218792Snp	else if (speed == SPEED_1000)
1071218792Snp		ifmr->ifm_active |= IFM_1000_T;
1072218792Snp	else if (speed == SPEED_100)
1073218792Snp		ifmr->ifm_active |= IFM_100_TX;
1074218792Snp	else if (speed == SPEED_10)
1075218792Snp		ifmr->ifm_active |= IFM_10_T;
1076218792Snp	else
1077218792Snp		KASSERT(0, ("%s: link up but speed unknown (%u)", __func__,
1078218792Snp			    speed));
1079218792Snp}
1080218792Snp
1081218792Snpvoid
1082218792Snpt4_fatal_err(struct adapter *sc)
1083218792Snp{
1084218792Snp	t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0);
1085218792Snp	t4_intr_disable(sc);
1086218792Snp	log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n",
1087218792Snp	    device_get_nameunit(sc->dev));
1088218792Snp}
1089218792Snp
1090218792Snpstatic int
1091218792Snpmap_bars(struct adapter *sc)
1092218792Snp{
1093218792Snp	sc->regs_rid = PCIR_BAR(0);
1094218792Snp	sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1095218792Snp	    &sc->regs_rid, RF_ACTIVE);
1096218792Snp	if (sc->regs_res == NULL) {
1097218792Snp		device_printf(sc->dev, "cannot map registers.\n");
1098218792Snp		return (ENXIO);
1099218792Snp	}
1100218792Snp	sc->bt = rman_get_bustag(sc->regs_res);
1101218792Snp	sc->bh = rman_get_bushandle(sc->regs_res);
1102218792Snp	sc->mmio_len = rman_get_size(sc->regs_res);
1103218792Snp
1104218792Snp	sc->msix_rid = PCIR_BAR(4);
1105218792Snp	sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1106218792Snp	    &sc->msix_rid, RF_ACTIVE);
1107218792Snp	if (sc->msix_res == NULL) {
1108218792Snp		device_printf(sc->dev, "cannot map MSI-X BAR.\n");
1109218792Snp		return (ENXIO);
1110218792Snp	}
1111218792Snp
1112218792Snp	return (0);
1113218792Snp}
1114218792Snp
1115218792Snpstatic void
1116218792Snpsetup_memwin(struct adapter *sc)
1117218792Snp{
1118218792Snp	u_long bar0;
1119218792Snp
1120218792Snp	bar0 = rman_get_start(sc->regs_res);
1121218792Snp
1122218792Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0),
1123218792Snp	    	     (bar0 + MEMWIN0_BASE) | V_BIR(0) |
1124218792Snp		     V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10));
1125218792Snp
1126218792Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1),
1127218792Snp		     (bar0 + MEMWIN1_BASE) | V_BIR(0) |
1128218792Snp		     V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10));
1129218792Snp
1130218792Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2),
1131218792Snp		     (bar0 + MEMWIN2_BASE) | V_BIR(0) |
1132218792Snp		     V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10));
1133218792Snp}
1134218792Snp
1135218792Snpstatic int
1136218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g,
1137218792Snp    struct intrs_and_queues *iaq)
1138218792Snp{
1139218792Snp	int rc, itype, navail, nc, nrxq10g, nrxq1g;
1140218792Snp
1141218792Snp	bzero(iaq, sizeof(*iaq));
1142218792Snp	nc = mp_ncpus;	/* our snapshot of the number of CPUs */
1143218792Snp
1144218792Snp	for (itype = 4; itype; itype >>= 1) {
1145218792Snp
1146218792Snp		if ((itype & intr_types) == 0)
1147218792Snp			continue;	/* not allowed */
1148218792Snp
1149218792Snp		if (itype == 4)
1150218792Snp			navail = pci_msix_count(sc->dev);
1151218792Snp		else if (itype == 2)
1152218792Snp			navail = pci_msi_count(sc->dev);
1153218792Snp		else
1154218792Snp			navail = 1;
1155218792Snp
1156218792Snp		if (navail == 0)
1157218792Snp			continue;
1158218792Snp
1159218792Snp		iaq->intr_type = itype;
1160218792Snp
1161218792Snp		iaq->ntxq10g = min(nc, max_ntxq_10g);
1162218792Snp		iaq->ntxq1g = min(nc, max_ntxq_1g);
1163218792Snp
1164218792Snp		nrxq10g = min(nc, max_nrxq_10g);
1165218792Snp		nrxq1g = min(nc, max_nrxq_1g);
1166218792Snp
1167218792Snp		/* Extra 2 is for a) error interrupt b) firmware event */
1168218792Snp		iaq->nirq = n10g * nrxq10g + n1g * nrxq1g + 2;
1169218792Snp		if (iaq->nirq <= navail && intr_fwd == 0) {
1170218792Snp
1171218792Snp			/* One for err, one for fwq, and one for each rxq */
1172218792Snp
1173218792Snp			iaq->intr_fwd = 0;
1174218792Snp			iaq->nrxq10g = nrxq10g;
1175218792Snp			iaq->nrxq1g = nrxq1g;
1176218792Snp			if (itype == 2) {
1177218792Snp				/* # of vectors requested must be power of 2 */
1178218792Snp				while (!powerof2(iaq->nirq))
1179218792Snp					iaq->nirq++;
1180218792Snp				KASSERT(iaq->nirq <= navail,
1181218792Snp				    ("%s: bad MSI calculation", __func__));
1182218792Snp			}
1183218792Snp		} else {
1184218792Snpfwd:
1185218792Snp			iaq->intr_fwd = 1;
1186218792Snp			iaq->nirq = navail;
1187218792Snp
1188218792Snp			/*
1189218792Snp			 * If we have multiple vectors available reserve one
1190218792Snp			 * exclusively for errors.  The rest will be shared by
1191218792Snp			 * the fwq and data.
1192218792Snp			 */
1193218792Snp			if (navail > 1) {
1194218792Snp				navail--;
1195218792Snp
1196218792Snp				if (navail > nc && itype == 4)
1197218792Snp					iaq->nirq = nc + 1;
1198218792Snp			}
1199218792Snp
1200218792Snp			iaq->nrxq10g = min(nrxq10g, navail);
1201218792Snp			iaq->nrxq1g = min(nrxq1g, navail);
1202218792Snp		}
1203218792Snp
1204218792Snp		navail = iaq->nirq;
1205218792Snp		rc = 0;
1206218792Snp		if (itype == 4)
1207218792Snp			rc = pci_alloc_msix(sc->dev, &navail);
1208218792Snp		else if (itype == 2)
1209218792Snp			rc = pci_alloc_msi(sc->dev, &navail);
1210218792Snp
1211218792Snp		if (rc == 0) {
1212218792Snp			if (navail == iaq->nirq)
1213218792Snp				return (0);
1214218792Snp
1215218792Snp			/*
1216218792Snp			 * Didn't get the number requested.  Use whatever number
1217218792Snp			 * the kernel is willing to allocate (it's in navail).
1218218792Snp			 */
1219218792Snp			pci_release_msi(sc->dev);
1220218792Snp			goto fwd;
1221218792Snp		}
1222218792Snp
1223218792Snp		device_printf(sc->dev,
1224218792Snp		    "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n",
1225218792Snp		    itype, rc, iaq->nirq, navail);
1226218792Snp	}
1227218792Snp
1228218792Snp	device_printf(sc->dev,
1229218792Snp	    "failed to find a usable interrupt type.  "
1230218792Snp	    "allowed=%d, msi-x=%d, msi=%d, intx=1", intr_types,
1231218792Snp	    pci_msix_count(sc->dev), pci_msi_count(sc->dev));
1232218792Snp
1233218792Snp	return (ENXIO);
1234218792Snp}
1235218792Snp
1236218792Snp/*
1237218792Snp * Install a compatible firmware (if required), establish contact with it,
1238218792Snp * become the master, and reset the device.
1239218792Snp */
1240218792Snpstatic int
1241218792Snpprep_firmware(struct adapter *sc)
1242218792Snp{
1243218792Snp	const struct firmware *fw;
1244218792Snp	int rc;
1245218792Snp	enum dev_state state;
1246218792Snp
1247218792Snp	/* Check firmware version and install a different one if necessary */
1248218792Snp	rc = t4_check_fw_version(sc);
1249218792Snp	if (rc != 0 || force_firmware_install) {
1250218792Snp
1251218792Snp		fw = firmware_get(T4_FWNAME);
1252218792Snp		if (fw == NULL) {
1253218792Snp			device_printf(sc->dev,
1254218792Snp			    "Could not find firmware image %s\n", T4_FWNAME);
1255218792Snp			return (ENOENT);
1256218792Snp		}
1257218792Snp
1258218792Snp		device_printf(sc->dev,
1259218792Snp		    "installing firmware %d.%d.%d on card.\n",
1260218792Snp		    FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
1261218792Snp		rc = -t4_load_fw(sc, fw->data, fw->datasize);
1262218792Snp		if (rc != 0) {
1263218792Snp			device_printf(sc->dev,
1264218792Snp			    "failed to install firmware: %d\n", rc);
1265218792Snp			return (rc);
1266218792Snp		} else {
1267218792Snp			t4_get_fw_version(sc, &sc->params.fw_vers);
1268218792Snp			t4_get_tp_version(sc, &sc->params.tp_vers);
1269218792Snp		}
1270218792Snp
1271218792Snp		firmware_put(fw, FIRMWARE_UNLOAD);
1272218792Snp	}
1273218792Snp
1274218792Snp	/* Contact firmware, request master */
1275218792Snp	rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MUST, &state);
1276218792Snp	if (rc < 0) {
1277218792Snp		rc = -rc;
1278218792Snp		device_printf(sc->dev,
1279218792Snp		    "failed to connect to the firmware: %d.\n", rc);
1280218792Snp		return (rc);
1281218792Snp	}
1282218792Snp
1283218792Snp	/* Reset device */
1284218792Snp	rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST);
1285218792Snp	if (rc != 0) {
1286218792Snp		device_printf(sc->dev, "firmware reset failed: %d.\n", rc);
1287218792Snp		if (rc != ETIMEDOUT && rc != EIO)
1288218792Snp			t4_fw_bye(sc, sc->mbox);
1289218792Snp		return (rc);
1290218792Snp	}
1291218792Snp
1292218792Snp	snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u",
1293218792Snp	    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
1294218792Snp	    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
1295218792Snp	    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
1296218792Snp	    G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers));
1297218792Snp	sc->flags |= FW_OK;
1298218792Snp
1299218792Snp	return (0);
1300218792Snp}
1301218792Snp
1302218792Snpstatic int
1303218792Snpget_capabilities(struct adapter *sc, struct fw_caps_config_cmd *caps)
1304218792Snp{
1305218792Snp	int rc;
1306218792Snp
1307218792Snp	bzero(caps, sizeof(*caps));
1308218792Snp	caps->op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
1309218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
1310218792Snp	caps->retval_len16 = htobe32(FW_LEN16(*caps));
1311218792Snp
1312218792Snp	rc = -t4_wr_mbox(sc, sc->mbox, caps, sizeof(*caps), caps);
1313218792Snp	if (rc != 0)
1314218792Snp		return (rc);
1315218792Snp
1316218792Snp	if (caps->niccaps & htobe16(FW_CAPS_CONFIG_NIC_VM))
1317218792Snp		caps->niccaps ^= htobe16(FW_CAPS_CONFIG_NIC_VM);
1318218792Snp
1319218792Snp	caps->op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
1320218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
1321218792Snp	rc = -t4_wr_mbox(sc, sc->mbox, caps, sizeof(*caps), NULL);
1322218792Snp
1323218792Snp	return (rc);
1324218792Snp}
1325218792Snp
1326218792Snpstatic int
1327218792Snpget_params(struct adapter *sc, struct fw_caps_config_cmd *caps)
1328218792Snp{
1329218792Snp	int rc;
1330218792Snp	uint32_t params[7], val[7];
1331218792Snp
1332218792Snp#define FW_PARAM_DEV(param) \
1333218792Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
1334218792Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
1335218792Snp#define FW_PARAM_PFVF(param) \
1336218792Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
1337218792Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param))
1338218792Snp
1339218792Snp	params[0] = FW_PARAM_DEV(PORTVEC);
1340218792Snp	params[1] = FW_PARAM_PFVF(IQFLINT_START);
1341218792Snp	params[2] = FW_PARAM_PFVF(EQ_START);
1342218792Snp	params[3] = FW_PARAM_PFVF(FILTER_START);
1343218792Snp	params[4] = FW_PARAM_PFVF(FILTER_END);
1344218792Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 5, params, val);
1345218792Snp	if (rc != 0) {
1346218792Snp		device_printf(sc->dev,
1347218792Snp		    "failed to query parameters: %d.\n", rc);
1348218792Snp		goto done;
1349218792Snp	}
1350218792Snp
1351218792Snp	sc->params.portvec = val[0];
1352218792Snp	sc->params.nports = 0;
1353218792Snp	while (val[0]) {
1354218792Snp		sc->params.nports++;
1355218792Snp		val[0] &= val[0] - 1;
1356218792Snp	}
1357218792Snp
1358218792Snp	sc->sge.iq_start = val[1];
1359218792Snp	sc->sge.eq_start = val[2];
1360218792Snp	sc->tids.ftid_base = val[3];
1361218792Snp	sc->tids.nftids = val[4] - val[3] + 1;
1362218792Snp
1363218792Snp	if (caps->toecaps) {
1364218792Snp		/* query offload-related parameters */
1365218792Snp		params[0] = FW_PARAM_DEV(NTID);
1366218792Snp		params[1] = FW_PARAM_PFVF(SERVER_START);
1367218792Snp		params[2] = FW_PARAM_PFVF(SERVER_END);
1368218792Snp		params[3] = FW_PARAM_PFVF(TDDP_START);
1369218792Snp		params[4] = FW_PARAM_PFVF(TDDP_END);
1370218792Snp		params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
1371218792Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, params, val);
1372218792Snp		if (rc != 0) {
1373218792Snp			device_printf(sc->dev,
1374218792Snp			    "failed to query TOE parameters: %d.\n", rc);
1375218792Snp			goto done;
1376218792Snp		}
1377218792Snp		sc->tids.ntids = val[0];
1378218792Snp		sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS);
1379218792Snp		sc->tids.stid_base = val[1];
1380218792Snp		sc->tids.nstids = val[2] - val[1] + 1;
1381218792Snp		sc->vres.ddp.start = val[3];
1382218792Snp		sc->vres.ddp.size = val[4] - val[3] + 1;
1383218792Snp		sc->params.ofldq_wr_cred = val[5];
1384218792Snp		sc->params.offload = 1;
1385218792Snp	}
1386218792Snp	if (caps->rdmacaps) {
1387218792Snp		params[0] = FW_PARAM_PFVF(STAG_START);
1388218792Snp		params[1] = FW_PARAM_PFVF(STAG_END);
1389218792Snp		params[2] = FW_PARAM_PFVF(RQ_START);
1390218792Snp		params[3] = FW_PARAM_PFVF(RQ_END);
1391218792Snp		params[4] = FW_PARAM_PFVF(PBL_START);
1392218792Snp		params[5] = FW_PARAM_PFVF(PBL_END);
1393218792Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, params, val);
1394218792Snp		if (rc != 0) {
1395218792Snp			device_printf(sc->dev,
1396218792Snp			    "failed to query RDMA parameters: %d.\n", rc);
1397218792Snp			goto done;
1398218792Snp		}
1399218792Snp		sc->vres.stag.start = val[0];
1400218792Snp		sc->vres.stag.size = val[1] - val[0] + 1;
1401218792Snp		sc->vres.rq.start = val[2];
1402218792Snp		sc->vres.rq.size = val[3] - val[2] + 1;
1403218792Snp		sc->vres.pbl.start = val[4];
1404218792Snp		sc->vres.pbl.size = val[5] - val[4] + 1;
1405218792Snp	}
1406218792Snp	if (caps->iscsicaps) {
1407218792Snp		params[0] = FW_PARAM_PFVF(ISCSI_START);
1408218792Snp		params[1] = FW_PARAM_PFVF(ISCSI_END);
1409218792Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, params, val);
1410218792Snp		if (rc != 0) {
1411218792Snp			device_printf(sc->dev,
1412218792Snp			    "failed to query iSCSI parameters: %d.\n", rc);
1413218792Snp			goto done;
1414218792Snp		}
1415218792Snp		sc->vres.iscsi.start = val[0];
1416218792Snp		sc->vres.iscsi.size = val[1] - val[0] + 1;
1417218792Snp	}
1418218792Snp#undef FW_PARAM_PFVF
1419218792Snp#undef FW_PARAM_DEV
1420218792Snp
1421218792Snpdone:
1422218792Snp	return (rc);
1423218792Snp}
1424218792Snp
1425218792Snpstatic void
1426218792Snpt4_set_desc(struct adapter *sc)
1427218792Snp{
1428218792Snp	char buf[128];
1429218792Snp	struct adapter_params *p = &sc->params;
1430218792Snp
1431218792Snp	snprintf(buf, sizeof(buf),
1432218792Snp	    "Chelsio %s (rev %d) %d port %sNIC PCIe-x%d %s, S/N:%s, E/C:%s",
1433218792Snp	    p->vpd.id, p->rev, p->nports, is_offload(sc) ? "R" : "",
1434218792Snp	    p->pci.width, (sc->intr_type == 4 ) ? "MSI-X" :
1435218792Snp	    (sc->intr_type == 2) ? "MSI" : "INTx", p->vpd.sn, p->vpd.ec);
1436218792Snp
1437218792Snp	device_set_desc_copy(sc->dev, buf);
1438218792Snp}
1439218792Snp
1440218792Snpstatic void
1441218792Snpbuild_medialist(struct port_info *pi)
1442218792Snp{
1443218792Snp	struct ifmedia *media = &pi->media;
1444218792Snp	int data, m;
1445218792Snp
1446218792Snp	PORT_LOCK(pi);
1447218792Snp
1448218792Snp	ifmedia_removeall(media);
1449218792Snp
1450218792Snp	m = IFM_ETHER | IFM_FDX;
1451218792Snp	data = (pi->port_type << 8) | pi->mod_type;
1452218792Snp
1453218792Snp	switch(pi->port_type) {
1454218792Snp	case FW_PORT_TYPE_BT_XFI:
1455218792Snp		ifmedia_add(media, m | IFM_10G_T, data, NULL);
1456218792Snp		break;
1457218792Snp
1458218792Snp	case FW_PORT_TYPE_BT_XAUI:
1459218792Snp		ifmedia_add(media, m | IFM_10G_T, data, NULL);
1460218792Snp		/* fall through */
1461218792Snp
1462218792Snp	case FW_PORT_TYPE_BT_SGMII:
1463218792Snp		ifmedia_add(media, m | IFM_1000_T, data, NULL);
1464218792Snp		ifmedia_add(media, m | IFM_100_TX, data, NULL);
1465218792Snp		ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL);
1466218792Snp		ifmedia_set(media, IFM_ETHER | IFM_AUTO);
1467218792Snp		break;
1468218792Snp
1469218792Snp	case FW_PORT_TYPE_CX4:
1470218792Snp		ifmedia_add(media, m | IFM_10G_CX4, data, NULL);
1471218792Snp		ifmedia_set(media, m | IFM_10G_CX4);
1472218792Snp		break;
1473218792Snp
1474218792Snp	case FW_PORT_TYPE_SFP:
1475218792Snp	case FW_PORT_TYPE_FIBER_XFI:
1476218792Snp	case FW_PORT_TYPE_FIBER_XAUI:
1477218792Snp		switch (pi->mod_type) {
1478218792Snp
1479218792Snp		case FW_PORT_MOD_TYPE_LR:
1480218792Snp			ifmedia_add(media, m | IFM_10G_LR, data, NULL);
1481218792Snp			ifmedia_set(media, m | IFM_10G_LR);
1482218792Snp			break;
1483218792Snp
1484218792Snp		case FW_PORT_MOD_TYPE_SR:
1485218792Snp			ifmedia_add(media, m | IFM_10G_SR, data, NULL);
1486218792Snp			ifmedia_set(media, m | IFM_10G_SR);
1487218792Snp			break;
1488218792Snp
1489218792Snp		case FW_PORT_MOD_TYPE_LRM:
1490218792Snp			ifmedia_add(media, m | IFM_10G_LRM, data, NULL);
1491218792Snp			ifmedia_set(media, m | IFM_10G_LRM);
1492218792Snp			break;
1493218792Snp
1494218792Snp		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
1495218792Snp		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
1496218792Snp			ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL);
1497218792Snp			ifmedia_set(media, m | IFM_10G_TWINAX);
1498218792Snp			break;
1499218792Snp
1500218792Snp		case FW_PORT_MOD_TYPE_NONE:
1501218792Snp			m &= ~IFM_FDX;
1502218792Snp			ifmedia_add(media, m | IFM_NONE, data, NULL);
1503218792Snp			ifmedia_set(media, m | IFM_NONE);
1504218792Snp			break;
1505218792Snp
1506218792Snp		case FW_PORT_MOD_TYPE_NA:
1507218792Snp		case FW_PORT_MOD_TYPE_ER:
1508218792Snp		default:
1509218792Snp			ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
1510218792Snp			ifmedia_set(media, m | IFM_UNKNOWN);
1511218792Snp			break;
1512218792Snp		}
1513218792Snp		break;
1514218792Snp
1515218792Snp	case FW_PORT_TYPE_KX4:
1516218792Snp	case FW_PORT_TYPE_KX:
1517218792Snp	case FW_PORT_TYPE_KR:
1518218792Snp	default:
1519218792Snp		ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
1520218792Snp		ifmedia_set(media, m | IFM_UNKNOWN);
1521218792Snp		break;
1522218792Snp	}
1523218792Snp
1524218792Snp	PORT_UNLOCK(pi);
1525218792Snp}
1526218792Snp
1527218792Snp/*
1528218792Snp * Program the port's XGMAC based on parameters in ifnet.  The caller also
1529218792Snp * indicates which parameters should be programmed (the rest are left alone).
1530218792Snp */
1531218792Snpstatic int
1532218792Snpupdate_mac_settings(struct port_info *pi, int flags)
1533218792Snp{
1534218792Snp	int rc;
1535218792Snp	struct ifnet *ifp = pi->ifp;
1536218792Snp	struct adapter *sc = pi->adapter;
1537218792Snp	int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1;
1538218792Snp
1539218792Snp	PORT_LOCK_ASSERT_OWNED(pi);
1540218792Snp	KASSERT(flags, ("%s: not told what to update.", __func__));
1541218792Snp
1542218792Snp	if (flags & XGMAC_MTU)
1543218792Snp		mtu = ifp->if_mtu;
1544218792Snp
1545218792Snp	if (flags & XGMAC_PROMISC)
1546218792Snp		promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0;
1547218792Snp
1548218792Snp	if (flags & XGMAC_ALLMULTI)
1549218792Snp		allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0;
1550218792Snp
1551218792Snp	if (flags & XGMAC_VLANEX)
1552218792Snp		vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0;
1553218792Snp
1554218792Snp	rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1,
1555218792Snp	    vlanex, false);
1556218792Snp	if (rc) {
1557218792Snp		if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc);
1558218792Snp		return (rc);
1559218792Snp	}
1560218792Snp
1561218792Snp	if (flags & XGMAC_UCADDR) {
1562218792Snp		uint8_t ucaddr[ETHER_ADDR_LEN];
1563218792Snp
1564218792Snp		bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr));
1565218792Snp		rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt,
1566218792Snp		    ucaddr, true, true);
1567218792Snp		if (rc < 0) {
1568218792Snp			rc = -rc;
1569218792Snp			if_printf(ifp, "change_mac failed: %d\n", rc);
1570218792Snp			return (rc);
1571218792Snp		} else {
1572218792Snp			pi->xact_addr_filt = rc;
1573218792Snp			rc = 0;
1574218792Snp		}
1575218792Snp	}
1576218792Snp
1577218792Snp	if (flags & XGMAC_MCADDRS) {
1578218792Snp		const uint8_t *mcaddr;
1579218792Snp		int del = 1;
1580218792Snp		uint64_t hash = 0;
1581218792Snp		struct ifmultiaddr *ifma;
1582218792Snp
1583218792Snp		if_maddr_rlock(ifp);
1584218792Snp		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1585218792Snp			if (ifma->ifma_addr->sa_family != AF_LINK)
1586218792Snp				continue;
1587218792Snp			mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
1588218792Snp
1589218792Snp			rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, del, 1,
1590218792Snp			    &mcaddr, NULL, &hash, 0);
1591218792Snp			if (rc < 0) {
1592218792Snp				rc = -rc;
1593218792Snp				if_printf(ifp, "failed to add mc address"
1594218792Snp				    " %02x:%02x:%02x:%02x:%02x:%02x rc=%d\n",
1595218792Snp				    mcaddr[0], mcaddr[1], mcaddr[2], mcaddr[3],
1596218792Snp				    mcaddr[4], mcaddr[5], rc);
1597218792Snp				goto mcfail;
1598218792Snp			}
1599218792Snp			del = 0;
1600218792Snp		}
1601218792Snp
1602218792Snp		rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0);
1603218792Snp		if (rc != 0)
1604218792Snp			if_printf(ifp, "failed to set mc address hash: %d", rc);
1605218792Snpmcfail:
1606218792Snp		if_maddr_runlock(ifp);
1607218792Snp	}
1608218792Snp
1609218792Snp	return (rc);
1610218792Snp}
1611218792Snp
1612218792Snpstatic int
1613218792Snpcxgbe_init_locked(struct port_info *pi)
1614218792Snp{
1615218792Snp	struct adapter *sc = pi->adapter;
1616218792Snp	int rc = 0;
1617218792Snp
1618218792Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
1619218792Snp
1620218792Snp	while (!IS_DOOMED(pi) && IS_BUSY(sc)) {
1621218792Snp		if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4init", 0)) {
1622218792Snp			rc = EINTR;
1623218792Snp			goto done;
1624218792Snp		}
1625218792Snp	}
1626218792Snp	if (IS_DOOMED(pi)) {
1627218792Snp		rc = ENXIO;
1628218792Snp		goto done;
1629218792Snp	}
1630218792Snp	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
1631218792Snp
1632218792Snp	/* Give up the adapter lock, port init code can sleep. */
1633218792Snp	SET_BUSY(sc);
1634218792Snp	ADAPTER_UNLOCK(sc);
1635218792Snp
1636218792Snp	rc = cxgbe_init_synchronized(pi);
1637218792Snp
1638218792Snpdone:
1639218792Snp	ADAPTER_LOCK(sc);
1640218792Snp	KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
1641218792Snp	CLR_BUSY(sc);
1642218792Snp	wakeup_one(&sc->flags);
1643218792Snp	ADAPTER_UNLOCK(sc);
1644218792Snp	return (rc);
1645218792Snp}
1646218792Snp
1647218792Snpstatic int
1648218792Snpcxgbe_init_synchronized(struct port_info *pi)
1649218792Snp{
1650218792Snp	struct adapter *sc = pi->adapter;
1651218792Snp	struct ifnet *ifp = pi->ifp;
1652218792Snp	int rc = 0, i;
1653218792Snp	uint16_t *rss;
1654218792Snp	struct sge_rxq *rxq;
1655218792Snp
1656218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1657218792Snp
1658218792Snp	if (isset(&sc->open_device_map, pi->port_id)) {
1659218792Snp		KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING,
1660218792Snp		    ("mismatch between open_device_map and if_drv_flags"));
1661218792Snp		return (0);	/* already running */
1662218792Snp	}
1663218792Snp
1664218792Snp	if (sc->open_device_map == 0 && ((rc = first_port_up(sc)) != 0))
1665218792Snp		return (rc);	/* error message displayed already */
1666218792Snp
1667218792Snp	/*
1668218792Snp	 * Allocate tx/rx/fl queues for this port.
1669218792Snp	 */
1670218792Snp	rc = t4_setup_eth_queues(pi);
1671218792Snp	if (rc != 0)
1672218792Snp		goto done;	/* error message displayed already */
1673218792Snp
1674218792Snp	/*
1675218792Snp	 * Setup RSS for this port.
1676218792Snp	 */
1677218792Snp	rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK);
1678218792Snp	for_each_rxq(pi, i, rxq) {
1679218792Snp		rss[i] = rxq->iq.abs_id;
1680218792Snp	}
1681218792Snp	rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, pi->rss_size, rss,
1682218792Snp	    pi->nrxq);
1683218792Snp	free(rss, M_CXGBE);
1684218792Snp	if (rc != 0) {
1685218792Snp		if_printf(ifp, "rss_config failed: %d\n", rc);
1686218792Snp		goto done;
1687218792Snp	}
1688218792Snp
1689218792Snp	PORT_LOCK(pi);
1690218792Snp	rc = update_mac_settings(pi, XGMAC_ALL);
1691218792Snp	PORT_UNLOCK(pi);
1692218792Snp	if (rc)
1693218792Snp		goto done;	/* error message displayed already */
1694218792Snp
1695218792Snp	rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg);
1696218792Snp	if (rc != 0) {
1697218792Snp		if_printf(ifp, "start_link failed: %d\n", rc);
1698218792Snp		goto done;
1699218792Snp	}
1700218792Snp
1701218792Snp	rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true);
1702218792Snp	if (rc != 0) {
1703218792Snp		if_printf(ifp, "enable_vi failed: %d\n", rc);
1704218792Snp		goto done;
1705218792Snp	}
1706218792Snp	pi->flags |= VI_ENABLED;
1707218792Snp
1708218792Snp	/* all ok */
1709218792Snp	setbit(&sc->open_device_map, pi->port_id);
1710218792Snp	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1711218792Snp	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1712218792Snp
1713218792Snp	callout_reset(&pi->tick, hz, cxgbe_tick, pi);
1714218792Snpdone:
1715218792Snp	if (rc != 0)
1716218792Snp		cxgbe_uninit_synchronized(pi);
1717218792Snp
1718218792Snp	return (rc);
1719218792Snp}
1720218792Snp
1721218792Snpstatic int
1722218792Snpcxgbe_uninit_locked(struct port_info *pi)
1723218792Snp{
1724218792Snp	struct adapter *sc = pi->adapter;
1725218792Snp	int rc;
1726218792Snp
1727218792Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
1728218792Snp
1729218792Snp	while (!IS_DOOMED(pi) && IS_BUSY(sc)) {
1730218792Snp		if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4uninit", 0)) {
1731218792Snp			rc = EINTR;
1732218792Snp			goto done;
1733218792Snp		}
1734218792Snp	}
1735218792Snp	if (IS_DOOMED(pi)) {
1736218792Snp		rc = ENXIO;
1737218792Snp		goto done;
1738218792Snp	}
1739218792Snp	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
1740218792Snp	SET_BUSY(sc);
1741218792Snp	ADAPTER_UNLOCK(sc);
1742218792Snp
1743218792Snp	rc = cxgbe_uninit_synchronized(pi);
1744218792Snp
1745218792Snp	ADAPTER_LOCK(sc);
1746218792Snp	KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
1747218792Snp	CLR_BUSY(sc);
1748218792Snp	wakeup_one(&sc->flags);
1749218792Snpdone:
1750218792Snp	ADAPTER_UNLOCK(sc);
1751218792Snp	return (rc);
1752218792Snp}
1753218792Snp
1754218792Snp/*
1755218792Snp * Idempotent.
1756218792Snp */
1757218792Snpstatic int
1758218792Snpcxgbe_uninit_synchronized(struct port_info *pi)
1759218792Snp{
1760218792Snp	struct adapter *sc = pi->adapter;
1761218792Snp	struct ifnet *ifp = pi->ifp;
1762218792Snp	int rc;
1763218792Snp
1764218792Snp	/*
1765218792Snp	 * taskqueue_drain may cause a deadlock if the adapter lock is held.
1766218792Snp	 */
1767218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1768218792Snp
1769218792Snp	/*
1770218792Snp	 * Clear this port's bit from the open device map, and then drain
1771218792Snp	 * tasks and callouts.
1772218792Snp	 */
1773218792Snp	clrbit(&sc->open_device_map, pi->port_id);
1774218792Snp
1775218792Snp	PORT_LOCK(pi);
1776218792Snp	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1777218792Snp	callout_stop(&pi->tick);
1778218792Snp	PORT_UNLOCK(pi);
1779218792Snp	callout_drain(&pi->tick);
1780218792Snp
1781218792Snp	/*
1782218792Snp	 * Stop and then free the queues' resources, including the queues
1783218792Snp	 * themselves.
1784218792Snp	 *
1785218792Snp	 * XXX: we could just stop the queues here (on ifconfig down) and free
1786218792Snp	 * them later (on port detach), but having up/down go through the entire
1787218792Snp	 * allocate/activate/deactivate/free sequence is a good way to find
1788218792Snp	 * leaks and bugs.
1789218792Snp	 */
1790218792Snp	rc = t4_teardown_eth_queues(pi);
1791218792Snp	if (rc != 0)
1792218792Snp		if_printf(ifp, "teardown failed: %d\n", rc);
1793218792Snp
1794218792Snp	if (pi->flags & VI_ENABLED) {
1795218792Snp		rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false);
1796218792Snp		if (rc)
1797218792Snp			if_printf(ifp, "disable_vi failed: %d\n", rc);
1798218792Snp		else
1799218792Snp			pi->flags &= ~VI_ENABLED;
1800218792Snp	}
1801218792Snp
1802218792Snp	pi->link_cfg.link_ok = 0;
1803218792Snp	pi->link_cfg.speed = 0;
1804218792Snp	t4_os_link_changed(sc, pi->port_id, 0);
1805218792Snp
1806218792Snp	if (sc->open_device_map == 0)
1807218792Snp		last_port_down(sc);
1808218792Snp
1809218792Snp	return (0);
1810218792Snp}
1811218792Snp
1812218792Snp#define T4_ALLOC_IRQ(sc, irqid, rid, handler, arg, name) do { \
1813218792Snp	rc = t4_alloc_irq(sc, &sc->irq[irqid], rid, handler, arg, name); \
1814218792Snp	if (rc != 0) \
1815218792Snp		goto done; \
1816218792Snp} while (0)
1817218792Snpstatic int
1818218792Snpfirst_port_up(struct adapter *sc)
1819218792Snp{
1820218792Snp	int rc, i;
1821218792Snp	char name[8];
1822218792Snp
1823218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1824218792Snp
1825218792Snp	/*
1826218792Snp	 * The firmware event queue and the optional forwarded interrupt queues.
1827218792Snp	 */
1828218792Snp	rc = t4_setup_adapter_iqs(sc);
1829218792Snp	if (rc != 0)
1830218792Snp		goto done;
1831218792Snp
1832218792Snp	/*
1833218792Snp	 * Setup interrupts.
1834218792Snp	 */
1835218792Snp	if (sc->intr_count == 1) {
1836218792Snp		KASSERT(sc->flags & INTR_FWD,
1837218792Snp		    ("%s: single interrupt but not forwarded?", __func__));
1838218792Snp		T4_ALLOC_IRQ(sc, 0, 0, t4_intr_all, sc, "all");
1839218792Snp	} else {
1840218792Snp		/* Multiple interrupts.  The first one is always error intr */
1841218792Snp		T4_ALLOC_IRQ(sc, 0, 1, t4_intr_err, sc, "err");
1842218792Snp
1843218792Snp		if (sc->flags & INTR_FWD) {
1844218792Snp			/* The rest are shared by the fwq and all data intr */
1845218792Snp			for (i = 1; i < sc->intr_count; i++) {
1846218792Snp				snprintf(name, sizeof(name), "mux%d", i - 1);
1847218792Snp				T4_ALLOC_IRQ(sc, i, i + 1, t4_intr_fwd,
1848218792Snp				    &sc->sge.fiq[i - 1], name);
1849218792Snp			}
1850218792Snp		} else {
1851218792Snp			struct port_info *pi;
1852218792Snp			int p, q;
1853218792Snp
1854218792Snp			T4_ALLOC_IRQ(sc, 1, 2, t4_intr_evt, &sc->sge.fwq,
1855218792Snp			    "evt");
1856218792Snp
1857218792Snp			p = q = 0;
1858218792Snp			pi = sc->port[p];
1859218792Snp			for (i = 2; i < sc->intr_count; i++) {
1860218792Snp				snprintf(name, sizeof(name), "p%dq%d", p, q);
1861218792Snp				if (++q >= pi->nrxq) {
1862218792Snp					p++;
1863218792Snp					q = 0;
1864218792Snp					pi = sc->port[p];
1865218792Snp				}
1866218792Snp				T4_ALLOC_IRQ(sc, i, i + 1, t4_intr_data,
1867218792Snp				    &sc->sge.rxq[i - 2], name);
1868218792Snp			}
1869218792Snp		}
1870218792Snp	}
1871218792Snp
1872218792Snp	t4_intr_enable(sc);
1873218792Snp	sc->flags |= FULL_INIT_DONE;
1874218792Snp
1875218792Snpdone:
1876218792Snp	if (rc != 0)
1877218792Snp		last_port_down(sc);
1878218792Snp
1879218792Snp	return (rc);
1880218792Snp}
1881218792Snp#undef T4_ALLOC_IRQ
1882218792Snp
1883218792Snp/*
1884218792Snp * Idempotent.
1885218792Snp */
1886218792Snpstatic int
1887218792Snplast_port_down(struct adapter *sc)
1888218792Snp{
1889218792Snp	int i;
1890218792Snp
1891218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1892218792Snp
1893218792Snp	t4_intr_disable(sc);
1894218792Snp
1895218792Snp	t4_teardown_adapter_iqs(sc);
1896218792Snp
1897218792Snp	for (i = 0; i < sc->intr_count; i++)
1898218792Snp		t4_free_irq(sc, &sc->irq[i]);
1899218792Snp
1900218792Snp	sc->flags &= ~FULL_INIT_DONE;
1901218792Snp
1902218792Snp	return (0);
1903218792Snp}
1904218792Snp
1905218792Snpstatic int
1906218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid,
1907218792Snp    iq_intr_handler_t *handler, void *arg, char *name)
1908218792Snp{
1909218792Snp	int rc;
1910218792Snp
1911218792Snp	irq->rid = rid;
1912218792Snp	irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid,
1913218792Snp	    RF_SHAREABLE | RF_ACTIVE);
1914218792Snp	if (irq->res == NULL) {
1915218792Snp		device_printf(sc->dev,
1916218792Snp		    "failed to allocate IRQ for rid %d, name %s.\n", rid, name);
1917218792Snp		return (ENOMEM);
1918218792Snp	}
1919218792Snp
1920218792Snp	rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET,
1921218792Snp	    NULL, handler, arg, &irq->tag);
1922218792Snp	if (rc != 0) {
1923218792Snp		device_printf(sc->dev,
1924218792Snp		    "failed to setup interrupt for rid %d, name %s: %d\n",
1925218792Snp		    rid, name, rc);
1926218792Snp	} else if (name)
1927218792Snp		bus_describe_intr(sc->dev, irq->res, irq->tag, name);
1928218792Snp
1929218792Snp	return (rc);
1930218792Snp}
1931218792Snp
1932218792Snpstatic int
1933218792Snpt4_free_irq(struct adapter *sc, struct irq *irq)
1934218792Snp{
1935218792Snp	if (irq->tag)
1936218792Snp		bus_teardown_intr(sc->dev, irq->res, irq->tag);
1937218792Snp	if (irq->res)
1938218792Snp		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res);
1939218792Snp
1940218792Snp	bzero(irq, sizeof(*irq));
1941218792Snp
1942218792Snp	return (0);
1943218792Snp}
1944218792Snp
1945218792Snpstatic void
1946218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start,
1947218792Snp    unsigned int end)
1948218792Snp{
1949218792Snp	uint32_t *p = (uint32_t *)(buf + start);
1950218792Snp
1951218792Snp	for ( ; start <= end; start += sizeof(uint32_t))
1952218792Snp		*p++ = t4_read_reg(sc, start);
1953218792Snp}
1954218792Snp
1955218792Snpstatic void
1956218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf)
1957218792Snp{
1958218792Snp	int i;
1959218792Snp	static const unsigned int reg_ranges[] = {
1960218792Snp		0x1008, 0x1108,
1961218792Snp		0x1180, 0x11b4,
1962218792Snp		0x11fc, 0x123c,
1963218792Snp		0x1300, 0x173c,
1964218792Snp		0x1800, 0x18fc,
1965218792Snp		0x3000, 0x30d8,
1966218792Snp		0x30e0, 0x5924,
1967218792Snp		0x5960, 0x59d4,
1968218792Snp		0x5a00, 0x5af8,
1969218792Snp		0x6000, 0x6098,
1970218792Snp		0x6100, 0x6150,
1971218792Snp		0x6200, 0x6208,
1972218792Snp		0x6240, 0x6248,
1973218792Snp		0x6280, 0x6338,
1974218792Snp		0x6370, 0x638c,
1975218792Snp		0x6400, 0x643c,
1976218792Snp		0x6500, 0x6524,
1977218792Snp		0x6a00, 0x6a38,
1978218792Snp		0x6a60, 0x6a78,
1979218792Snp		0x6b00, 0x6b84,
1980218792Snp		0x6bf0, 0x6c84,
1981218792Snp		0x6cf0, 0x6d84,
1982218792Snp		0x6df0, 0x6e84,
1983218792Snp		0x6ef0, 0x6f84,
1984218792Snp		0x6ff0, 0x7084,
1985218792Snp		0x70f0, 0x7184,
1986218792Snp		0x71f0, 0x7284,
1987218792Snp		0x72f0, 0x7384,
1988218792Snp		0x73f0, 0x7450,
1989218792Snp		0x7500, 0x7530,
1990218792Snp		0x7600, 0x761c,
1991218792Snp		0x7680, 0x76cc,
1992218792Snp		0x7700, 0x7798,
1993218792Snp		0x77c0, 0x77fc,
1994218792Snp		0x7900, 0x79fc,
1995218792Snp		0x7b00, 0x7c38,
1996218792Snp		0x7d00, 0x7efc,
1997218792Snp		0x8dc0, 0x8e1c,
1998218792Snp		0x8e30, 0x8e78,
1999218792Snp		0x8ea0, 0x8f6c,
2000218792Snp		0x8fc0, 0x9074,
2001218792Snp		0x90fc, 0x90fc,
2002218792Snp		0x9400, 0x9458,
2003218792Snp		0x9600, 0x96bc,
2004218792Snp		0x9800, 0x9808,
2005218792Snp		0x9820, 0x983c,
2006218792Snp		0x9850, 0x9864,
2007218792Snp		0x9c00, 0x9c6c,
2008218792Snp		0x9c80, 0x9cec,
2009218792Snp		0x9d00, 0x9d6c,
2010218792Snp		0x9d80, 0x9dec,
2011218792Snp		0x9e00, 0x9e6c,
2012218792Snp		0x9e80, 0x9eec,
2013218792Snp		0x9f00, 0x9f6c,
2014218792Snp		0x9f80, 0x9fec,
2015218792Snp		0xd004, 0xd03c,
2016218792Snp		0xdfc0, 0xdfe0,
2017218792Snp		0xe000, 0xea7c,
2018218792Snp		0xf000, 0x11190,
2019218792Snp		0x19040, 0x19124,
2020218792Snp		0x19150, 0x191b0,
2021218792Snp		0x191d0, 0x191e8,
2022218792Snp		0x19238, 0x1924c,
2023218792Snp		0x193f8, 0x19474,
2024218792Snp		0x19490, 0x194f8,
2025218792Snp		0x19800, 0x19f30,
2026218792Snp		0x1a000, 0x1a06c,
2027218792Snp		0x1a0b0, 0x1a120,
2028218792Snp		0x1a128, 0x1a138,
2029218792Snp		0x1a190, 0x1a1c4,
2030218792Snp		0x1a1fc, 0x1a1fc,
2031218792Snp		0x1e040, 0x1e04c,
2032218792Snp		0x1e240, 0x1e28c,
2033218792Snp		0x1e2c0, 0x1e2c0,
2034218792Snp		0x1e2e0, 0x1e2e0,
2035218792Snp		0x1e300, 0x1e384,
2036218792Snp		0x1e3c0, 0x1e3c8,
2037218792Snp		0x1e440, 0x1e44c,
2038218792Snp		0x1e640, 0x1e68c,
2039218792Snp		0x1e6c0, 0x1e6c0,
2040218792Snp		0x1e6e0, 0x1e6e0,
2041218792Snp		0x1e700, 0x1e784,
2042218792Snp		0x1e7c0, 0x1e7c8,
2043218792Snp		0x1e840, 0x1e84c,
2044218792Snp		0x1ea40, 0x1ea8c,
2045218792Snp		0x1eac0, 0x1eac0,
2046218792Snp		0x1eae0, 0x1eae0,
2047218792Snp		0x1eb00, 0x1eb84,
2048218792Snp		0x1ebc0, 0x1ebc8,
2049218792Snp		0x1ec40, 0x1ec4c,
2050218792Snp		0x1ee40, 0x1ee8c,
2051218792Snp		0x1eec0, 0x1eec0,
2052218792Snp		0x1eee0, 0x1eee0,
2053218792Snp		0x1ef00, 0x1ef84,
2054218792Snp		0x1efc0, 0x1efc8,
2055218792Snp		0x1f040, 0x1f04c,
2056218792Snp		0x1f240, 0x1f28c,
2057218792Snp		0x1f2c0, 0x1f2c0,
2058218792Snp		0x1f2e0, 0x1f2e0,
2059218792Snp		0x1f300, 0x1f384,
2060218792Snp		0x1f3c0, 0x1f3c8,
2061218792Snp		0x1f440, 0x1f44c,
2062218792Snp		0x1f640, 0x1f68c,
2063218792Snp		0x1f6c0, 0x1f6c0,
2064218792Snp		0x1f6e0, 0x1f6e0,
2065218792Snp		0x1f700, 0x1f784,
2066218792Snp		0x1f7c0, 0x1f7c8,
2067218792Snp		0x1f840, 0x1f84c,
2068218792Snp		0x1fa40, 0x1fa8c,
2069218792Snp		0x1fac0, 0x1fac0,
2070218792Snp		0x1fae0, 0x1fae0,
2071218792Snp		0x1fb00, 0x1fb84,
2072218792Snp		0x1fbc0, 0x1fbc8,
2073218792Snp		0x1fc40, 0x1fc4c,
2074218792Snp		0x1fe40, 0x1fe8c,
2075218792Snp		0x1fec0, 0x1fec0,
2076218792Snp		0x1fee0, 0x1fee0,
2077218792Snp		0x1ff00, 0x1ff84,
2078218792Snp		0x1ffc0, 0x1ffc8,
2079218792Snp		0x20000, 0x2002c,
2080218792Snp		0x20100, 0x2013c,
2081218792Snp		0x20190, 0x201c8,
2082218792Snp		0x20200, 0x20318,
2083218792Snp		0x20400, 0x20528,
2084218792Snp		0x20540, 0x20614,
2085218792Snp		0x21000, 0x21040,
2086218792Snp		0x2104c, 0x21060,
2087218792Snp		0x210c0, 0x210ec,
2088218792Snp		0x21200, 0x21268,
2089218792Snp		0x21270, 0x21284,
2090218792Snp		0x212fc, 0x21388,
2091218792Snp		0x21400, 0x21404,
2092218792Snp		0x21500, 0x21518,
2093218792Snp		0x2152c, 0x2153c,
2094218792Snp		0x21550, 0x21554,
2095218792Snp		0x21600, 0x21600,
2096218792Snp		0x21608, 0x21628,
2097218792Snp		0x21630, 0x2163c,
2098218792Snp		0x21700, 0x2171c,
2099218792Snp		0x21780, 0x2178c,
2100218792Snp		0x21800, 0x21c38,
2101218792Snp		0x21c80, 0x21d7c,
2102218792Snp		0x21e00, 0x21e04,
2103218792Snp		0x22000, 0x2202c,
2104218792Snp		0x22100, 0x2213c,
2105218792Snp		0x22190, 0x221c8,
2106218792Snp		0x22200, 0x22318,
2107218792Snp		0x22400, 0x22528,
2108218792Snp		0x22540, 0x22614,
2109218792Snp		0x23000, 0x23040,
2110218792Snp		0x2304c, 0x23060,
2111218792Snp		0x230c0, 0x230ec,
2112218792Snp		0x23200, 0x23268,
2113218792Snp		0x23270, 0x23284,
2114218792Snp		0x232fc, 0x23388,
2115218792Snp		0x23400, 0x23404,
2116218792Snp		0x23500, 0x23518,
2117218792Snp		0x2352c, 0x2353c,
2118218792Snp		0x23550, 0x23554,
2119218792Snp		0x23600, 0x23600,
2120218792Snp		0x23608, 0x23628,
2121218792Snp		0x23630, 0x2363c,
2122218792Snp		0x23700, 0x2371c,
2123218792Snp		0x23780, 0x2378c,
2124218792Snp		0x23800, 0x23c38,
2125218792Snp		0x23c80, 0x23d7c,
2126218792Snp		0x23e00, 0x23e04,
2127218792Snp		0x24000, 0x2402c,
2128218792Snp		0x24100, 0x2413c,
2129218792Snp		0x24190, 0x241c8,
2130218792Snp		0x24200, 0x24318,
2131218792Snp		0x24400, 0x24528,
2132218792Snp		0x24540, 0x24614,
2133218792Snp		0x25000, 0x25040,
2134218792Snp		0x2504c, 0x25060,
2135218792Snp		0x250c0, 0x250ec,
2136218792Snp		0x25200, 0x25268,
2137218792Snp		0x25270, 0x25284,
2138218792Snp		0x252fc, 0x25388,
2139218792Snp		0x25400, 0x25404,
2140218792Snp		0x25500, 0x25518,
2141218792Snp		0x2552c, 0x2553c,
2142218792Snp		0x25550, 0x25554,
2143218792Snp		0x25600, 0x25600,
2144218792Snp		0x25608, 0x25628,
2145218792Snp		0x25630, 0x2563c,
2146218792Snp		0x25700, 0x2571c,
2147218792Snp		0x25780, 0x2578c,
2148218792Snp		0x25800, 0x25c38,
2149218792Snp		0x25c80, 0x25d7c,
2150218792Snp		0x25e00, 0x25e04,
2151218792Snp		0x26000, 0x2602c,
2152218792Snp		0x26100, 0x2613c,
2153218792Snp		0x26190, 0x261c8,
2154218792Snp		0x26200, 0x26318,
2155218792Snp		0x26400, 0x26528,
2156218792Snp		0x26540, 0x26614,
2157218792Snp		0x27000, 0x27040,
2158218792Snp		0x2704c, 0x27060,
2159218792Snp		0x270c0, 0x270ec,
2160218792Snp		0x27200, 0x27268,
2161218792Snp		0x27270, 0x27284,
2162218792Snp		0x272fc, 0x27388,
2163218792Snp		0x27400, 0x27404,
2164218792Snp		0x27500, 0x27518,
2165218792Snp		0x2752c, 0x2753c,
2166218792Snp		0x27550, 0x27554,
2167218792Snp		0x27600, 0x27600,
2168218792Snp		0x27608, 0x27628,
2169218792Snp		0x27630, 0x2763c,
2170218792Snp		0x27700, 0x2771c,
2171218792Snp		0x27780, 0x2778c,
2172218792Snp		0x27800, 0x27c38,
2173218792Snp		0x27c80, 0x27d7c,
2174218792Snp		0x27e00, 0x27e04
2175218792Snp	};
2176218792Snp
2177218792Snp	regs->version = 4 | (sc->params.rev << 10);
2178218792Snp	for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2)
2179218792Snp		reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]);
2180218792Snp}
2181218792Snp
2182218792Snpstatic void
2183218792Snpcxgbe_tick(void *arg)
2184218792Snp{
2185218792Snp	struct port_info *pi = arg;
2186218792Snp	struct ifnet *ifp = pi->ifp;
2187218792Snp	struct sge_txq *txq;
2188218792Snp	int i, drops;
2189218792Snp	struct port_stats *s = &pi->stats;
2190218792Snp
2191218792Snp	PORT_LOCK(pi);
2192218792Snp	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2193218792Snp		PORT_UNLOCK(pi);
2194218792Snp		return;	/* without scheduling another callout */
2195218792Snp	}
2196218792Snp
2197218792Snp	t4_get_port_stats(pi->adapter, pi->tx_chan, s);
2198218792Snp
2199218792Snp	ifp->if_opackets = s->tx_frames;
2200218792Snp	ifp->if_ipackets = s->rx_frames;
2201218792Snp	ifp->if_obytes = s->tx_octets;
2202218792Snp	ifp->if_ibytes = s->rx_octets;
2203218792Snp	ifp->if_omcasts = s->tx_mcast_frames;
2204218792Snp	ifp->if_imcasts = s->rx_mcast_frames;
2205218792Snp	ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 +
2206218792Snp	    s->rx_ovflow3;
2207218792Snp
2208218792Snp	drops = s->tx_drop;
2209218792Snp	for_each_txq(pi, i, txq)
2210218792Snp		drops += txq->eq.br->br_drops;
2211218792Snp	ifp->if_snd.ifq_drops = drops;
2212218792Snp
2213218792Snp	ifp->if_oerrors = s->tx_error_frames;
2214218792Snp	ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long +
2215218792Snp	    s->rx_fcs_err + s->rx_len_err;
2216218792Snp
2217218792Snp	callout_schedule(&pi->tick, hz);
2218218792Snp	PORT_UNLOCK(pi);
2219218792Snp}
2220218792Snp
2221218792Snpstatic int
2222218792Snpt4_sysctls(struct adapter *sc)
2223218792Snp{
2224218792Snp	struct sysctl_ctx_list *ctx;
2225218792Snp	struct sysctl_oid *oid;
2226218792Snp	struct sysctl_oid_list *children;
2227218792Snp
2228218792Snp	ctx = device_get_sysctl_ctx(sc->dev);
2229218792Snp	oid = device_get_sysctl_tree(sc->dev);
2230218792Snp	children = SYSCTL_CHILDREN(oid);
2231218792Snp
2232218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD,
2233218792Snp	    &sc->params.nports, 0, "# of ports");
2234218792Snp
2235218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD,
2236218792Snp	    &sc->params.rev, 0, "chip hardware revision");
2237218792Snp
2238218792Snp	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version",
2239218792Snp	    CTLFLAG_RD, &sc->fw_version, 0, "firmware version");
2240218792Snp
2241218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "TOE", CTLFLAG_RD,
2242218792Snp	    &sc->params.offload, 0, "hardware is capable of TCP offload");
2243218792Snp
2244218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD,
2245218792Snp	    &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)");
2246218792Snp
2247218792Snp	/* XXX: this doesn't seem to show up */
2248218792Snp	SYSCTL_ADD_OPAQUE(ctx, children, OID_AUTO, "holdoff_tmr",
2249218792Snp	    CTLFLAG_RD, &intr_timer, sizeof(intr_timer), "IU",
2250218792Snp	    "interrupt holdoff timer values (us)");
2251218792Snp
2252218792Snp	/* XXX: this doesn't seem to show up */
2253218792Snp	SYSCTL_ADD_OPAQUE(ctx, children, OID_AUTO, "holdoff_pktc",
2254218792Snp	    CTLFLAG_RD, &intr_pktcount, sizeof(intr_pktcount), "IU",
2255218792Snp	    "interrupt holdoff packet counter values");
2256218792Snp
2257218792Snp	return (0);
2258218792Snp}
2259218792Snp
2260218792Snpstatic int
2261218792Snpcxgbe_sysctls(struct port_info *pi)
2262218792Snp{
2263218792Snp	struct sysctl_ctx_list *ctx;
2264218792Snp	struct sysctl_oid *oid;
2265218792Snp	struct sysctl_oid_list *children;
2266218792Snp
2267218792Snp	ctx = device_get_sysctl_ctx(pi->dev);
2268218792Snp
2269218792Snp	/*
2270218792Snp	 * dev.cxgbe.X.
2271218792Snp	 */
2272218792Snp	oid = device_get_sysctl_tree(pi->dev);
2273218792Snp	children = SYSCTL_CHILDREN(oid);
2274218792Snp
2275218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD,
2276218792Snp	    &pi->nrxq, 0, "# of rx queues");
2277218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD,
2278218792Snp	    &pi->ntxq, 0, "# of tx queues");
2279218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD,
2280218792Snp	    &pi->first_rxq, 0, "index of first rx queue");
2281218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD,
2282218792Snp	    &pi->first_txq, 0, "index of first tx queue");
2283218792Snp
2284218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx",
2285218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I",
2286218792Snp	    "holdoff timer index");
2287218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx",
2288218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I",
2289218792Snp	    "holdoff packet counter index");
2290218792Snp
2291218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq",
2292218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I",
2293218792Snp	    "rx queue size");
2294218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq",
2295218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I",
2296218792Snp	    "tx queue size");
2297218792Snp
2298218792Snp	/*
2299218792Snp	 * dev.cxgbe.X.stats.
2300218792Snp	 */
2301218792Snp	oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD,
2302218792Snp	    NULL, "port statistics");
2303218792Snp	children = SYSCTL_CHILDREN(oid);
2304218792Snp
2305218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \
2306218792Snp	SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \
2307218792Snp	    CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \
2308218792Snp	    sysctl_handle_t4_reg64, "QU", desc)
2309218792Snp
2310218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames",
2311218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L));
2312218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames",
2313218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L));
2314218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames",
2315218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L));
2316218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames",
2317218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L));
2318218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames",
2319218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L));
2320218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames",
2321218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L));
2322218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_64",
2323218792Snp	    "# of tx frames in this range",
2324218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L));
2325218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127",
2326218792Snp	    "# of tx frames in this range",
2327218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L));
2328218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255",
2329218792Snp	    "# of tx frames in this range",
2330218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L));
2331218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511",
2332218792Snp	    "# of tx frames in this range",
2333218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L));
2334218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023",
2335218792Snp	    "# of tx frames in this range",
2336218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L));
2337218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518",
2338218792Snp	    "# of tx frames in this range",
2339218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L));
2340218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max",
2341218792Snp	    "# of tx frames in this range",
2342218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L));
2343218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames",
2344218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L));
2345218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted",
2346218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L));
2347218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted",
2348218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L));
2349218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted",
2350218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L));
2351218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted",
2352218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L));
2353218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted",
2354218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L));
2355218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted",
2356218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L));
2357218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted",
2358218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L));
2359218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted",
2360218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L));
2361218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted",
2362218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L));
2363218792Snp
2364218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames",
2365218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L));
2366218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames",
2367218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L));
2368218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames",
2369218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L));
2370218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames",
2371218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L));
2372218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames",
2373218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L));
2374218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU",
2375218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L));
2376218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames",
2377218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L));
2378218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err",
2379218792Snp	    "# of frames received with bad FCS",
2380218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L));
2381218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_len_err",
2382218792Snp	    "# of frames received with length error",
2383218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L));
2384218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors",
2385218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L));
2386218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received",
2387218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L));
2388218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_64",
2389218792Snp	    "# of rx frames in this range",
2390218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L));
2391218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127",
2392218792Snp	    "# of rx frames in this range",
2393218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L));
2394218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255",
2395218792Snp	    "# of rx frames in this range",
2396218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L));
2397218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511",
2398218792Snp	    "# of rx frames in this range",
2399218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L));
2400218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023",
2401218792Snp	    "# of rx frames in this range",
2402218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L));
2403218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518",
2404218792Snp	    "# of rx frames in this range",
2405218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L));
2406218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max",
2407218792Snp	    "# of rx frames in this range",
2408218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L));
2409218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received",
2410218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L));
2411218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received",
2412218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L));
2413218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received",
2414218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L));
2415218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received",
2416218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L));
2417218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received",
2418218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L));
2419218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received",
2420218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L));
2421218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received",
2422218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L));
2423218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received",
2424218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L));
2425218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received",
2426218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L));
2427218792Snp
2428218792Snp#undef SYSCTL_ADD_T4_REG64
2429218792Snp
2430218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \
2431218792Snp	SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \
2432218792Snp	    &pi->stats.name, desc)
2433218792Snp
2434218792Snp	/* We get these from port_stats and they may be stale by upto 1s */
2435218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0,
2436218792Snp	    "# drops due to buffer-group 0 overflows");
2437218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1,
2438218792Snp	    "# drops due to buffer-group 1 overflows");
2439218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2,
2440218792Snp	    "# drops due to buffer-group 2 overflows");
2441218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3,
2442218792Snp	    "# drops due to buffer-group 3 overflows");
2443218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc0,
2444218792Snp	    "# of buffer-group 0 truncated packets");
2445218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc1,
2446218792Snp	    "# of buffer-group 1 truncated packets");
2447218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc2,
2448218792Snp	    "# of buffer-group 2 truncated packets");
2449218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc3,
2450218792Snp	    "# of buffer-group 3 truncated packets");
2451218792Snp
2452218792Snp#undef SYSCTL_ADD_T4_PORTSTAT
2453218792Snp
2454218792Snp	return (0);
2455218792Snp}
2456218792Snp
2457218792Snpstatic int
2458218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS)
2459218792Snp{
2460218792Snp	struct port_info *pi = arg1;
2461218792Snp	struct adapter *sc = pi->adapter;
2462218792Snp	struct sge_rxq *rxq;
2463218792Snp	int idx, rc, i;
2464218792Snp
2465218792Snp	idx = pi->tmr_idx;
2466218792Snp
2467218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
2468218792Snp	if (rc != 0 || req->newptr == NULL)
2469218792Snp		return (rc);
2470218792Snp
2471218792Snp	if (idx < 0 || idx >= SGE_NTIMERS)
2472218792Snp		return (EINVAL);
2473218792Snp
2474218792Snp	ADAPTER_LOCK(sc);
2475218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
2476218792Snp	if (rc == 0) {
2477218792Snp		for_each_rxq(pi, i, rxq) {
2478218792Snp			rxq->iq.intr_params = V_QINTR_TIMER_IDX(idx) |
2479218792Snp			    V_QINTR_CNT_EN(pi->pktc_idx != -1);
2480218792Snp		}
2481218792Snp		pi->tmr_idx = idx;
2482218792Snp	}
2483218792Snp
2484218792Snp	ADAPTER_UNLOCK(sc);
2485218792Snp	return (rc);
2486218792Snp}
2487218792Snp
2488218792Snpstatic int
2489218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS)
2490218792Snp{
2491218792Snp	struct port_info *pi = arg1;
2492218792Snp	struct adapter *sc = pi->adapter;
2493218792Snp	int idx, rc;
2494218792Snp
2495218792Snp	idx = pi->pktc_idx;
2496218792Snp
2497218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
2498218792Snp	if (rc != 0 || req->newptr == NULL)
2499218792Snp		return (rc);
2500218792Snp
2501218792Snp	if (idx < -1 || idx >= SGE_NCOUNTERS)
2502218792Snp		return (EINVAL);
2503218792Snp
2504218792Snp	ADAPTER_LOCK(sc);
2505218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
2506218792Snp	if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING)
2507218792Snp		rc = EBUSY; /* can be changed only when port is down */
2508218792Snp
2509218792Snp	if (rc == 0)
2510218792Snp		pi->pktc_idx = idx;
2511218792Snp
2512218792Snp	ADAPTER_UNLOCK(sc);
2513218792Snp	return (rc);
2514218792Snp}
2515218792Snp
2516218792Snpstatic int
2517218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS)
2518218792Snp{
2519218792Snp	struct port_info *pi = arg1;
2520218792Snp	struct adapter *sc = pi->adapter;
2521218792Snp	int qsize, rc;
2522218792Snp
2523218792Snp	qsize = pi->qsize_rxq;
2524218792Snp
2525218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
2526218792Snp	if (rc != 0 || req->newptr == NULL)
2527218792Snp		return (rc);
2528218792Snp
2529218792Snp	if (qsize < 128 || (qsize & 7))
2530218792Snp		return (EINVAL);
2531218792Snp
2532218792Snp	ADAPTER_LOCK(sc);
2533218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
2534218792Snp	if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING)
2535218792Snp		rc = EBUSY; /* can be changed only when port is down */
2536218792Snp
2537218792Snp	if (rc == 0)
2538218792Snp		pi->qsize_rxq = qsize;
2539218792Snp
2540218792Snp	ADAPTER_UNLOCK(sc);
2541218792Snp	return (rc);
2542218792Snp}
2543218792Snp
2544218792Snpstatic int
2545218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS)
2546218792Snp{
2547218792Snp	struct port_info *pi = arg1;
2548218792Snp	struct adapter *sc = pi->adapter;
2549218792Snp	int qsize, rc;
2550218792Snp
2551218792Snp	qsize = pi->qsize_txq;
2552218792Snp
2553218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
2554218792Snp	if (rc != 0 || req->newptr == NULL)
2555218792Snp		return (rc);
2556218792Snp
2557218792Snp	if (qsize < 128)
2558218792Snp		return (EINVAL);
2559218792Snp
2560218792Snp	ADAPTER_LOCK(sc);
2561218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
2562218792Snp	if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING)
2563218792Snp		rc = EBUSY; /* can be changed only when port is down */
2564218792Snp
2565218792Snp	if (rc == 0)
2566218792Snp		pi->qsize_txq = qsize;
2567218792Snp
2568218792Snp	ADAPTER_UNLOCK(sc);
2569218792Snp	return (rc);
2570218792Snp}
2571218792Snp
2572218792Snpstatic int
2573218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS)
2574218792Snp{
2575218792Snp	struct adapter *sc = arg1;
2576218792Snp	int reg = arg2;
2577218792Snp	uint64_t val;
2578218792Snp
2579218792Snp	val = t4_read_reg64(sc, reg);
2580218792Snp
2581218792Snp	return (sysctl_handle_64(oidp, &val, 0, req));
2582218792Snp}
2583218792Snp
2584218792Snpint
2585218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap)
2586218792Snp{
2587218792Snp	device_t dev;
2588218792Snp	struct pci_devinfo *dinfo;
2589218792Snp	pcicfgregs *cfg;
2590218792Snp	uint32_t status;
2591218792Snp	uint8_t ptr;
2592218792Snp
2593218792Snp	dev = sc->dev;
2594218792Snp	dinfo = device_get_ivars(dev);
2595218792Snp	cfg = &dinfo->cfg;
2596218792Snp
2597218792Snp	status = pci_read_config(dev, PCIR_STATUS, 2);
2598218792Snp	if (!(status & PCIM_STATUS_CAPPRESENT))
2599218792Snp		return (0);
2600218792Snp
2601218792Snp	switch (cfg->hdrtype & PCIM_HDRTYPE) {
2602218792Snp	case 0:
2603218792Snp	case 1:
2604218792Snp		ptr = PCIR_CAP_PTR;
2605218792Snp		break;
2606218792Snp	case 2:
2607218792Snp		ptr = PCIR_CAP_PTR_2;
2608218792Snp		break;
2609218792Snp	default:
2610218792Snp		return (0);
2611218792Snp		break;
2612218792Snp	}
2613218792Snp	ptr = pci_read_config(dev, ptr, 1);
2614218792Snp
2615218792Snp	while (ptr != 0) {
2616218792Snp		if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap)
2617218792Snp			return (ptr);
2618218792Snp		ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1);
2619218792Snp	}
2620218792Snp
2621218792Snp	return (0);
2622218792Snp}
2623218792Snp
2624218792Snpint
2625218792Snpt4_os_pci_save_state(struct adapter *sc)
2626218792Snp{
2627218792Snp	device_t dev;
2628218792Snp	struct pci_devinfo *dinfo;
2629218792Snp
2630218792Snp	dev = sc->dev;
2631218792Snp	dinfo = device_get_ivars(dev);
2632218792Snp
2633218792Snp	pci_cfg_save(dev, dinfo, 0);
2634218792Snp	return (0);
2635218792Snp}
2636218792Snp
2637218792Snpint
2638218792Snpt4_os_pci_restore_state(struct adapter *sc)
2639218792Snp{
2640218792Snp	device_t dev;
2641218792Snp	struct pci_devinfo *dinfo;
2642218792Snp
2643218792Snp	dev = sc->dev;
2644218792Snp	dinfo = device_get_ivars(dev);
2645218792Snp
2646218792Snp	pci_cfg_restore(dev, dinfo);
2647218792Snp	return (0);
2648218792Snp}
2649218792Snpvoid
2650218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx)
2651218792Snp{
2652218792Snp	struct port_info *pi = sc->port[idx];
2653218792Snp	static const char *mod_str[] = {
2654218792Snp		NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX"
2655218792Snp	};
2656218792Snp
2657218792Snp	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
2658218792Snp		if_printf(pi->ifp, "transceiver unplugged.\n");
2659218792Snp	else
2660218792Snp		if_printf(pi->ifp, "%s transceiver inserted.\n",
2661218792Snp		    mod_str[pi->mod_type]);
2662218792Snp
2663218792Snp}
2664218792Snp
2665218792Snpvoid
2666218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat)
2667218792Snp{
2668218792Snp	struct port_info *pi = sc->port[idx];
2669218792Snp	struct ifnet *ifp = pi->ifp;
2670218792Snp
2671218792Snp	if (link_stat) {
2672218792Snp		ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed);
2673218792Snp		if_link_state_change(ifp, LINK_STATE_UP);
2674218792Snp	} else
2675218792Snp		if_link_state_change(ifp, LINK_STATE_DOWN);
2676218792Snp}
2677218792Snp
2678218792Snpstatic int
2679218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td)
2680218792Snp{
2681218792Snp       return (0);
2682218792Snp}
2683218792Snp
2684218792Snpstatic int
2685218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td)
2686218792Snp{
2687218792Snp       return (0);
2688218792Snp}
2689218792Snp
2690218792Snpstatic int
2691218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag,
2692218792Snp    struct thread *td)
2693218792Snp{
2694218792Snp	int rc;
2695218792Snp	struct adapter *sc = dev->si_drv1;
2696218792Snp
2697218792Snp	rc = priv_check(td, PRIV_DRIVER);
2698218792Snp	if (rc != 0)
2699218792Snp		return (rc);
2700218792Snp
2701218792Snp	switch (cmd) {
2702218792Snp	case CHELSIO_T4_GETREG32: {
2703218792Snp		struct t4_reg32 *edata = (struct t4_reg32 *)data;
2704218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2705218792Snp			return (EFAULT);
2706218792Snp		edata->val = t4_read_reg(sc, edata->addr);
2707218792Snp		break;
2708218792Snp	}
2709218792Snp	case CHELSIO_T4_SETREG32: {
2710218792Snp		struct t4_reg32 *edata = (struct t4_reg32 *)data;
2711218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2712218792Snp			return (EFAULT);
2713218792Snp		t4_write_reg(sc, edata->addr, edata->val);
2714218792Snp		break;
2715218792Snp	}
2716218792Snp	case CHELSIO_T4_REGDUMP: {
2717218792Snp		struct t4_regdump *regs = (struct t4_regdump *)data;
2718218792Snp		int reglen = T4_REGDUMP_SIZE;
2719218792Snp		uint8_t *buf;
2720218792Snp
2721218792Snp		if (regs->len < reglen) {
2722218792Snp			regs->len = reglen; /* hint to the caller */
2723218792Snp			return (ENOBUFS);
2724218792Snp		}
2725218792Snp
2726218792Snp		regs->len = reglen;
2727218792Snp		buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO);
2728218792Snp		t4_get_regs(sc, regs, buf);
2729218792Snp		rc = copyout(buf, regs->data, reglen);
2730218792Snp		free(buf, M_CXGBE);
2731218792Snp		break;
2732218792Snp	}
2733218792Snp	default:
2734218792Snp		rc = EINVAL;
2735218792Snp	}
2736218792Snp
2737218792Snp	return (rc);
2738218792Snp}
2739218792Snp
2740218792Snpstatic devclass_t t4_devclass;
2741218792Snpstatic devclass_t cxgbe_devclass;
2742218792Snp
2743218792SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, 0, 0);
2744218792SnpMODULE_VERSION(t4nex, 1);
2745218792Snp
2746218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0);
2747218792SnpMODULE_VERSION(cxgbe, 1);
2748