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: stable/10/sys/dev/cxgbe/t4_main.c 353418 2019-10-10 23:27:02Z np $");
30218792Snp
31308318Sjhb#include "opt_ddb.h"
32218792Snp#include "opt_inet.h"
33237819Snp#include "opt_inet6.h"
34218792Snp
35218792Snp#include <sys/param.h>
36218792Snp#include <sys/conf.h>
37218792Snp#include <sys/priv.h>
38218792Snp#include <sys/kernel.h>
39218792Snp#include <sys/bus.h>
40284052Snp#include <sys/systm.h>
41284052Snp#include <sys/counter.h>
42218792Snp#include <sys/module.h>
43219286Snp#include <sys/malloc.h>
44219286Snp#include <sys/queue.h>
45219286Snp#include <sys/taskqueue.h>
46218792Snp#include <sys/pciio.h>
47218792Snp#include <dev/pci/pcireg.h>
48218792Snp#include <dev/pci/pcivar.h>
49218792Snp#include <dev/pci/pci_private.h>
50218792Snp#include <sys/firmware.h>
51219436Snp#include <sys/sbuf.h>
52218792Snp#include <sys/smp.h>
53218792Snp#include <sys/socket.h>
54218792Snp#include <sys/sockio.h>
55218792Snp#include <sys/sysctl.h>
56218792Snp#include <net/ethernet.h>
57218792Snp#include <net/if.h>
58218792Snp#include <net/if_types.h>
59218792Snp#include <net/if_dl.h>
60222003Snp#include <net/if_vlan_var.h>
61308153Sjhb#ifdef RSS
62308153Sjhb#include <net/rss_config.h>
63308153Sjhb#endif
64248925Snp#if defined(__i386__) || defined(__amd64__)
65248925Snp#include <vm/vm.h>
66248925Snp#include <vm/pmap.h>
67248925Snp#endif
68308318Sjhb#ifdef DDB
69308318Sjhb#include <ddb/ddb.h>
70308318Sjhb#include <ddb/db_lex.h>
71308318Sjhb#endif
72218792Snp
73218792Snp#include "common/common.h"
74221474Snp#include "common/t4_msg.h"
75218792Snp#include "common/t4_regs.h"
76218792Snp#include "common/t4_regs_values.h"
77218792Snp#include "t4_ioctl.h"
78222509Snp#include "t4_l2t.h"
79284052Snp#include "t4_mp_ring.h"
80218792Snp
81218792Snp/* T4 bus driver interface */
82218792Snpstatic int t4_probe(device_t);
83218792Snpstatic int t4_attach(device_t);
84218792Snpstatic int t4_detach(device_t);
85218792Snpstatic device_method_t t4_methods[] = {
86218792Snp	DEVMETHOD(device_probe,		t4_probe),
87218792Snp	DEVMETHOD(device_attach,	t4_attach),
88218792Snp	DEVMETHOD(device_detach,	t4_detach),
89218792Snp
90227843Smarius	DEVMETHOD_END
91218792Snp};
92218792Snpstatic driver_t t4_driver = {
93218792Snp	"t4nex",
94218792Snp	t4_methods,
95218792Snp	sizeof(struct adapter)
96218792Snp};
97218792Snp
98218792Snp
99218792Snp/* T4 port (cxgbe) interface */
100218792Snpstatic int cxgbe_probe(device_t);
101218792Snpstatic int cxgbe_attach(device_t);
102218792Snpstatic int cxgbe_detach(device_t);
103309447Sjhbdevice_method_t cxgbe_methods[] = {
104218792Snp	DEVMETHOD(device_probe,		cxgbe_probe),
105218792Snp	DEVMETHOD(device_attach,	cxgbe_attach),
106218792Snp	DEVMETHOD(device_detach,	cxgbe_detach),
107218792Snp	{ 0, 0 }
108218792Snp};
109218792Snpstatic driver_t cxgbe_driver = {
110218792Snp	"cxgbe",
111218792Snp	cxgbe_methods,
112218792Snp	sizeof(struct port_info)
113218792Snp};
114218792Snp
115308154Sjhb/* T4 VI (vcxgbe) interface */
116308154Sjhbstatic int vcxgbe_probe(device_t);
117308154Sjhbstatic int vcxgbe_attach(device_t);
118308154Sjhbstatic int vcxgbe_detach(device_t);
119308154Sjhbstatic device_method_t vcxgbe_methods[] = {
120308154Sjhb	DEVMETHOD(device_probe,		vcxgbe_probe),
121308154Sjhb	DEVMETHOD(device_attach,	vcxgbe_attach),
122308154Sjhb	DEVMETHOD(device_detach,	vcxgbe_detach),
123308154Sjhb	{ 0, 0 }
124308154Sjhb};
125308154Sjhbstatic driver_t vcxgbe_driver = {
126308154Sjhb	"vcxgbe",
127308154Sjhb	vcxgbe_methods,
128308154Sjhb	sizeof(struct vi_info)
129308154Sjhb};
130308154Sjhb
131218792Snpstatic d_ioctl_t t4_ioctl;
132218792Snp
133218792Snpstatic struct cdevsw t4_cdevsw = {
134218792Snp       .d_version = D_VERSION,
135218792Snp       .d_ioctl = t4_ioctl,
136218792Snp       .d_name = "t4nex",
137218792Snp};
138218792Snp
139248925Snp/* T5 bus driver interface */
140248925Snpstatic int t5_probe(device_t);
141248925Snpstatic device_method_t t5_methods[] = {
142248925Snp	DEVMETHOD(device_probe,		t5_probe),
143248925Snp	DEVMETHOD(device_attach,	t4_attach),
144248925Snp	DEVMETHOD(device_detach,	t4_detach),
145248925Snp
146248925Snp	DEVMETHOD_END
147248925Snp};
148248925Snpstatic driver_t t5_driver = {
149248925Snp	"t5nex",
150248925Snp	t5_methods,
151248925Snp	sizeof(struct adapter)
152248925Snp};
153248925Snp
154248925Snp
155248925Snp/* T5 port (cxl) interface */
156248925Snpstatic driver_t cxl_driver = {
157248925Snp	"cxl",
158248925Snp	cxgbe_methods,
159248925Snp	sizeof(struct port_info)
160248925Snp};
161248925Snp
162308154Sjhb/* T5 VI (vcxl) interface */
163308154Sjhbstatic driver_t vcxl_driver = {
164308154Sjhb	"vcxl",
165308154Sjhb	vcxgbe_methods,
166308154Sjhb	sizeof(struct vi_info)
167308154Sjhb};
168308154Sjhb
169309560Sjhb/* T6 bus driver interface */
170309560Sjhbstatic int t6_probe(device_t);
171309560Sjhbstatic device_method_t t6_methods[] = {
172309560Sjhb	DEVMETHOD(device_probe,		t6_probe),
173309560Sjhb	DEVMETHOD(device_attach,	t4_attach),
174309560Sjhb	DEVMETHOD(device_detach,	t4_detach),
175309560Sjhb
176309560Sjhb	DEVMETHOD_END
177309560Sjhb};
178309560Sjhbstatic driver_t t6_driver = {
179309560Sjhb	"t6nex",
180309560Sjhb	t6_methods,
181309560Sjhb	sizeof(struct adapter)
182309560Sjhb};
183309560Sjhb
184309560Sjhb
185309560Sjhb/* T6 port (cc) interface */
186309560Sjhbstatic driver_t cc_driver = {
187309560Sjhb	"cc",
188309560Sjhb	cxgbe_methods,
189309560Sjhb	sizeof(struct port_info)
190309560Sjhb};
191309560Sjhb
192309560Sjhb/* T6 VI (vcc) interface */
193309560Sjhbstatic driver_t vcc_driver = {
194309560Sjhb	"vcc",
195309560Sjhb	vcxgbe_methods,
196309560Sjhb	sizeof(struct vi_info)
197309560Sjhb};
198309560Sjhb
199218792Snp/* ifnet + media interface */
200218792Snpstatic void cxgbe_init(void *);
201218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t);
202218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *);
203218792Snpstatic void cxgbe_qflush(struct ifnet *);
204218792Snpstatic int cxgbe_media_change(struct ifnet *);
205218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *);
206218792Snp
207248925SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4/T5 Ethernet driver and services");
208218792Snp
209237263Snp/*
210237263Snp * Correct lock order when you need to acquire multiple locks is t4_list_lock,
211237263Snp * then ADAPTER_LOCK, then t4_uld_list_lock.
212237263Snp */
213255006Snpstatic struct sx t4_list_lock;
214259241SnpSLIST_HEAD(, adapter) t4_list;
215237263Snp#ifdef TCP_OFFLOAD
216255006Snpstatic struct sx t4_uld_list_lock;
217259241SnpSLIST_HEAD(, uld_info) t4_uld_list;
218228561Snp#endif
219218792Snp
220218792Snp/*
221228561Snp * Tunables.  See tweak_tunables() too.
222248925Snp *
223248925Snp * Each tunable is set to a default value here if it's known at compile-time.
224318809Snp * Otherwise it is set to -n as an indication to tweak_tunables() that it should
225318809Snp * provide a reasonable default (upto n) when the driver is loaded.
226248925Snp *
227248925Snp * Tunables applicable to both T4 and T5 are under hw.cxgbe.  Those specific to
228248925Snp * T5 are under hw.cxl.
229218792Snp */
230218792Snp
231218792Snp/*
232228561Snp * Number of queues for tx and rx, 10G and 1G, NIC and offload.
233218792Snp */
234228561Snp#define NTXQ_10G 16
235318809Snpint t4_ntxq10g = -NTXQ_10G;
236228561SnpTUNABLE_INT("hw.cxgbe.ntxq10g", &t4_ntxq10g);
237218792Snp
238228561Snp#define NRXQ_10G 8
239318809Snpint t4_nrxq10g = -NRXQ_10G;
240228561SnpTUNABLE_INT("hw.cxgbe.nrxq10g", &t4_nrxq10g);
241218792Snp
242228561Snp#define NTXQ_1G 4
243318809Snpint t4_ntxq1g = -NTXQ_1G;
244228561SnpTUNABLE_INT("hw.cxgbe.ntxq1g", &t4_ntxq1g);
245218792Snp
246228561Snp#define NRXQ_1G 2
247318809Snpint t4_nrxq1g = -NRXQ_1G;
248228561SnpTUNABLE_INT("hw.cxgbe.nrxq1g", &t4_nrxq1g);
249218792Snp
250308154Sjhb#define NTXQ_VI 1
251318809Snpstatic int t4_ntxq_vi = -NTXQ_VI;
252308154SjhbTUNABLE_INT("hw.cxgbe.ntxq_vi", &t4_ntxq_vi);
253308154Sjhb
254308154Sjhb#define NRXQ_VI 1
255318809Snpstatic int t4_nrxq_vi = -NRXQ_VI;
256308154SjhbTUNABLE_INT("hw.cxgbe.nrxq_vi", &t4_nrxq_vi);
257308154Sjhb
258264493Sscottlstatic int t4_rsrv_noflowq = 0;
259264493SscottlTUNABLE_INT("hw.cxgbe.rsrv_noflowq", &t4_rsrv_noflowq);
260264493Sscottl
261237263Snp#ifdef TCP_OFFLOAD
262228561Snp#define NOFLDTXQ_10G 8
263318809Snpstatic int t4_nofldtxq10g = -NOFLDTXQ_10G;
264228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq10g", &t4_nofldtxq10g);
265228561Snp
266228561Snp#define NOFLDRXQ_10G 2
267318809Snpstatic int t4_nofldrxq10g = -NOFLDRXQ_10G;
268228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq10g", &t4_nofldrxq10g);
269228561Snp
270228561Snp#define NOFLDTXQ_1G 2
271318809Snpstatic int t4_nofldtxq1g = -NOFLDTXQ_1G;
272228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq1g", &t4_nofldtxq1g);
273228561Snp
274228561Snp#define NOFLDRXQ_1G 1
275318809Snpstatic int t4_nofldrxq1g = -NOFLDRXQ_1G;
276228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq1g", &t4_nofldrxq1g);
277308154Sjhb
278308154Sjhb#define NOFLDTXQ_VI 1
279318809Snpstatic int t4_nofldtxq_vi = -NOFLDTXQ_VI;
280308154SjhbTUNABLE_INT("hw.cxgbe.nofldtxq_vi", &t4_nofldtxq_vi);
281308154Sjhb
282308154Sjhb#define NOFLDRXQ_VI 1
283318809Snpstatic int t4_nofldrxq_vi = -NOFLDRXQ_VI;
284308154SjhbTUNABLE_INT("hw.cxgbe.nofldrxq_vi", &t4_nofldrxq_vi);
285228561Snp#endif
286228561Snp
287270297Snp#ifdef DEV_NETMAP
288308154Sjhb#define NNMTXQ_VI 2
289318809Snpstatic int t4_nnmtxq_vi = -NNMTXQ_VI;
290308154SjhbTUNABLE_INT("hw.cxgbe.nnmtxq_vi", &t4_nnmtxq_vi);
291270297Snp
292308154Sjhb#define NNMRXQ_VI 2
293318809Snpstatic int t4_nnmrxq_vi = -NNMRXQ_VI;
294308154SjhbTUNABLE_INT("hw.cxgbe.nnmrxq_vi", &t4_nnmrxq_vi);
295270297Snp#endif
296270297Snp
297218792Snp/*
298218792Snp * Holdoff parameters for 10G and 1G ports.
299218792Snp */
300228561Snp#define TMR_IDX_10G 1
301309447Sjhbint t4_tmr_idx_10g = TMR_IDX_10G;
302228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &t4_tmr_idx_10g);
303218792Snp
304234833Snp#define PKTC_IDX_10G (-1)
305309447Sjhbint t4_pktc_idx_10g = PKTC_IDX_10G;
306228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &t4_pktc_idx_10g);
307218792Snp
308228561Snp#define TMR_IDX_1G 1
309309447Sjhbint t4_tmr_idx_1g = TMR_IDX_1G;
310228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &t4_tmr_idx_1g);
311218792Snp
312234833Snp#define PKTC_IDX_1G (-1)
313309447Sjhbint t4_pktc_idx_1g = PKTC_IDX_1G;
314228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &t4_pktc_idx_1g);
315218792Snp
316218792Snp/*
317218792Snp * Size (# of entries) of each tx and rx queue.
318218792Snp */
319309447Sjhbunsigned int t4_qsize_txq = TX_EQ_QSIZE;
320228561SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &t4_qsize_txq);
321218792Snp
322309447Sjhbunsigned int t4_qsize_rxq = RX_IQ_QSIZE;
323228561SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &t4_qsize_rxq);
324218792Snp
325218792Snp/*
326228561Snp * Interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively).
327218792Snp */
328309447Sjhbint t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX;
329228561SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types);
330218792Snp
331218792Snp/*
332228561Snp * Configuration file.
333218792Snp */
334248925Snp#define DEFAULT_CF	"default"
335248925Snp#define FLASH_CF	"flash"
336248925Snp#define UWIRE_CF	"uwire"
337249376Snp#define FPGA_CF		"fpga"
338248925Snpstatic char t4_cfg_file[32] = DEFAULT_CF;
339228561SnpTUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file));
340218792Snp
341228561Snp/*
342271961Snp * PAUSE settings (bit 0, 1 = rx_pause, tx_pause respectively).
343271961Snp * rx_pause = 1 to heed incoming PAUSE frames, 0 to ignore them.
344271961Snp * tx_pause = 1 to emit PAUSE frames when the rx FIFO reaches its high water
345271961Snp *            mark or when signalled to do so, 0 to never emit PAUSE.
346271961Snp */
347271961Snpstatic int t4_pause_settings = PAUSE_TX | PAUSE_RX;
348271961SnpTUNABLE_INT("hw.cxgbe.pause_settings", &t4_pause_settings);
349271961Snp
350271961Snp/*
351311261Snp * Forward Error Correction settings (bit 0, 1, 2 = FEC_RS, FEC_BASER_RS,
352311261Snp * FEC_RESERVED respectively).
353311261Snp * -1 to run with the firmware default.
354311261Snp *  0 to disable FEC.
355311261Snp */
356311261Snpstatic int t4_fec = -1;
357311261SnpTUNABLE_INT("hw.cxgbe.fec", &t4_fec);
358311261Snp
359311261Snp/*
360311261Snp * Link autonegotiation.
361311261Snp * -1 to run with the firmware default.
362311261Snp *  0 to disable.
363311261Snp *  1 to enable.
364311261Snp */
365311261Snpstatic int t4_autoneg = -1;
366311261SnpTUNABLE_INT("hw.cxgbe.autoneg", &t4_autoneg);
367311261Snp
368311261Snp/*
369247347Snp * Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed,
370247347Snp * encouraged respectively).
371247347Snp */
372247347Snpstatic unsigned int t4_fw_install = 1;
373247347SnpTUNABLE_INT("hw.cxgbe.fw_install", &t4_fw_install);
374247347Snp
375247347Snp/*
376228561Snp * ASIC features that will be used.  Disable the ones you don't want so that the
377228561Snp * chip resources aren't wasted on features that will not be used.
378228561Snp */
379308304Sjhbstatic int t4_nbmcaps_allowed = 0;
380308304SjhbTUNABLE_INT("hw.cxgbe.nbmcaps_allowed", &t4_nbmcaps_allowed);
381308304Sjhb
382228561Snpstatic int t4_linkcaps_allowed = 0;	/* No DCBX, PPP, etc. by default */
383228561SnpTUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed);
384221474Snp
385308313Sjhbstatic int t4_switchcaps_allowed = FW_CAPS_CONFIG_SWITCH_INGRESS |
386308313Sjhb    FW_CAPS_CONFIG_SWITCH_EGRESS;
387308304SjhbTUNABLE_INT("hw.cxgbe.switchcaps_allowed", &t4_switchcaps_allowed);
388308304Sjhb
389228561Snpstatic int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC;
390228561SnpTUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed);
391228561Snp
392238028Snpstatic int t4_toecaps_allowed = -1;
393228561SnpTUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed);
394228561Snp
395308313Sjhbstatic int t4_rdmacaps_allowed = -1;
396228561SnpTUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed);
397228561Snp
398309560Sjhbstatic int t4_cryptocaps_allowed = 0;
399309560SjhbTUNABLE_INT("hw.cxgbe.cryptocaps_allowed", &t4_cryptocaps_allowed);
400308304Sjhb
401308313Sjhbstatic int t4_iscsicaps_allowed = -1;
402228561SnpTUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed);
403228561Snp
404228561Snpstatic int t4_fcoecaps_allowed = 0;
405228561SnpTUNABLE_INT("hw.cxgbe.fcoecaps_allowed", &t4_fcoecaps_allowed);
406228561Snp
407248925Snpstatic int t5_write_combine = 0;
408248925SnpTUNABLE_INT("hw.cxl.write_combine", &t5_write_combine);
409248925Snp
410308154Sjhbstatic int t4_num_vis = 1;
411308154SjhbTUNABLE_INT("hw.cxgbe.num_vis", &t4_num_vis);
412308154Sjhb
413308154Sjhb/* Functions used by extra VIs to obtain unique MAC addresses for each VI. */
414308154Sjhbstatic int vi_mac_funcs[] = {
415308154Sjhb	FW_VI_FUNC_OFLD,
416308154Sjhb	FW_VI_FUNC_IWARP,
417308154Sjhb	FW_VI_FUNC_OPENISCSI,
418308154Sjhb	FW_VI_FUNC_OPENFCOE,
419308154Sjhb	FW_VI_FUNC_FOISCSI,
420308154Sjhb	FW_VI_FUNC_FOFCOE,
421308154Sjhb};
422308154Sjhb
423218792Snpstruct intrs_and_queues {
424270297Snp	uint16_t intr_type;	/* INTx, MSI, or MSI-X */
425270297Snp	uint16_t nirq;		/* Total # of vectors */
426270297Snp	uint16_t intr_flags_10g;/* Interrupt flags for each 10G port */
427270297Snp	uint16_t intr_flags_1g;	/* Interrupt flags for each 1G port */
428270297Snp	uint16_t ntxq10g;	/* # of NIC txq's for each 10G port */
429270297Snp	uint16_t nrxq10g;	/* # of NIC rxq's for each 10G port */
430270297Snp	uint16_t ntxq1g;	/* # of NIC txq's for each 1G port */
431270297Snp	uint16_t nrxq1g;	/* # of NIC rxq's for each 1G port */
432270297Snp	uint16_t rsrv_noflowq;	/* Flag whether to reserve queue 0 */
433270297Snp	uint16_t nofldtxq10g;	/* # of TOE txq's for each 10G port */
434270297Snp	uint16_t nofldrxq10g;	/* # of TOE rxq's for each 10G port */
435270297Snp	uint16_t nofldtxq1g;	/* # of TOE txq's for each 1G port */
436270297Snp	uint16_t nofldrxq1g;	/* # of TOE rxq's for each 1G port */
437308154Sjhb
438308154Sjhb	/* The vcxgbe/vcxl interfaces use these and not the ones above. */
439308154Sjhb	uint16_t ntxq_vi;	/* # of NIC txq's */
440308154Sjhb	uint16_t nrxq_vi;	/* # of NIC rxq's */
441308154Sjhb	uint16_t nofldtxq_vi;	/* # of TOE txq's */
442308154Sjhb	uint16_t nofldrxq_vi;	/* # of TOE rxq's */
443308154Sjhb	uint16_t nnmtxq_vi;	/* # of netmap txq's */
444308154Sjhb	uint16_t nnmrxq_vi;	/* # of netmap rxq's */
445218792Snp};
446218792Snp
447221474Snpstruct filter_entry {
448221474Snp        uint32_t valid:1;	/* filter allocated and valid */
449221474Snp        uint32_t locked:1;	/* filter is administratively locked */
450221474Snp        uint32_t pending:1;	/* filter action is pending firmware reply */
451221474Snp	uint32_t smtidx:8;	/* Source MAC Table index for smac */
452222509Snp	struct l2t_entry *l2t;	/* Layer Two Table entry for dmac */
453221474Snp
454221474Snp        struct t4_filter_specification fs;
455221474Snp};
456221474Snp
457218792Snpstatic void setup_memwin(struct adapter *);
458308305Sjhbstatic void position_memwin(struct adapter *, int, uint32_t);
459308305Sjhbstatic int rw_via_memwin(struct adapter *, int, uint32_t, uint32_t *, int, int);
460308305Sjhbstatic inline int read_via_memwin(struct adapter *, int, uint32_t, uint32_t *,
461308305Sjhb    int);
462308305Sjhbstatic inline int write_via_memwin(struct adapter *, int, uint32_t,
463308305Sjhb    const uint32_t *, int);
464248925Snpstatic int validate_mem_range(struct adapter *, uint32_t, int);
465256791Snpstatic int fwmtype_to_hwmtype(int);
466248925Snpstatic int validate_mt_off_len(struct adapter *, int, uint32_t, int,
467248925Snp    uint32_t *);
468308305Sjhbstatic int fixup_devlog_params(struct adapter *);
469308154Sjhbstatic int cfg_itype_and_nqueues(struct adapter *, int, int, int,
470218792Snp    struct intrs_and_queues *);
471218792Snpstatic int prep_firmware(struct adapter *);
472248925Snpstatic int partition_resources(struct adapter *, const struct firmware *,
473248925Snp    const char *);
474228561Snpstatic int get_params__pre_init(struct adapter *);
475228561Snpstatic int get_params__post_init(struct adapter *);
476247291Snpstatic int set_params__post_init(struct adapter *);
477218792Snpstatic void t4_set_desc(struct adapter *);
478270297Snpstatic void build_medialist(struct port_info *, struct ifmedia *);
479353418Snpstatic void init_l1cfg(struct port_info *);
480353418Snpstatic int apply_l1cfg(struct port_info *);
481308154Sjhbstatic int cxgbe_init_synchronized(struct vi_info *);
482308154Sjhbstatic int cxgbe_uninit_synchronized(struct vi_info *);
483284052Snpstatic void quiesce_txq(struct adapter *, struct sge_txq *);
484284052Snpstatic void quiesce_wrq(struct adapter *, struct sge_wrq *);
485228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *);
486228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *);
487218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid,
488228561Snp    driver_intr_t *, void *, char *);
489218792Snpstatic int t4_free_irq(struct adapter *, struct irq *);
490308304Sjhbstatic void get_regs(struct adapter *, struct t4_regdump *, uint8_t *);
491308154Sjhbstatic void vi_refresh_stats(struct adapter *, struct vi_info *);
492282486Snpstatic void cxgbe_refresh_stats(struct adapter *, struct port_info *);
493218792Snpstatic void cxgbe_tick(void *);
494237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t);
495308154Sjhbstatic void cxgbe_sysctls(struct port_info *);
496219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS);
497228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS);
498252747Snpstatic int sysctl_btphy(SYSCTL_HANDLER_ARGS);
499264493Sscottlstatic int sysctl_noflowq(SYSCTL_HANDLER_ARGS);
500218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS);
501218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS);
502218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS);
503218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS);
504271961Snpstatic int sysctl_pause_settings(SYSCTL_HANDLER_ARGS);
505311261Snpstatic int sysctl_fec(SYSCTL_HANDLER_ARGS);
506311261Snpstatic int sysctl_autoneg(SYSCTL_HANDLER_ARGS);
507218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS);
508253890Snpstatic int sysctl_temperature(SYSCTL_HANDLER_ARGS);
509231115Snp#ifdef SBUF_DRAIN
510228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS);
511247122Snpstatic int sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS);
512247122Snpstatic int sysctl_cim_la(SYSCTL_HANDLER_ARGS);
513308304Sjhbstatic int sysctl_cim_la_t6(SYSCTL_HANDLER_ARGS);
514251213Snpstatic int sysctl_cim_ma_la(SYSCTL_HANDLER_ARGS);
515251213Snpstatic int sysctl_cim_pif_la(SYSCTL_HANDLER_ARGS);
516247122Snpstatic int sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS);
517228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS);
518228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS);
519222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS);
520228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS);
521228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS);
522228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS);
523253701Snpstatic int sysctl_linkdnrc(SYSCTL_HANDLER_ARGS);
524228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS);
525251213Snpstatic int sysctl_mps_tcam(SYSCTL_HANDLER_ARGS);
526308304Sjhbstatic int sysctl_mps_tcam_t6(SYSCTL_HANDLER_ARGS);
527228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS);
528228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS);
529228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS);
530228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS);
531228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS);
532228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS);
533308311Sjhbstatic int sysctl_tp_la_mask(SYSCTL_HANDLER_ARGS);
534251213Snpstatic int sysctl_tp_la(SYSCTL_HANDLER_ARGS);
535228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS);
536251213Snpstatic int sysctl_ulprx_la(SYSCTL_HANDLER_ARGS);
537249392Snpstatic int sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS);
538308321Sjhbstatic int sysctl_tc_params(SYSCTL_HANDLER_ARGS);
539231115Snp#endif
540308311Sjhb#ifdef TCP_OFFLOAD
541308311Sjhbstatic int sysctl_tp_tick(SYSCTL_HANDLER_ARGS);
542308311Sjhbstatic int sysctl_tp_dack_timer(SYSCTL_HANDLER_ARGS);
543308311Sjhbstatic int sysctl_tp_timer(SYSCTL_HANDLER_ARGS);
544308311Sjhb#endif
545308304Sjhbstatic uint32_t fconf_iconf_to_mode(uint32_t, uint32_t);
546221474Snpstatic uint32_t mode_to_fconf(uint32_t);
547308304Sjhbstatic uint32_t mode_to_iconf(uint32_t);
548308304Sjhbstatic int check_fspec_against_fconf_iconf(struct adapter *,
549308304Sjhb    struct t4_filter_specification *);
550221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *);
551221474Snpstatic int set_filter_mode(struct adapter *, uint32_t);
552222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t);
553221474Snpstatic int get_filter(struct adapter *, struct t4_filter *);
554221474Snpstatic int set_filter(struct adapter *, struct t4_filter *);
555221474Snpstatic int del_filter(struct adapter *, struct t4_filter *);
556222509Snpstatic void clear_filter(struct filter_entry *);
557221474Snpstatic int set_filter_wr(struct adapter *, int);
558221474Snpstatic int del_filter_wr(struct adapter *, int);
559309442Sjhbstatic int set_tcb_rpl(struct sge_iq *, const struct rss_header *,
560309442Sjhb    struct mbuf *);
561222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *);
562245274Snpstatic int load_fw(struct adapter *, struct t4_data *);
563309569Sjhbstatic int load_cfg(struct adapter *, struct t4_data *);
564248925Snpstatic int read_card_mem(struct adapter *, int, struct t4_mem_range *);
565241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *);
566237263Snp#ifdef TCP_OFFLOAD
567308154Sjhbstatic int toe_capability(struct vi_info *, int);
568228561Snp#endif
569249370Snpstatic int mod_event(module_t, int, void *);
570218792Snp
571248925Snpstruct {
572218792Snp	uint16_t device;
573218792Snp	char *desc;
574218792Snp} t4_pciids[] = {
575237587Snp	{0xa000, "Chelsio Terminator 4 FPGA"},
576237587Snp	{0x4400, "Chelsio T440-dbg"},
577237587Snp	{0x4401, "Chelsio T420-CR"},
578237587Snp	{0x4402, "Chelsio T422-CR"},
579237587Snp	{0x4403, "Chelsio T440-CR"},
580237587Snp	{0x4404, "Chelsio T420-BCH"},
581237587Snp	{0x4405, "Chelsio T440-BCH"},
582237587Snp	{0x4406, "Chelsio T440-CH"},
583237587Snp	{0x4407, "Chelsio T420-SO"},
584237587Snp	{0x4408, "Chelsio T420-CX"},
585237587Snp	{0x4409, "Chelsio T420-BT"},
586237587Snp	{0x440a, "Chelsio T404-BT"},
587244580Snp	{0x440e, "Chelsio T440-LP-CR"},
588248925Snp}, t5_pciids[] = {
589248925Snp	{0xb000, "Chelsio Terminator 5 FPGA"},
590248925Snp	{0x5400, "Chelsio T580-dbg"},
591253699Snp	{0x5401,  "Chelsio T520-CR"},		/* 2 x 10G */
592253699Snp	{0x5402,  "Chelsio T522-CR"},		/* 2 x 10G, 2 X 1G */
593253217Snp	{0x5403,  "Chelsio T540-CR"},		/* 4 x 10G */
594253699Snp	{0x5407,  "Chelsio T520-SO"},		/* 2 x 10G, nomem */
595253699Snp	{0x5409,  "Chelsio T520-BT"},		/* 2 x 10GBaseT */
596253699Snp	{0x540a,  "Chelsio T504-BT"},		/* 4 x 1G */
597253699Snp	{0x540d,  "Chelsio T580-CR"},		/* 2 x 40G */
598253699Snp	{0x540e,  "Chelsio T540-LP-CR"},	/* 4 x 10G */
599250093Snp	{0x5410,  "Chelsio T580-LP-CR"},	/* 2 x 40G */
600253699Snp	{0x5411,  "Chelsio T520-LL-CR"},	/* 2 x 10G */
601253699Snp	{0x5412,  "Chelsio T560-CR"},		/* 1 x 40G, 2 x 10G */
602253699Snp	{0x5414,  "Chelsio T580-LP-SO-CR"},	/* 2 x 40G, nomem */
603278286Sjhb	{0x5415,  "Chelsio T502-BT"},		/* 2 x 1G */
604353418Snp	{0x5418,  "Chelsio T540-BT"},		/* 4 x 10GBaseT */
605353418Snp	{0x5419,  "Chelsio T540-LP-BT"},	/* 4 x 10GBaseT */
606353418Snp	{0x541a,  "Chelsio T540-SO-BT"},	/* 4 x 10GBaseT, nomem */
607353418Snp	{0x541b,  "Chelsio T540-SO-CR"},	/* 4 x 10G, nomem */
608353418Snp
609353418Snp	/* Custom */
610353418Snp	{0x5483, "Custom T540-CR"},
611353418Snp	{0x5484, "Custom T540-BT"},
612309560Sjhb}, t6_pciids[] = {
613309560Sjhb	{0xc006, "Chelsio Terminator 6 FPGA"},	/* T6 PE10K6 FPGA (PF0) */
614318844Snp	{0x6400, "Chelsio T6-DBG-25"},		/* 2 x 10/25G, debug */
615309560Sjhb	{0x6401, "Chelsio T6225-CR"},		/* 2 x 10/25G */
616309560Sjhb	{0x6402, "Chelsio T6225-SO-CR"},	/* 2 x 10/25G, nomem */
617318844Snp	{0x6403, "Chelsio T6425-CR"},		/* 4 x 10/25G */
618318844Snp	{0x6404, "Chelsio T6425-SO-CR"},	/* 4 x 10/25G, nomem */
619318844Snp	{0x6405, "Chelsio T6225-OCP-SO"},	/* 2 x 10/25G, nomem */
620318844Snp	{0x6406, "Chelsio T62100-OCP-SO"},	/* 2 x 40/50/100G, nomem */
621309560Sjhb	{0x6407, "Chelsio T62100-LP-CR"},	/* 2 x 40/50/100G */
622309560Sjhb	{0x6408, "Chelsio T62100-SO-CR"},	/* 2 x 40/50/100G, nomem */
623318844Snp	{0x6409, "Chelsio T6210-BT"},		/* 2 x 10GBASE-T */
624309560Sjhb	{0x640d, "Chelsio T62100-CR"},		/* 2 x 40/50/100G */
625318844Snp	{0x6410, "Chelsio T6-DBG-100"},		/* 2 x 40/50/100G, debug */
626318844Snp	{0x6411, "Chelsio T6225-LL-CR"},	/* 2 x 10/25G */
627318844Snp	{0x6414, "Chelsio T61100-OCP-SO"},	/* 1 x 40/50/100G, nomem */
628318844Snp	{0x6415, "Chelsio T6201-BT"},		/* 2 x 1000BASE-T */
629318844Snp
630318844Snp	/* Custom */
631353418Snp	{0x6480, "Custom T6225-CR"},
632353418Snp	{0x6481, "Custom T62100-CR"},
633353418Snp	{0x6482, "Custom T6225-CR"},
634353418Snp	{0x6483, "Custom T62100-CR"},
635353418Snp	{0x6484, "Custom T64100-CR"},
636353418Snp	{0x6485, "Custom T6240-SO"},
637353418Snp	{0x6486, "Custom T6225-SO-CR"},
638353418Snp	{0x6487, "Custom T6225-CR"},
639218792Snp};
640218792Snp
641237263Snp#ifdef TCP_OFFLOAD
642237263Snp/*
643237263Snp * service_iq() has an iq and needs the fl.  Offset of fl from the iq should be
644237263Snp * exactly the same for both rxq and ofld_rxq.
645237263Snp */
646237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq));
647228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl));
648228561Snp#endif
649265425SnpCTASSERT(sizeof(struct cluster_metadata) <= CL_METADATA_SIZE);
650265425Snp
651218792Snpstatic int
652218792Snpt4_probe(device_t dev)
653218792Snp{
654218792Snp	int i;
655218792Snp	uint16_t v = pci_get_vendor(dev);
656218792Snp	uint16_t d = pci_get_device(dev);
657237587Snp	uint8_t f = pci_get_function(dev);
658218792Snp
659218792Snp	if (v != PCI_VENDOR_ID_CHELSIO)
660218792Snp		return (ENXIO);
661218792Snp
662237587Snp	/* Attach only to PF0 of the FPGA */
663237587Snp	if (d == 0xa000 && f != 0)
664237587Snp		return (ENXIO);
665237587Snp
666240452Snp	for (i = 0; i < nitems(t4_pciids); i++) {
667237587Snp		if (d == t4_pciids[i].device) {
668218792Snp			device_set_desc(dev, t4_pciids[i].desc);
669218792Snp			return (BUS_PROBE_DEFAULT);
670218792Snp		}
671218792Snp	}
672218792Snp
673218792Snp	return (ENXIO);
674218792Snp}
675218792Snp
676218792Snpstatic int
677248925Snpt5_probe(device_t dev)
678248925Snp{
679248925Snp	int i;
680248925Snp	uint16_t v = pci_get_vendor(dev);
681248925Snp	uint16_t d = pci_get_device(dev);
682248925Snp	uint8_t f = pci_get_function(dev);
683248925Snp
684248925Snp	if (v != PCI_VENDOR_ID_CHELSIO)
685248925Snp		return (ENXIO);
686248925Snp
687248925Snp	/* Attach only to PF0 of the FPGA */
688248925Snp	if (d == 0xb000 && f != 0)
689248925Snp		return (ENXIO);
690248925Snp
691248925Snp	for (i = 0; i < nitems(t5_pciids); i++) {
692248925Snp		if (d == t5_pciids[i].device) {
693248925Snp			device_set_desc(dev, t5_pciids[i].desc);
694248925Snp			return (BUS_PROBE_DEFAULT);
695248925Snp		}
696248925Snp	}
697248925Snp
698248925Snp	return (ENXIO);
699248925Snp}
700248925Snp
701309560Sjhbstatic int
702309560Sjhbt6_probe(device_t dev)
703309560Sjhb{
704309560Sjhb	int i;
705309560Sjhb	uint16_t v = pci_get_vendor(dev);
706309560Sjhb	uint16_t d = pci_get_device(dev);
707309560Sjhb
708309560Sjhb	if (v != PCI_VENDOR_ID_CHELSIO)
709309560Sjhb		return (ENXIO);
710309560Sjhb
711309560Sjhb	for (i = 0; i < nitems(t6_pciids); i++) {
712309560Sjhb		if (d == t6_pciids[i].device) {
713309560Sjhb			device_set_desc(dev, t6_pciids[i].desc);
714309560Sjhb			return (BUS_PROBE_DEFAULT);
715309560Sjhb		}
716309560Sjhb	}
717309560Sjhb
718309560Sjhb	return (ENXIO);
719309560Sjhb}
720309560Sjhb
721291083Sjhbstatic void
722291083Sjhbt5_attribute_workaround(device_t dev)
723291083Sjhb{
724291083Sjhb	device_t root_port;
725291083Sjhb	uint32_t v;
726291083Sjhb
727291083Sjhb	/*
728291083Sjhb	 * The T5 chips do not properly echo the No Snoop and Relaxed
729291083Sjhb	 * Ordering attributes when replying to a TLP from a Root
730291083Sjhb	 * Port.  As a workaround, find the parent Root Port and
731291083Sjhb	 * disable No Snoop and Relaxed Ordering.  Note that this
732291083Sjhb	 * affects all devices under this root port.
733291083Sjhb	 */
734291083Sjhb	root_port = pci_find_pcie_root_port(dev);
735291083Sjhb	if (root_port == NULL) {
736291083Sjhb		device_printf(dev, "Unable to find parent root port\n");
737291083Sjhb		return;
738291083Sjhb	}
739291083Sjhb
740291083Sjhb	v = pcie_adjust_config(root_port, PCIER_DEVICE_CTL,
741291083Sjhb	    PCIEM_CTL_RELAXED_ORD_ENABLE | PCIEM_CTL_NOSNOOP_ENABLE, 0, 2);
742291083Sjhb	if ((v & (PCIEM_CTL_RELAXED_ORD_ENABLE | PCIEM_CTL_NOSNOOP_ENABLE)) !=
743291083Sjhb	    0)
744291083Sjhb		device_printf(dev, "Disabled No Snoop/Relaxed Ordering on %s\n",
745291083Sjhb		    device_get_nameunit(root_port));
746291083Sjhb}
747291083Sjhb
748309560Sjhbstatic const struct devnames devnames[] = {
749309560Sjhb	{
750309560Sjhb		.nexus_name = "t4nex",
751309560Sjhb		.ifnet_name = "cxgbe",
752309560Sjhb		.vi_ifnet_name = "vcxgbe",
753309560Sjhb		.pf03_drv_name = "t4iov",
754309560Sjhb		.vf_nexus_name = "t4vf",
755309560Sjhb		.vf_ifnet_name = "cxgbev"
756309560Sjhb	}, {
757309560Sjhb		.nexus_name = "t5nex",
758309560Sjhb		.ifnet_name = "cxl",
759309560Sjhb		.vi_ifnet_name = "vcxl",
760309560Sjhb		.pf03_drv_name = "t5iov",
761309560Sjhb		.vf_nexus_name = "t5vf",
762309560Sjhb		.vf_ifnet_name = "cxlv"
763309560Sjhb	}, {
764309560Sjhb		.nexus_name = "t6nex",
765309560Sjhb		.ifnet_name = "cc",
766309560Sjhb		.vi_ifnet_name = "vcc",
767309560Sjhb		.pf03_drv_name = "t6iov",
768309560Sjhb		.vf_nexus_name = "t6vf",
769309560Sjhb		.vf_ifnet_name = "ccv"
770309560Sjhb	}
771309560Sjhb};
772309560Sjhb
773309560Sjhbvoid
774309560Sjhbt4_init_devnames(struct adapter *sc)
775309560Sjhb{
776309560Sjhb	int id;
777309560Sjhb
778309560Sjhb	id = chip_id(sc);
779309560Sjhb	if (id >= CHELSIO_T4 && id - CHELSIO_T4 < nitems(devnames))
780309560Sjhb		sc->names = &devnames[id - CHELSIO_T4];
781309560Sjhb	else {
782309560Sjhb		device_printf(sc->dev, "chip id %d is not supported.\n", id);
783309560Sjhb		sc->names = NULL;
784309560Sjhb	}
785309560Sjhb}
786309560Sjhb
787248925Snpstatic int
788218792Snpt4_attach(device_t dev)
789218792Snp{
790218792Snp	struct adapter *sc;
791308154Sjhb	int rc = 0, i, j, n10g, n1g, rqidx, tqidx;
792309447Sjhb	struct make_dev_args mda;
793218792Snp	struct intrs_and_queues iaq;
794218792Snp	struct sge *s;
795308304Sjhb	uint8_t *buf;
796237263Snp#ifdef TCP_OFFLOAD
797228561Snp	int ofld_rqidx, ofld_tqidx;
798228561Snp#endif
799270297Snp#ifdef DEV_NETMAP
800270297Snp	int nm_rqidx, nm_tqidx;
801270297Snp#endif
802308154Sjhb	int num_vis;
803218792Snp
804218792Snp	sc = device_get_softc(dev);
805218792Snp	sc->dev = dev;
806309458Sjhb	TUNABLE_INT_FETCH("hw.cxgbe.dflags", &sc->debug_flags);
807218792Snp
808291083Sjhb	if ((pci_get_device(dev) & 0xff00) == 0x5400)
809291083Sjhb		t5_attribute_workaround(dev);
810218792Snp	pci_enable_busmaster(dev);
811222085Snp	if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) {
812228561Snp		uint32_t v;
813228561Snp
814222085Snp		pci_set_max_read_req(dev, 4096);
815240680Sgavin		v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2);
816240680Sgavin		v |= PCIEM_CTL_RELAXED_ORD_ENABLE;
817240680Sgavin		pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2);
818275092Snp
819275092Snp		sc->params.pci.mps = 128 << ((v & PCIEM_CTL_MAX_PAYLOAD) >> 5);
820222085Snp	}
821222085Snp
822309447Sjhb	sc->sge_gts_reg = MYPF_REG(A_SGE_PF_GTS);
823309447Sjhb	sc->sge_kdoorbell_reg = MYPF_REG(A_SGE_PF_KDOORBELL);
824253691Snp	sc->traceq = -1;
825253691Snp	mtx_init(&sc->ifp_lock, sc->ifp_lockname, 0, MTX_DEF);
826253691Snp	snprintf(sc->ifp_lockname, sizeof(sc->ifp_lockname), "%s tracer",
827253691Snp	    device_get_nameunit(dev));
828253691Snp
829218792Snp	snprintf(sc->lockname, sizeof(sc->lockname), "%s",
830218792Snp	    device_get_nameunit(dev));
831218792Snp	mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF);
832309447Sjhb	t4_add_adapter(sc);
833218792Snp
834228561Snp	mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF);
835228561Snp	TAILQ_INIT(&sc->sfl);
836308154Sjhb	callout_init_mtx(&sc->sfl_callout, &sc->sfl_lock, 0);
837228561Snp
838308305Sjhb	mtx_init(&sc->reg_lock, "indirect register access", 0, MTX_DEF);
839282486Snp
840309447Sjhb	rc = t4_map_bars_0_and_4(sc);
841218792Snp	if (rc != 0)
842218792Snp		goto done; /* error message displayed already */
843218792Snp
844218792Snp	memset(sc->chan_map, 0xff, sizeof(sc->chan_map));
845218792Snp
846308304Sjhb	/* Prepare the adapter for operation. */
847308304Sjhb	buf = malloc(PAGE_SIZE, M_CXGBE, M_ZERO | M_WAITOK);
848308304Sjhb	rc = -t4_prep_adapter(sc, buf);
849308304Sjhb	free(buf, M_CXGBE);
850218792Snp	if (rc != 0) {
851218792Snp		device_printf(dev, "failed to prepare adapter: %d.\n", rc);
852218792Snp		goto done;
853218792Snp	}
854218792Snp
855228561Snp	/*
856309560Sjhb	 * This is the real PF# to which we're attaching.  Works from within PCI
857309560Sjhb	 * passthrough environments too, where pci_get_function() could return a
858309560Sjhb	 * different PF# depending on the passthrough configuration.  We need to
859309560Sjhb	 * use the real PF# in all our communication with the firmware.
860309560Sjhb	 */
861309560Sjhb	j = t4_read_reg(sc, A_PL_WHOAMI);
862309560Sjhb	sc->pf = chip_id(sc) <= CHELSIO_T5 ? G_SOURCEPF(j) : G_T6_SOURCEPF(j);
863309560Sjhb	sc->mbox = sc->pf;
864309560Sjhb
865309560Sjhb	t4_init_devnames(sc);
866309560Sjhb	if (sc->names == NULL) {
867309560Sjhb		rc = ENOTSUP;
868309560Sjhb		goto done; /* error message displayed already */
869309560Sjhb	}
870309560Sjhb
871309560Sjhb	/*
872228561Snp	 * Do this really early, with the memory windows set up even before the
873228561Snp	 * character device.  The userland tool's register i/o and mem read
874228561Snp	 * will work even in "recovery mode".
875228561Snp	 */
876228561Snp	setup_memwin(sc);
877308305Sjhb	if (t4_init_devlog_params(sc, 0) == 0)
878308305Sjhb		fixup_devlog_params(sc);
879309447Sjhb	make_dev_args_init(&mda);
880309447Sjhb	mda.mda_devsw = &t4_cdevsw;
881309447Sjhb	mda.mda_uid = UID_ROOT;
882309447Sjhb	mda.mda_gid = GID_WHEEL;
883309447Sjhb	mda.mda_mode = 0600;
884309447Sjhb	mda.mda_si_drv1 = sc;
885309447Sjhb	rc = make_dev_s(&mda, &sc->cdev, "%s", device_get_nameunit(dev));
886309447Sjhb	if (rc != 0)
887309447Sjhb		device_printf(dev, "failed to create nexus char device: %d.\n",
888309447Sjhb		    rc);
889218792Snp
890228561Snp	/* Go no further if recovery mode has been requested. */
891228561Snp	if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) {
892228561Snp		device_printf(dev, "recovery mode.\n");
893228561Snp		goto done;
894228561Snp	}
895228561Snp
896284052Snp#if defined(__i386__)
897284052Snp	if ((cpu_feature & CPUID_CX8) == 0) {
898284052Snp		device_printf(dev, "64 bit atomics not available.\n");
899284052Snp		rc = ENOTSUP;
900284052Snp		goto done;
901284052Snp	}
902284052Snp#endif
903284052Snp
904218792Snp	/* Prepare the firmware for operation */
905218792Snp	rc = prep_firmware(sc);
906218792Snp	if (rc != 0)
907218792Snp		goto done; /* error message displayed already */
908218792Snp
909248925Snp	rc = get_params__post_init(sc);
910228561Snp	if (rc != 0)
911228561Snp		goto done; /* error message displayed already */
912222551Snp
913248925Snp	rc = set_params__post_init(sc);
914228561Snp	if (rc != 0)
915228561Snp		goto done; /* error message displayed already */
916218792Snp
917309447Sjhb	rc = t4_map_bar_2(sc);
918228561Snp	if (rc != 0)
919228561Snp		goto done; /* error message displayed already */
920218792Snp
921218792Snp	rc = t4_create_dma_tag(sc);
922218792Snp	if (rc != 0)
923218792Snp		goto done; /* error message displayed already */
924218792Snp
925218792Snp	/*
926308154Sjhb	 * Number of VIs to create per-port.  The first VI is the "main" regular
927308154Sjhb	 * VI for the port.  The rest are additional virtual interfaces on the
928308154Sjhb	 * same physical port.  Note that the main VI does not have native
929308154Sjhb	 * netmap support but the extra VIs do.
930308154Sjhb	 *
931308154Sjhb	 * Limit the number of VIs per port to the number of available
932308154Sjhb	 * MAC addresses per port.
933308154Sjhb	 */
934308154Sjhb	if (t4_num_vis >= 1)
935308154Sjhb		num_vis = t4_num_vis;
936308154Sjhb	else
937308154Sjhb		num_vis = 1;
938308154Sjhb	if (num_vis > nitems(vi_mac_funcs)) {
939308154Sjhb		num_vis = nitems(vi_mac_funcs);
940308154Sjhb		device_printf(dev, "Number of VIs limited to %d\n", num_vis);
941308154Sjhb	}
942308154Sjhb
943308154Sjhb	/*
944218792Snp	 * First pass over all the ports - allocate VIs and initialize some
945218792Snp	 * basic parameters like mac address, port type, etc.  We also figure
946218792Snp	 * out whether a port is 10G or 1G and use that information when
947218792Snp	 * calculating how many interrupts to attempt to allocate.
948218792Snp	 */
949218792Snp	n10g = n1g = 0;
950218792Snp	for_each_port(sc, i) {
951218792Snp		struct port_info *pi;
952218792Snp
953218792Snp		pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK);
954218792Snp		sc->port[i] = pi;
955218792Snp
956218792Snp		/* These must be set before t4_port_init */
957218792Snp		pi->adapter = sc;
958218792Snp		pi->port_id = i;
959308154Sjhb		/*
960308154Sjhb		 * XXX: vi[0] is special so we can't delay this allocation until
961308154Sjhb		 * pi->nvi's final value is known.
962308154Sjhb		 */
963308154Sjhb		pi->vi = malloc(sizeof(struct vi_info) * num_vis, M_CXGBE,
964308154Sjhb		    M_ZERO | M_WAITOK);
965218792Snp
966308154Sjhb		/*
967308154Sjhb		 * Allocate the "main" VI and initialize parameters
968308154Sjhb		 * like mac addr.
969308154Sjhb		 */
970308304Sjhb		rc = -t4_port_init(sc, sc->mbox, sc->pf, 0, i);
971218792Snp		if (rc != 0) {
972218792Snp			device_printf(dev, "unable to initialize port %d: %d\n",
973218792Snp			    i, rc);
974308154Sjhb			free(pi->vi, M_CXGBE);
975218792Snp			free(pi, M_CXGBE);
976222510Snp			sc->port[i] = NULL;
977222510Snp			goto done;
978218792Snp		}
979271961Snp
980218792Snp		snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d",
981218792Snp		    device_get_nameunit(dev), i);
982218792Snp		mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
983253691Snp		sc->chan_map[pi->tx_chan] = i;
984218792Snp
985309560Sjhb		if (port_top_speed(pi) >= 10) {
986218792Snp			n10g++;
987218792Snp		} else {
988218792Snp			n1g++;
989218792Snp		}
990218792Snp
991353418Snp		/* All VIs on this port share this media. */
992353418Snp		ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change,
993353418Snp		    cxgbe_media_status);
994353418Snp
995309560Sjhb		pi->dev = device_add_child(dev, sc->names->ifnet_name, -1);
996218792Snp		if (pi->dev == NULL) {
997218792Snp			device_printf(dev,
998218792Snp			    "failed to add device for port %d.\n", i);
999218792Snp			rc = ENXIO;
1000218792Snp			goto done;
1001218792Snp		}
1002308154Sjhb		pi->vi[0].dev = pi->dev;
1003218792Snp		device_set_softc(pi->dev, pi);
1004218792Snp	}
1005218792Snp
1006218792Snp	/*
1007218792Snp	 * Interrupt type, # of interrupts, # of rx/tx queues, etc.
1008218792Snp	 */
1009308154Sjhb	rc = cfg_itype_and_nqueues(sc, n10g, n1g, num_vis, &iaq);
1010218792Snp	if (rc != 0)
1011218792Snp		goto done; /* error message displayed already */
1012308154Sjhb	if (iaq.nrxq_vi + iaq.nofldrxq_vi + iaq.nnmrxq_vi == 0)
1013308154Sjhb		num_vis = 1;
1014218792Snp
1015218792Snp	sc->intr_type = iaq.intr_type;
1016218792Snp	sc->intr_count = iaq.nirq;
1017218792Snp
1018218792Snp	s = &sc->sge;
1019218792Snp	s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g;
1020218792Snp	s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g;
1021308154Sjhb	if (num_vis > 1) {
1022308154Sjhb		s->nrxq += (n10g + n1g) * (num_vis - 1) * iaq.nrxq_vi;
1023308154Sjhb		s->ntxq += (n10g + n1g) * (num_vis - 1) * iaq.ntxq_vi;
1024308154Sjhb	}
1025220873Snp	s->neq = s->ntxq + s->nrxq;	/* the free list in an rxq is an eq */
1026228561Snp	s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */
1027218792Snp	s->niq = s->nrxq + 1;		/* 1 extra for firmware event queue */
1028237263Snp#ifdef TCP_OFFLOAD
1029228561Snp	if (is_offload(sc)) {
1030228561Snp		s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g;
1031228561Snp		s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g;
1032308154Sjhb		if (num_vis > 1) {
1033308154Sjhb			s->nofldrxq += (n10g + n1g) * (num_vis - 1) *
1034308154Sjhb			    iaq.nofldrxq_vi;
1035308154Sjhb			s->nofldtxq += (n10g + n1g) * (num_vis - 1) *
1036308154Sjhb			    iaq.nofldtxq_vi;
1037308154Sjhb		}
1038228561Snp		s->neq += s->nofldtxq + s->nofldrxq;
1039228561Snp		s->niq += s->nofldrxq;
1040228561Snp
1041228561Snp		s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq),
1042228561Snp		    M_CXGBE, M_ZERO | M_WAITOK);
1043228561Snp		s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq),
1044228561Snp		    M_CXGBE, M_ZERO | M_WAITOK);
1045228561Snp	}
1046228561Snp#endif
1047270297Snp#ifdef DEV_NETMAP
1048308154Sjhb	if (num_vis > 1) {
1049308154Sjhb		s->nnmrxq = (n10g + n1g) * (num_vis - 1) * iaq.nnmrxq_vi;
1050308154Sjhb		s->nnmtxq = (n10g + n1g) * (num_vis - 1) * iaq.nnmtxq_vi;
1051308154Sjhb	}
1052270297Snp	s->neq += s->nnmtxq + s->nnmrxq;
1053270297Snp	s->niq += s->nnmrxq;
1054228561Snp
1055270297Snp	s->nm_rxq = malloc(s->nnmrxq * sizeof(struct sge_nm_rxq),
1056270297Snp	    M_CXGBE, M_ZERO | M_WAITOK);
1057270297Snp	s->nm_txq = malloc(s->nnmtxq * sizeof(struct sge_nm_txq),
1058270297Snp	    M_CXGBE, M_ZERO | M_WAITOK);
1059270297Snp#endif
1060270297Snp
1061228561Snp	s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE,
1062220873Snp	    M_ZERO | M_WAITOK);
1063218792Snp	s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE,
1064218792Snp	    M_ZERO | M_WAITOK);
1065218792Snp	s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE,
1066218792Snp	    M_ZERO | M_WAITOK);
1067218792Snp	s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE,
1068218792Snp	    M_ZERO | M_WAITOK);
1069218792Snp	s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE,
1070218792Snp	    M_ZERO | M_WAITOK);
1071218792Snp
1072218792Snp	sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE,
1073218792Snp	    M_ZERO | M_WAITOK);
1074218792Snp
1075228561Snp	t4_init_l2t(sc, M_WAITOK);
1076318851Snp	t4_init_tx_sched(sc);
1077222509Snp
1078218792Snp	/*
1079218792Snp	 * Second pass over the ports.  This time we know the number of rx and
1080218792Snp	 * tx queues that each port should get.
1081218792Snp	 */
1082218792Snp	rqidx = tqidx = 0;
1083237263Snp#ifdef TCP_OFFLOAD
1084228561Snp	ofld_rqidx = ofld_tqidx = 0;
1085228561Snp#endif
1086270297Snp#ifdef DEV_NETMAP
1087270297Snp	nm_rqidx = nm_tqidx = 0;
1088270297Snp#endif
1089218792Snp	for_each_port(sc, i) {
1090218792Snp		struct port_info *pi = sc->port[i];
1091308154Sjhb		struct vi_info *vi;
1092218792Snp
1093218792Snp		if (pi == NULL)
1094218792Snp			continue;
1095218792Snp
1096308154Sjhb		pi->nvi = num_vis;
1097308154Sjhb		for_each_vi(pi, j, vi) {
1098308154Sjhb			vi->pi = pi;
1099308154Sjhb			vi->qsize_rxq = t4_qsize_rxq;
1100308154Sjhb			vi->qsize_txq = t4_qsize_txq;
1101218792Snp
1102308154Sjhb			vi->first_rxq = rqidx;
1103308154Sjhb			vi->first_txq = tqidx;
1104309560Sjhb			if (port_top_speed(pi) >= 10) {
1105308154Sjhb				vi->tmr_idx = t4_tmr_idx_10g;
1106308154Sjhb				vi->pktc_idx = t4_pktc_idx_10g;
1107308154Sjhb				vi->flags |= iaq.intr_flags_10g & INTR_RXQ;
1108308154Sjhb				vi->nrxq = j == 0 ? iaq.nrxq10g : iaq.nrxq_vi;
1109308154Sjhb				vi->ntxq = j == 0 ? iaq.ntxq10g : iaq.ntxq_vi;
1110308154Sjhb			} else {
1111308154Sjhb				vi->tmr_idx = t4_tmr_idx_1g;
1112308154Sjhb				vi->pktc_idx = t4_pktc_idx_1g;
1113308154Sjhb				vi->flags |= iaq.intr_flags_1g & INTR_RXQ;
1114308154Sjhb				vi->nrxq = j == 0 ? iaq.nrxq1g : iaq.nrxq_vi;
1115308154Sjhb				vi->ntxq = j == 0 ? iaq.ntxq1g : iaq.ntxq_vi;
1116308154Sjhb			}
1117308154Sjhb			rqidx += vi->nrxq;
1118308154Sjhb			tqidx += vi->ntxq;
1119264493Sscottl
1120308154Sjhb			if (j == 0 && vi->ntxq > 1)
1121308154Sjhb				vi->rsrv_noflowq = iaq.rsrv_noflowq ? 1 : 0;
1122308154Sjhb			else
1123308154Sjhb				vi->rsrv_noflowq = 0;
1124308154Sjhb
1125237263Snp#ifdef TCP_OFFLOAD
1126308154Sjhb			vi->first_ofld_rxq = ofld_rqidx;
1127308154Sjhb			vi->first_ofld_txq = ofld_tqidx;
1128309560Sjhb			if (port_top_speed(pi) >= 10) {
1129308154Sjhb				vi->flags |= iaq.intr_flags_10g & INTR_OFLD_RXQ;
1130308154Sjhb				vi->nofldrxq = j == 0 ? iaq.nofldrxq10g :
1131308154Sjhb				    iaq.nofldrxq_vi;
1132308154Sjhb				vi->nofldtxq = j == 0 ? iaq.nofldtxq10g :
1133308154Sjhb				    iaq.nofldtxq_vi;
1134228561Snp			} else {
1135308154Sjhb				vi->flags |= iaq.intr_flags_1g & INTR_OFLD_RXQ;
1136308154Sjhb				vi->nofldrxq = j == 0 ? iaq.nofldrxq1g :
1137308154Sjhb				    iaq.nofldrxq_vi;
1138308154Sjhb				vi->nofldtxq = j == 0 ? iaq.nofldtxq1g :
1139308154Sjhb				    iaq.nofldtxq_vi;
1140228561Snp			}
1141308154Sjhb			ofld_rqidx += vi->nofldrxq;
1142308154Sjhb			ofld_tqidx += vi->nofldtxq;
1143228561Snp#endif
1144270297Snp#ifdef DEV_NETMAP
1145308154Sjhb			if (j > 0) {
1146308154Sjhb				vi->first_nm_rxq = nm_rqidx;
1147308154Sjhb				vi->first_nm_txq = nm_tqidx;
1148308154Sjhb				vi->nnmrxq = iaq.nnmrxq_vi;
1149308154Sjhb				vi->nnmtxq = iaq.nnmtxq_vi;
1150308154Sjhb				nm_rqidx += vi->nnmrxq;
1151308154Sjhb				nm_tqidx += vi->nnmtxq;
1152308154Sjhb			}
1153308154Sjhb#endif
1154270297Snp		}
1155218792Snp	}
1156218792Snp
1157309447Sjhb	rc = t4_setup_intr_handlers(sc);
1158240453Snp	if (rc != 0) {
1159240453Snp		device_printf(dev,
1160240453Snp		    "failed to setup interrupt handlers: %d\n", rc);
1161240453Snp		goto done;
1162240453Snp	}
1163240453Snp
1164331647Sjhb	rc = bus_generic_probe(dev);
1165331647Sjhb	if (rc != 0) {
1166331647Sjhb		device_printf(dev, "failed to probe child drivers: %d\n", rc);
1167331647Sjhb		goto done;
1168331647Sjhb	}
1169331647Sjhb
1170218792Snp	rc = bus_generic_attach(dev);
1171218792Snp	if (rc != 0) {
1172218792Snp		device_printf(dev,
1173218792Snp		    "failed to attach all child ports: %d\n", rc);
1174218792Snp		goto done;
1175218792Snp	}
1176218792Snp
1177218792Snp	device_printf(dev,
1178284098Snp	    "PCIe gen%d x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n",
1179284098Snp	    sc->params.pci.speed, sc->params.pci.width, sc->params.nports,
1180284098Snp	    sc->intr_count, sc->intr_type == INTR_MSIX ? "MSI-X" :
1181228561Snp	    (sc->intr_type == INTR_MSI ? "MSI" : "INTx"),
1182228561Snp	    sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq);
1183228561Snp
1184218792Snp	t4_set_desc(sc);
1185218792Snp
1186218792Snpdone:
1187228561Snp	if (rc != 0 && sc->cdev) {
1188228561Snp		/* cdev was created and so cxgbetool works; recover that way. */
1189228561Snp		device_printf(dev,
1190228561Snp		    "error during attach, adapter is now in recovery mode.\n");
1191228561Snp		rc = 0;
1192228561Snp	}
1193228561Snp
1194218792Snp	if (rc != 0)
1195309447Sjhb		t4_detach_common(dev);
1196228561Snp	else
1197228561Snp		t4_sysctls(sc);
1198218792Snp
1199218792Snp	return (rc);
1200218792Snp}
1201218792Snp
1202218792Snp/*
1203218792Snp * Idempotent
1204218792Snp */
1205218792Snpstatic int
1206218792Snpt4_detach(device_t dev)
1207218792Snp{
1208218792Snp	struct adapter *sc;
1209309447Sjhb
1210309447Sjhb	sc = device_get_softc(dev);
1211309447Sjhb
1212309447Sjhb	return (t4_detach_common(dev));
1213309447Sjhb}
1214309447Sjhb
1215309447Sjhbint
1216309447Sjhbt4_detach_common(device_t dev)
1217309447Sjhb{
1218309447Sjhb	struct adapter *sc;
1219218792Snp	struct port_info *pi;
1220228561Snp	int i, rc;
1221218792Snp
1222218792Snp	sc = device_get_softc(dev);
1223218792Snp
1224309447Sjhb	if (sc->flags & FULL_INIT_DONE) {
1225309447Sjhb		if (!(sc->flags & IS_VF))
1226309447Sjhb			t4_intr_disable(sc);
1227309447Sjhb	}
1228228561Snp
1229228561Snp	if (sc->cdev) {
1230218792Snp		destroy_dev(sc->cdev);
1231228561Snp		sc->cdev = NULL;
1232228561Snp	}
1233218792Snp
1234309447Sjhb	if (device_is_attached(dev)) {
1235309447Sjhb		rc = bus_generic_detach(dev);
1236309447Sjhb		if (rc) {
1237309447Sjhb			device_printf(dev,
1238309447Sjhb			    "failed to detach child devices: %d\n", rc);
1239309447Sjhb			return (rc);
1240309447Sjhb		}
1241228561Snp	}
1242228561Snp
1243240453Snp	for (i = 0; i < sc->intr_count; i++)
1244240453Snp		t4_free_irq(sc, &sc->irq[i]);
1245240453Snp
1246318851Snp	if ((sc->flags & (IS_VF | FW_OK)) == FW_OK)
1247318851Snp		t4_free_tx_sched(sc);
1248318851Snp
1249218792Snp	for (i = 0; i < MAX_NPORTS; i++) {
1250218792Snp		pi = sc->port[i];
1251218792Snp		if (pi) {
1252308154Sjhb			t4_free_vi(sc, sc->mbox, sc->pf, 0, pi->vi[0].viid);
1253218792Snp			if (pi->dev)
1254218792Snp				device_delete_child(dev, pi->dev);
1255218792Snp
1256218792Snp			mtx_destroy(&pi->pi_lock);
1257308154Sjhb			free(pi->vi, M_CXGBE);
1258218792Snp			free(pi, M_CXGBE);
1259218792Snp		}
1260218792Snp	}
1261218792Snp
1262331647Sjhb	device_delete_children(dev);
1263331647Sjhb
1264228561Snp	if (sc->flags & FULL_INIT_DONE)
1265228561Snp		adapter_full_uninit(sc);
1266228561Snp
1267309447Sjhb	if ((sc->flags & (IS_VF | FW_OK)) == FW_OK)
1268218792Snp		t4_fw_bye(sc, sc->mbox);
1269218792Snp
1270219944Snp	if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX)
1271218792Snp		pci_release_msi(dev);
1272218792Snp
1273218792Snp	if (sc->regs_res)
1274218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid,
1275218792Snp		    sc->regs_res);
1276218792Snp
1277248925Snp	if (sc->udbs_res)
1278248925Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->udbs_rid,
1279248925Snp		    sc->udbs_res);
1280248925Snp
1281218792Snp	if (sc->msix_res)
1282218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid,
1283218792Snp		    sc->msix_res);
1284218792Snp
1285222509Snp	if (sc->l2t)
1286222509Snp		t4_free_l2t(sc->l2t);
1287222509Snp
1288237263Snp#ifdef TCP_OFFLOAD
1289228561Snp	free(sc->sge.ofld_rxq, M_CXGBE);
1290228561Snp	free(sc->sge.ofld_txq, M_CXGBE);
1291228561Snp#endif
1292270297Snp#ifdef DEV_NETMAP
1293270297Snp	free(sc->sge.nm_rxq, M_CXGBE);
1294270297Snp	free(sc->sge.nm_txq, M_CXGBE);
1295270297Snp#endif
1296218792Snp	free(sc->irq, M_CXGBE);
1297218792Snp	free(sc->sge.rxq, M_CXGBE);
1298218792Snp	free(sc->sge.txq, M_CXGBE);
1299220873Snp	free(sc->sge.ctrlq, M_CXGBE);
1300218792Snp	free(sc->sge.iqmap, M_CXGBE);
1301218792Snp	free(sc->sge.eqmap, M_CXGBE);
1302221474Snp	free(sc->tids.ftid_tab, M_CXGBE);
1303218792Snp	t4_destroy_dma_tag(sc);
1304228561Snp	if (mtx_initialized(&sc->sc_lock)) {
1305255006Snp		sx_xlock(&t4_list_lock);
1306228561Snp		SLIST_REMOVE(&t4_list, sc, adapter, link);
1307255006Snp		sx_xunlock(&t4_list_lock);
1308228561Snp		mtx_destroy(&sc->sc_lock);
1309228561Snp	}
1310218792Snp
1311308154Sjhb	callout_drain(&sc->sfl_callout);
1312245274Snp	if (mtx_initialized(&sc->tids.ftid_lock))
1313245274Snp		mtx_destroy(&sc->tids.ftid_lock);
1314228561Snp	if (mtx_initialized(&sc->sfl_lock))
1315228561Snp		mtx_destroy(&sc->sfl_lock);
1316253691Snp	if (mtx_initialized(&sc->ifp_lock))
1317253691Snp		mtx_destroy(&sc->ifp_lock);
1318308305Sjhb	if (mtx_initialized(&sc->reg_lock))
1319308305Sjhb		mtx_destroy(&sc->reg_lock);
1320228561Snp
1321308305Sjhb	for (i = 0; i < NUM_MEMWIN; i++) {
1322308305Sjhb		struct memwin *mw = &sc->memwin[i];
1323308305Sjhb
1324308305Sjhb		if (rw_initialized(&mw->mw_lock))
1325308305Sjhb			rw_destroy(&mw->mw_lock);
1326308305Sjhb	}
1327308305Sjhb
1328218792Snp	bzero(sc, sizeof(*sc));
1329218792Snp
1330218792Snp	return (0);
1331218792Snp}
1332218792Snp
1333218792Snpstatic int
1334218792Snpcxgbe_probe(device_t dev)
1335218792Snp{
1336218792Snp	char buf[128];
1337218792Snp	struct port_info *pi = device_get_softc(dev);
1338218792Snp
1339228561Snp	snprintf(buf, sizeof(buf), "port %d", pi->port_id);
1340218792Snp	device_set_desc_copy(dev, buf);
1341218792Snp
1342218792Snp	return (BUS_PROBE_DEFAULT);
1343218792Snp}
1344218792Snp
1345218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \
1346218792Snp    IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \
1347256218Sglebius    IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6 | IFCAP_HWSTATS)
1348237819Snp#define T4_CAP_ENABLE (T4_CAP)
1349218792Snp
1350218792Snpstatic int
1351308154Sjhbcxgbe_vi_attach(device_t dev, struct vi_info *vi)
1352218792Snp{
1353218792Snp	struct ifnet *ifp;
1354308154Sjhb	struct sbuf *sb;
1355218792Snp
1356308154Sjhb	vi->xact_addr_filt = -1;
1357308154Sjhb	callout_init(&vi->tick, 1);
1358308154Sjhb
1359218792Snp	/* Allocate an ifnet and set it up */
1360218792Snp	ifp = if_alloc(IFT_ETHER);
1361218792Snp	if (ifp == NULL) {
1362218792Snp		device_printf(dev, "Cannot allocate ifnet\n");
1363218792Snp		return (ENOMEM);
1364218792Snp	}
1365308154Sjhb	vi->ifp = ifp;
1366308154Sjhb	ifp->if_softc = vi;
1367218792Snp
1368218792Snp	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1369218792Snp	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1370218792Snp
1371218792Snp	ifp->if_init = cxgbe_init;
1372218792Snp	ifp->if_ioctl = cxgbe_ioctl;
1373218792Snp	ifp->if_transmit = cxgbe_transmit;
1374218792Snp	ifp->if_qflush = cxgbe_qflush;
1375218792Snp
1376218792Snp	ifp->if_capabilities = T4_CAP;
1377237263Snp#ifdef TCP_OFFLOAD
1378308154Sjhb	if (vi->nofldrxq != 0)
1379245933Snp		ifp->if_capabilities |= IFCAP_TOE;
1380228561Snp#endif
1381318826Snp#ifdef DEV_NETMAP
1382318826Snp	if (vi->nnmrxq != 0)
1383318826Snp		ifp->if_capabilities |= IFCAP_NETMAP;
1384318826Snp#endif
1385218792Snp	ifp->if_capenable = T4_CAP_ENABLE;
1386237799Snp	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO |
1387237799Snp	    CSUM_UDP_IPV6 | CSUM_TCP_IPV6;
1388218792Snp
1389274440Snp	ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
1390274440Snp	ifp->if_hw_tsomaxsegcount = TX_SGL_SEGS;
1391274440Snp	ifp->if_hw_tsomaxsegsize = 65536;
1392274440Snp
1393308154Sjhb	vi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp,
1394237263Snp	    EVENTHANDLER_PRI_ANY);
1395237263Snp
1396308154Sjhb	ether_ifattach(ifp, vi->hw_addr);
1397308154Sjhb#ifdef DEV_NETMAP
1398318826Snp	if (ifp->if_capabilities & IFCAP_NETMAP)
1399308154Sjhb		cxgbe_nm_attach(vi);
1400308154Sjhb#endif
1401308154Sjhb	sb = sbuf_new_auto();
1402308154Sjhb	sbuf_printf(sb, "%d txq, %d rxq (NIC)", vi->ntxq, vi->nrxq);
1403237263Snp#ifdef TCP_OFFLOAD
1404308154Sjhb	if (ifp->if_capabilities & IFCAP_TOE)
1405308154Sjhb		sbuf_printf(sb, "; %d txq, %d rxq (TOE)",
1406308154Sjhb		    vi->nofldtxq, vi->nofldrxq);
1407218792Snp#endif
1408270297Snp#ifdef DEV_NETMAP
1409308154Sjhb	if (ifp->if_capabilities & IFCAP_NETMAP)
1410308154Sjhb		sbuf_printf(sb, "; %d txq, %d rxq (netmap)",
1411308154Sjhb		    vi->nnmtxq, vi->nnmrxq);
1412270297Snp#endif
1413308154Sjhb	sbuf_finish(sb);
1414308154Sjhb	device_printf(dev, "%s\n", sbuf_data(sb));
1415308154Sjhb	sbuf_delete(sb);
1416218792Snp
1417308154Sjhb	vi_sysctls(vi);
1418308154Sjhb
1419308154Sjhb	return (0);
1420308154Sjhb}
1421308154Sjhb
1422308154Sjhbstatic int
1423308154Sjhbcxgbe_attach(device_t dev)
1424308154Sjhb{
1425308154Sjhb	struct port_info *pi = device_get_softc(dev);
1426309560Sjhb	struct adapter *sc = pi->adapter;
1427308154Sjhb	struct vi_info *vi;
1428308154Sjhb	int i, rc;
1429308154Sjhb
1430308154Sjhb	callout_init_mtx(&pi->tick, &pi->pi_lock, 0);
1431308154Sjhb
1432308154Sjhb	rc = cxgbe_vi_attach(dev, &pi->vi[0]);
1433308154Sjhb	if (rc)
1434308154Sjhb		return (rc);
1435308154Sjhb
1436308154Sjhb	for_each_vi(pi, i, vi) {
1437308154Sjhb		if (i == 0)
1438308154Sjhb			continue;
1439309560Sjhb		vi->dev = device_add_child(dev, sc->names->vi_ifnet_name, -1);
1440308154Sjhb		if (vi->dev == NULL) {
1441308154Sjhb			device_printf(dev, "failed to add VI %d\n", i);
1442308154Sjhb			continue;
1443308154Sjhb		}
1444308154Sjhb		device_set_softc(vi->dev, vi);
1445308154Sjhb	}
1446308154Sjhb
1447218792Snp	cxgbe_sysctls(pi);
1448218792Snp
1449308154Sjhb	bus_generic_attach(dev);
1450308154Sjhb
1451218792Snp	return (0);
1452218792Snp}
1453218792Snp
1454308154Sjhbstatic void
1455308154Sjhbcxgbe_vi_detach(struct vi_info *vi)
1456308154Sjhb{
1457308154Sjhb	struct ifnet *ifp = vi->ifp;
1458308154Sjhb
1459308154Sjhb	ether_ifdetach(ifp);
1460308154Sjhb
1461308154Sjhb	if (vi->vlan_c)
1462308154Sjhb		EVENTHANDLER_DEREGISTER(vlan_config, vi->vlan_c);
1463308154Sjhb
1464308154Sjhb	/* Let detach proceed even if these fail. */
1465308154Sjhb#ifdef DEV_NETMAP
1466308154Sjhb	if (ifp->if_capabilities & IFCAP_NETMAP)
1467308154Sjhb		cxgbe_nm_detach(vi);
1468308154Sjhb#endif
1469308154Sjhb	cxgbe_uninit_synchronized(vi);
1470308154Sjhb	callout_drain(&vi->tick);
1471308154Sjhb	vi_full_uninit(vi);
1472308154Sjhb
1473308154Sjhb	if_free(vi->ifp);
1474308154Sjhb	vi->ifp = NULL;
1475308154Sjhb}
1476308154Sjhb
1477218792Snpstatic int
1478218792Snpcxgbe_detach(device_t dev)
1479218792Snp{
1480218792Snp	struct port_info *pi = device_get_softc(dev);
1481218792Snp	struct adapter *sc = pi->adapter;
1482308154Sjhb	int rc;
1483218792Snp
1484308154Sjhb	/* Detach the extra VIs first. */
1485308154Sjhb	rc = bus_generic_detach(dev);
1486308154Sjhb	if (rc)
1487308154Sjhb		return (rc);
1488308154Sjhb	device_delete_children(dev);
1489218792Snp
1490308154Sjhb	doom_vi(sc, &pi->vi[0]);
1491308154Sjhb
1492253691Snp	if (pi->flags & HAS_TRACEQ) {
1493253691Snp		sc->traceq = -1;	/* cloner should not create ifnet */
1494253691Snp		t4_tracer_port_detach(sc);
1495253691Snp	}
1496253691Snp
1497308154Sjhb	cxgbe_vi_detach(&pi->vi[0]);
1498228561Snp	callout_drain(&pi->tick);
1499353418Snp	ifmedia_removeall(&pi->media);
1500218792Snp
1501308154Sjhb	end_synchronized_op(sc, 0);
1502219286Snp
1503218792Snp	return (0);
1504218792Snp}
1505218792Snp
1506218792Snpstatic void
1507218792Snpcxgbe_init(void *arg)
1508218792Snp{
1509308154Sjhb	struct vi_info *vi = arg;
1510308154Sjhb	struct adapter *sc = vi->pi->adapter;
1511218792Snp
1512308154Sjhb	if (begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4init") != 0)
1513245274Snp		return;
1514308154Sjhb	cxgbe_init_synchronized(vi);
1515245274Snp	end_synchronized_op(sc, 0);
1516218792Snp}
1517218792Snp
1518218792Snpstatic int
1519218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
1520218792Snp{
1521270297Snp	int rc = 0, mtu, flags, can_sleep;
1522308154Sjhb	struct vi_info *vi = ifp->if_softc;
1523353418Snp	struct port_info *pi = vi->pi;
1524353418Snp	struct adapter *sc = pi->adapter;
1525218792Snp	struct ifreq *ifr = (struct ifreq *)data;
1526218792Snp	uint32_t mask;
1527218792Snp
1528218792Snp	switch (cmd) {
1529218792Snp	case SIOCSIFMTU:
1530245274Snp		mtu = ifr->ifr_mtu;
1531309575Sjhb		if (mtu < ETHERMIN || mtu > MAX_MTU)
1532245274Snp			return (EINVAL);
1533245274Snp
1534308154Sjhb		rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4mtu");
1535245274Snp		if (rc)
1536218792Snp			return (rc);
1537245274Snp		ifp->if_mtu = mtu;
1538308154Sjhb		if (vi->flags & VI_INIT_DONE) {
1539245274Snp			t4_update_fl_bufsize(ifp);
1540252728Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1541270297Snp				rc = update_mac_settings(ifp, XGMAC_MTU);
1542218792Snp		}
1543245274Snp		end_synchronized_op(sc, 0);
1544218792Snp		break;
1545218792Snp
1546218792Snp	case SIOCSIFFLAGS:
1547270297Snp		can_sleep = 0;
1548270297Snpredo_sifflags:
1549308154Sjhb		rc = begin_synchronized_op(sc, vi,
1550270297Snp		    can_sleep ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4flg");
1551245274Snp		if (rc)
1552245274Snp			return (rc);
1553245274Snp
1554218792Snp		if (ifp->if_flags & IFF_UP) {
1555218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1556308154Sjhb				flags = vi->if_flags;
1557218792Snp				if ((ifp->if_flags ^ flags) &
1558218792Snp				    (IFF_PROMISC | IFF_ALLMULTI)) {
1559270297Snp					if (can_sleep == 1) {
1560270297Snp						end_synchronized_op(sc, 0);
1561270297Snp						can_sleep = 0;
1562270297Snp						goto redo_sifflags;
1563270297Snp					}
1564270297Snp					rc = update_mac_settings(ifp,
1565218792Snp					    XGMAC_PROMISC | XGMAC_ALLMULTI);
1566218792Snp				}
1567270297Snp			} else {
1568270297Snp				if (can_sleep == 0) {
1569270297Snp					end_synchronized_op(sc, LOCK_HELD);
1570270297Snp					can_sleep = 1;
1571270297Snp					goto redo_sifflags;
1572270297Snp				}
1573308154Sjhb				rc = cxgbe_init_synchronized(vi);
1574270297Snp			}
1575308154Sjhb			vi->if_flags = ifp->if_flags;
1576270297Snp		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1577270297Snp			if (can_sleep == 0) {
1578270297Snp				end_synchronized_op(sc, LOCK_HELD);
1579270297Snp				can_sleep = 1;
1580270297Snp				goto redo_sifflags;
1581270297Snp			}
1582308154Sjhb			rc = cxgbe_uninit_synchronized(vi);
1583270297Snp		}
1584270297Snp		end_synchronized_op(sc, can_sleep ? 0 : LOCK_HELD);
1585218792Snp		break;
1586218792Snp
1587270297Snp	case SIOCADDMULTI:
1588245274Snp	case SIOCDELMULTI: /* these two are called with a mutex held :-( */
1589308154Sjhb		rc = begin_synchronized_op(sc, vi, HOLD_LOCK, "t4multi");
1590218792Snp		if (rc)
1591245274Snp			return (rc);
1592245274Snp		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1593270297Snp			rc = update_mac_settings(ifp, XGMAC_MCADDRS);
1594245274Snp		end_synchronized_op(sc, LOCK_HELD);
1595218792Snp		break;
1596218792Snp
1597218792Snp	case SIOCSIFCAP:
1598308154Sjhb		rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4cap");
1599218792Snp		if (rc)
1600245274Snp			return (rc);
1601218792Snp
1602218792Snp		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1603218792Snp		if (mask & IFCAP_TXCSUM) {
1604218792Snp			ifp->if_capenable ^= IFCAP_TXCSUM;
1605218792Snp			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
1606218792Snp
1607237831Snp			if (IFCAP_TSO4 & ifp->if_capenable &&
1608218792Snp			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
1609237799Snp				ifp->if_capenable &= ~IFCAP_TSO4;
1610218792Snp				if_printf(ifp,
1611237831Snp				    "tso4 disabled due to -txcsum.\n");
1612218792Snp			}
1613218792Snp		}
1614237799Snp		if (mask & IFCAP_TXCSUM_IPV6) {
1615237799Snp			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
1616237799Snp			ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
1617237799Snp
1618237799Snp			if (IFCAP_TSO6 & ifp->if_capenable &&
1619237799Snp			    !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) {
1620237799Snp				ifp->if_capenable &= ~IFCAP_TSO6;
1621237799Snp				if_printf(ifp,
1622237799Snp				    "tso6 disabled due to -txcsum6.\n");
1623237799Snp			}
1624237799Snp		}
1625218792Snp		if (mask & IFCAP_RXCSUM)
1626218792Snp			ifp->if_capenable ^= IFCAP_RXCSUM;
1627237799Snp		if (mask & IFCAP_RXCSUM_IPV6)
1628237799Snp			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
1629237799Snp
1630237799Snp		/*
1631237799Snp		 * Note that we leave CSUM_TSO alone (it is always set).  The
1632237799Snp		 * kernel takes both IFCAP_TSOx and CSUM_TSO into account before
1633237799Snp		 * sending a TSO request our way, so it's sufficient to toggle
1634237799Snp		 * IFCAP_TSOx only.
1635237799Snp		 */
1636218792Snp		if (mask & IFCAP_TSO4) {
1637237799Snp			if (!(IFCAP_TSO4 & ifp->if_capenable) &&
1638237799Snp			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
1639237799Snp				if_printf(ifp, "enable txcsum first.\n");
1640237799Snp				rc = EAGAIN;
1641237799Snp				goto fail;
1642237799Snp			}
1643218792Snp			ifp->if_capenable ^= IFCAP_TSO4;
1644218792Snp		}
1645237799Snp		if (mask & IFCAP_TSO6) {
1646237799Snp			if (!(IFCAP_TSO6 & ifp->if_capenable) &&
1647237799Snp			    !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) {
1648237799Snp				if_printf(ifp, "enable txcsum6 first.\n");
1649237799Snp				rc = EAGAIN;
1650237799Snp				goto fail;
1651237799Snp			}
1652237799Snp			ifp->if_capenable ^= IFCAP_TSO6;
1653237799Snp		}
1654218792Snp		if (mask & IFCAP_LRO) {
1655237819Snp#if defined(INET) || defined(INET6)
1656218792Snp			int i;
1657218792Snp			struct sge_rxq *rxq;
1658218792Snp
1659218792Snp			ifp->if_capenable ^= IFCAP_LRO;
1660308154Sjhb			for_each_rxq(vi, i, rxq) {
1661218792Snp				if (ifp->if_capenable & IFCAP_LRO)
1662228561Snp					rxq->iq.flags |= IQ_LRO_ENABLED;
1663218792Snp				else
1664228561Snp					rxq->iq.flags &= ~IQ_LRO_ENABLED;
1665218792Snp			}
1666218792Snp#endif
1667218792Snp		}
1668237263Snp#ifdef TCP_OFFLOAD
1669228561Snp		if (mask & IFCAP_TOE) {
1670228561Snp			int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE;
1671228561Snp
1672308154Sjhb			rc = toe_capability(vi, enable);
1673228561Snp			if (rc != 0)
1674228561Snp				goto fail;
1675228561Snp
1676228561Snp			ifp->if_capenable ^= mask;
1677218792Snp		}
1678218792Snp#endif
1679218792Snp		if (mask & IFCAP_VLAN_HWTAGGING) {
1680218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1681245274Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1682270297Snp				rc = update_mac_settings(ifp, XGMAC_VLANEX);
1683218792Snp		}
1684218792Snp		if (mask & IFCAP_VLAN_MTU) {
1685218792Snp			ifp->if_capenable ^= IFCAP_VLAN_MTU;
1686218792Snp
1687218792Snp			/* Need to find out how to disable auto-mtu-inflation */
1688218792Snp		}
1689218792Snp		if (mask & IFCAP_VLAN_HWTSO)
1690218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
1691218792Snp		if (mask & IFCAP_VLAN_HWCSUM)
1692218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
1693218792Snp
1694218792Snp#ifdef VLAN_CAPABILITIES
1695218792Snp		VLAN_CAPABILITIES(ifp);
1696218792Snp#endif
1697245274Snpfail:
1698245274Snp		end_synchronized_op(sc, 0);
1699218792Snp		break;
1700218792Snp
1701218792Snp	case SIOCSIFMEDIA:
1702218792Snp	case SIOCGIFMEDIA:
1703309560Sjhb	case SIOCGIFXMEDIA:
1704353418Snp		ifmedia_ioctl(ifp, ifr, &pi->media, cmd);
1705218792Snp		break;
1706218792Snp
1707286898Snp	case SIOCGI2C: {
1708286898Snp		struct ifi2creq i2c;
1709286898Snp
1710286898Snp		rc = copyin(ifr->ifr_data, &i2c, sizeof(i2c));
1711286898Snp		if (rc != 0)
1712286898Snp			break;
1713286898Snp		if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) {
1714286898Snp			rc = EPERM;
1715286898Snp			break;
1716286898Snp		}
1717286898Snp		if (i2c.len > sizeof(i2c.data)) {
1718286898Snp			rc = EINVAL;
1719286898Snp			break;
1720286898Snp		}
1721308154Sjhb		rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4i2c");
1722286898Snp		if (rc)
1723286898Snp			return (rc);
1724353418Snp		rc = -t4_i2c_rd(sc, sc->mbox, pi->port_id, i2c.dev_addr,
1725286898Snp		    i2c.offset, i2c.len, &i2c.data[0]);
1726286898Snp		end_synchronized_op(sc, 0);
1727286898Snp		if (rc == 0)
1728286898Snp			rc = copyout(&i2c, ifr->ifr_data, sizeof(i2c));
1729286898Snp		break;
1730286898Snp	}
1731286898Snp
1732218792Snp	default:
1733218792Snp		rc = ether_ioctl(ifp, cmd, data);
1734218792Snp	}
1735218792Snp
1736218792Snp	return (rc);
1737218792Snp}
1738218792Snp
1739218792Snpstatic int
1740218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m)
1741218792Snp{
1742308154Sjhb	struct vi_info *vi = ifp->if_softc;
1743308154Sjhb	struct port_info *pi = vi->pi;
1744218792Snp	struct adapter *sc = pi->adapter;
1745284052Snp	struct sge_txq *txq;
1746284052Snp	void *items[1];
1747218792Snp	int rc;
1748218792Snp
1749218792Snp	M_ASSERTPKTHDR(m);
1750284052Snp	MPASS(m->m_nextpkt == NULL);	/* not quite ready for this yet */
1751218792Snp
1752228561Snp	if (__predict_false(pi->link_cfg.link_ok == 0)) {
1753218792Snp		m_freem(m);
1754228561Snp		return (ENETDOWN);
1755218792Snp	}
1756218792Snp
1757309447Sjhb	rc = parse_pkt(sc, &m);
1758284052Snp	if (__predict_false(rc != 0)) {
1759284052Snp		MPASS(m == NULL);			/* was freed already */
1760284052Snp		atomic_add_int(&pi->tx_parse_error, 1);	/* rare, atomic is ok */
1761228561Snp		return (rc);
1762218792Snp	}
1763218792Snp
1764284052Snp	/* Select a txq. */
1765308154Sjhb	txq = &sc->sge.txq[vi->first_txq];
1766284052Snp	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
1767308154Sjhb		txq += ((m->m_pkthdr.flowid % (vi->ntxq - vi->rsrv_noflowq)) +
1768308154Sjhb		    vi->rsrv_noflowq);
1769218792Snp
1770284052Snp	items[0] = m;
1771284052Snp	rc = mp_ring_enqueue(txq->r, items, 1, 4096);
1772284052Snp	if (__predict_false(rc != 0))
1773284052Snp		m_freem(m);
1774218792Snp
1775218792Snp	return (rc);
1776218792Snp}
1777218792Snp
1778218792Snpstatic void
1779218792Snpcxgbe_qflush(struct ifnet *ifp)
1780218792Snp{
1781308154Sjhb	struct vi_info *vi = ifp->if_softc;
1782220649Snp	struct sge_txq *txq;
1783220649Snp	int i;
1784218792Snp
1785308154Sjhb	/* queues do not exist if !VI_INIT_DONE. */
1786308154Sjhb	if (vi->flags & VI_INIT_DONE) {
1787308154Sjhb		for_each_txq(vi, i, txq) {
1788220649Snp			TXQ_LOCK(txq);
1789318855Snp			txq->eq.flags |= EQ_QFLUSH;
1790220649Snp			TXQ_UNLOCK(txq);
1791284052Snp			while (!mp_ring_is_idle(txq->r)) {
1792284052Snp				mp_ring_check_drainage(txq->r, 0);
1793284052Snp				pause("qflush", 1);
1794284052Snp			}
1795318855Snp			TXQ_LOCK(txq);
1796318855Snp			txq->eq.flags &= ~EQ_QFLUSH;
1797318855Snp			TXQ_UNLOCK(txq);
1798220649Snp		}
1799220649Snp	}
1800220649Snp	if_qflush(ifp);
1801218792Snp}
1802218792Snp
1803353418Snp/*
1804353418Snp * The kernel picks a media from the list we had provided so we do not have to
1805353418Snp * validate the request.
1806353418Snp */
1807218792Snpstatic int
1808218792Snpcxgbe_media_change(struct ifnet *ifp)
1809218792Snp{
1810308154Sjhb	struct vi_info *vi = ifp->if_softc;
1811353418Snp	struct port_info *pi = vi->pi;
1812353418Snp	struct ifmedia *ifm = &pi->media;
1813353418Snp	struct link_config *lc = &pi->link_cfg;
1814353418Snp	struct adapter *sc = pi->adapter;
1815353418Snp	int rc;
1816218792Snp
1817353418Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4mec");
1818353418Snp	if (rc != 0)
1819353418Snp		return (rc);
1820353418Snp	PORT_LOCK(pi);
1821353418Snp	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
1822353418Snp		MPASS(lc->supported & FW_PORT_CAP_ANEG);
1823353418Snp		lc->requested_aneg = AUTONEG_ENABLE;
1824353418Snp	} else {
1825353418Snp		lc->requested_aneg = AUTONEG_DISABLE;
1826353418Snp		lc->requested_speed =
1827353418Snp		    ifmedia_baudrate(ifm->ifm_media) / 1000000;
1828353418Snp		lc->requested_fc = 0;
1829353418Snp		if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_RXPAUSE)
1830353418Snp			lc->requested_fc |= PAUSE_RX;
1831353418Snp		if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE)
1832353418Snp			lc->requested_fc |= PAUSE_TX;
1833353418Snp	}
1834353418Snp	if (pi->up_vis > 0)
1835353418Snp		rc = apply_l1cfg(pi);
1836353418Snp	PORT_UNLOCK(pi);
1837353418Snp	end_synchronized_op(sc, 0);
1838353418Snp	return (rc);
1839353418Snp}
1840218792Snp
1841353418Snp/*
1842353418Snp * Mbps to FW_PORT_CAP_SPEED_* bit.
1843353418Snp */
1844353418Snpstatic uint16_t
1845353418Snpspeed_to_fwspeed(int speed)
1846353418Snp{
1847353418Snp
1848353418Snp	switch (speed) {
1849353418Snp	case 100000:
1850353418Snp		return (FW_PORT_CAP_SPEED_100G);
1851353418Snp	case 40000:
1852353418Snp		return (FW_PORT_CAP_SPEED_40G);
1853353418Snp	case 25000:
1854353418Snp		return (FW_PORT_CAP_SPEED_25G);
1855353418Snp	case 10000:
1856353418Snp		return (FW_PORT_CAP_SPEED_10G);
1857353418Snp	case 1000:
1858353418Snp		return (FW_PORT_CAP_SPEED_1G);
1859353418Snp	case 100:
1860353418Snp		return (FW_PORT_CAP_SPEED_100M);
1861353418Snp	}
1862353418Snp
1863353418Snp	return (0);
1864218792Snp}
1865218792Snp
1866353418Snp/*
1867353418Snp * Base media word (without ETHER, pause, link active, etc.) for the port at the
1868353418Snp * given speed.
1869353418Snp */
1870353418Snpstatic int
1871353418Snpport_mword(struct port_info *pi, uint16_t speed)
1872353418Snp{
1873353418Snp
1874353418Snp	MPASS(speed & M_FW_PORT_CAP_SPEED);
1875353418Snp	MPASS(powerof2(speed));
1876353418Snp
1877353418Snp	switch(pi->port_type) {
1878353418Snp	case FW_PORT_TYPE_BT_SGMII:
1879353418Snp	case FW_PORT_TYPE_BT_XFI:
1880353418Snp	case FW_PORT_TYPE_BT_XAUI:
1881353418Snp		/* BaseT */
1882353418Snp		switch (speed) {
1883353418Snp		case FW_PORT_CAP_SPEED_100M:
1884353418Snp			return (IFM_100_T);
1885353418Snp		case FW_PORT_CAP_SPEED_1G:
1886353418Snp			return (IFM_1000_T);
1887353418Snp		case FW_PORT_CAP_SPEED_10G:
1888353418Snp			return (IFM_10G_T);
1889353418Snp		}
1890353418Snp		break;
1891353418Snp	case FW_PORT_TYPE_KX4:
1892353418Snp		if (speed == FW_PORT_CAP_SPEED_10G)
1893353418Snp			return (IFM_10G_KX4);
1894353418Snp		break;
1895353418Snp	case FW_PORT_TYPE_CX4:
1896353418Snp		if (speed == FW_PORT_CAP_SPEED_10G)
1897353418Snp			return (IFM_10G_CX4);
1898353418Snp		break;
1899353418Snp	case FW_PORT_TYPE_KX:
1900353418Snp		if (speed == FW_PORT_CAP_SPEED_1G)
1901353418Snp			return (IFM_1000_KX);
1902353418Snp		break;
1903353418Snp	case FW_PORT_TYPE_KR:
1904353418Snp	case FW_PORT_TYPE_BP_AP:
1905353418Snp	case FW_PORT_TYPE_BP4_AP:
1906353418Snp	case FW_PORT_TYPE_BP40_BA:
1907353418Snp	case FW_PORT_TYPE_KR4_100G:
1908353418Snp	case FW_PORT_TYPE_KR_SFP28:
1909353418Snp	case FW_PORT_TYPE_KR_XLAUI:
1910353418Snp		switch (speed) {
1911353418Snp		case FW_PORT_CAP_SPEED_1G:
1912353418Snp			return (IFM_1000_KX);
1913353418Snp		case FW_PORT_CAP_SPEED_10G:
1914353418Snp			return (IFM_10G_KR);
1915353418Snp		case FW_PORT_CAP_SPEED_25G:
1916353418Snp			return (IFM_25G_KR);
1917353418Snp		case FW_PORT_CAP_SPEED_40G:
1918353418Snp			return (IFM_40G_KR4);
1919353418Snp		case FW_PORT_CAP_SPEED_100G:
1920353418Snp			return (IFM_100G_KR4);
1921353418Snp		}
1922353418Snp		break;
1923353418Snp	case FW_PORT_TYPE_FIBER_XFI:
1924353418Snp	case FW_PORT_TYPE_FIBER_XAUI:
1925353418Snp	case FW_PORT_TYPE_SFP:
1926353418Snp	case FW_PORT_TYPE_QSFP_10G:
1927353418Snp	case FW_PORT_TYPE_QSA:
1928353418Snp	case FW_PORT_TYPE_QSFP:
1929353418Snp	case FW_PORT_TYPE_CR4_QSFP:
1930353418Snp	case FW_PORT_TYPE_CR_QSFP:
1931353418Snp	case FW_PORT_TYPE_CR2_QSFP:
1932353418Snp	case FW_PORT_TYPE_SFP28:
1933353418Snp		/* Pluggable transceiver */
1934353418Snp		switch (pi->mod_type) {
1935353418Snp		case FW_PORT_MOD_TYPE_LR:
1936353418Snp			switch (speed) {
1937353418Snp			case FW_PORT_CAP_SPEED_1G:
1938353418Snp				return (IFM_1000_LX);
1939353418Snp			case FW_PORT_CAP_SPEED_10G:
1940353418Snp				return (IFM_10G_LR);
1941353418Snp			case FW_PORT_CAP_SPEED_25G:
1942353418Snp				return (IFM_25G_LR);
1943353418Snp			case FW_PORT_CAP_SPEED_40G:
1944353418Snp				return (IFM_40G_LR4);
1945353418Snp			case FW_PORT_CAP_SPEED_100G:
1946353418Snp				return (IFM_100G_LR4);
1947353418Snp			}
1948353418Snp			break;
1949353418Snp		case FW_PORT_MOD_TYPE_SR:
1950353418Snp			switch (speed) {
1951353418Snp			case FW_PORT_CAP_SPEED_1G:
1952353418Snp				return (IFM_1000_SX);
1953353418Snp			case FW_PORT_CAP_SPEED_10G:
1954353418Snp				return (IFM_10G_SR);
1955353418Snp			case FW_PORT_CAP_SPEED_25G:
1956353418Snp				return (IFM_25G_SR);
1957353418Snp			case FW_PORT_CAP_SPEED_40G:
1958353418Snp				return (IFM_40G_SR4);
1959353418Snp			case FW_PORT_CAP_SPEED_100G:
1960353418Snp				return (IFM_100G_SR4);
1961353418Snp			}
1962353418Snp			break;
1963353418Snp		case FW_PORT_MOD_TYPE_ER:
1964353418Snp			if (speed == FW_PORT_CAP_SPEED_10G)
1965353418Snp				return (IFM_10G_ER);
1966353418Snp			break;
1967353418Snp		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
1968353418Snp		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
1969353418Snp			switch (speed) {
1970353418Snp			case FW_PORT_CAP_SPEED_1G:
1971353418Snp				return (IFM_1000_CX);
1972353418Snp			case FW_PORT_CAP_SPEED_10G:
1973353418Snp				return (IFM_10G_TWINAX);
1974353418Snp			case FW_PORT_CAP_SPEED_25G:
1975353418Snp				return (IFM_25G_CR);
1976353418Snp			case FW_PORT_CAP_SPEED_40G:
1977353418Snp				return (IFM_40G_CR4);
1978353418Snp			case FW_PORT_CAP_SPEED_100G:
1979353418Snp				return (IFM_100G_CR4);
1980353418Snp			}
1981353418Snp			break;
1982353418Snp		case FW_PORT_MOD_TYPE_LRM:
1983353418Snp			if (speed == FW_PORT_CAP_SPEED_10G)
1984353418Snp				return (IFM_10G_LRM);
1985353418Snp			break;
1986353418Snp		case FW_PORT_MOD_TYPE_NA:
1987353418Snp			MPASS(0);	/* Not pluggable? */
1988353418Snp			/* fall throough */
1989353418Snp		case FW_PORT_MOD_TYPE_ERROR:
1990353418Snp		case FW_PORT_MOD_TYPE_UNKNOWN:
1991353418Snp		case FW_PORT_MOD_TYPE_NOTSUPPORTED:
1992353418Snp			break;
1993353418Snp		case FW_PORT_MOD_TYPE_NONE:
1994353418Snp			return (IFM_NONE);
1995353418Snp		}
1996353418Snp		break;
1997353418Snp	case FW_PORT_TYPE_NONE:
1998353418Snp		return (IFM_NONE);
1999353418Snp	}
2000353418Snp
2001353418Snp	return (IFM_UNKNOWN);
2002353418Snp}
2003353418Snp
2004218792Snpstatic void
2005218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
2006218792Snp{
2007308154Sjhb	struct vi_info *vi = ifp->if_softc;
2008308154Sjhb	struct port_info *pi = vi->pi;
2009353418Snp	struct adapter *sc = pi->adapter;
2010353418Snp	struct link_config *lc = &pi->link_cfg;
2011218792Snp
2012353418Snp	if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4med") != 0)
2013353418Snp		return;
2014353418Snp	PORT_LOCK(pi);
2015270297Snp
2016353418Snp	if (pi->up_vis == 0) {
2017353418Snp		/*
2018353418Snp		 * If all the interfaces are administratively down the firmware
2019353418Snp		 * does not report transceiver changes.  Refresh port info here
2020353418Snp		 * so that ifconfig displays accurate ifmedia at all times.
2021353418Snp		 * This is the only reason we have a synchronized op in this
2022353418Snp		 * function.  Just PORT_LOCK would have been enough otherwise.
2023353418Snp		 */
2024353418Snp		t4_update_port_info(pi);
2025353418Snp		build_medialist(pi, &pi->media);
2026353418Snp	}
2027353418Snp
2028353418Snp	/* ifm_status */
2029218792Snp	ifmr->ifm_status = IFM_AVALID;
2030353418Snp	if (lc->link_ok == 0)
2031353418Snp		goto done;
2032218792Snp	ifmr->ifm_status |= IFM_ACTIVE;
2033218792Snp
2034353418Snp	/* ifm_active */
2035218792Snp	ifmr->ifm_active = IFM_ETHER | IFM_FDX;
2036353418Snp	ifmr->ifm_active &= ~(IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
2037353418Snp	if (lc->fc & PAUSE_RX)
2038353418Snp		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
2039353418Snp	if (lc->fc & PAUSE_TX)
2040353418Snp		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
2041353418Snp	ifmr->ifm_active |= port_mword(pi, speed_to_fwspeed(lc->speed));
2042353418Snpdone:
2043353418Snp	PORT_UNLOCK(pi);
2044353418Snp	end_synchronized_op(sc, 0);
2045218792Snp}
2046218792Snp
2047308154Sjhbstatic int
2048308154Sjhbvcxgbe_probe(device_t dev)
2049308154Sjhb{
2050308154Sjhb	char buf[128];
2051308154Sjhb	struct vi_info *vi = device_get_softc(dev);
2052308154Sjhb
2053308154Sjhb	snprintf(buf, sizeof(buf), "port %d vi %td", vi->pi->port_id,
2054308154Sjhb	    vi - vi->pi->vi);
2055308154Sjhb	device_set_desc_copy(dev, buf);
2056308154Sjhb
2057308154Sjhb	return (BUS_PROBE_DEFAULT);
2058308154Sjhb}
2059308154Sjhb
2060308154Sjhbstatic int
2061308154Sjhbvcxgbe_attach(device_t dev)
2062308154Sjhb{
2063308154Sjhb	struct vi_info *vi;
2064308154Sjhb	struct port_info *pi;
2065308154Sjhb	struct adapter *sc;
2066308154Sjhb	int func, index, rc;
2067308154Sjhb	u32 param, val;
2068308154Sjhb
2069308154Sjhb	vi = device_get_softc(dev);
2070308154Sjhb	pi = vi->pi;
2071308154Sjhb	sc = pi->adapter;
2072308154Sjhb
2073308154Sjhb	index = vi - pi->vi;
2074308154Sjhb	KASSERT(index < nitems(vi_mac_funcs),
2075308154Sjhb	    ("%s: VI %s doesn't have a MAC func", __func__,
2076308154Sjhb	    device_get_nameunit(dev)));
2077308154Sjhb	func = vi_mac_funcs[index];
2078308154Sjhb	rc = t4_alloc_vi_func(sc, sc->mbox, pi->tx_chan, sc->pf, 0, 1,
2079308154Sjhb	    vi->hw_addr, &vi->rss_size, func, 0);
2080308154Sjhb	if (rc < 0) {
2081308154Sjhb		device_printf(dev, "Failed to allocate virtual interface "
2082308154Sjhb		    "for port %d: %d\n", pi->port_id, -rc);
2083308154Sjhb		return (-rc);
2084308154Sjhb	}
2085308154Sjhb	vi->viid = rc;
2086309560Sjhb	if (chip_id(sc) <= CHELSIO_T5)
2087309560Sjhb		vi->smt_idx = (rc & 0x7f) << 1;
2088309560Sjhb	else
2089309560Sjhb		vi->smt_idx = (rc & 0x7f);
2090308154Sjhb
2091308154Sjhb	param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
2092308154Sjhb	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_RSSINFO) |
2093308154Sjhb	    V_FW_PARAMS_PARAM_YZ(vi->viid);
2094308154Sjhb	rc = t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
2095308154Sjhb	if (rc)
2096308154Sjhb		vi->rss_base = 0xffff;
2097308154Sjhb	else {
2098308154Sjhb		/* MPASS((val >> 16) == rss_size); */
2099308154Sjhb		vi->rss_base = val & 0xffff;
2100308154Sjhb	}
2101308154Sjhb
2102308154Sjhb	rc = cxgbe_vi_attach(dev, vi);
2103308154Sjhb	if (rc) {
2104308154Sjhb		t4_free_vi(sc, sc->mbox, sc->pf, 0, vi->viid);
2105308154Sjhb		return (rc);
2106308154Sjhb	}
2107308154Sjhb	return (0);
2108308154Sjhb}
2109308154Sjhb
2110308154Sjhbstatic int
2111308154Sjhbvcxgbe_detach(device_t dev)
2112308154Sjhb{
2113308154Sjhb	struct vi_info *vi;
2114308154Sjhb	struct adapter *sc;
2115308154Sjhb
2116308154Sjhb	vi = device_get_softc(dev);
2117308154Sjhb	sc = vi->pi->adapter;
2118308154Sjhb
2119308154Sjhb	doom_vi(sc, vi);
2120308154Sjhb
2121308154Sjhb	cxgbe_vi_detach(vi);
2122308154Sjhb	t4_free_vi(sc, sc->mbox, sc->pf, 0, vi->viid);
2123308154Sjhb
2124308154Sjhb	end_synchronized_op(sc, 0);
2125308154Sjhb
2126308154Sjhb	return (0);
2127308154Sjhb}
2128308154Sjhb
2129218792Snpvoid
2130218792Snpt4_fatal_err(struct adapter *sc)
2131218792Snp{
2132218792Snp	t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0);
2133218792Snp	t4_intr_disable(sc);
2134218792Snp	log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n",
2135218792Snp	    device_get_nameunit(sc->dev));
2136218792Snp}
2137218792Snp
2138309447Sjhbvoid
2139309447Sjhbt4_add_adapter(struct adapter *sc)
2140218792Snp{
2141309447Sjhb	sx_xlock(&t4_list_lock);
2142309447Sjhb	SLIST_INSERT_HEAD(&t4_list, sc, link);
2143309447Sjhb	sx_xunlock(&t4_list_lock);
2144309447Sjhb}
2145309447Sjhb
2146309447Sjhbint
2147309447Sjhbt4_map_bars_0_and_4(struct adapter *sc)
2148309447Sjhb{
2149218792Snp	sc->regs_rid = PCIR_BAR(0);
2150218792Snp	sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
2151218792Snp	    &sc->regs_rid, RF_ACTIVE);
2152218792Snp	if (sc->regs_res == NULL) {
2153218792Snp		device_printf(sc->dev, "cannot map registers.\n");
2154218792Snp		return (ENXIO);
2155218792Snp	}
2156218792Snp	sc->bt = rman_get_bustag(sc->regs_res);
2157218792Snp	sc->bh = rman_get_bushandle(sc->regs_res);
2158218792Snp	sc->mmio_len = rman_get_size(sc->regs_res);
2159248925Snp	setbit(&sc->doorbells, DOORBELL_KDB);
2160218792Snp
2161218792Snp	sc->msix_rid = PCIR_BAR(4);
2162218792Snp	sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
2163218792Snp	    &sc->msix_rid, RF_ACTIVE);
2164218792Snp	if (sc->msix_res == NULL) {
2165218792Snp		device_printf(sc->dev, "cannot map MSI-X BAR.\n");
2166218792Snp		return (ENXIO);
2167218792Snp	}
2168218792Snp
2169218792Snp	return (0);
2170218792Snp}
2171218792Snp
2172309447Sjhbint
2173309447Sjhbt4_map_bar_2(struct adapter *sc)
2174248925Snp{
2175248925Snp
2176248925Snp	/*
2177248925Snp	 * T4: only iWARP driver uses the userspace doorbells.  There is no need
2178248925Snp	 * to map it if RDMA is disabled.
2179248925Snp	 */
2180248925Snp	if (is_t4(sc) && sc->rdmacaps == 0)
2181248925Snp		return (0);
2182248925Snp
2183248925Snp	sc->udbs_rid = PCIR_BAR(2);
2184248925Snp	sc->udbs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
2185248925Snp	    &sc->udbs_rid, RF_ACTIVE);
2186248925Snp	if (sc->udbs_res == NULL) {
2187248925Snp		device_printf(sc->dev, "cannot map doorbell BAR.\n");
2188248925Snp		return (ENXIO);
2189248925Snp	}
2190248925Snp	sc->udbs_base = rman_get_virtual(sc->udbs_res);
2191248925Snp
2192309560Sjhb	if (chip_id(sc) >= CHELSIO_T5) {
2193248925Snp		setbit(&sc->doorbells, DOORBELL_UDB);
2194248925Snp#if defined(__i386__) || defined(__amd64__)
2195248925Snp		if (t5_write_combine) {
2196309560Sjhb			int rc, mode;
2197248925Snp
2198248925Snp			/*
2199248925Snp			 * Enable write combining on BAR2.  This is the
2200248925Snp			 * userspace doorbell BAR and is split into 128B
2201248925Snp			 * (UDBS_SEG_SIZE) doorbell regions, each associated
2202248925Snp			 * with an egress queue.  The first 64B has the doorbell
2203248925Snp			 * and the second 64B can be used to submit a tx work
2204248925Snp			 * request with an implicit doorbell.
2205248925Snp			 */
2206248925Snp
2207248925Snp			rc = pmap_change_attr((vm_offset_t)sc->udbs_base,
2208248925Snp			    rman_get_size(sc->udbs_res), PAT_WRITE_COMBINING);
2209248925Snp			if (rc == 0) {
2210248925Snp				clrbit(&sc->doorbells, DOORBELL_UDB);
2211249392Snp				setbit(&sc->doorbells, DOORBELL_WCWR);
2212248925Snp				setbit(&sc->doorbells, DOORBELL_UDBWC);
2213248925Snp			} else {
2214248925Snp				device_printf(sc->dev,
2215248925Snp				    "couldn't enable write combining: %d\n",
2216248925Snp				    rc);
2217248925Snp			}
2218248925Snp
2219309560Sjhb			mode = is_t5(sc) ? V_STATMODE(0) : V_T6_STATMODE(0);
2220248925Snp			t4_write_reg(sc, A_SGE_STAT_CFG,
2221309560Sjhb			    V_STATSOURCE_T5(7) | mode);
2222248925Snp		}
2223248925Snp#endif
2224248925Snp	}
2225248925Snp
2226248925Snp	return (0);
2227248925Snp}
2228248925Snp
2229308305Sjhbstruct memwin_init {
2230308305Sjhb	uint32_t base;
2231308305Sjhb	uint32_t aperture;
2232308305Sjhb};
2233308305Sjhb
2234308305Sjhbstatic const struct memwin_init t4_memwin[NUM_MEMWIN] = {
2235248925Snp	{ MEMWIN0_BASE, MEMWIN0_APERTURE },
2236248925Snp	{ MEMWIN1_BASE, MEMWIN1_APERTURE },
2237248925Snp	{ MEMWIN2_BASE_T4, MEMWIN2_APERTURE_T4 }
2238248925Snp};
2239248925Snp
2240308305Sjhbstatic const struct memwin_init t5_memwin[NUM_MEMWIN] = {
2241248925Snp	{ MEMWIN0_BASE, MEMWIN0_APERTURE },
2242248925Snp	{ MEMWIN1_BASE, MEMWIN1_APERTURE },
2243248925Snp	{ MEMWIN2_BASE_T5, MEMWIN2_APERTURE_T5 },
2244248925Snp};
2245248925Snp
2246218792Snpstatic void
2247218792Snpsetup_memwin(struct adapter *sc)
2248218792Snp{
2249308305Sjhb	const struct memwin_init *mw_init;
2250308305Sjhb	struct memwin *mw;
2251308305Sjhb	int i;
2252237587Snp	uint32_t bar0;
2253218792Snp
2254248925Snp	if (is_t4(sc)) {
2255248925Snp		/*
2256248925Snp		 * Read low 32b of bar0 indirectly via the hardware backdoor
2257248925Snp		 * mechanism.  Works from within PCI passthrough environments
2258248925Snp		 * too, where rman_get_start() can return a different value.  We
2259248925Snp		 * need to program the T4 memory window decoders with the actual
2260248925Snp		 * addresses that will be coming across the PCIe link.
2261248925Snp		 */
2262248925Snp		bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0));
2263248925Snp		bar0 &= (uint32_t) PCIM_BAR_MEM_BASE;
2264218792Snp
2265308305Sjhb		mw_init = &t4_memwin[0];
2266248925Snp	} else {
2267308305Sjhb		/* T5+ use the relative offset inside the PCIe BAR */
2268248925Snp		bar0 = 0;
2269218792Snp
2270308305Sjhb		mw_init = &t5_memwin[0];
2271248925Snp	}
2272218792Snp
2273308305Sjhb	for (i = 0, mw = &sc->memwin[0]; i < NUM_MEMWIN; i++, mw_init++, mw++) {
2274308305Sjhb		rw_init(&mw->mw_lock, "memory window access");
2275308305Sjhb		mw->mw_base = mw_init->base;
2276308305Sjhb		mw->mw_aperture = mw_init->aperture;
2277308305Sjhb		mw->mw_curpos = 0;
2278248925Snp		t4_write_reg(sc,
2279248925Snp		    PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, i),
2280308305Sjhb		    (mw->mw_base + bar0) | V_BIR(0) |
2281308305Sjhb		    V_WINDOW(ilog2(mw->mw_aperture) - 10));
2282308305Sjhb		rw_wlock(&mw->mw_lock);
2283308305Sjhb		position_memwin(sc, i, 0);
2284308305Sjhb		rw_wunlock(&mw->mw_lock);
2285248925Snp	}
2286237587Snp
2287237587Snp	/* flush */
2288237587Snp	t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2));
2289218792Snp}
2290218792Snp
2291248925Snp/*
2292308305Sjhb * Positions the memory window at the given address in the card's address space.
2293308305Sjhb * There are some alignment requirements and the actual position may be at an
2294308305Sjhb * address prior to the requested address.  mw->mw_curpos always has the actual
2295308305Sjhb * position of the window.
2296248925Snp */
2297308305Sjhbstatic void
2298308305Sjhbposition_memwin(struct adapter *sc, int idx, uint32_t addr)
2299308305Sjhb{
2300308305Sjhb	struct memwin *mw;
2301308305Sjhb	uint32_t pf;
2302308305Sjhb	uint32_t reg;
2303308305Sjhb
2304308305Sjhb	MPASS(idx >= 0 && idx < NUM_MEMWIN);
2305308305Sjhb	mw = &sc->memwin[idx];
2306308305Sjhb	rw_assert(&mw->mw_lock, RA_WLOCKED);
2307308305Sjhb
2308308305Sjhb	if (is_t4(sc)) {
2309308305Sjhb		pf = 0;
2310308305Sjhb		mw->mw_curpos = addr & ~0xf;	/* start must be 16B aligned */
2311308305Sjhb	} else {
2312308305Sjhb		pf = V_PFNUM(sc->pf);
2313308305Sjhb		mw->mw_curpos = addr & ~0x7f;	/* start must be 128B aligned */
2314308305Sjhb	}
2315308305Sjhb	reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, idx);
2316308305Sjhb	t4_write_reg(sc, reg, mw->mw_curpos | pf);
2317308305Sjhb	t4_read_reg(sc, reg);	/* flush */
2318308305Sjhb}
2319308305Sjhb
2320218792Snpstatic int
2321308305Sjhbrw_via_memwin(struct adapter *sc, int idx, uint32_t addr, uint32_t *val,
2322308305Sjhb    int len, int rw)
2323308305Sjhb{
2324308305Sjhb	struct memwin *mw;
2325308305Sjhb	uint32_t mw_end, v;
2326308305Sjhb
2327308305Sjhb	MPASS(idx >= 0 && idx < NUM_MEMWIN);
2328308305Sjhb
2329308305Sjhb	/* Memory can only be accessed in naturally aligned 4 byte units */
2330308305Sjhb	if (addr & 3 || len & 3 || len <= 0)
2331308305Sjhb		return (EINVAL);
2332308305Sjhb
2333308305Sjhb	mw = &sc->memwin[idx];
2334308305Sjhb	while (len > 0) {
2335308305Sjhb		rw_rlock(&mw->mw_lock);
2336308305Sjhb		mw_end = mw->mw_curpos + mw->mw_aperture;
2337308305Sjhb		if (addr >= mw_end || addr < mw->mw_curpos) {
2338308305Sjhb			/* Will need to reposition the window */
2339308305Sjhb			if (!rw_try_upgrade(&mw->mw_lock)) {
2340308305Sjhb				rw_runlock(&mw->mw_lock);
2341308305Sjhb				rw_wlock(&mw->mw_lock);
2342308305Sjhb			}
2343308305Sjhb			rw_assert(&mw->mw_lock, RA_WLOCKED);
2344308305Sjhb			position_memwin(sc, idx, addr);
2345308305Sjhb			rw_downgrade(&mw->mw_lock);
2346308305Sjhb			mw_end = mw->mw_curpos + mw->mw_aperture;
2347308305Sjhb		}
2348308305Sjhb		rw_assert(&mw->mw_lock, RA_RLOCKED);
2349308305Sjhb		while (addr < mw_end && len > 0) {
2350308305Sjhb			if (rw == 0) {
2351308305Sjhb				v = t4_read_reg(sc, mw->mw_base + addr -
2352308305Sjhb				    mw->mw_curpos);
2353308305Sjhb				*val++ = le32toh(v);
2354308305Sjhb			} else {
2355308305Sjhb				v = *val++;
2356308305Sjhb				t4_write_reg(sc, mw->mw_base + addr -
2357308305Sjhb				    mw->mw_curpos, htole32(v));;
2358308305Sjhb			}
2359308305Sjhb			addr += 4;
2360308305Sjhb			len -= 4;
2361308305Sjhb		}
2362308305Sjhb		rw_runlock(&mw->mw_lock);
2363308305Sjhb	}
2364308305Sjhb
2365308305Sjhb	return (0);
2366308305Sjhb}
2367308305Sjhb
2368308305Sjhbstatic inline int
2369308305Sjhbread_via_memwin(struct adapter *sc, int idx, uint32_t addr, uint32_t *val,
2370308305Sjhb    int len)
2371308305Sjhb{
2372308305Sjhb
2373308305Sjhb	return (rw_via_memwin(sc, idx, addr, val, len, 0));
2374308305Sjhb}
2375308305Sjhb
2376308305Sjhbstatic inline int
2377308305Sjhbwrite_via_memwin(struct adapter *sc, int idx, uint32_t addr,
2378308305Sjhb    const uint32_t *val, int len)
2379308305Sjhb{
2380308305Sjhb
2381308305Sjhb	return (rw_via_memwin(sc, idx, addr, (void *)(uintptr_t)val, len, 1));
2382308305Sjhb}
2383308305Sjhb
2384308305Sjhbstatic int
2385308305Sjhbt4_range_cmp(const void *a, const void *b)
2386308305Sjhb{
2387308305Sjhb	return ((const struct t4_range *)a)->start -
2388308305Sjhb	       ((const struct t4_range *)b)->start;
2389308305Sjhb}
2390308305Sjhb
2391308305Sjhb/*
2392308305Sjhb * Verify that the memory range specified by the addr/len pair is valid within
2393308305Sjhb * the card's address space.
2394308305Sjhb */
2395308305Sjhbstatic int
2396248925Snpvalidate_mem_range(struct adapter *sc, uint32_t addr, int len)
2397248925Snp{
2398308305Sjhb	struct t4_range mem_ranges[4], *r, *next;
2399308305Sjhb	uint32_t em, addr_len;
2400308305Sjhb	int i, n, remaining;
2401248925Snp
2402248925Snp	/* Memory can only be accessed in naturally aligned 4 byte units */
2403308305Sjhb	if (addr & 3 || len & 3 || len <= 0)
2404248925Snp		return (EINVAL);
2405248925Snp
2406248925Snp	/* Enabled memories */
2407248925Snp	em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
2408308305Sjhb
2409308305Sjhb	r = &mem_ranges[0];
2410308305Sjhb	n = 0;
2411308305Sjhb	bzero(r, sizeof(mem_ranges));
2412248925Snp	if (em & F_EDRAM0_ENABLE) {
2413248925Snp		addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR);
2414308305Sjhb		r->size = G_EDRAM0_SIZE(addr_len) << 20;
2415308305Sjhb		if (r->size > 0) {
2416308305Sjhb			r->start = G_EDRAM0_BASE(addr_len) << 20;
2417308305Sjhb			if (addr >= r->start &&
2418308305Sjhb			    addr + len <= r->start + r->size)
2419308305Sjhb				return (0);
2420308305Sjhb			r++;
2421308305Sjhb			n++;
2422308305Sjhb		}
2423248925Snp	}
2424248925Snp	if (em & F_EDRAM1_ENABLE) {
2425248925Snp		addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR);
2426308305Sjhb		r->size = G_EDRAM1_SIZE(addr_len) << 20;
2427308305Sjhb		if (r->size > 0) {
2428308305Sjhb			r->start = G_EDRAM1_BASE(addr_len) << 20;
2429308305Sjhb			if (addr >= r->start &&
2430308305Sjhb			    addr + len <= r->start + r->size)
2431308305Sjhb				return (0);
2432308305Sjhb			r++;
2433308305Sjhb			n++;
2434308305Sjhb		}
2435248925Snp	}
2436248925Snp	if (em & F_EXT_MEM_ENABLE) {
2437248925Snp		addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
2438308305Sjhb		r->size = G_EXT_MEM_SIZE(addr_len) << 20;
2439308305Sjhb		if (r->size > 0) {
2440308305Sjhb			r->start = G_EXT_MEM_BASE(addr_len) << 20;
2441308305Sjhb			if (addr >= r->start &&
2442308305Sjhb			    addr + len <= r->start + r->size)
2443308305Sjhb				return (0);
2444308305Sjhb			r++;
2445308305Sjhb			n++;
2446308305Sjhb		}
2447248925Snp	}
2448308305Sjhb	if (is_t5(sc) && em & F_EXT_MEM1_ENABLE) {
2449248925Snp		addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR);
2450308305Sjhb		r->size = G_EXT_MEM1_SIZE(addr_len) << 20;
2451308305Sjhb		if (r->size > 0) {
2452308305Sjhb			r->start = G_EXT_MEM1_BASE(addr_len) << 20;
2453308305Sjhb			if (addr >= r->start &&
2454308305Sjhb			    addr + len <= r->start + r->size)
2455308305Sjhb				return (0);
2456308305Sjhb			r++;
2457308305Sjhb			n++;
2458308305Sjhb		}
2459248925Snp	}
2460308305Sjhb	MPASS(n <= nitems(mem_ranges));
2461248925Snp
2462308305Sjhb	if (n > 1) {
2463308305Sjhb		/* Sort and merge the ranges. */
2464308305Sjhb		qsort(mem_ranges, n, sizeof(struct t4_range), t4_range_cmp);
2465308305Sjhb
2466308305Sjhb		/* Start from index 0 and examine the next n - 1 entries. */
2467308305Sjhb		r = &mem_ranges[0];
2468308305Sjhb		for (remaining = n - 1; remaining > 0; remaining--, r++) {
2469308305Sjhb
2470308305Sjhb			MPASS(r->size > 0);	/* r is a valid entry. */
2471308305Sjhb			next = r + 1;
2472308305Sjhb			MPASS(next->size > 0);	/* and so is the next one. */
2473308305Sjhb
2474308305Sjhb			while (r->start + r->size >= next->start) {
2475308305Sjhb				/* Merge the next one into the current entry. */
2476308305Sjhb				r->size = max(r->start + r->size,
2477308305Sjhb				    next->start + next->size) - r->start;
2478308305Sjhb				n--;	/* One fewer entry in total. */
2479308305Sjhb				if (--remaining == 0)
2480308305Sjhb					goto done;	/* short circuit */
2481308305Sjhb				next++;
2482308305Sjhb			}
2483308305Sjhb			if (next != r + 1) {
2484308305Sjhb				/*
2485308305Sjhb				 * Some entries were merged into r and next
2486308305Sjhb				 * points to the first valid entry that couldn't
2487308305Sjhb				 * be merged.
2488308305Sjhb				 */
2489308305Sjhb				MPASS(next->size > 0);	/* must be valid */
2490308305Sjhb				memcpy(r + 1, next, remaining * sizeof(*r));
2491308305Sjhb#ifdef INVARIANTS
2492308305Sjhb				/*
2493308305Sjhb				 * This so that the foo->size assertion in the
2494308305Sjhb				 * next iteration of the loop do the right
2495308305Sjhb				 * thing for entries that were pulled up and are
2496308305Sjhb				 * no longer valid.
2497308305Sjhb				 */
2498308305Sjhb				MPASS(n < nitems(mem_ranges));
2499308305Sjhb				bzero(&mem_ranges[n], (nitems(mem_ranges) - n) *
2500308305Sjhb				    sizeof(struct t4_range));
2501308305Sjhb#endif
2502308305Sjhb			}
2503308305Sjhb		}
2504308305Sjhbdone:
2505308305Sjhb		/* Done merging the ranges. */
2506308305Sjhb		MPASS(n > 0);
2507308305Sjhb		r = &mem_ranges[0];
2508308305Sjhb		for (i = 0; i < n; i++, r++) {
2509308305Sjhb			if (addr >= r->start &&
2510308305Sjhb			    addr + len <= r->start + r->size)
2511308305Sjhb				return (0);
2512308305Sjhb		}
2513308305Sjhb	}
2514308305Sjhb
2515248925Snp	return (EFAULT);
2516248925Snp}
2517248925Snp
2518256791Snpstatic int
2519256791Snpfwmtype_to_hwmtype(int mtype)
2520256791Snp{
2521256791Snp
2522256791Snp	switch (mtype) {
2523256791Snp	case FW_MEMTYPE_EDC0:
2524256791Snp		return (MEM_EDC0);
2525256791Snp	case FW_MEMTYPE_EDC1:
2526256791Snp		return (MEM_EDC1);
2527256791Snp	case FW_MEMTYPE_EXTMEM:
2528256791Snp		return (MEM_MC0);
2529256791Snp	case FW_MEMTYPE_EXTMEM1:
2530256791Snp		return (MEM_MC1);
2531256791Snp	default:
2532256791Snp		panic("%s: cannot translate fw mtype %d.", __func__, mtype);
2533256791Snp	}
2534256791Snp}
2535256791Snp
2536248925Snp/*
2537248925Snp * Verify that the memory range specified by the memtype/offset/len pair is
2538248925Snp * valid and lies entirely within the memtype specified.  The global address of
2539248925Snp * the start of the range is returned in addr.
2540248925Snp */
2541248925Snpstatic int
2542248925Snpvalidate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len,
2543248925Snp    uint32_t *addr)
2544248925Snp{
2545308305Sjhb	uint32_t em, addr_len, maddr;
2546248925Snp
2547248925Snp	/* Memory can only be accessed in naturally aligned 4 byte units */
2548248925Snp	if (off & 3 || len & 3 || len == 0)
2549248925Snp		return (EINVAL);
2550248925Snp
2551248925Snp	em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
2552256791Snp	switch (fwmtype_to_hwmtype(mtype)) {
2553248925Snp	case MEM_EDC0:
2554248925Snp		if (!(em & F_EDRAM0_ENABLE))
2555248925Snp			return (EINVAL);
2556248925Snp		addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR);
2557248925Snp		maddr = G_EDRAM0_BASE(addr_len) << 20;
2558248925Snp		break;
2559248925Snp	case MEM_EDC1:
2560248925Snp		if (!(em & F_EDRAM1_ENABLE))
2561248925Snp			return (EINVAL);
2562248925Snp		addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR);
2563248925Snp		maddr = G_EDRAM1_BASE(addr_len) << 20;
2564248925Snp		break;
2565248925Snp	case MEM_MC:
2566248925Snp		if (!(em & F_EXT_MEM_ENABLE))
2567248925Snp			return (EINVAL);
2568248925Snp		addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
2569248925Snp		maddr = G_EXT_MEM_BASE(addr_len) << 20;
2570248925Snp		break;
2571248925Snp	case MEM_MC1:
2572308305Sjhb		if (!is_t5(sc) || !(em & F_EXT_MEM1_ENABLE))
2573248925Snp			return (EINVAL);
2574248925Snp		addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR);
2575248925Snp		maddr = G_EXT_MEM1_BASE(addr_len) << 20;
2576248925Snp		break;
2577248925Snp	default:
2578248925Snp		return (EINVAL);
2579248925Snp	}
2580248925Snp
2581308305Sjhb	*addr = maddr + off;	/* global address */
2582308305Sjhb	return (validate_mem_range(sc, *addr, len));
2583248925Snp}
2584248925Snp
2585308305Sjhbstatic int
2586308305Sjhbfixup_devlog_params(struct adapter *sc)
2587248925Snp{
2588308305Sjhb	struct devlog_params *dparams = &sc->params.devlog;
2589308305Sjhb	int rc;
2590248925Snp
2591308305Sjhb	rc = validate_mt_off_len(sc, dparams->memtype, dparams->start,
2592308305Sjhb	    dparams->size, &dparams->addr);
2593248925Snp
2594308305Sjhb	return (rc);
2595248925Snp}
2596248925Snp
2597248925Snpstatic int
2598308154Sjhbcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, int num_vis,
2599218792Snp    struct intrs_and_queues *iaq)
2600218792Snp{
2601228561Snp	int rc, itype, navail, nrxq10g, nrxq1g, n;
2602228561Snp	int nofldrxq10g = 0, nofldrxq1g = 0;
2603218792Snp
2604218792Snp	bzero(iaq, sizeof(*iaq));
2605218792Snp
2606228561Snp	iaq->ntxq10g = t4_ntxq10g;
2607228561Snp	iaq->ntxq1g = t4_ntxq1g;
2608308154Sjhb	iaq->ntxq_vi = t4_ntxq_vi;
2609228561Snp	iaq->nrxq10g = nrxq10g = t4_nrxq10g;
2610228561Snp	iaq->nrxq1g = nrxq1g = t4_nrxq1g;
2611308154Sjhb	iaq->nrxq_vi = t4_nrxq_vi;
2612264493Sscottl	iaq->rsrv_noflowq = t4_rsrv_noflowq;
2613237263Snp#ifdef TCP_OFFLOAD
2614237463Snp	if (is_offload(sc)) {
2615237463Snp		iaq->nofldtxq10g = t4_nofldtxq10g;
2616237463Snp		iaq->nofldtxq1g = t4_nofldtxq1g;
2617308154Sjhb		iaq->nofldtxq_vi = t4_nofldtxq_vi;
2618237463Snp		iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g;
2619237463Snp		iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g;
2620308154Sjhb		iaq->nofldrxq_vi = t4_nofldrxq_vi;
2621237463Snp	}
2622228561Snp#endif
2623270297Snp#ifdef DEV_NETMAP
2624308154Sjhb	iaq->nnmtxq_vi = t4_nnmtxq_vi;
2625308154Sjhb	iaq->nnmrxq_vi = t4_nnmrxq_vi;
2626270297Snp#endif
2627228561Snp
2628219944Snp	for (itype = INTR_MSIX; itype; itype >>= 1) {
2629218792Snp
2630228561Snp		if ((itype & t4_intr_types) == 0)
2631218792Snp			continue;	/* not allowed */
2632218792Snp
2633219944Snp		if (itype == INTR_MSIX)
2634218792Snp			navail = pci_msix_count(sc->dev);
2635219944Snp		else if (itype == INTR_MSI)
2636218792Snp			navail = pci_msi_count(sc->dev);
2637218792Snp		else
2638218792Snp			navail = 1;
2639228561Snprestart:
2640218792Snp		if (navail == 0)
2641218792Snp			continue;
2642218792Snp
2643218792Snp		iaq->intr_type = itype;
2644270297Snp		iaq->intr_flags_10g = 0;
2645270297Snp		iaq->intr_flags_1g = 0;
2646218792Snp
2647228561Snp		/*
2648228561Snp		 * Best option: an interrupt vector for errors, one for the
2649308154Sjhb		 * firmware event queue, and one for every rxq (NIC and TOE) of
2650308154Sjhb		 * every VI.  The VIs that support netmap use the same
2651308154Sjhb		 * interrupts for the NIC rx queues and the netmap rx queues
2652308154Sjhb		 * because only one set of queues is active at a time.
2653228561Snp		 */
2654228561Snp		iaq->nirq = T4_EXTRA_INTR;
2655308154Sjhb		iaq->nirq += n10g * (nrxq10g + nofldrxq10g);
2656308154Sjhb		iaq->nirq += n1g * (nrxq1g + nofldrxq1g);
2657308154Sjhb		iaq->nirq += (n10g + n1g) * (num_vis - 1) *
2658308154Sjhb		    max(iaq->nrxq_vi, iaq->nnmrxq_vi);	/* See comment above. */
2659308154Sjhb		iaq->nirq += (n10g + n1g) * (num_vis - 1) * iaq->nofldrxq_vi;
2660228561Snp		if (iaq->nirq <= navail &&
2661228561Snp		    (itype != INTR_MSI || powerof2(iaq->nirq))) {
2662270297Snp			iaq->intr_flags_10g = INTR_ALL;
2663270297Snp			iaq->intr_flags_1g = INTR_ALL;
2664228561Snp			goto allocate;
2665228561Snp		}
2666218792Snp
2667308154Sjhb		/* Disable the VIs (and netmap) if there aren't enough intrs */
2668308154Sjhb		if (num_vis > 1) {
2669308154Sjhb			device_printf(sc->dev, "virtual interfaces disabled "
2670308154Sjhb			    "because num_vis=%u with current settings "
2671308154Sjhb			    "(nrxq10g=%u, nrxq1g=%u, nofldrxq10g=%u, "
2672308154Sjhb			    "nofldrxq1g=%u, nrxq_vi=%u nofldrxq_vi=%u, "
2673308154Sjhb			    "nnmrxq_vi=%u) would need %u interrupts but "
2674308154Sjhb			    "only %u are available.\n", num_vis, nrxq10g,
2675308154Sjhb			    nrxq1g, nofldrxq10g, nofldrxq1g, iaq->nrxq_vi,
2676308154Sjhb			    iaq->nofldrxq_vi, iaq->nnmrxq_vi, iaq->nirq,
2677308154Sjhb			    navail);
2678308154Sjhb			num_vis = 1;
2679308154Sjhb			iaq->ntxq_vi = iaq->nrxq_vi = 0;
2680308154Sjhb			iaq->nofldtxq_vi = iaq->nofldrxq_vi = 0;
2681308154Sjhb			iaq->nnmtxq_vi = iaq->nnmrxq_vi = 0;
2682308154Sjhb			goto restart;
2683308154Sjhb		}
2684308154Sjhb
2685228561Snp		/*
2686270297Snp		 * Second best option: a vector for errors, one for the firmware
2687270297Snp		 * event queue, and vectors for either all the NIC rx queues or
2688270297Snp		 * all the TOE rx queues.  The queues that don't get vectors
2689270297Snp		 * will forward their interrupts to those that do.
2690228561Snp		 */
2691228561Snp		iaq->nirq = T4_EXTRA_INTR;
2692270297Snp		if (nrxq10g >= nofldrxq10g) {
2693270297Snp			iaq->intr_flags_10g = INTR_RXQ;
2694270297Snp			iaq->nirq += n10g * nrxq10g;
2695270297Snp		} else {
2696270297Snp			iaq->intr_flags_10g = INTR_OFLD_RXQ;
2697270297Snp			iaq->nirq += n10g * nofldrxq10g;
2698270297Snp		}
2699270297Snp		if (nrxq1g >= nofldrxq1g) {
2700270297Snp			iaq->intr_flags_1g = INTR_RXQ;
2701270297Snp			iaq->nirq += n1g * nrxq1g;
2702270297Snp		} else {
2703270297Snp			iaq->intr_flags_1g = INTR_OFLD_RXQ;
2704270297Snp			iaq->nirq += n1g * nofldrxq1g;
2705270297Snp		}
2706228561Snp		if (iaq->nirq <= navail &&
2707228561Snp		    (itype != INTR_MSI || powerof2(iaq->nirq)))
2708228561Snp			goto allocate;
2709218792Snp
2710228561Snp		/*
2711228561Snp		 * Next best option: an interrupt vector for errors, one for the
2712308154Sjhb		 * firmware event queue, and at least one per main-VI.  At this
2713308154Sjhb		 * point we know we'll have to downsize nrxq and/or nofldrxq to
2714308154Sjhb		 * fit what's available to us.
2715228561Snp		 */
2716228561Snp		iaq->nirq = T4_EXTRA_INTR;
2717228561Snp		iaq->nirq += n10g + n1g;
2718228561Snp		if (iaq->nirq <= navail) {
2719228561Snp			int leftover = navail - iaq->nirq;
2720218792Snp
2721228561Snp			if (n10g > 0) {
2722228561Snp				int target = max(nrxq10g, nofldrxq10g);
2723219944Snp
2724270297Snp				iaq->intr_flags_10g = nrxq10g >= nofldrxq10g ?
2725270297Snp				    INTR_RXQ : INTR_OFLD_RXQ;
2726270297Snp
2727228561Snp				n = 1;
2728228561Snp				while (n < target && leftover >= n10g) {
2729228561Snp					leftover -= n10g;
2730228561Snp					iaq->nirq += n10g;
2731228561Snp					n++;
2732228561Snp				}
2733228561Snp				iaq->nrxq10g = min(n, nrxq10g);
2734237263Snp#ifdef TCP_OFFLOAD
2735270297Snp				iaq->nofldrxq10g = min(n, nofldrxq10g);
2736228561Snp#endif
2737228561Snp			}
2738218792Snp
2739228561Snp			if (n1g > 0) {
2740228561Snp				int target = max(nrxq1g, nofldrxq1g);
2741219944Snp
2742270297Snp				iaq->intr_flags_1g = nrxq1g >= nofldrxq1g ?
2743270297Snp				    INTR_RXQ : INTR_OFLD_RXQ;
2744270297Snp
2745228561Snp				n = 1;
2746228561Snp				while (n < target && leftover >= n1g) {
2747228561Snp					leftover -= n1g;
2748228561Snp					iaq->nirq += n1g;
2749228561Snp					n++;
2750219944Snp				}
2751228561Snp				iaq->nrxq1g = min(n, nrxq1g);
2752237263Snp#ifdef TCP_OFFLOAD
2753270297Snp				iaq->nofldrxq1g = min(n, nofldrxq1g);
2754228561Snp#endif
2755219944Snp			}
2756219944Snp
2757228561Snp			if (itype != INTR_MSI || powerof2(iaq->nirq))
2758228561Snp				goto allocate;
2759218792Snp		}
2760218792Snp
2761228561Snp		/*
2762228561Snp		 * Least desirable option: one interrupt vector for everything.
2763228561Snp		 */
2764228561Snp		iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1;
2765270297Snp		iaq->intr_flags_10g = iaq->intr_flags_1g = 0;
2766237263Snp#ifdef TCP_OFFLOAD
2767237463Snp		if (is_offload(sc))
2768237463Snp			iaq->nofldrxq10g = iaq->nofldrxq1g = 1;
2769228561Snp#endif
2770228561Snpallocate:
2771218792Snp		navail = iaq->nirq;
2772218792Snp		rc = 0;
2773219944Snp		if (itype == INTR_MSIX)
2774218792Snp			rc = pci_alloc_msix(sc->dev, &navail);
2775219944Snp		else if (itype == INTR_MSI)
2776218792Snp			rc = pci_alloc_msi(sc->dev, &navail);
2777218792Snp
2778218792Snp		if (rc == 0) {
2779218792Snp			if (navail == iaq->nirq)
2780218792Snp				return (0);
2781218792Snp
2782218792Snp			/*
2783218792Snp			 * Didn't get the number requested.  Use whatever number
2784218792Snp			 * the kernel is willing to allocate (it's in navail).
2785218792Snp			 */
2786228561Snp			device_printf(sc->dev, "fewer vectors than requested, "
2787228561Snp			    "type=%d, req=%d, rcvd=%d; will downshift req.\n",
2788228561Snp			    itype, iaq->nirq, navail);
2789218792Snp			pci_release_msi(sc->dev);
2790228561Snp			goto restart;
2791218792Snp		}
2792218792Snp
2793218792Snp		device_printf(sc->dev,
2794218792Snp		    "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n",
2795218792Snp		    itype, rc, iaq->nirq, navail);
2796218792Snp	}
2797218792Snp
2798218792Snp	device_printf(sc->dev,
2799218792Snp	    "failed to find a usable interrupt type.  "
2800228561Snp	    "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types,
2801218792Snp	    pci_msix_count(sc->dev), pci_msi_count(sc->dev));
2802218792Snp
2803218792Snp	return (ENXIO);
2804218792Snp}
2805218792Snp
2806248925Snp#define FW_VERSION(chip) ( \
2807252661Snp    V_FW_HDR_FW_VER_MAJOR(chip##FW_VERSION_MAJOR) | \
2808252661Snp    V_FW_HDR_FW_VER_MINOR(chip##FW_VERSION_MINOR) | \
2809252661Snp    V_FW_HDR_FW_VER_MICRO(chip##FW_VERSION_MICRO) | \
2810252661Snp    V_FW_HDR_FW_VER_BUILD(chip##FW_VERSION_BUILD))
2811252661Snp#define FW_INTFVER(chip, intf) (chip##FW_HDR_INTFVER_##intf)
2812248925Snp
2813248925Snpstruct fw_info {
2814248925Snp	uint8_t chip;
2815248925Snp	char *kld_name;
2816248925Snp	char *fw_mod_name;
2817248925Snp	struct fw_hdr fw_hdr;	/* XXX: waste of space, need a sparse struct */
2818248925Snp} fw_info[] = {
2819248925Snp	{
2820248925Snp		.chip = CHELSIO_T4,
2821248925Snp		.kld_name = "t4fw_cfg",
2822248925Snp		.fw_mod_name = "t4fw",
2823248925Snp		.fw_hdr = {
2824248925Snp			.chip = FW_HDR_CHIP_T4,
2825248925Snp			.fw_ver = htobe32_const(FW_VERSION(T4)),
2826248925Snp			.intfver_nic = FW_INTFVER(T4, NIC),
2827248925Snp			.intfver_vnic = FW_INTFVER(T4, VNIC),
2828248925Snp			.intfver_ofld = FW_INTFVER(T4, OFLD),
2829248925Snp			.intfver_ri = FW_INTFVER(T4, RI),
2830248925Snp			.intfver_iscsipdu = FW_INTFVER(T4, ISCSIPDU),
2831248925Snp			.intfver_iscsi = FW_INTFVER(T4, ISCSI),
2832248925Snp			.intfver_fcoepdu = FW_INTFVER(T4, FCOEPDU),
2833248925Snp			.intfver_fcoe = FW_INTFVER(T4, FCOE),
2834248925Snp		},
2835248925Snp	}, {
2836248925Snp		.chip = CHELSIO_T5,
2837248925Snp		.kld_name = "t5fw_cfg",
2838248925Snp		.fw_mod_name = "t5fw",
2839248925Snp		.fw_hdr = {
2840248925Snp			.chip = FW_HDR_CHIP_T5,
2841248925Snp			.fw_ver = htobe32_const(FW_VERSION(T5)),
2842248925Snp			.intfver_nic = FW_INTFVER(T5, NIC),
2843248925Snp			.intfver_vnic = FW_INTFVER(T5, VNIC),
2844248925Snp			.intfver_ofld = FW_INTFVER(T5, OFLD),
2845248925Snp			.intfver_ri = FW_INTFVER(T5, RI),
2846248925Snp			.intfver_iscsipdu = FW_INTFVER(T5, ISCSIPDU),
2847248925Snp			.intfver_iscsi = FW_INTFVER(T5, ISCSI),
2848248925Snp			.intfver_fcoepdu = FW_INTFVER(T5, FCOEPDU),
2849248925Snp			.intfver_fcoe = FW_INTFVER(T5, FCOE),
2850248925Snp		},
2851309560Sjhb	}, {
2852309560Sjhb		.chip = CHELSIO_T6,
2853309560Sjhb		.kld_name = "t6fw_cfg",
2854309560Sjhb		.fw_mod_name = "t6fw",
2855309560Sjhb		.fw_hdr = {
2856309560Sjhb			.chip = FW_HDR_CHIP_T6,
2857309560Sjhb			.fw_ver = htobe32_const(FW_VERSION(T6)),
2858309560Sjhb			.intfver_nic = FW_INTFVER(T6, NIC),
2859309560Sjhb			.intfver_vnic = FW_INTFVER(T6, VNIC),
2860309560Sjhb			.intfver_ofld = FW_INTFVER(T6, OFLD),
2861309560Sjhb			.intfver_ri = FW_INTFVER(T6, RI),
2862309560Sjhb			.intfver_iscsipdu = FW_INTFVER(T6, ISCSIPDU),
2863309560Sjhb			.intfver_iscsi = FW_INTFVER(T6, ISCSI),
2864309560Sjhb			.intfver_fcoepdu = FW_INTFVER(T6, FCOEPDU),
2865309560Sjhb			.intfver_fcoe = FW_INTFVER(T6, FCOE),
2866309560Sjhb		},
2867248925Snp	}
2868248925Snp};
2869248925Snp
2870248925Snpstatic struct fw_info *
2871248925Snpfind_fw_info(int chip)
2872248925Snp{
2873248925Snp	int i;
2874248925Snp
2875248925Snp	for (i = 0; i < nitems(fw_info); i++) {
2876248925Snp		if (fw_info[i].chip == chip)
2877248925Snp			return (&fw_info[i]);
2878248925Snp	}
2879248925Snp	return (NULL);
2880248925Snp}
2881248925Snp
2882218792Snp/*
2883248925Snp * Is the given firmware API compatible with the one the driver was compiled
2884248925Snp * with?
2885247347Snp */
2886247347Snpstatic int
2887248925Snpfw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2)
2888247347Snp{
2889247347Snp
2890248925Snp	/* short circuit if it's the exact same firmware version */
2891248925Snp	if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver)
2892247347Snp		return (1);
2893247347Snp
2894247347Snp	/*
2895247347Snp	 * XXX: Is this too conservative?  Perhaps I should limit this to the
2896247347Snp	 * features that are supported in the driver.
2897247347Snp	 */
2898248925Snp#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x)
2899248925Snp	if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) &&
2900248925Snp	    SAME_INTF(ofld) && SAME_INTF(ri) && SAME_INTF(iscsipdu) &&
2901248925Snp	    SAME_INTF(iscsi) && SAME_INTF(fcoepdu) && SAME_INTF(fcoe))
2902247347Snp		return (1);
2903248925Snp#undef SAME_INTF
2904247347Snp
2905247347Snp	return (0);
2906247347Snp}
2907247347Snp
2908247347Snp/*
2909251434Snp * The firmware in the KLD is usable, but should it be installed?  This routine
2910251434Snp * explains itself in detail if it indicates the KLD firmware should be
2911251434Snp * installed.
2912249376Snp */
2913249376Snpstatic int
2914249376Snpshould_install_kld_fw(struct adapter *sc, int card_fw_usable, int k, int c)
2915249376Snp{
2916249376Snp	const char *reason;
2917249376Snp
2918249376Snp	if (!card_fw_usable) {
2919249376Snp		reason = "incompatible or unusable";
2920249376Snp		goto install;
2921249376Snp	}
2922249376Snp
2923249376Snp	if (k > c) {
2924249376Snp		reason = "older than the version bundled with this driver";
2925249376Snp		goto install;
2926249376Snp	}
2927249376Snp
2928249376Snp	if (t4_fw_install == 2 && k != c) {
2929249376Snp		reason = "different than the version bundled with this driver";
2930249376Snp		goto install;
2931249376Snp	}
2932249376Snp
2933249376Snp	return (0);
2934249376Snp
2935249376Snpinstall:
2936251434Snp	if (t4_fw_install == 0) {
2937251434Snp		device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, "
2938251434Snp		    "but the driver is prohibited from installing a different "
2939251434Snp		    "firmware on the card.\n",
2940251434Snp		    G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c),
2941251434Snp		    G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason);
2942251434Snp
2943251434Snp		return (0);
2944251434Snp	}
2945251434Snp
2946249376Snp	device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, "
2947249376Snp	    "installing firmware %u.%u.%u.%u on card.\n",
2948249376Snp	    G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c),
2949249376Snp	    G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason,
2950249376Snp	    G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k),
2951249376Snp	    G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k));
2952249376Snp
2953249376Snp	return (1);
2954249376Snp}
2955249376Snp/*
2956248925Snp * Establish contact with the firmware and determine if we are the master driver
2957248925Snp * or not, and whether we are responsible for chip initialization.
2958218792Snp */
2959218792Snpstatic int
2960218792Snpprep_firmware(struct adapter *sc)
2961218792Snp{
2962248925Snp	const struct firmware *fw = NULL, *default_cfg;
2963248925Snp	int rc, pf, card_fw_usable, kld_fw_usable, need_fw_reset = 1;
2964218792Snp	enum dev_state state;
2965248925Snp	struct fw_info *fw_info;
2966248925Snp	struct fw_hdr *card_fw;		/* fw on the card */
2967248925Snp	const struct fw_hdr *kld_fw;	/* fw in the KLD */
2968248925Snp	const struct fw_hdr *drv_fw;	/* fw header the driver was compiled
2969248925Snp					   against */
2970218792Snp
2971248925Snp	/* Contact firmware. */
2972248925Snp	rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state);
2973248925Snp	if (rc < 0 || state == DEV_STATE_ERR) {
2974248925Snp		rc = -rc;
2975248925Snp		device_printf(sc->dev,
2976248925Snp		    "failed to connect to the firmware: %d, %d.\n", rc, state);
2977248925Snp		return (rc);
2978248925Snp	}
2979248925Snp	pf = rc;
2980248925Snp	if (pf == sc->mbox)
2981248925Snp		sc->flags |= MASTER_PF;
2982248925Snp	else if (state == DEV_STATE_UNINIT) {
2983248925Snp		/*
2984248925Snp		 * We didn't get to be the master so we definitely won't be
2985248925Snp		 * configuring the chip.  It's a bug if someone else hasn't
2986248925Snp		 * configured it already.
2987248925Snp		 */
2988248925Snp		device_printf(sc->dev, "couldn't be master(%d), "
2989248925Snp		    "device not already initialized either(%d).\n", rc, state);
2990248925Snp		return (EDOOFUS);
2991248925Snp	}
2992228561Snp
2993248925Snp	/* This is the firmware whose headers the driver was compiled against */
2994248925Snp	fw_info = find_fw_info(chip_id(sc));
2995248925Snp	if (fw_info == NULL) {
2996248925Snp		device_printf(sc->dev,
2997248925Snp		    "unable to look up firmware information for chip %d.\n",
2998248925Snp		    chip_id(sc));
2999248925Snp		return (EINVAL);
3000248925Snp	}
3001248925Snp	drv_fw = &fw_info->fw_hdr;
3002248925Snp
3003248925Snp	/*
3004248925Snp	 * The firmware KLD contains many modules.  The KLD name is also the
3005248925Snp	 * name of the module that contains the default config file.
3006248925Snp	 */
3007248925Snp	default_cfg = firmware_get(fw_info->kld_name);
3008248925Snp
3009247347Snp	/* Read the header of the firmware on the card */
3010247347Snp	card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK);
3011247347Snp	rc = -t4_read_flash(sc, FLASH_FW_START,
3012247347Snp	    sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1);
3013247347Snp	if (rc == 0)
3014248925Snp		card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw);
3015247347Snp	else {
3016247347Snp		device_printf(sc->dev,
3017247347Snp		    "Unable to read card's firmware header: %d\n", rc);
3018247347Snp		card_fw_usable = 0;
3019247347Snp	}
3020218792Snp
3021247347Snp	/* This is the firmware in the KLD */
3022248925Snp	fw = firmware_get(fw_info->fw_mod_name);
3023247347Snp	if (fw != NULL) {
3024247347Snp		kld_fw = (const void *)fw->data;
3025248925Snp		kld_fw_usable = fw_compatible(drv_fw, kld_fw);
3026247347Snp	} else {
3027247347Snp		kld_fw = NULL;
3028247347Snp		kld_fw_usable = 0;
3029247347Snp	}
3030219287Snp
3031248925Snp	if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver &&
3032251434Snp	    (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver)) {
3033248925Snp		/*
3034248925Snp		 * Common case: the firmware on the card is an exact match and
3035248925Snp		 * the KLD is an exact match too, or the KLD is
3036251434Snp		 * absent/incompatible.  Note that t4_fw_install = 2 is ignored
3037251434Snp		 * here -- use cxgbetool loadfw if you want to reinstall the
3038251434Snp		 * same firmware as the one on the card.
3039248925Snp		 */
3040248925Snp	} else if (kld_fw_usable && state == DEV_STATE_UNINIT &&
3041249376Snp	    should_install_kld_fw(sc, card_fw_usable, be32toh(kld_fw->fw_ver),
3042249376Snp	    be32toh(card_fw->fw_ver))) {
3043219287Snp
3044250221Snp		rc = -t4_fw_upgrade(sc, sc->mbox, fw->data, fw->datasize, 0);
3045247347Snp		if (rc != 0) {
3046247347Snp			device_printf(sc->dev,
3047247347Snp			    "failed to install firmware: %d\n", rc);
3048228561Snp			goto done;
3049219287Snp		}
3050219287Snp
3051247347Snp		/* Installed successfully, update the cached header too. */
3052247347Snp		memcpy(card_fw, kld_fw, sizeof(*card_fw));
3053247347Snp		card_fw_usable = 1;
3054248925Snp		need_fw_reset = 0;	/* already reset as part of load_fw */
3055247347Snp	}
3056219287Snp
3057247347Snp	if (!card_fw_usable) {
3058248925Snp		uint32_t d, c, k;
3059247347Snp
3060248925Snp		d = ntohl(drv_fw->fw_ver);
3061247347Snp		c = ntohl(card_fw->fw_ver);
3062247347Snp		k = kld_fw ? ntohl(kld_fw->fw_ver) : 0;
3063247347Snp
3064247347Snp		device_printf(sc->dev, "Cannot find a usable firmware: "
3065248925Snp		    "fw_install %d, chip state %d, "
3066248925Snp		    "driver compiled with %d.%d.%d.%d, "
3067247347Snp		    "card has %d.%d.%d.%d, KLD has %d.%d.%d.%d\n",
3068248925Snp		    t4_fw_install, state,
3069248925Snp		    G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d),
3070248925Snp		    G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d),
3071247347Snp		    G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c),
3072247347Snp		    G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c),
3073247347Snp		    G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k),
3074247347Snp		    G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k));
3075248925Snp		rc = EINVAL;
3076247347Snp		goto done;
3077218792Snp	}
3078218792Snp
3079218792Snp	/* Reset device */
3080248925Snp	if (need_fw_reset &&
3081248925Snp	    (rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST)) != 0) {
3082218792Snp		device_printf(sc->dev, "firmware reset failed: %d.\n", rc);
3083218792Snp		if (rc != ETIMEDOUT && rc != EIO)
3084218792Snp			t4_fw_bye(sc, sc->mbox);
3085228561Snp		goto done;
3086218792Snp	}
3087248925Snp	sc->flags |= FW_OK;
3088218792Snp
3089248925Snp	rc = get_params__pre_init(sc);
3090248925Snp	if (rc != 0)
3091248925Snp		goto done; /* error message displayed already */
3092248925Snp
3093228561Snp	/* Partition adapter resources as specified in the config file. */
3094248925Snp	if (state == DEV_STATE_UNINIT) {
3095228561Snp
3096248925Snp		KASSERT(sc->flags & MASTER_PF,
3097248925Snp		    ("%s: trying to change chip settings when not master.",
3098248925Snp		    __func__));
3099228561Snp
3100248925Snp		rc = partition_resources(sc, default_cfg, fw_info->kld_name);
3101228561Snp		if (rc != 0)
3102228561Snp			goto done;	/* error message displayed already */
3103248925Snp
3104248925Snp		t4_tweak_chip_settings(sc);
3105248925Snp
3106248925Snp		/* get basic stuff going */
3107248925Snp		rc = -t4_fw_initialize(sc, sc->mbox);
3108248925Snp		if (rc != 0) {
3109248925Snp			device_printf(sc->dev, "fw init failed: %d.\n", rc);
3110248925Snp			goto done;
3111248925Snp		}
3112245936Snp	} else {
3113248925Snp		snprintf(sc->cfg_file, sizeof(sc->cfg_file), "pf%d", pf);
3114248925Snp		sc->cfcsum = 0;
3115228561Snp	}
3116228561Snp
3117228561Snpdone:
3118247347Snp	free(card_fw, M_CXGBE);
3119228561Snp	if (fw != NULL)
3120228561Snp		firmware_put(fw, FIRMWARE_UNLOAD);
3121228561Snp	if (default_cfg != NULL)
3122228561Snp		firmware_put(default_cfg, FIRMWARE_UNLOAD);
3123228561Snp
3124228561Snp	return (rc);
3125218792Snp}
3126218792Snp
3127228561Snp#define FW_PARAM_DEV(param) \
3128228561Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
3129228561Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
3130228561Snp#define FW_PARAM_PFVF(param) \
3131228561Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
3132228561Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param))
3133228561Snp
3134228561Snp/*
3135248925Snp * Partition chip resources for use between various PFs, VFs, etc.
3136228561Snp */
3137218792Snpstatic int
3138248925Snppartition_resources(struct adapter *sc, const struct firmware *default_cfg,
3139248925Snp    const char *name_prefix)
3140222551Snp{
3141248925Snp	const struct firmware *cfg = NULL;
3142248925Snp	int rc = 0;
3143248925Snp	struct fw_caps_config_cmd caps;
3144248925Snp	uint32_t mtype, moff, finicsum, cfcsum;
3145222551Snp
3146248925Snp	/*
3147248925Snp	 * Figure out what configuration file to use.  Pick the default config
3148248925Snp	 * file for the card if the user hasn't specified one explicitly.
3149248925Snp	 */
3150248925Snp	snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", t4_cfg_file);
3151248925Snp	if (strncmp(t4_cfg_file, DEFAULT_CF, sizeof(t4_cfg_file)) == 0) {
3152248925Snp		/* Card specific overrides go here. */
3153248925Snp		if (pci_get_device(sc->dev) == 0x440a)
3154248925Snp			snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF);
3155249376Snp		if (is_fpga(sc))
3156249376Snp			snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF);
3157222551Snp	}
3158222551Snp
3159248925Snp	/*
3160248925Snp	 * We need to load another module if the profile is anything except
3161248925Snp	 * "default" or "flash".
3162248925Snp	 */
3163248925Snp	if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) != 0 &&
3164248925Snp	    strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) {
3165248925Snp		char s[32];
3166248925Snp
3167248925Snp		snprintf(s, sizeof(s), "%s_%s", name_prefix, sc->cfg_file);
3168248925Snp		cfg = firmware_get(s);
3169248925Snp		if (cfg == NULL) {
3170248925Snp			if (default_cfg != NULL) {
3171249376Snp				device_printf(sc->dev,
3172249376Snp				    "unable to load module \"%s\" for "
3173249376Snp				    "configuration profile \"%s\", will use "
3174249376Snp				    "the default config file instead.\n",
3175249376Snp				    s, sc->cfg_file);
3176248925Snp				snprintf(sc->cfg_file, sizeof(sc->cfg_file),
3177248925Snp				    "%s", DEFAULT_CF);
3178248925Snp			} else {
3179249376Snp				device_printf(sc->dev,
3180249376Snp				    "unable to load module \"%s\" for "
3181249376Snp				    "configuration profile \"%s\", will use "
3182249376Snp				    "the config file on the card's flash "
3183249376Snp				    "instead.\n", s, sc->cfg_file);
3184248925Snp				snprintf(sc->cfg_file, sizeof(sc->cfg_file),
3185248925Snp				    "%s", FLASH_CF);
3186248925Snp			}
3187248925Snp		}
3188228561Snp	}
3189222551Snp
3190248925Snp	if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) == 0 &&
3191248925Snp	    default_cfg == NULL) {
3192228561Snp		device_printf(sc->dev,
3193248925Snp		    "default config file not available, will use the config "
3194248925Snp		    "file on the card's flash instead.\n");
3195248925Snp		snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", FLASH_CF);
3196228561Snp	}
3197228561Snp
3198248925Snp	if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) {
3199308305Sjhb		u_int cflen;
3200248925Snp		const uint32_t *cfdata;
3201308305Sjhb		uint32_t param, val, addr;
3202228561Snp
3203248925Snp		KASSERT(cfg != NULL || default_cfg != NULL,
3204248925Snp		    ("%s: no config to upload", __func__));
3205228561Snp
3206248925Snp		/*
3207248925Snp		 * Ask the firmware where it wants us to upload the config file.
3208248925Snp		 */
3209248925Snp		param = FW_PARAM_DEV(CF);
3210248925Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
3211248925Snp		if (rc != 0) {
3212248925Snp			/* No support for config file?  Shouldn't happen. */
3213248925Snp			device_printf(sc->dev,
3214248925Snp			    "failed to query config file location: %d.\n", rc);
3215248925Snp			goto done;
3216248925Snp		}
3217248925Snp		mtype = G_FW_PARAMS_PARAM_Y(val);
3218248925Snp		moff = G_FW_PARAMS_PARAM_Z(val) << 16;
3219228561Snp
3220248925Snp		/*
3221248925Snp		 * XXX: sheer laziness.  We deliberately added 4 bytes of
3222248925Snp		 * useless stuffing/comments at the end of the config file so
3223248925Snp		 * it's ok to simply throw away the last remaining bytes when
3224248925Snp		 * the config file is not an exact multiple of 4.  This also
3225248925Snp		 * helps with the validate_mt_off_len check.
3226248925Snp		 */
3227248925Snp		if (cfg != NULL) {
3228248925Snp			cflen = cfg->datasize & ~3;
3229248925Snp			cfdata = cfg->data;
3230248925Snp		} else {
3231248925Snp			cflen = default_cfg->datasize & ~3;
3232248925Snp			cfdata = default_cfg->data;
3233248925Snp		}
3234222551Snp
3235248925Snp		if (cflen > FLASH_CFG_MAX_SIZE) {
3236248925Snp			device_printf(sc->dev,
3237248925Snp			    "config file too long (%d, max allowed is %d).  "
3238248925Snp			    "Will try to use the config on the card, if any.\n",
3239248925Snp			    cflen, FLASH_CFG_MAX_SIZE);
3240248925Snp			goto use_config_on_flash;
3241248925Snp		}
3242218792Snp
3243248925Snp		rc = validate_mt_off_len(sc, mtype, moff, cflen, &addr);
3244248925Snp		if (rc != 0) {
3245248925Snp			device_printf(sc->dev,
3246248925Snp			    "%s: addr (%d/0x%x) or len %d is not valid: %d.  "
3247248925Snp			    "Will try to use the config on the card, if any.\n",
3248248925Snp			    __func__, mtype, moff, cflen, rc);
3249248925Snp			goto use_config_on_flash;
3250248925Snp		}
3251308305Sjhb		write_via_memwin(sc, 2, addr, cfdata, cflen);
3252248925Snp	} else {
3253248925Snpuse_config_on_flash:
3254256791Snp		mtype = FW_MEMTYPE_FLASH;
3255248925Snp		moff = t4_flash_cfg_addr(sc);
3256228561Snp	}
3257228561Snp
3258228561Snp	bzero(&caps, sizeof(caps));
3259228561Snp	caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
3260218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
3261228561Snp	caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID |
3262228561Snp	    V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
3263248925Snp	    V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(moff >> 16) | FW_LEN16(caps));
3264228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps);
3265228561Snp	if (rc != 0) {
3266228561Snp		device_printf(sc->dev,
3267249376Snp		    "failed to pre-process config file: %d "
3268249376Snp		    "(mtype %d, moff 0x%x).\n", rc, mtype, moff);
3269248925Snp		goto done;
3270228561Snp	}
3271218792Snp
3272228561Snp	finicsum = be32toh(caps.finicsum);
3273228561Snp	cfcsum = be32toh(caps.cfcsum);
3274228561Snp	if (finicsum != cfcsum) {
3275228561Snp		device_printf(sc->dev,
3276228561Snp		    "WARNING: config file checksum mismatch: %08x %08x\n",
3277228561Snp		    finicsum, cfcsum);
3278228561Snp	}
3279228561Snp	sc->cfcsum = cfcsum;
3280218792Snp
3281228561Snp#define LIMIT_CAPS(x) do { \
3282228561Snp	caps.x &= htobe16(t4_##x##_allowed); \
3283228561Snp} while (0)
3284228561Snp
3285228561Snp	/*
3286228561Snp	 * Let the firmware know what features will (not) be used so it can tune
3287228561Snp	 * things accordingly.
3288228561Snp	 */
3289308304Sjhb	LIMIT_CAPS(nbmcaps);
3290228561Snp	LIMIT_CAPS(linkcaps);
3291308304Sjhb	LIMIT_CAPS(switchcaps);
3292228561Snp	LIMIT_CAPS(niccaps);
3293228561Snp	LIMIT_CAPS(toecaps);
3294228561Snp	LIMIT_CAPS(rdmacaps);
3295309560Sjhb	LIMIT_CAPS(cryptocaps);
3296228561Snp	LIMIT_CAPS(iscsicaps);
3297228561Snp	LIMIT_CAPS(fcoecaps);
3298228561Snp#undef LIMIT_CAPS
3299228561Snp
3300228561Snp	caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
3301218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
3302228561Snp	caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps));
3303228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL);
3304228561Snp	if (rc != 0) {
3305228561Snp		device_printf(sc->dev,
3306228561Snp		    "failed to process config file: %d.\n", rc);
3307228561Snp	}
3308248925Snpdone:
3309248925Snp	if (cfg != NULL)
3310248925Snp		firmware_put(cfg, FIRMWARE_UNLOAD);
3311248925Snp	return (rc);
3312218792Snp}
3313218792Snp
3314228561Snp/*
3315248925Snp * Retrieve parameters that are needed (or nice to have) very early.
3316228561Snp */
3317218792Snpstatic int
3318228561Snpget_params__pre_init(struct adapter *sc)
3319218792Snp{
3320218792Snp	int rc;
3321228561Snp	uint32_t param[2], val[2];
3322218792Snp
3323309458Sjhb	t4_get_version_info(sc);
3324309458Sjhb
3325309458Sjhb	snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u",
3326309458Sjhb	    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
3327309458Sjhb	    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
3328309458Sjhb	    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
3329309458Sjhb	    G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers));
3330309458Sjhb
3331309458Sjhb	snprintf(sc->bs_version, sizeof(sc->bs_version), "%u.%u.%u.%u",
3332309458Sjhb	    G_FW_HDR_FW_VER_MAJOR(sc->params.bs_vers),
3333309458Sjhb	    G_FW_HDR_FW_VER_MINOR(sc->params.bs_vers),
3334309458Sjhb	    G_FW_HDR_FW_VER_MICRO(sc->params.bs_vers),
3335309458Sjhb	    G_FW_HDR_FW_VER_BUILD(sc->params.bs_vers));
3336309458Sjhb
3337309458Sjhb	snprintf(sc->tp_version, sizeof(sc->tp_version), "%u.%u.%u.%u",
3338309458Sjhb	    G_FW_HDR_FW_VER_MAJOR(sc->params.tp_vers),
3339309458Sjhb	    G_FW_HDR_FW_VER_MINOR(sc->params.tp_vers),
3340309458Sjhb	    G_FW_HDR_FW_VER_MICRO(sc->params.tp_vers),
3341309458Sjhb	    G_FW_HDR_FW_VER_BUILD(sc->params.tp_vers));
3342309458Sjhb
3343309458Sjhb	snprintf(sc->er_version, sizeof(sc->er_version), "%u.%u.%u.%u",
3344309458Sjhb	    G_FW_HDR_FW_VER_MAJOR(sc->params.er_vers),
3345309458Sjhb	    G_FW_HDR_FW_VER_MINOR(sc->params.er_vers),
3346309458Sjhb	    G_FW_HDR_FW_VER_MICRO(sc->params.er_vers),
3347309458Sjhb	    G_FW_HDR_FW_VER_BUILD(sc->params.er_vers));
3348309458Sjhb
3349228561Snp	param[0] = FW_PARAM_DEV(PORTVEC);
3350228561Snp	param[1] = FW_PARAM_DEV(CCLK);
3351228561Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val);
3352218792Snp	if (rc != 0) {
3353218792Snp		device_printf(sc->dev,
3354228561Snp		    "failed to query parameters (pre_init): %d.\n", rc);
3355228561Snp		return (rc);
3356218792Snp	}
3357218792Snp
3358218792Snp	sc->params.portvec = val[0];
3359240452Snp	sc->params.nports = bitcount32(val[0]);
3360228561Snp	sc->params.vpd.cclk = val[1];
3361218792Snp
3362228561Snp	/* Read device log parameters. */
3363308305Sjhb	rc = -t4_init_devlog_params(sc, 1);
3364308305Sjhb	if (rc == 0)
3365308305Sjhb		fixup_devlog_params(sc);
3366308305Sjhb	else {
3367228561Snp		device_printf(sc->dev,
3368228561Snp		    "failed to get devlog parameters: %d.\n", rc);
3369228561Snp		rc = 0;	/* devlog isn't critical for device operation */
3370228561Snp	}
3371228561Snp
3372228561Snp	return (rc);
3373228561Snp}
3374228561Snp
3375228561Snp/*
3376228561Snp * Retrieve various parameters that are of interest to the driver.  The device
3377228561Snp * has been initialized by the firmware at this point.
3378228561Snp */
3379228561Snpstatic int
3380228561Snpget_params__post_init(struct adapter *sc)
3381228561Snp{
3382228561Snp	int rc;
3383228561Snp	uint32_t param[7], val[7];
3384228561Snp	struct fw_caps_config_cmd caps;
3385228561Snp
3386228561Snp	param[0] = FW_PARAM_PFVF(IQFLINT_START);
3387228561Snp	param[1] = FW_PARAM_PFVF(EQ_START);
3388228561Snp	param[2] = FW_PARAM_PFVF(FILTER_START);
3389228561Snp	param[3] = FW_PARAM_PFVF(FILTER_END);
3390245434Snp	param[4] = FW_PARAM_PFVF(L2T_START);
3391245434Snp	param[5] = FW_PARAM_PFVF(L2T_END);
3392245434Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
3393228561Snp	if (rc != 0) {
3394228561Snp		device_printf(sc->dev,
3395228561Snp		    "failed to query parameters (post_init): %d.\n", rc);
3396228561Snp		return (rc);
3397228561Snp	}
3398228561Snp
3399228561Snp	sc->sge.iq_start = val[0];
3400228561Snp	sc->sge.eq_start = val[1];
3401228561Snp	sc->tids.ftid_base = val[2];
3402228561Snp	sc->tids.nftids = val[3] - val[2] + 1;
3403265426Snp	sc->params.ftid_min = val[2];
3404265426Snp	sc->params.ftid_max = val[3];
3405245434Snp	sc->vres.l2t.start = val[4];
3406245434Snp	sc->vres.l2t.size = val[5] - val[4] + 1;
3407245434Snp	KASSERT(sc->vres.l2t.size <= L2T_SIZE,
3408245434Snp	    ("%s: L2 table size (%u) larger than expected (%u)",
3409245434Snp	    __func__, sc->vres.l2t.size, L2T_SIZE));
3410228561Snp
3411228561Snp	/* get capabilites */
3412228561Snp	bzero(&caps, sizeof(caps));
3413228561Snp	caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
3414228561Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
3415228561Snp	caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps));
3416228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps);
3417228561Snp	if (rc != 0) {
3418228561Snp		device_printf(sc->dev,
3419228561Snp		    "failed to get card capabilities: %d.\n", rc);
3420228561Snp		return (rc);
3421228561Snp	}
3422228561Snp
3423265426Snp#define READ_CAPS(x) do { \
3424265426Snp	sc->x = htobe16(caps.x); \
3425265426Snp} while (0)
3426308304Sjhb	READ_CAPS(nbmcaps);
3427265426Snp	READ_CAPS(linkcaps);
3428308304Sjhb	READ_CAPS(switchcaps);
3429265426Snp	READ_CAPS(niccaps);
3430265426Snp	READ_CAPS(toecaps);
3431265426Snp	READ_CAPS(rdmacaps);
3432309560Sjhb	READ_CAPS(cryptocaps);
3433265426Snp	READ_CAPS(iscsicaps);
3434265426Snp	READ_CAPS(fcoecaps);
3435265426Snp
3436265426Snp	if (sc->niccaps & FW_CAPS_CONFIG_NIC_ETHOFLD) {
3437265426Snp		param[0] = FW_PARAM_PFVF(ETHOFLD_START);
3438265426Snp		param[1] = FW_PARAM_PFVF(ETHOFLD_END);
3439265426Snp		param[2] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
3440265426Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 3, param, val);
3441265426Snp		if (rc != 0) {
3442265426Snp			device_printf(sc->dev,
3443265426Snp			    "failed to query NIC parameters: %d.\n", rc);
3444265426Snp			return (rc);
3445265426Snp		}
3446265426Snp		sc->tids.etid_base = val[0];
3447265426Snp		sc->params.etid_min = val[0];
3448265426Snp		sc->tids.netids = val[1] - val[0] + 1;
3449265426Snp		sc->params.netids = sc->tids.netids;
3450265426Snp		sc->params.eo_wr_cred = val[2];
3451265426Snp		sc->params.ethoffload = 1;
3452265426Snp	}
3453265426Snp
3454265426Snp	if (sc->toecaps) {
3455218792Snp		/* query offload-related parameters */
3456228561Snp		param[0] = FW_PARAM_DEV(NTID);
3457228561Snp		param[1] = FW_PARAM_PFVF(SERVER_START);
3458228561Snp		param[2] = FW_PARAM_PFVF(SERVER_END);
3459228561Snp		param[3] = FW_PARAM_PFVF(TDDP_START);
3460228561Snp		param[4] = FW_PARAM_PFVF(TDDP_END);
3461228561Snp		param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
3462228561Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
3463218792Snp		if (rc != 0) {
3464218792Snp			device_printf(sc->dev,
3465218792Snp			    "failed to query TOE parameters: %d.\n", rc);
3466228561Snp			return (rc);
3467218792Snp		}
3468218792Snp		sc->tids.ntids = val[0];
3469218792Snp		sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS);
3470218792Snp		sc->tids.stid_base = val[1];
3471218792Snp		sc->tids.nstids = val[2] - val[1] + 1;
3472218792Snp		sc->vres.ddp.start = val[3];
3473218792Snp		sc->vres.ddp.size = val[4] - val[3] + 1;
3474218792Snp		sc->params.ofldq_wr_cred = val[5];
3475218792Snp		sc->params.offload = 1;
3476218792Snp	}
3477265426Snp	if (sc->rdmacaps) {
3478228561Snp		param[0] = FW_PARAM_PFVF(STAG_START);
3479228561Snp		param[1] = FW_PARAM_PFVF(STAG_END);
3480228561Snp		param[2] = FW_PARAM_PFVF(RQ_START);
3481228561Snp		param[3] = FW_PARAM_PFVF(RQ_END);
3482228561Snp		param[4] = FW_PARAM_PFVF(PBL_START);
3483228561Snp		param[5] = FW_PARAM_PFVF(PBL_END);
3484228561Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
3485218792Snp		if (rc != 0) {
3486218792Snp			device_printf(sc->dev,
3487228561Snp			    "failed to query RDMA parameters(1): %d.\n", rc);
3488228561Snp			return (rc);
3489218792Snp		}
3490218792Snp		sc->vres.stag.start = val[0];
3491218792Snp		sc->vres.stag.size = val[1] - val[0] + 1;
3492218792Snp		sc->vres.rq.start = val[2];
3493218792Snp		sc->vres.rq.size = val[3] - val[2] + 1;
3494218792Snp		sc->vres.pbl.start = val[4];
3495218792Snp		sc->vres.pbl.size = val[5] - val[4] + 1;
3496228561Snp
3497228561Snp		param[0] = FW_PARAM_PFVF(SQRQ_START);
3498228561Snp		param[1] = FW_PARAM_PFVF(SQRQ_END);
3499228561Snp		param[2] = FW_PARAM_PFVF(CQ_START);
3500228561Snp		param[3] = FW_PARAM_PFVF(CQ_END);
3501228561Snp		param[4] = FW_PARAM_PFVF(OCQ_START);
3502228561Snp		param[5] = FW_PARAM_PFVF(OCQ_END);
3503254933Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
3504228561Snp		if (rc != 0) {
3505228561Snp			device_printf(sc->dev,
3506228561Snp			    "failed to query RDMA parameters(2): %d.\n", rc);
3507228561Snp			return (rc);
3508228561Snp		}
3509228561Snp		sc->vres.qp.start = val[0];
3510228561Snp		sc->vres.qp.size = val[1] - val[0] + 1;
3511228561Snp		sc->vres.cq.start = val[2];
3512228561Snp		sc->vres.cq.size = val[3] - val[2] + 1;
3513228561Snp		sc->vres.ocq.start = val[4];
3514228561Snp		sc->vres.ocq.size = val[5] - val[4] + 1;
3515318797Snp
3516318797Snp		param[0] = FW_PARAM_PFVF(SRQ_START);
3517318797Snp		param[1] = FW_PARAM_PFVF(SRQ_END);
3518318797Snp		param[2] = FW_PARAM_DEV(MAXORDIRD_QP);
3519318797Snp		param[3] = FW_PARAM_DEV(MAXIRD_ADAPTER);
3520318797Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 4, param, val);
3521318797Snp		if (rc != 0) {
3522318797Snp			device_printf(sc->dev,
3523318797Snp			    "failed to query RDMA parameters(3): %d.\n", rc);
3524318797Snp			return (rc);
3525318797Snp		}
3526318797Snp		sc->vres.srq.start = val[0];
3527318797Snp		sc->vres.srq.size = val[1] - val[0] + 1;
3528318797Snp		sc->params.max_ordird_qp = val[2];
3529318797Snp		sc->params.max_ird_adapter = val[3];
3530218792Snp	}
3531265426Snp	if (sc->iscsicaps) {
3532228561Snp		param[0] = FW_PARAM_PFVF(ISCSI_START);
3533228561Snp		param[1] = FW_PARAM_PFVF(ISCSI_END);
3534228561Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val);
3535218792Snp		if (rc != 0) {
3536218792Snp			device_printf(sc->dev,
3537218792Snp			    "failed to query iSCSI parameters: %d.\n", rc);
3538228561Snp			return (rc);
3539218792Snp		}
3540218792Snp		sc->vres.iscsi.start = val[0];
3541218792Snp		sc->vres.iscsi.size = val[1] - val[0] + 1;
3542218792Snp	}
3543218792Snp
3544309447Sjhb	t4_init_sge_params(sc);
3545309447Sjhb
3546248925Snp	/*
3547248925Snp	 * We've got the params we wanted to query via the firmware.  Now grab
3548248925Snp	 * some others directly from the chip.
3549248925Snp	 */
3550248925Snp	rc = t4_read_chip_settings(sc);
3551228561Snp
3552218792Snp	return (rc);
3553218792Snp}
3554218792Snp
3555247291Snpstatic int
3556247291Snpset_params__post_init(struct adapter *sc)
3557247291Snp{
3558247291Snp	uint32_t param, val;
3559247291Snp
3560249382Snp	/* ask for encapsulated CPLs */
3561247291Snp	param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP);
3562249382Snp	val = 1;
3563249382Snp	(void)t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
3564247291Snp
3565249382Snp	return (0);
3566247291Snp}
3567247291Snp
3568228561Snp#undef FW_PARAM_PFVF
3569228561Snp#undef FW_PARAM_DEV
3570228561Snp
3571218792Snpstatic void
3572218792Snpt4_set_desc(struct adapter *sc)
3573218792Snp{
3574218792Snp	char buf[128];
3575218792Snp	struct adapter_params *p = &sc->params;
3576218792Snp
3577309458Sjhb	snprintf(buf, sizeof(buf), "Chelsio %s", p->vpd.id);
3578218792Snp
3579218792Snp	device_set_desc_copy(sc->dev, buf);
3580218792Snp}
3581218792Snp
3582353418Snpstatic inline void
3583353418Snpifmedia_add4(struct ifmedia *ifm, int m)
3584218792Snp{
3585218792Snp
3586353418Snp	ifmedia_add(ifm, m, 0, NULL);
3587353418Snp	ifmedia_add(ifm, m | IFM_ETH_TXPAUSE, 0, NULL);
3588353418Snp	ifmedia_add(ifm, m | IFM_ETH_RXPAUSE, 0, NULL);
3589353418Snp	ifmedia_add(ifm, m | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE, 0, NULL);
3590353418Snp}
3591218792Snp
3592353418Snpstatic void
3593353418Snpset_current_media(struct port_info *pi, struct ifmedia *ifm)
3594353418Snp{
3595353418Snp	struct link_config *lc;
3596353418Snp	int mword;
3597218792Snp
3598353418Snp	PORT_LOCK_ASSERT_OWNED(pi);
3599218792Snp
3600353418Snp	/* Leave current media alone if it's already set to IFM_NONE. */
3601353418Snp	if (ifm->ifm_cur != NULL &&
3602353418Snp	    IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_NONE)
3603353418Snp		return;
3604218792Snp
3605353418Snp	lc = &pi->link_cfg;
3606353418Snp	if (lc->requested_aneg == AUTONEG_ENABLE &&
3607353418Snp	    lc->supported & FW_PORT_CAP_ANEG) {
3608353418Snp		ifmedia_set(ifm, IFM_ETHER | IFM_AUTO);
3609353418Snp		return;
3610353418Snp	}
3611353418Snp	mword = IFM_ETHER | IFM_FDX;
3612353418Snp	if (lc->requested_fc & PAUSE_TX)
3613353418Snp		mword |= IFM_ETH_TXPAUSE;
3614353418Snp	if (lc->requested_fc & PAUSE_RX)
3615353418Snp		mword |= IFM_ETH_RXPAUSE;
3616353418Snp	mword |= port_mword(pi, speed_to_fwspeed(lc->requested_speed));
3617353418Snp	ifmedia_set(ifm, mword);
3618353418Snp}
3619218792Snp
3620353418Snpstatic void
3621353418Snpbuild_medialist(struct port_info *pi, struct ifmedia *ifm)
3622353418Snp{
3623353418Snp	uint16_t ss, speed;
3624353418Snp	int unknown, mword, bit;
3625353418Snp	struct link_config *lc;
3626218792Snp
3627353418Snp	PORT_LOCK_ASSERT_OWNED(pi);
3628218792Snp
3629353418Snp	if (pi->flags & FIXED_IFMEDIA)
3630353418Snp		return;
3631218792Snp
3632353418Snp	/*
3633353418Snp	 * First setup all the requested_ fields so that they comply with what's
3634353418Snp	 * supported by the port + transceiver.  Note that this clobbers any
3635353418Snp	 * user preferences set via sysctl_pause_settings or sysctl_autoneg.
3636353418Snp	 */
3637353418Snp	init_l1cfg(pi);
3638218792Snp
3639353418Snp	/*
3640353418Snp	 * Now (re)build the ifmedia list.
3641353418Snp	 */
3642353418Snp	ifmedia_removeall(ifm);
3643353418Snp	lc = &pi->link_cfg;
3644353418Snp	ss = G_FW_PORT_CAP_SPEED(lc->supported); /* Supported Speeds */
3645353418Snp	if (__predict_false(ss == 0)) {	/* not supposed to happen. */
3646353418Snp		MPASS(ss != 0);
3647353418Snpno_media:
3648353418Snp		MPASS(LIST_EMPTY(&ifm->ifm_list));
3649353418Snp		ifmedia_add(ifm, IFM_ETHER | IFM_NONE, 0, NULL);
3650353418Snp		ifmedia_set(ifm, IFM_ETHER | IFM_NONE);
3651353418Snp		return;
3652353418Snp	}
3653218792Snp
3654353418Snp	unknown = 0;
3655353418Snp	for (bit = 0; bit < fls(ss); bit++) {
3656353418Snp		speed = 1 << bit;
3657353418Snp		MPASS(speed & M_FW_PORT_CAP_SPEED);
3658353418Snp		if (ss & speed) {
3659353418Snp			mword = port_mword(pi, speed);
3660353418Snp			if (mword == IFM_NONE) {
3661353418Snp				goto no_media;
3662353418Snp			} else if (mword == IFM_UNKNOWN)
3663353418Snp				unknown++;
3664353418Snp			else
3665353418Snp				ifmedia_add4(ifm, IFM_ETHER | IFM_FDX | mword);
3666218792Snp		}
3667353418Snp	}
3668353418Snp	if (unknown > 0) /* Add one unknown for all unknown media types. */
3669353418Snp		ifmedia_add4(ifm, IFM_ETHER | IFM_FDX | IFM_UNKNOWN);
3670353418Snp	if (lc->supported & FW_PORT_CAP_ANEG)
3671353418Snp		ifmedia_add(ifm, IFM_ETHER | IFM_AUTO, 0, NULL);
3672218792Snp
3673353418Snp	set_current_media(pi, ifm);
3674353418Snp}
3675309560Sjhb
3676353418Snp/*
3677353418Snp * Update all the requested_* fields in the link config to something valid (and
3678353418Snp * reasonable).
3679353418Snp */
3680353418Snpstatic void
3681353418Snpinit_l1cfg(struct port_info *pi)
3682353418Snp{
3683353418Snp	struct link_config *lc = &pi->link_cfg;
3684309560Sjhb
3685353418Snp	PORT_LOCK_ASSERT_OWNED(pi);
3686309560Sjhb
3687353418Snp	/* Gbps -> Mbps */
3688353418Snp	lc->requested_speed = port_top_speed(pi) * 1000;
3689309560Sjhb
3690353418Snp	if (t4_autoneg != 0 && lc->supported & FW_PORT_CAP_ANEG) {
3691353418Snp		lc->requested_aneg = AUTONEG_ENABLE;
3692353418Snp	} else {
3693353418Snp		lc->requested_aneg = AUTONEG_DISABLE;
3694353418Snp	}
3695309560Sjhb
3696353418Snp	lc->requested_fc = t4_pause_settings & (PAUSE_TX | PAUSE_RX);
3697250092Snp
3698353418Snp	if (t4_fec != -1) {
3699353418Snp		if (t4_fec & FEC_RS && lc->supported & FW_PORT_CAP_FEC_RS) {
3700353418Snp			lc->requested_fec = FEC_RS;
3701353418Snp		} else if (t4_fec & FEC_BASER_RS &&
3702353418Snp		    lc->supported & FW_PORT_CAP_FEC_BASER_RS) {
3703353418Snp			lc->requested_fec = FEC_BASER_RS;
3704353418Snp		} else {
3705353418Snp			lc->requested_fec = 0;
3706250092Snp		}
3707353418Snp	} else {
3708353418Snp		/* Use the suggested value provided by the firmware in acaps */
3709353418Snp		if (lc->advertising & FW_PORT_CAP_FEC_RS &&
3710353418Snp		    lc->supported & FW_PORT_CAP_FEC_RS) {
3711353418Snp			lc->requested_fec = FEC_RS;
3712353418Snp		} else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS &&
3713353418Snp		    lc->supported & FW_PORT_CAP_FEC_BASER_RS) {
3714353418Snp			lc->requested_fec = FEC_BASER_RS;
3715353418Snp		} else {
3716353418Snp			lc->requested_fec = 0;
3717353418Snp		}
3718353418Snp	}
3719353418Snp}
3720250092Snp
3721353418Snp/*
3722353418Snp * Apply the settings in requested_* to the hardware.  The parameters are
3723353418Snp * expected to be sane.
3724353418Snp */
3725353418Snpstatic int
3726353418Snpapply_l1cfg(struct port_info *pi)
3727353418Snp{
3728353418Snp	struct adapter *sc = pi->adapter;
3729353418Snp	struct link_config *lc = &pi->link_cfg;
3730353418Snp	int rc;
3731353418Snp#ifdef INVARIANTS
3732353418Snp	uint16_t fwspeed;
3733309560Sjhb
3734353418Snp	ASSERT_SYNCHRONIZED_OP(sc);
3735353418Snp	PORT_LOCK_ASSERT_OWNED(pi);
3736309560Sjhb
3737353418Snp	if (lc->requested_aneg == AUTONEG_ENABLE)
3738353418Snp		MPASS(lc->supported & FW_PORT_CAP_ANEG);
3739353418Snp	if (lc->requested_fc & PAUSE_TX)
3740353418Snp		MPASS(lc->supported & FW_PORT_CAP_FC_TX);
3741353418Snp	if (lc->requested_fc & PAUSE_RX)
3742353418Snp		MPASS(lc->supported & FW_PORT_CAP_FC_RX);
3743353418Snp	if (lc->requested_fec == FEC_RS)
3744353418Snp		MPASS(lc->supported & FW_PORT_CAP_FEC_RS);
3745353418Snp	if (lc->requested_fec == FEC_BASER_RS)
3746353418Snp		MPASS(lc->supported & FW_PORT_CAP_FEC_BASER_RS);
3747353418Snp	fwspeed = speed_to_fwspeed(lc->requested_speed);
3748353418Snp	MPASS(fwspeed != 0);
3749353418Snp	MPASS(lc->supported & fwspeed);
3750353418Snp#endif
3751353418Snp	rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
3752353418Snp	if (rc != 0) {
3753353418Snp		device_printf(pi->dev, "l1cfg failed: %d\n", rc);
3754353418Snp	} else {
3755353418Snp		lc->fc = lc->requested_fc;
3756353418Snp		lc->fec = lc->requested_fec;
3757218792Snp	}
3758353418Snp	return (rc);
3759218792Snp}
3760218792Snp
3761231172Snp#define FW_MAC_EXACT_CHUNK	7
3762231172Snp
3763218792Snp/*
3764218792Snp * Program the port's XGMAC based on parameters in ifnet.  The caller also
3765218792Snp * indicates which parameters should be programmed (the rest are left alone).
3766218792Snp */
3767270297Snpint
3768270297Snpupdate_mac_settings(struct ifnet *ifp, int flags)
3769218792Snp{
3770270297Snp	int rc = 0;
3771308154Sjhb	struct vi_info *vi = ifp->if_softc;
3772308154Sjhb	struct port_info *pi = vi->pi;
3773218792Snp	struct adapter *sc = pi->adapter;
3774218792Snp	int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1;
3775218792Snp
3776245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
3777218792Snp	KASSERT(flags, ("%s: not told what to update.", __func__));
3778218792Snp
3779218792Snp	if (flags & XGMAC_MTU)
3780218792Snp		mtu = ifp->if_mtu;
3781218792Snp
3782218792Snp	if (flags & XGMAC_PROMISC)
3783218792Snp		promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0;
3784218792Snp
3785218792Snp	if (flags & XGMAC_ALLMULTI)
3786218792Snp		allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0;
3787218792Snp
3788218792Snp	if (flags & XGMAC_VLANEX)
3789218792Snp		vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0;
3790218792Snp
3791270297Snp	if (flags & (XGMAC_MTU|XGMAC_PROMISC|XGMAC_ALLMULTI|XGMAC_VLANEX)) {
3792308154Sjhb		rc = -t4_set_rxmode(sc, sc->mbox, vi->viid, mtu, promisc,
3793308154Sjhb		    allmulti, 1, vlanex, false);
3794270297Snp		if (rc) {
3795270297Snp			if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags,
3796270297Snp			    rc);
3797270297Snp			return (rc);
3798270297Snp		}
3799218792Snp	}
3800218792Snp
3801218792Snp	if (flags & XGMAC_UCADDR) {
3802218792Snp		uint8_t ucaddr[ETHER_ADDR_LEN];
3803218792Snp
3804218792Snp		bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr));
3805308154Sjhb		rc = t4_change_mac(sc, sc->mbox, vi->viid, vi->xact_addr_filt,
3806308154Sjhb		    ucaddr, true, true);
3807218792Snp		if (rc < 0) {
3808218792Snp			rc = -rc;
3809218792Snp			if_printf(ifp, "change_mac failed: %d\n", rc);
3810218792Snp			return (rc);
3811218792Snp		} else {
3812308154Sjhb			vi->xact_addr_filt = rc;
3813218792Snp			rc = 0;
3814218792Snp		}
3815218792Snp	}
3816218792Snp
3817218792Snp	if (flags & XGMAC_MCADDRS) {
3818231172Snp		const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK];
3819218792Snp		int del = 1;
3820218792Snp		uint64_t hash = 0;
3821218792Snp		struct ifmultiaddr *ifma;
3822231172Snp		int i = 0, j;
3823218792Snp
3824218792Snp		if_maddr_rlock(ifp);
3825218792Snp		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
3826238054Snp			if (ifma->ifma_addr->sa_family != AF_LINK)
3827218792Snp				continue;
3828282365Snp			mcaddr[i] =
3829231172Snp			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
3830282365Snp			MPASS(ETHER_IS_MULTICAST(mcaddr[i]));
3831282365Snp			i++;
3832218792Snp
3833231172Snp			if (i == FW_MAC_EXACT_CHUNK) {
3834308154Sjhb				rc = t4_alloc_mac_filt(sc, sc->mbox, vi->viid,
3835308154Sjhb				    del, i, mcaddr, NULL, &hash, 0);
3836231172Snp				if (rc < 0) {
3837231172Snp					rc = -rc;
3838231172Snp					for (j = 0; j < i; j++) {
3839231172Snp						if_printf(ifp,
3840231172Snp						    "failed to add mc address"
3841231172Snp						    " %02x:%02x:%02x:"
3842231172Snp						    "%02x:%02x:%02x rc=%d\n",
3843231172Snp						    mcaddr[j][0], mcaddr[j][1],
3844231172Snp						    mcaddr[j][2], mcaddr[j][3],
3845231172Snp						    mcaddr[j][4], mcaddr[j][5],
3846231172Snp						    rc);
3847231172Snp					}
3848231172Snp					goto mcfail;
3849231172Snp				}
3850231172Snp				del = 0;
3851231172Snp				i = 0;
3852231172Snp			}
3853231172Snp		}
3854231172Snp		if (i > 0) {
3855308154Sjhb			rc = t4_alloc_mac_filt(sc, sc->mbox, vi->viid, del, i,
3856270297Snp			    mcaddr, NULL, &hash, 0);
3857218792Snp			if (rc < 0) {
3858218792Snp				rc = -rc;
3859231172Snp				for (j = 0; j < i; j++) {
3860231172Snp					if_printf(ifp,
3861231172Snp					    "failed to add mc address"
3862231172Snp					    " %02x:%02x:%02x:"
3863231172Snp					    "%02x:%02x:%02x rc=%d\n",
3864231172Snp					    mcaddr[j][0], mcaddr[j][1],
3865231172Snp					    mcaddr[j][2], mcaddr[j][3],
3866231172Snp					    mcaddr[j][4], mcaddr[j][5],
3867231172Snp					    rc);
3868231172Snp				}
3869218792Snp				goto mcfail;
3870218792Snp			}
3871218792Snp		}
3872218792Snp
3873308154Sjhb		rc = -t4_set_addr_hash(sc, sc->mbox, vi->viid, 0, hash, 0);
3874218792Snp		if (rc != 0)
3875218792Snp			if_printf(ifp, "failed to set mc address hash: %d", rc);
3876218792Snpmcfail:
3877218792Snp		if_maddr_runlock(ifp);
3878218792Snp	}
3879218792Snp
3880218792Snp	return (rc);
3881218792Snp}
3882218792Snp
3883281249Snp/*
3884281249Snp * {begin|end}_synchronized_op must be called from the same thread.
3885281249Snp */
3886245274Snpint
3887308154Sjhbbegin_synchronized_op(struct adapter *sc, struct vi_info *vi, int flags,
3888245274Snp    char *wmesg)
3889218792Snp{
3890245274Snp	int rc, pri;
3891218792Snp
3892245274Snp#ifdef WITNESS
3893245274Snp	/* the caller thinks it's ok to sleep, but is it really? */
3894245274Snp	if (flags & SLEEP_OK)
3895308154Sjhb		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
3896308154Sjhb		    "begin_synchronized_op");
3897245274Snp#endif
3898218792Snp
3899245274Snp	if (INTR_OK)
3900245274Snp		pri = PCATCH;
3901245274Snp	else
3902245274Snp		pri = 0;
3903245274Snp
3904245274Snp	ADAPTER_LOCK(sc);
3905245274Snp	for (;;) {
3906245274Snp
3907308154Sjhb		if (vi && IS_DOOMED(vi)) {
3908245274Snp			rc = ENXIO;
3909245274Snp			goto done;
3910245274Snp		}
3911245274Snp
3912245274Snp		if (!IS_BUSY(sc)) {
3913245274Snp			rc = 0;
3914245274Snp			break;
3915245274Snp		}
3916245274Snp
3917245274Snp		if (!(flags & SLEEP_OK)) {
3918245274Snp			rc = EBUSY;
3919245274Snp			goto done;
3920245274Snp		}
3921245274Snp
3922245274Snp		if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) {
3923218792Snp			rc = EINTR;
3924218792Snp			goto done;
3925218792Snp		}
3926218792Snp	}
3927245274Snp
3928218792Snp	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
3929218792Snp	SET_BUSY(sc);
3930245274Snp#ifdef INVARIANTS
3931245274Snp	sc->last_op = wmesg;
3932245274Snp	sc->last_op_thr = curthread;
3933287149Snp	sc->last_op_flags = flags;
3934245274Snp#endif
3935218792Snp
3936245274Snpdone:
3937245274Snp	if (!(flags & HOLD_LOCK) || rc)
3938245274Snp		ADAPTER_UNLOCK(sc);
3939218792Snp
3940245274Snp	return (rc);
3941245274Snp}
3942245274Snp
3943281249Snp/*
3944308154Sjhb * Tell if_ioctl and if_init that the VI is going away.  This is
3945308154Sjhb * special variant of begin_synchronized_op and must be paired with a
3946308154Sjhb * call to end_synchronized_op.
3947308154Sjhb */
3948308154Sjhbvoid
3949308154Sjhbdoom_vi(struct adapter *sc, struct vi_info *vi)
3950308154Sjhb{
3951308154Sjhb
3952308154Sjhb	ADAPTER_LOCK(sc);
3953308154Sjhb	SET_DOOMED(vi);
3954308154Sjhb	wakeup(&sc->flags);
3955308154Sjhb	while (IS_BUSY(sc))
3956308154Sjhb		mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0);
3957308154Sjhb	SET_BUSY(sc);
3958308154Sjhb#ifdef INVARIANTS
3959308154Sjhb	sc->last_op = "t4detach";
3960308154Sjhb	sc->last_op_thr = curthread;
3961308154Sjhb	sc->last_op_flags = 0;
3962308154Sjhb#endif
3963308154Sjhb	ADAPTER_UNLOCK(sc);
3964308154Sjhb}
3965308154Sjhb
3966308154Sjhb/*
3967281249Snp * {begin|end}_synchronized_op must be called from the same thread.
3968281249Snp */
3969245274Snpvoid
3970245274Snpend_synchronized_op(struct adapter *sc, int flags)
3971245274Snp{
3972245274Snp
3973245274Snp	if (flags & LOCK_HELD)
3974245274Snp		ADAPTER_LOCK_ASSERT_OWNED(sc);
3975245274Snp	else
3976245274Snp		ADAPTER_LOCK(sc);
3977245274Snp
3978218792Snp	KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
3979218792Snp	CLR_BUSY(sc);
3980245274Snp	wakeup(&sc->flags);
3981218792Snp	ADAPTER_UNLOCK(sc);
3982218792Snp}
3983218792Snp
3984218792Snpstatic int
3985308154Sjhbcxgbe_init_synchronized(struct vi_info *vi)
3986218792Snp{
3987308154Sjhb	struct port_info *pi = vi->pi;
3988218792Snp	struct adapter *sc = pi->adapter;
3989308154Sjhb	struct ifnet *ifp = vi->ifp;
3990284052Snp	int rc = 0, i;
3991284052Snp	struct sge_txq *txq;
3992218792Snp
3993245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
3994218792Snp
3995308154Sjhb	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
3996218792Snp		return (0);	/* already running */
3997218792Snp
3998228561Snp	if (!(sc->flags & FULL_INIT_DONE) &&
3999228561Snp	    ((rc = adapter_full_init(sc)) != 0))
4000218792Snp		return (rc);	/* error message displayed already */
4001218792Snp
4002308154Sjhb	if (!(vi->flags & VI_INIT_DONE) &&
4003308154Sjhb	    ((rc = vi_full_init(vi)) != 0))
4004228561Snp		return (rc); /* error message displayed already */
4005218792Snp
4006270297Snp	rc = update_mac_settings(ifp, XGMAC_ALL);
4007218792Snp	if (rc)
4008218792Snp		goto done;	/* error message displayed already */
4009218792Snp
4010308154Sjhb	rc = -t4_enable_vi(sc, sc->mbox, vi->viid, true, true);
4011218792Snp	if (rc != 0) {
4012218792Snp		if_printf(ifp, "enable_vi failed: %d\n", rc);
4013218792Snp		goto done;
4014218792Snp	}
4015218792Snp
4016253691Snp	/*
4017284052Snp	 * Can't fail from this point onwards.  Review cxgbe_uninit_synchronized
4018284052Snp	 * if this changes.
4019284052Snp	 */
4020284052Snp
4021308154Sjhb	for_each_txq(vi, i, txq) {
4022284052Snp		TXQ_LOCK(txq);
4023284052Snp		txq->eq.flags |= EQ_ENABLED;
4024284052Snp		TXQ_UNLOCK(txq);
4025284052Snp	}
4026284052Snp
4027284052Snp	/*
4028253691Snp	 * The first iq of the first port to come up is used for tracing.
4029253691Snp	 */
4030308154Sjhb	if (sc->traceq < 0 && IS_MAIN_VI(vi)) {
4031308154Sjhb		sc->traceq = sc->sge.rxq[vi->first_rxq].iq.abs_id;
4032253691Snp		t4_write_reg(sc, is_t4(sc) ?  A_MPS_TRC_RSS_CONTROL :
4033253691Snp		    A_MPS_T5_TRC_RSS_CONTROL, V_RSSCONTROL(pi->tx_chan) |
4034253691Snp		    V_QUEUENUMBER(sc->traceq));
4035253691Snp		pi->flags |= HAS_TRACEQ;
4036253691Snp	}
4037253691Snp
4038218792Snp	/* all ok */
4039245274Snp	PORT_LOCK(pi);
4040353418Snp	if (pi->up_vis++ == 0) {
4041353418Snp		t4_update_port_info(pi);
4042353418Snp		build_medialist(pi, &pi->media);
4043353418Snp		apply_l1cfg(pi);
4044353418Snp	}
4045218792Snp	ifp->if_drv_flags |= IFF_DRV_RUNNING;
4046308154Sjhb
4047309447Sjhb	if (pi->nvi > 1 || sc->flags & IS_VF)
4048308154Sjhb		callout_reset(&vi->tick, hz, vi_tick, vi);
4049308154Sjhb	else
4050308154Sjhb		callout_reset(&pi->tick, hz, cxgbe_tick, pi);
4051245274Snp	PORT_UNLOCK(pi);
4052218792Snpdone:
4053218792Snp	if (rc != 0)
4054308154Sjhb		cxgbe_uninit_synchronized(vi);
4055218792Snp
4056218792Snp	return (rc);
4057218792Snp}
4058218792Snp
4059218792Snp/*
4060218792Snp * Idempotent.
4061218792Snp */
4062218792Snpstatic int
4063308154Sjhbcxgbe_uninit_synchronized(struct vi_info *vi)
4064218792Snp{
4065308154Sjhb	struct port_info *pi = vi->pi;
4066218792Snp	struct adapter *sc = pi->adapter;
4067308154Sjhb	struct ifnet *ifp = vi->ifp;
4068284052Snp	int rc, i;
4069284052Snp	struct sge_txq *txq;
4070218792Snp
4071245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
4072218792Snp
4073308154Sjhb	if (!(vi->flags & VI_INIT_DONE)) {
4074297059Snp		KASSERT(!(ifp->if_drv_flags & IFF_DRV_RUNNING),
4075308154Sjhb		    ("uninited VI is running"));
4076297059Snp		return (0);
4077297059Snp	}
4078297059Snp
4079218792Snp	/*
4080228561Snp	 * Disable the VI so that all its data in either direction is discarded
4081228561Snp	 * by the MPS.  Leave everything else (the queues, interrupts, and 1Hz
4082228561Snp	 * tick) intact as the TP can deliver negative advice or data that it's
4083228561Snp	 * holding in its RAM (for an offloaded connection) even after the VI is
4084228561Snp	 * disabled.
4085218792Snp	 */
4086308154Sjhb	rc = -t4_enable_vi(sc, sc->mbox, vi->viid, false, false);
4087228561Snp	if (rc) {
4088228561Snp		if_printf(ifp, "disable_vi failed: %d\n", rc);
4089228561Snp		return (rc);
4090228561Snp	}
4091228561Snp
4092308154Sjhb	for_each_txq(vi, i, txq) {
4093284052Snp		TXQ_LOCK(txq);
4094284052Snp		txq->eq.flags &= ~EQ_ENABLED;
4095284052Snp		TXQ_UNLOCK(txq);
4096284052Snp	}
4097284052Snp
4098245274Snp	PORT_LOCK(pi);
4099309447Sjhb	if (pi->nvi > 1 || sc->flags & IS_VF)
4100309447Sjhb		callout_stop(&vi->tick);
4101309447Sjhb	else
4102308154Sjhb		callout_stop(&pi->tick);
4103308154Sjhb	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
4104308154Sjhb		PORT_UNLOCK(pi);
4105308154Sjhb		return (0);
4106308154Sjhb	}
4107228561Snp	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
4108308154Sjhb	pi->up_vis--;
4109308154Sjhb	if (pi->up_vis > 0) {
4110308154Sjhb		PORT_UNLOCK(pi);
4111308154Sjhb		return (0);
4112308154Sjhb	}
4113218792Snp
4114218792Snp	pi->link_cfg.link_ok = 0;
4115218792Snp	pi->link_cfg.speed = 0;
4116311261Snp	pi->link_cfg.link_down_rc = 255;
4117353418Snp	t4_os_link_changed(pi);
4118353418Snp	pi->old_link_cfg = pi->link_cfg;
4119353418Snp	PORT_UNLOCK(pi);
4120218792Snp
4121218792Snp	return (0);
4122218792Snp}
4123218792Snp
4124240453Snp/*
4125240453Snp * It is ok for this function to fail midway and return right away.  t4_detach
4126240453Snp * will walk the entire sc->irq list and clean up whatever is valid.
4127240453Snp */
4128309447Sjhbint
4129309447Sjhbt4_setup_intr_handlers(struct adapter *sc)
4130218792Snp{
4131308154Sjhb	int rc, rid, p, q, v;
4132222510Snp	char s[8];
4133222510Snp	struct irq *irq;
4134228561Snp	struct port_info *pi;
4135308154Sjhb	struct vi_info *vi;
4136308154Sjhb	struct sge *sge = &sc->sge;
4137228561Snp	struct sge_rxq *rxq;
4138237263Snp#ifdef TCP_OFFLOAD
4139228561Snp	struct sge_ofld_rxq *ofld_rxq;
4140228561Snp#endif
4141270297Snp#ifdef DEV_NETMAP
4142270297Snp	struct sge_nm_rxq *nm_rxq;
4143270297Snp#endif
4144218792Snp
4145218792Snp	/*
4146218792Snp	 * Setup interrupts.
4147218792Snp	 */
4148222510Snp	irq = &sc->irq[0];
4149222510Snp	rid = sc->intr_type == INTR_INTX ? 0 : 1;
4150270297Snp	if (sc->intr_count == 1)
4151270297Snp		return (t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all"));
4152222510Snp
4153270297Snp	/* Multiple interrupts. */
4154309447Sjhb	if (sc->flags & IS_VF)
4155309447Sjhb		KASSERT(sc->intr_count >= T4VF_EXTRA_INTR + sc->params.nports,
4156309447Sjhb		    ("%s: too few intr.", __func__));
4157309447Sjhb	else
4158309447Sjhb		KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports,
4159309447Sjhb		    ("%s: too few intr.", __func__));
4160228561Snp
4161309447Sjhb	/* The first one is always error intr on PFs */
4162309447Sjhb	if (!(sc->flags & IS_VF)) {
4163309447Sjhb		rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err");
4164309447Sjhb		if (rc != 0)
4165309447Sjhb			return (rc);
4166309447Sjhb		irq++;
4167309447Sjhb		rid++;
4168309447Sjhb	}
4169218792Snp
4170309447Sjhb	/* The second one is always the firmware event queue (first on VFs) */
4171308154Sjhb	rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sge->fwq, "evt");
4172270297Snp	if (rc != 0)
4173270297Snp		return (rc);
4174270297Snp	irq++;
4175270297Snp	rid++;
4176222510Snp
4177270297Snp	for_each_port(sc, p) {
4178270297Snp		pi = sc->port[p];
4179308154Sjhb		for_each_vi(pi, v, vi) {
4180308154Sjhb			vi->first_intr = rid - 1;
4181222510Snp
4182308154Sjhb			if (vi->nnmrxq > 0) {
4183308154Sjhb				int n = max(vi->nrxq, vi->nnmrxq);
4184308154Sjhb
4185308154Sjhb				MPASS(vi->flags & INTR_RXQ);
4186308154Sjhb
4187308154Sjhb				rxq = &sge->rxq[vi->first_rxq];
4188308154Sjhb#ifdef DEV_NETMAP
4189308154Sjhb				nm_rxq = &sge->nm_rxq[vi->first_nm_rxq];
4190308154Sjhb#endif
4191308154Sjhb				for (q = 0; q < n; q++) {
4192308154Sjhb					snprintf(s, sizeof(s), "%x%c%x", p,
4193308154Sjhb					    'a' + v, q);
4194308154Sjhb					if (q < vi->nrxq)
4195308154Sjhb						irq->rxq = rxq++;
4196308154Sjhb#ifdef DEV_NETMAP
4197308154Sjhb					if (q < vi->nnmrxq)
4198308154Sjhb						irq->nm_rxq = nm_rxq++;
4199308154Sjhb#endif
4200308154Sjhb					rc = t4_alloc_irq(sc, irq, rid,
4201308154Sjhb					    t4_vi_intr, irq, s);
4202308154Sjhb					if (rc != 0)
4203308154Sjhb						return (rc);
4204308154Sjhb					irq++;
4205308154Sjhb					rid++;
4206308154Sjhb					vi->nintr++;
4207308154Sjhb				}
4208308154Sjhb			} else if (vi->flags & INTR_RXQ) {
4209308154Sjhb				for_each_rxq(vi, q, rxq) {
4210308154Sjhb					snprintf(s, sizeof(s), "%x%c%x", p,
4211308154Sjhb					    'a' + v, q);
4212308154Sjhb					rc = t4_alloc_irq(sc, irq, rid,
4213308154Sjhb					    t4_intr, rxq, s);
4214308154Sjhb					if (rc != 0)
4215308154Sjhb						return (rc);
4216308154Sjhb					irq++;
4217308154Sjhb					rid++;
4218308154Sjhb					vi->nintr++;
4219308154Sjhb				}
4220218792Snp			}
4221237263Snp#ifdef TCP_OFFLOAD
4222308154Sjhb			if (vi->flags & INTR_OFLD_RXQ) {
4223308154Sjhb				for_each_ofld_rxq(vi, q, ofld_rxq) {
4224308154Sjhb					snprintf(s, sizeof(s), "%x%c%x", p,
4225308154Sjhb					    'A' + v, q);
4226308154Sjhb					rc = t4_alloc_irq(sc, irq, rid,
4227308154Sjhb					    t4_intr, ofld_rxq, s);
4228308154Sjhb					if (rc != 0)
4229308154Sjhb						return (rc);
4230308154Sjhb					irq++;
4231308154Sjhb					rid++;
4232308154Sjhb					vi->nintr++;
4233308154Sjhb				}
4234218792Snp			}
4235228561Snp#endif
4236218792Snp		}
4237218792Snp	}
4238270297Snp	MPASS(irq == &sc->irq[sc->intr_count]);
4239218792Snp
4240240453Snp	return (0);
4241240453Snp}
4242240453Snp
4243270297Snpint
4244240453Snpadapter_full_init(struct adapter *sc)
4245240453Snp{
4246240453Snp	int rc, i;
4247318838Snp#ifdef RSS
4248318838Snp	uint32_t raw_rss_key[RSS_KEYSIZE / sizeof(uint32_t)];
4249318838Snp	uint32_t rss_key[RSS_KEYSIZE / sizeof(uint32_t)];
4250318838Snp#endif
4251240453Snp
4252281250Snp	ASSERT_SYNCHRONIZED_OP(sc);
4253240453Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
4254240453Snp	KASSERT((sc->flags & FULL_INIT_DONE) == 0,
4255240453Snp	    ("%s: FULL_INIT_DONE already", __func__));
4256240453Snp
4257240453Snp	/*
4258240453Snp	 * queues that belong to the adapter (not any particular port).
4259240453Snp	 */
4260240453Snp	rc = t4_setup_adapter_queues(sc);
4261240453Snp	if (rc != 0)
4262240453Snp		goto done;
4263240453Snp
4264240453Snp	for (i = 0; i < nitems(sc->tq); i++) {
4265240453Snp		sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT,
4266240453Snp		    taskqueue_thread_enqueue, &sc->tq[i]);
4267240453Snp		if (sc->tq[i] == NULL) {
4268240453Snp			device_printf(sc->dev,
4269240453Snp			    "failed to allocate task queue %d\n", i);
4270240453Snp			rc = ENOMEM;
4271240453Snp			goto done;
4272240453Snp		}
4273240453Snp		taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d",
4274240453Snp		    device_get_nameunit(sc->dev), i);
4275240453Snp	}
4276318838Snp#ifdef RSS
4277318838Snp	MPASS(RSS_KEYSIZE == 40);
4278318838Snp	rss_getkey((void *)&raw_rss_key[0]);
4279318838Snp	for (i = 0; i < nitems(rss_key); i++) {
4280318838Snp		rss_key[i] = htobe32(raw_rss_key[nitems(rss_key) - 1 - i]);
4281318838Snp	}
4282353418Snp	t4_write_rss_key(sc, &rss_key[0], -1, 1);
4283318838Snp#endif
4284240453Snp
4285309447Sjhb	if (!(sc->flags & IS_VF))
4286309447Sjhb		t4_intr_enable(sc);
4287218792Snp	sc->flags |= FULL_INIT_DONE;
4288218792Snpdone:
4289218792Snp	if (rc != 0)
4290228561Snp		adapter_full_uninit(sc);
4291218792Snp
4292218792Snp	return (rc);
4293218792Snp}
4294218792Snp
4295270297Snpint
4296228561Snpadapter_full_uninit(struct adapter *sc)
4297218792Snp{
4298218792Snp	int i;
4299218792Snp
4300218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
4301218792Snp
4302220873Snp	t4_teardown_adapter_queues(sc);
4303218792Snp
4304240452Snp	for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) {
4305228561Snp		taskqueue_free(sc->tq[i]);
4306228561Snp		sc->tq[i] = NULL;
4307228561Snp	}
4308228561Snp
4309218792Snp	sc->flags &= ~FULL_INIT_DONE;
4310218792Snp
4311218792Snp	return (0);
4312218792Snp}
4313218792Snp
4314308153Sjhb#ifdef RSS
4315308153Sjhb#define SUPPORTED_RSS_HASHTYPES (RSS_HASHTYPE_RSS_IPV4 | \
4316308153Sjhb    RSS_HASHTYPE_RSS_TCP_IPV4 | RSS_HASHTYPE_RSS_IPV6 | \
4317308153Sjhb    RSS_HASHTYPE_RSS_TCP_IPV6 | RSS_HASHTYPE_RSS_UDP_IPV4 | \
4318308153Sjhb    RSS_HASHTYPE_RSS_UDP_IPV6)
4319308153Sjhb
4320308153Sjhb/* Translates kernel hash types to hardware. */
4321308153Sjhbstatic int
4322308153Sjhbhashconfig_to_hashen(int hashconfig)
4323308153Sjhb{
4324308153Sjhb	int hashen = 0;
4325308153Sjhb
4326308153Sjhb	if (hashconfig & RSS_HASHTYPE_RSS_IPV4)
4327308153Sjhb		hashen |= F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN;
4328308153Sjhb	if (hashconfig & RSS_HASHTYPE_RSS_IPV6)
4329308153Sjhb		hashen |= F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN;
4330308153Sjhb	if (hashconfig & RSS_HASHTYPE_RSS_UDP_IPV4) {
4331308153Sjhb		hashen |= F_FW_RSS_VI_CONFIG_CMD_UDPEN |
4332308153Sjhb		    F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN;
4333308153Sjhb	}
4334308153Sjhb	if (hashconfig & RSS_HASHTYPE_RSS_UDP_IPV6) {
4335308153Sjhb		hashen |= F_FW_RSS_VI_CONFIG_CMD_UDPEN |
4336308153Sjhb		    F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN;
4337308153Sjhb	}
4338308153Sjhb	if (hashconfig & RSS_HASHTYPE_RSS_TCP_IPV4)
4339308153Sjhb		hashen |= F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN;
4340308153Sjhb	if (hashconfig & RSS_HASHTYPE_RSS_TCP_IPV6)
4341308153Sjhb		hashen |= F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN;
4342308153Sjhb
4343308153Sjhb	return (hashen);
4344308153Sjhb}
4345308153Sjhb
4346308153Sjhb/* Translates hardware hash types to kernel. */
4347308153Sjhbstatic int
4348308153Sjhbhashen_to_hashconfig(int hashen)
4349308153Sjhb{
4350308153Sjhb	int hashconfig = 0;
4351308153Sjhb
4352308153Sjhb	if (hashen & F_FW_RSS_VI_CONFIG_CMD_UDPEN) {
4353308153Sjhb		/*
4354308153Sjhb		 * If UDP hashing was enabled it must have been enabled for
4355308153Sjhb		 * either IPv4 or IPv6 (inclusive or).  Enabling UDP without
4356308153Sjhb		 * enabling any 4-tuple hash is nonsense configuration.
4357308153Sjhb		 */
4358308153Sjhb		MPASS(hashen & (F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN |
4359308153Sjhb		    F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN));
4360308153Sjhb
4361308153Sjhb		if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN)
4362308153Sjhb			hashconfig |= RSS_HASHTYPE_RSS_UDP_IPV4;
4363308153Sjhb		if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN)
4364308153Sjhb			hashconfig |= RSS_HASHTYPE_RSS_UDP_IPV6;
4365308153Sjhb	}
4366308153Sjhb	if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN)
4367308153Sjhb		hashconfig |= RSS_HASHTYPE_RSS_TCP_IPV4;
4368308153Sjhb	if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN)
4369308153Sjhb		hashconfig |= RSS_HASHTYPE_RSS_TCP_IPV6;
4370308153Sjhb	if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN)
4371308153Sjhb		hashconfig |= RSS_HASHTYPE_RSS_IPV4;
4372308153Sjhb	if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN)
4373308153Sjhb		hashconfig |= RSS_HASHTYPE_RSS_IPV6;
4374308153Sjhb
4375308153Sjhb	return (hashconfig);
4376308153Sjhb}
4377308153Sjhb#endif
4378308153Sjhb
4379270297Snpint
4380308154Sjhbvi_full_init(struct vi_info *vi)
4381228561Snp{
4382308154Sjhb	struct adapter *sc = vi->pi->adapter;
4383308154Sjhb	struct ifnet *ifp = vi->ifp;
4384228561Snp	uint16_t *rss;
4385228561Snp	struct sge_rxq *rxq;
4386308153Sjhb	int rc, i, j, hashen;
4387308153Sjhb#ifdef RSS
4388308153Sjhb	int nbuckets = rss_getnumbuckets();
4389308153Sjhb	int hashconfig = rss_gethashconfig();
4390308153Sjhb	int extra;
4391308153Sjhb#endif
4392228561Snp
4393245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
4394308154Sjhb	KASSERT((vi->flags & VI_INIT_DONE) == 0,
4395308154Sjhb	    ("%s: VI_INIT_DONE already", __func__));
4396228561Snp
4397308154Sjhb	sysctl_ctx_init(&vi->ctx);
4398308154Sjhb	vi->flags |= VI_SYSCTL_CTX;
4399228561Snp
4400228561Snp	/*
4401308154Sjhb	 * Allocate tx/rx/fl queues for this VI.
4402228561Snp	 */
4403308154Sjhb	rc = t4_setup_vi_queues(vi);
4404228561Snp	if (rc != 0)
4405228561Snp		goto done;	/* error message displayed already */
4406228561Snp
4407228561Snp	/*
4408308154Sjhb	 * Setup RSS for this VI.  Save a copy of the RSS table for later use.
4409228561Snp	 */
4410308154Sjhb	if (vi->nrxq > vi->rss_size) {
4411308153Sjhb		if_printf(ifp, "nrxq (%d) > hw RSS table size (%d); "
4412308154Sjhb		    "some queues will never receive traffic.\n", vi->nrxq,
4413308154Sjhb		    vi->rss_size);
4414308154Sjhb	} else if (vi->rss_size % vi->nrxq) {
4415308153Sjhb		if_printf(ifp, "nrxq (%d), hw RSS table size (%d); "
4416308154Sjhb		    "expect uneven traffic distribution.\n", vi->nrxq,
4417308154Sjhb		    vi->rss_size);
4418308153Sjhb	}
4419308153Sjhb#ifdef RSS
4420308154Sjhb	if (vi->nrxq != nbuckets) {
4421308153Sjhb		if_printf(ifp, "nrxq (%d) != kernel RSS buckets (%d);"
4422308154Sjhb		    "performance will be impacted.\n", vi->nrxq, nbuckets);
4423308153Sjhb	}
4424308153Sjhb#endif
4425308154Sjhb	rss = malloc(vi->rss_size * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK);
4426308154Sjhb	for (i = 0; i < vi->rss_size;) {
4427308153Sjhb#ifdef RSS
4428308153Sjhb		j = rss_get_indirection_to_bucket(i);
4429308154Sjhb		j %= vi->nrxq;
4430308154Sjhb		rxq = &sc->sge.rxq[vi->first_rxq + j];
4431308153Sjhb		rss[i++] = rxq->iq.abs_id;
4432308153Sjhb#else
4433308154Sjhb		for_each_rxq(vi, j, rxq) {
4434259142Snp			rss[i++] = rxq->iq.abs_id;
4435308154Sjhb			if (i == vi->rss_size)
4436259142Snp				break;
4437259142Snp		}
4438308153Sjhb#endif
4439228561Snp	}
4440259142Snp
4441308154Sjhb	rc = -t4_config_rss_range(sc, sc->mbox, vi->viid, 0, vi->rss_size, rss,
4442308154Sjhb	    vi->rss_size);
4443228561Snp	if (rc != 0) {
4444228561Snp		if_printf(ifp, "rss_config failed: %d\n", rc);
4445228561Snp		goto done;
4446228561Snp	}
4447228561Snp
4448308153Sjhb#ifdef RSS
4449308153Sjhb	hashen = hashconfig_to_hashen(hashconfig);
4450308153Sjhb
4451308153Sjhb	/*
4452308153Sjhb	 * We may have had to enable some hashes even though the global config
4453308153Sjhb	 * wants them disabled.  This is a potential problem that must be
4454308153Sjhb	 * reported to the user.
4455308153Sjhb	 */
4456308153Sjhb	extra = hashen_to_hashconfig(hashen) ^ hashconfig;
4457308153Sjhb
4458308153Sjhb	/*
4459308153Sjhb	 * If we consider only the supported hash types, then the enabled hashes
4460308153Sjhb	 * are a superset of the requested hashes.  In other words, there cannot
4461308153Sjhb	 * be any supported hash that was requested but not enabled, but there
4462308153Sjhb	 * can be hashes that were not requested but had to be enabled.
4463308153Sjhb	 */
4464308153Sjhb	extra &= SUPPORTED_RSS_HASHTYPES;
4465308153Sjhb	MPASS((extra & hashconfig) == 0);
4466308153Sjhb
4467308153Sjhb	if (extra) {
4468308153Sjhb		if_printf(ifp,
4469308153Sjhb		    "global RSS config (0x%x) cannot be accomodated.\n",
4470308153Sjhb		    hashconfig);
4471308153Sjhb	}
4472308153Sjhb	if (extra & RSS_HASHTYPE_RSS_IPV4)
4473308153Sjhb		if_printf(ifp, "IPv4 2-tuple hashing forced on.\n");
4474308153Sjhb	if (extra & RSS_HASHTYPE_RSS_TCP_IPV4)
4475308153Sjhb		if_printf(ifp, "TCP/IPv4 4-tuple hashing forced on.\n");
4476308153Sjhb	if (extra & RSS_HASHTYPE_RSS_IPV6)
4477308153Sjhb		if_printf(ifp, "IPv6 2-tuple hashing forced on.\n");
4478308153Sjhb	if (extra & RSS_HASHTYPE_RSS_TCP_IPV6)
4479308153Sjhb		if_printf(ifp, "TCP/IPv6 4-tuple hashing forced on.\n");
4480308153Sjhb	if (extra & RSS_HASHTYPE_RSS_UDP_IPV4)
4481308153Sjhb		if_printf(ifp, "UDP/IPv4 4-tuple hashing forced on.\n");
4482308153Sjhb	if (extra & RSS_HASHTYPE_RSS_UDP_IPV6)
4483308153Sjhb		if_printf(ifp, "UDP/IPv6 4-tuple hashing forced on.\n");
4484308153Sjhb#else
4485308153Sjhb	hashen = F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN |
4486308153Sjhb	    F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN |
4487308153Sjhb	    F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN |
4488308153Sjhb	    F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN | F_FW_RSS_VI_CONFIG_CMD_UDPEN;
4489308153Sjhb#endif
4490309560Sjhb	rc = -t4_config_vi_rss(sc, sc->mbox, vi->viid, hashen, rss[0], 0, 0);
4491308153Sjhb	if (rc != 0) {
4492308153Sjhb		if_printf(ifp, "rss hash/defaultq config failed: %d\n", rc);
4493308153Sjhb		goto done;
4494308153Sjhb	}
4495308153Sjhb
4496308154Sjhb	vi->rss = rss;
4497308154Sjhb	vi->flags |= VI_INIT_DONE;
4498228561Snpdone:
4499228561Snp	if (rc != 0)
4500308154Sjhb		vi_full_uninit(vi);
4501228561Snp
4502228561Snp	return (rc);
4503228561Snp}
4504228561Snp
4505228561Snp/*
4506228561Snp * Idempotent.
4507228561Snp */
4508270297Snpint
4509308154Sjhbvi_full_uninit(struct vi_info *vi)
4510228561Snp{
4511308154Sjhb	struct port_info *pi = vi->pi;
4512228561Snp	struct adapter *sc = pi->adapter;
4513228561Snp	int i;
4514228561Snp	struct sge_rxq *rxq;
4515228561Snp	struct sge_txq *txq;
4516237263Snp#ifdef TCP_OFFLOAD
4517228561Snp	struct sge_ofld_rxq *ofld_rxq;
4518228561Snp	struct sge_wrq *ofld_txq;
4519228561Snp#endif
4520228561Snp
4521308154Sjhb	if (vi->flags & VI_INIT_DONE) {
4522228561Snp
4523284052Snp		/* Need to quiesce queues.  */
4524228561Snp
4525308154Sjhb		/* XXX: Only for the first VI? */
4526309447Sjhb		if (IS_MAIN_VI(vi) && !(sc->flags & IS_VF))
4527308154Sjhb			quiesce_wrq(sc, &sc->sge.ctrlq[pi->port_id]);
4528284052Snp
4529308154Sjhb		for_each_txq(vi, i, txq) {
4530284052Snp			quiesce_txq(sc, txq);
4531228561Snp		}
4532228561Snp
4533237263Snp#ifdef TCP_OFFLOAD
4534308154Sjhb		for_each_ofld_txq(vi, i, ofld_txq) {
4535284052Snp			quiesce_wrq(sc, ofld_txq);
4536228561Snp		}
4537228561Snp#endif
4538228561Snp
4539308154Sjhb		for_each_rxq(vi, i, rxq) {
4540228561Snp			quiesce_iq(sc, &rxq->iq);
4541228561Snp			quiesce_fl(sc, &rxq->fl);
4542228561Snp		}
4543228561Snp
4544237263Snp#ifdef TCP_OFFLOAD
4545308154Sjhb		for_each_ofld_rxq(vi, i, ofld_rxq) {
4546228561Snp			quiesce_iq(sc, &ofld_rxq->iq);
4547228561Snp			quiesce_fl(sc, &ofld_rxq->fl);
4548228561Snp		}
4549228561Snp#endif
4550308154Sjhb		free(vi->rss, M_CXGBE);
4551308154Sjhb		free(vi->nm_rss, M_CXGBE);
4552228561Snp	}
4553228561Snp
4554308154Sjhb	t4_teardown_vi_queues(vi);
4555308154Sjhb	vi->flags &= ~VI_INIT_DONE;
4556228561Snp
4557228561Snp	return (0);
4558228561Snp}
4559228561Snp
4560228561Snpstatic void
4561284052Snpquiesce_txq(struct adapter *sc, struct sge_txq *txq)
4562228561Snp{
4563284052Snp	struct sge_eq *eq = &txq->eq;
4564284052Snp	struct sge_qstat *spg = (void *)&eq->desc[eq->sidx];
4565228561Snp
4566284052Snp	(void) sc;	/* unused */
4567228561Snp
4568284052Snp#ifdef INVARIANTS
4569284052Snp	TXQ_LOCK(txq);
4570284052Snp	MPASS((eq->flags & EQ_ENABLED) == 0);
4571284052Snp	TXQ_UNLOCK(txq);
4572284052Snp#endif
4573228561Snp
4574284052Snp	/* Wait for the mp_ring to empty. */
4575284052Snp	while (!mp_ring_is_idle(txq->r)) {
4576284052Snp		mp_ring_check_drainage(txq->r, 0);
4577284052Snp		pause("rquiesce", 1);
4578284052Snp	}
4579284052Snp
4580284052Snp	/* Then wait for the hardware to finish. */
4581284052Snp	while (spg->cidx != htobe16(eq->pidx))
4582284052Snp		pause("equiesce", 1);
4583284052Snp
4584284052Snp	/* Finally, wait for the driver to reclaim all descriptors. */
4585284052Snp	while (eq->cidx != eq->pidx)
4586284052Snp		pause("dquiesce", 1);
4587228561Snp}
4588228561Snp
4589228561Snpstatic void
4590284052Snpquiesce_wrq(struct adapter *sc, struct sge_wrq *wrq)
4591284052Snp{
4592284052Snp
4593284052Snp	/* XXXTX */
4594284052Snp}
4595284052Snp
4596284052Snpstatic void
4597228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq)
4598228561Snp{
4599228561Snp	(void) sc;	/* unused */
4600228561Snp
4601228561Snp	/* Synchronize with the interrupt handler */
4602228561Snp	while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED))
4603228561Snp		pause("iqfree", 1);
4604228561Snp}
4605228561Snp
4606228561Snpstatic void
4607228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl)
4608228561Snp{
4609228561Snp	mtx_lock(&sc->sfl_lock);
4610228561Snp	FL_LOCK(fl);
4611228561Snp	fl->flags |= FL_DOOMED;
4612228561Snp	FL_UNLOCK(fl);
4613308154Sjhb	callout_stop(&sc->sfl_callout);
4614228561Snp	mtx_unlock(&sc->sfl_lock);
4615228561Snp
4616228561Snp	KASSERT((fl->flags & FL_STARVING) == 0,
4617228561Snp	    ("%s: still starving", __func__));
4618228561Snp}
4619228561Snp
4620228561Snpstatic int
4621218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid,
4622228561Snp    driver_intr_t *handler, void *arg, char *name)
4623218792Snp{
4624218792Snp	int rc;
4625218792Snp
4626218792Snp	irq->rid = rid;
4627218792Snp	irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid,
4628218792Snp	    RF_SHAREABLE | RF_ACTIVE);
4629218792Snp	if (irq->res == NULL) {
4630218792Snp		device_printf(sc->dev,
4631218792Snp		    "failed to allocate IRQ for rid %d, name %s.\n", rid, name);
4632218792Snp		return (ENOMEM);
4633218792Snp	}
4634218792Snp
4635218792Snp	rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET,
4636218792Snp	    NULL, handler, arg, &irq->tag);
4637218792Snp	if (rc != 0) {
4638218792Snp		device_printf(sc->dev,
4639218792Snp		    "failed to setup interrupt for rid %d, name %s: %d\n",
4640218792Snp		    rid, name, rc);
4641218792Snp	} else if (name)
4642218792Snp		bus_describe_intr(sc->dev, irq->res, irq->tag, name);
4643218792Snp
4644218792Snp	return (rc);
4645218792Snp}
4646218792Snp
4647218792Snpstatic int
4648218792Snpt4_free_irq(struct adapter *sc, struct irq *irq)
4649218792Snp{
4650218792Snp	if (irq->tag)
4651218792Snp		bus_teardown_intr(sc->dev, irq->res, irq->tag);
4652218792Snp	if (irq->res)
4653218792Snp		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res);
4654218792Snp
4655218792Snp	bzero(irq, sizeof(*irq));
4656218792Snp
4657218792Snp	return (0);
4658218792Snp}
4659218792Snp
4660218792Snpstatic void
4661308304Sjhbget_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf)
4662218792Snp{
4663218792Snp
4664248925Snp	regs->version = chip_id(sc) | chip_rev(sc) << 10;
4665308304Sjhb	t4_get_regs(sc, buf, regs->len);
4666218792Snp}
4667218792Snp
4668308154Sjhb#define	A_PL_INDIR_CMD	0x1f8
4669308154Sjhb
4670308154Sjhb#define	S_PL_AUTOINC	31
4671308154Sjhb#define	M_PL_AUTOINC	0x1U
4672308154Sjhb#define	V_PL_AUTOINC(x)	((x) << S_PL_AUTOINC)
4673308154Sjhb#define	G_PL_AUTOINC(x)	(((x) >> S_PL_AUTOINC) & M_PL_AUTOINC)
4674308154Sjhb
4675308154Sjhb#define	S_PL_VFID	20
4676308154Sjhb#define	M_PL_VFID	0xffU
4677308154Sjhb#define	V_PL_VFID(x)	((x) << S_PL_VFID)
4678308154Sjhb#define	G_PL_VFID(x)	(((x) >> S_PL_VFID) & M_PL_VFID)
4679308154Sjhb
4680308154Sjhb#define	S_PL_ADDR	0
4681308154Sjhb#define	M_PL_ADDR	0xfffffU
4682308154Sjhb#define	V_PL_ADDR(x)	((x) << S_PL_ADDR)
4683308154Sjhb#define	G_PL_ADDR(x)	(((x) >> S_PL_ADDR) & M_PL_ADDR)
4684308154Sjhb
4685308154Sjhb#define	A_PL_INDIR_DATA	0x1fc
4686308154Sjhb
4687308154Sjhbstatic uint64_t
4688308154Sjhbread_vf_stat(struct adapter *sc, unsigned int viid, int reg)
4689308154Sjhb{
4690308154Sjhb	u32 stats[2];
4691308154Sjhb
4692308305Sjhb	mtx_assert(&sc->reg_lock, MA_OWNED);
4693309447Sjhb	if (sc->flags & IS_VF) {
4694309447Sjhb		stats[0] = t4_read_reg(sc, VF_MPS_REG(reg));
4695309447Sjhb		stats[1] = t4_read_reg(sc, VF_MPS_REG(reg + 4));
4696309447Sjhb	} else {
4697309447Sjhb		t4_write_reg(sc, A_PL_INDIR_CMD, V_PL_AUTOINC(1) |
4698309447Sjhb		    V_PL_VFID(G_FW_VIID_VIN(viid)) |
4699309447Sjhb		    V_PL_ADDR(VF_MPS_REG(reg)));
4700309447Sjhb		stats[0] = t4_read_reg(sc, A_PL_INDIR_DATA);
4701309447Sjhb		stats[1] = t4_read_reg(sc, A_PL_INDIR_DATA);
4702309447Sjhb	}
4703308154Sjhb	return (((uint64_t)stats[1]) << 32 | stats[0]);
4704308154Sjhb}
4705308154Sjhb
4706218792Snpstatic void
4707308154Sjhbt4_get_vi_stats(struct adapter *sc, unsigned int viid,
4708308154Sjhb    struct fw_vi_stats_vf *stats)
4709308154Sjhb{
4710308154Sjhb
4711308154Sjhb#define GET_STAT(name) \
4712308154Sjhb	read_vf_stat(sc, viid, A_MPS_VF_STAT_##name##_L)
4713308154Sjhb
4714308154Sjhb	stats->tx_bcast_bytes    = GET_STAT(TX_VF_BCAST_BYTES);
4715308154Sjhb	stats->tx_bcast_frames   = GET_STAT(TX_VF_BCAST_FRAMES);
4716308154Sjhb	stats->tx_mcast_bytes    = GET_STAT(TX_VF_MCAST_BYTES);
4717308154Sjhb	stats->tx_mcast_frames   = GET_STAT(TX_VF_MCAST_FRAMES);
4718308154Sjhb	stats->tx_ucast_bytes    = GET_STAT(TX_VF_UCAST_BYTES);
4719308154Sjhb	stats->tx_ucast_frames   = GET_STAT(TX_VF_UCAST_FRAMES);
4720308154Sjhb	stats->tx_drop_frames    = GET_STAT(TX_VF_DROP_FRAMES);
4721308154Sjhb	stats->tx_offload_bytes  = GET_STAT(TX_VF_OFFLOAD_BYTES);
4722308154Sjhb	stats->tx_offload_frames = GET_STAT(TX_VF_OFFLOAD_FRAMES);
4723308154Sjhb	stats->rx_bcast_bytes    = GET_STAT(RX_VF_BCAST_BYTES);
4724308154Sjhb	stats->rx_bcast_frames   = GET_STAT(RX_VF_BCAST_FRAMES);
4725308154Sjhb	stats->rx_mcast_bytes    = GET_STAT(RX_VF_MCAST_BYTES);
4726308154Sjhb	stats->rx_mcast_frames   = GET_STAT(RX_VF_MCAST_FRAMES);
4727308154Sjhb	stats->rx_ucast_bytes    = GET_STAT(RX_VF_UCAST_BYTES);
4728308154Sjhb	stats->rx_ucast_frames   = GET_STAT(RX_VF_UCAST_FRAMES);
4729308154Sjhb	stats->rx_err_frames     = GET_STAT(RX_VF_ERR_FRAMES);
4730308154Sjhb
4731308154Sjhb#undef GET_STAT
4732308154Sjhb}
4733308154Sjhb
4734308154Sjhbstatic void
4735308154Sjhbt4_clr_vi_stats(struct adapter *sc, unsigned int viid)
4736308154Sjhb{
4737308154Sjhb	int reg;
4738308154Sjhb
4739308154Sjhb	t4_write_reg(sc, A_PL_INDIR_CMD, V_PL_AUTOINC(1) |
4740308154Sjhb	    V_PL_VFID(G_FW_VIID_VIN(viid)) |
4741308154Sjhb	    V_PL_ADDR(VF_MPS_REG(A_MPS_VF_STAT_TX_VF_BCAST_BYTES_L)));
4742308154Sjhb	for (reg = A_MPS_VF_STAT_TX_VF_BCAST_BYTES_L;
4743308154Sjhb	     reg <= A_MPS_VF_STAT_RX_VF_ERR_FRAMES_H; reg += 4)
4744308154Sjhb		t4_write_reg(sc, A_PL_INDIR_DATA, 0);
4745308154Sjhb}
4746308154Sjhb
4747308154Sjhbstatic void
4748308154Sjhbvi_refresh_stats(struct adapter *sc, struct vi_info *vi)
4749308154Sjhb{
4750308154Sjhb	struct ifnet *ifp = vi->ifp;
4751308154Sjhb	struct sge_txq *txq;
4752308154Sjhb	int i, drops;
4753308154Sjhb	struct fw_vi_stats_vf *s = &vi->stats;
4754308154Sjhb	struct timeval tv;
4755308154Sjhb	const struct timeval interval = {0, 250000};	/* 250ms */
4756308154Sjhb
4757308154Sjhb	if (!(vi->flags & VI_INIT_DONE))
4758308154Sjhb		return;
4759308154Sjhb
4760308154Sjhb	getmicrotime(&tv);
4761308154Sjhb	timevalsub(&tv, &interval);
4762308154Sjhb	if (timevalcmp(&tv, &vi->last_refreshed, <))
4763308154Sjhb		return;
4764308154Sjhb
4765308305Sjhb	mtx_lock(&sc->reg_lock);
4766308154Sjhb	t4_get_vi_stats(sc, vi->viid, &vi->stats);
4767308154Sjhb
4768308154Sjhb	ifp->if_ipackets = s->rx_bcast_frames + s->rx_mcast_frames +
4769308154Sjhb	    s->rx_ucast_frames;
4770308154Sjhb	ifp->if_ierrors = s->rx_err_frames;
4771308154Sjhb	ifp->if_opackets = s->tx_bcast_frames + s->tx_mcast_frames +
4772308154Sjhb	    s->tx_ucast_frames + s->tx_offload_frames;
4773308154Sjhb	ifp->if_oerrors = s->tx_drop_frames;
4774308154Sjhb	ifp->if_ibytes = s->rx_bcast_bytes + s->rx_mcast_bytes +
4775308154Sjhb	    s->rx_ucast_bytes;
4776308154Sjhb	ifp->if_obytes = s->tx_bcast_bytes + s->tx_mcast_bytes +
4777308154Sjhb	    s->tx_ucast_bytes + s->tx_offload_bytes;
4778308154Sjhb	ifp->if_imcasts = s->rx_mcast_frames;
4779308154Sjhb	ifp->if_omcasts = s->tx_mcast_frames;
4780308154Sjhb
4781308154Sjhb	drops = 0;
4782308154Sjhb	for_each_txq(vi, i, txq)
4783308154Sjhb		drops += counter_u64_fetch(txq->r->drops);
4784308154Sjhb	ifp->if_snd.ifq_drops = drops;
4785308154Sjhb
4786308154Sjhb	getmicrotime(&vi->last_refreshed);
4787308305Sjhb	mtx_unlock(&sc->reg_lock);
4788308154Sjhb}
4789308154Sjhb
4790308154Sjhbstatic void
4791282486Snpcxgbe_refresh_stats(struct adapter *sc, struct port_info *pi)
4792218792Snp{
4793308154Sjhb	struct vi_info *vi = &pi->vi[0];
4794308154Sjhb	struct ifnet *ifp = vi->ifp;
4795218792Snp	struct sge_txq *txq;
4796218792Snp	int i, drops;
4797218792Snp	struct port_stats *s = &pi->stats;
4798282486Snp	struct timeval tv;
4799282486Snp	const struct timeval interval = {0, 250000};	/* 250ms */
4800218792Snp
4801282486Snp	getmicrotime(&tv);
4802282486Snp	timevalsub(&tv, &interval);
4803282486Snp	if (timevalcmp(&tv, &pi->last_refreshed, <))
4804282486Snp		return;
4805218792Snp
4806265425Snp	t4_get_port_stats(sc, pi->tx_chan, s);
4807218792Snp
4808308315Sjhb	ifp->if_opackets = s->tx_frames;
4809308315Sjhb	ifp->if_ipackets = s->rx_frames;
4810308315Sjhb	ifp->if_obytes = s->tx_octets;
4811308315Sjhb	ifp->if_ibytes = s->rx_octets;
4812308315Sjhb	ifp->if_omcasts = s->tx_mcast_frames;
4813308315Sjhb	ifp->if_imcasts = s->rx_mcast_frames;
4814218792Snp	ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 +
4815239259Snp	    s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 +
4816239259Snp	    s->rx_trunc3;
4817308304Sjhb	for (i = 0; i < sc->chip_params->nchan; i++) {
4818265425Snp		if (pi->rx_chan_map & (1 << i)) {
4819265425Snp			uint32_t v;
4820218792Snp
4821308305Sjhb			mtx_lock(&sc->reg_lock);
4822265425Snp			t4_read_indirect(sc, A_TP_MIB_INDEX, A_TP_MIB_DATA, &v,
4823265425Snp			    1, A_TP_MIB_TNL_CNG_DROP_0 + i);
4824308305Sjhb			mtx_unlock(&sc->reg_lock);
4825265425Snp			ifp->if_iqdrops += v;
4826265425Snp		}
4827265425Snp	}
4828265425Snp
4829218792Snp	drops = s->tx_drop;
4830308154Sjhb	for_each_txq(vi, i, txq)
4831284052Snp		drops += counter_u64_fetch(txq->r->drops);
4832218792Snp	ifp->if_snd.ifq_drops = drops;
4833218792Snp
4834218792Snp	ifp->if_oerrors = s->tx_error_frames;
4835218792Snp	ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long +
4836218792Snp	    s->rx_fcs_err + s->rx_len_err;
4837218792Snp
4838282486Snp	getmicrotime(&pi->last_refreshed);
4839282486Snp}
4840282486Snp
4841282486Snpstatic void
4842282486Snpcxgbe_tick(void *arg)
4843282486Snp{
4844282486Snp	struct port_info *pi = arg;
4845282486Snp	struct adapter *sc = pi->adapter;
4846282486Snp
4847308154Sjhb	PORT_LOCK_ASSERT_OWNED(pi);
4848282486Snp	cxgbe_refresh_stats(sc, pi);
4849282486Snp
4850218792Snp	callout_schedule(&pi->tick, hz);
4851218792Snp}
4852218792Snp
4853308154Sjhbvoid
4854308154Sjhbvi_tick(void *arg)
4855308154Sjhb{
4856308154Sjhb	struct vi_info *vi = arg;
4857308154Sjhb	struct adapter *sc = vi->pi->adapter;
4858308154Sjhb
4859308154Sjhb	vi_refresh_stats(sc, vi);
4860308154Sjhb
4861308154Sjhb	callout_schedule(&vi->tick, hz);
4862308154Sjhb}
4863308154Sjhb
4864237263Snpstatic void
4865237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid)
4866237263Snp{
4867237263Snp	struct ifnet *vlan;
4868237263Snp
4869241494Snp	if (arg != ifp || ifp->if_type != IFT_ETHER)
4870237263Snp		return;
4871237263Snp
4872237263Snp	vlan = VLAN_DEVAT(ifp, vid);
4873237263Snp	VLAN_SETCOOKIE(vlan, ifp);
4874237263Snp}
4875237263Snp
4876308304Sjhb/*
4877308304Sjhb * Should match fw_caps_config_<foo> enums in t4fw_interface.h
4878308304Sjhb */
4879308304Sjhbstatic char *caps_decoder[] = {
4880308304Sjhb	"\20\001IPMI\002NCSI",				/* 0: NBM */
4881308304Sjhb	"\20\001PPP\002QFC\003DCBX",			/* 1: link */
4882308304Sjhb	"\20\001INGRESS\002EGRESS",			/* 2: switch */
4883308304Sjhb	"\20\001NIC\002VM\003IDS\004UM\005UM_ISGL"	/* 3: NIC */
4884308304Sjhb	    "\006HASHFILTER\007ETHOFLD",
4885308304Sjhb	"\20\001TOE",					/* 4: TOE */
4886308304Sjhb	"\20\001RDDP\002RDMAC",				/* 5: RDMA */
4887308304Sjhb	"\20\001INITIATOR_PDU\002TARGET_PDU"		/* 6: iSCSI */
4888308304Sjhb	    "\003INITIATOR_CNXOFLD\004TARGET_CNXOFLD"
4889308304Sjhb	    "\005INITIATOR_SSNOFLD\006TARGET_SSNOFLD"
4890308304Sjhb	    "\007T10DIF"
4891308304Sjhb	    "\010INITIATOR_CMDOFLD\011TARGET_CMDOFLD",
4892309560Sjhb	"\20\001LOOKASIDE\002TLSKEYS",			/* 7: Crypto */
4893308304Sjhb	"\20\001INITIATOR\002TARGET\003CTRL_OFLD"	/* 8: FCoE */
4894308304Sjhb		    "\004PO_INITIATOR\005PO_TARGET",
4895308304Sjhb};
4896308304Sjhb
4897309447Sjhbvoid
4898218792Snpt4_sysctls(struct adapter *sc)
4899218792Snp{
4900218792Snp	struct sysctl_ctx_list *ctx;
4901218792Snp	struct sysctl_oid *oid;
4902228561Snp	struct sysctl_oid_list *children, *c0;
4903249392Snp	static char *doorbells = {"\20\1UDB\2WCWR\3UDBWC\4KDB"};
4904218792Snp
4905218792Snp	ctx = device_get_sysctl_ctx(sc->dev);
4906228561Snp
4907228561Snp	/*
4908228561Snp	 * dev.t4nex.X.
4909228561Snp	 */
4910218792Snp	oid = device_get_sysctl_tree(sc->dev);
4911228561Snp	c0 = children = SYSCTL_CHILDREN(oid);
4912218792Snp
4913265421Snp	sc->sc_do_rxcopy = 1;
4914265421Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "do_rx_copy", CTLFLAG_RW,
4915265421Snp	    &sc->sc_do_rxcopy, 1, "Do RX copy of small frames");
4916265421Snp
4917248925Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, NULL,
4918248925Snp	    sc->params.nports, "# of ports");
4919218792Snp
4920309447Sjhb	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "doorbells",
4921309447Sjhb	    CTLTYPE_STRING | CTLFLAG_RD, doorbells, sc->doorbells,
4922309447Sjhb	    sysctl_bitfield, "A", "available doorbells");
4923218792Snp
4924309447Sjhb	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, NULL,
4925309447Sjhb	    sc->params.vpd.cclk, "core clock frequency (in KHz)");
4926309447Sjhb
4927309447Sjhb	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers",
4928309447Sjhb	    CTLTYPE_STRING | CTLFLAG_RD, sc->params.sge.timer_val,
4929309447Sjhb	    sizeof(sc->params.sge.timer_val), sysctl_int_array, "A",
4930309447Sjhb	    "interrupt holdoff timer values (us)");
4931309447Sjhb
4932309447Sjhb	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts",
4933309447Sjhb	    CTLTYPE_STRING | CTLFLAG_RD, sc->params.sge.counter_val,
4934309447Sjhb	    sizeof(sc->params.sge.counter_val), sysctl_int_array, "A",
4935309447Sjhb	    "interrupt holdoff packet counter values");
4936309447Sjhb
4937309447Sjhb	t4_sge_sysctls(sc, ctx, children);
4938309447Sjhb
4939309447Sjhb	sc->lro_timeout = 100;
4940309447Sjhb	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "lro_timeout", CTLFLAG_RW,
4941309447Sjhb	    &sc->lro_timeout, 0, "lro inactive-flush timeout (in us)");
4942309447Sjhb
4943309458Sjhb	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "dflags", CTLFLAG_RW,
4944309447Sjhb	    &sc->debug_flags, 0, "flags to enable runtime debugging");
4945309447Sjhb
4946308311Sjhb	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "tp_version",
4947308311Sjhb	    CTLFLAG_RD, sc->tp_version, 0, "TP microcode version");
4948308311Sjhb
4949309447Sjhb	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version",
4950309447Sjhb	    CTLFLAG_RD, sc->fw_version, 0, "firmware version");
4951309447Sjhb
4952309447Sjhb	if (sc->flags & IS_VF)
4953309447Sjhb		return;
4954309447Sjhb
4955309447Sjhb	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD,
4956309447Sjhb	    NULL, chip_rev(sc), "chip hardware revision");
4957309447Sjhb
4958309458Sjhb	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "sn",
4959309458Sjhb	    CTLFLAG_RD, sc->params.vpd.sn, 0, "serial number");
4960308311Sjhb
4961309458Sjhb	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "pn",
4962309458Sjhb	    CTLFLAG_RD, sc->params.vpd.pn, 0, "part number");
4963309458Sjhb
4964309458Sjhb	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "ec",
4965309458Sjhb	    CTLFLAG_RD, sc->params.vpd.ec, 0, "engineering change");
4966309458Sjhb
4967309458Sjhb	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "na",
4968309458Sjhb	    CTLFLAG_RD, sc->params.vpd.na, 0, "network address");
4969309458Sjhb
4970309458Sjhb	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "er_version", CTLFLAG_RD,
4971309458Sjhb	    sc->er_version, 0, "expansion ROM version");
4972309458Sjhb
4973309458Sjhb	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "bs_version", CTLFLAG_RD,
4974309458Sjhb	    sc->bs_version, 0, "bootstrap firmware version");
4975309458Sjhb
4976309458Sjhb	SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "scfg_version", CTLFLAG_RD,
4977309458Sjhb	    NULL, sc->params.scfg_vers, "serial config version");
4978309458Sjhb
4979309458Sjhb	SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "vpd_version", CTLFLAG_RD,
4980309458Sjhb	    NULL, sc->params.vpd_vers, "VPD version");
4981309458Sjhb
4982228561Snp	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf",
4983273736Shselasky	    CTLFLAG_RD, sc->cfg_file, 0, "configuration file");
4984218792Snp
4985248925Snp	SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, NULL,
4986248925Snp	    sc->cfcsum, "config file checksum");
4987228561Snp
4988308304Sjhb#define SYSCTL_CAP(name, n, text) \
4989308304Sjhb	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, #name, \
4990308304Sjhb	    CTLTYPE_STRING | CTLFLAG_RD, caps_decoder[n], sc->name, \
4991309458Sjhb	    sysctl_bitfield, "A", "available " text " capabilities")
4992228561Snp
4993308304Sjhb	SYSCTL_CAP(nbmcaps, 0, "NBM");
4994308304Sjhb	SYSCTL_CAP(linkcaps, 1, "link");
4995308304Sjhb	SYSCTL_CAP(switchcaps, 2, "switch");
4996308304Sjhb	SYSCTL_CAP(niccaps, 3, "NIC");
4997308304Sjhb	SYSCTL_CAP(toecaps, 4, "TCP offload");
4998308304Sjhb	SYSCTL_CAP(rdmacaps, 5, "RDMA");
4999308304Sjhb	SYSCTL_CAP(iscsicaps, 6, "iSCSI");
5000309560Sjhb	SYSCTL_CAP(cryptocaps, 7, "crypto");
5001308304Sjhb	SYSCTL_CAP(fcoecaps, 8, "FCoE");
5002308304Sjhb#undef SYSCTL_CAP
5003228561Snp
5004252469Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nfilters", CTLFLAG_RD,
5005252469Snp	    NULL, sc->tids.nftids, "number of filters");
5006252469Snp
5007253890Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature", CTLTYPE_INT |
5008264736Semax	    CTLFLAG_RD, sc, 0, sysctl_temperature, "I",
5009253890Snp	    "chip temperature (in Celsius)");
5010253890Snp
5011231115Snp#ifdef SBUF_DRAIN
5012228561Snp	/*
5013228561Snp	 * dev.t4nex.X.misc.  Marked CTLFLAG_SKIP to avoid information overload.
5014228561Snp	 */
5015228561Snp	oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc",
5016228561Snp	    CTLFLAG_RD | CTLFLAG_SKIP, NULL,
5017228561Snp	    "logs and miscellaneous information");
5018228561Snp	children = SYSCTL_CHILDREN(oid);
5019228561Snp
5020228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl",
5021228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5022228561Snp	    sysctl_cctrl, "A", "congestion control");
5023228561Snp
5024247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0",
5025247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5026247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)");
5027247122Snp
5028247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1",
5029247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 1,
5030247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)");
5031247122Snp
5032247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp",
5033247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 2,
5034247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)");
5035247122Snp
5036247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0",
5037247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 3,
5038247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)");
5039247122Snp
5040247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1",
5041247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 4,
5042247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)");
5043247122Snp
5044247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi",
5045247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 5,
5046247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)");
5047247122Snp
5048247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la",
5049247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5050308304Sjhb	    chip_id(sc) <= CHELSIO_T5 ? sysctl_cim_la : sysctl_cim_la_t6,
5051308304Sjhb	    "A", "CIM logic analyzer");
5052247122Snp
5053251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ma_la",
5054251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5055251213Snp	    sysctl_cim_ma_la, "A", "CIM MA logic analyzer");
5056251213Snp
5057247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0",
5058247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ,
5059247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)");
5060247122Snp
5061247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1",
5062247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ,
5063247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)");
5064247122Snp
5065247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2",
5066247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ,
5067247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)");
5068247122Snp
5069247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3",
5070247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ,
5071247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)");
5072247122Snp
5073247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge",
5074247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ,
5075247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)");
5076247122Snp
5077247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi",
5078247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ,
5079247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)");
5080247122Snp
5081308304Sjhb	if (chip_id(sc) > CHELSIO_T4) {
5082248925Snp		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge0_rx",
5083248925Snp		    CTLTYPE_STRING | CTLFLAG_RD, sc, 6 + CIM_NUM_IBQ,
5084248925Snp		    sysctl_cim_ibq_obq, "A", "CIM OBQ 6 (SGE0-RX)");
5085248925Snp
5086248925Snp		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge1_rx",
5087248925Snp		    CTLTYPE_STRING | CTLFLAG_RD, sc, 7 + CIM_NUM_IBQ,
5088248925Snp		    sysctl_cim_ibq_obq, "A", "CIM OBQ 7 (SGE1-RX)");
5089248925Snp	}
5090248925Snp
5091251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_pif_la",
5092251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5093251213Snp	    sysctl_cim_pif_la, "A", "CIM PIF logic analyzer");
5094251213Snp
5095247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg",
5096247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5097247122Snp	    sysctl_cim_qcfg, "A", "CIM queue configuration");
5098247122Snp
5099228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats",
5100228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5101228561Snp	    sysctl_cpl_stats, "A", "CPL statistics");
5102228561Snp
5103228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats",
5104228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5105281241Snp	    sysctl_ddp_stats, "A", "non-TCP DDP statistics");
5106228561Snp
5107222551Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog",
5108222551Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5109228561Snp	    sysctl_devlog, "A", "firmware's device log");
5110222551Snp
5111228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats",
5112228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5113228561Snp	    sysctl_fcoe_stats, "A", "FCoE statistics");
5114228561Snp
5115228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched",
5116228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5117228561Snp	    sysctl_hw_sched, "A", "hardware scheduler ");
5118228561Snp
5119228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t",
5120228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5121228561Snp	    sysctl_l2t, "A", "hardware L2 table");
5122228561Snp
5123228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats",
5124228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5125228561Snp	    sysctl_lb_stats, "A", "loopback statistics");
5126228561Snp
5127228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo",
5128228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5129228561Snp	    sysctl_meminfo, "A", "memory regions");
5130228561Snp
5131251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mps_tcam",
5132251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5133308304Sjhb	    chip_id(sc) <= CHELSIO_T5 ? sysctl_mps_tcam : sysctl_mps_tcam_t6,
5134308304Sjhb	    "A", "MPS TCAM entries");
5135251213Snp
5136228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus",
5137228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5138228561Snp	    sysctl_path_mtus, "A", "path MTUs");
5139228561Snp
5140228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats",
5141228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5142228561Snp	    sysctl_pm_stats, "A", "PM statistics");
5143228561Snp
5144228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats",
5145228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5146228561Snp	    sysctl_rdma_stats, "A", "RDMA statistics");
5147228561Snp
5148228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats",
5149228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5150228561Snp	    sysctl_tcp_stats, "A", "TCP statistics");
5151228561Snp
5152228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids",
5153228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5154228561Snp	    sysctl_tids, "A", "TID information");
5155228561Snp
5156228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats",
5157228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5158228561Snp	    sysctl_tp_err_stats, "A", "TP error statistics");
5159228561Snp
5160308311Sjhb	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la_mask",
5161308311Sjhb	    CTLTYPE_INT | CTLFLAG_RW, sc, 0, sysctl_tp_la_mask, "I",
5162308311Sjhb	    "TP logic analyzer event capture mask");
5163308311Sjhb
5164251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la",
5165251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5166251213Snp	    sysctl_tp_la, "A", "TP logic analyzer");
5167251213Snp
5168228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate",
5169228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5170228561Snp	    sysctl_tx_rate, "A", "Tx rate");
5171248925Snp
5172251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ulprx_la",
5173251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5174251213Snp	    sysctl_ulprx_la, "A", "ULPRX logic analyzer");
5175251213Snp
5176309560Sjhb	if (chip_id(sc) >= CHELSIO_T5) {
5177249392Snp		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "wcwr_stats",
5178248925Snp		    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
5179249392Snp		    sysctl_wcwr_stats, "A", "write combined work requests");
5180248925Snp	}
5181231115Snp#endif
5182228561Snp
5183237263Snp#ifdef TCP_OFFLOAD
5184228561Snp	if (is_offload(sc)) {
5185228561Snp		/*
5186228561Snp		 * dev.t4nex.X.toe.
5187228561Snp		 */
5188228561Snp		oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD,
5189228561Snp		    NULL, "TOE parameters");
5190228561Snp		children = SYSCTL_CHILDREN(oid);
5191228561Snp
5192228561Snp		sc->tt.sndbuf = 256 * 1024;
5193228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW,
5194228561Snp		    &sc->tt.sndbuf, 0, "max hardware send buffer size");
5195228561Snp
5196228561Snp		sc->tt.ddp = 0;
5197228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW,
5198228561Snp		    &sc->tt.ddp, 0, "DDP allowed");
5199239341Snp
5200239341Snp		sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5));
5201228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW,
5202228561Snp		    &sc->tt.indsz, 0, "DDP max indicate size allowed");
5203239341Snp
5204239341Snp		sc->tt.ddp_thres =
5205239341Snp		    G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2));
5206228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW,
5207228561Snp		    &sc->tt.ddp_thres, 0, "DDP threshold");
5208252728Snp
5209252728Snp		sc->tt.rx_coalesce = 1;
5210252728Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_coalesce",
5211252728Snp		    CTLFLAG_RW, &sc->tt.rx_coalesce, 0, "receive coalescing");
5212281244Snp
5213281244Snp		sc->tt.tx_align = 1;
5214281244Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_align",
5215281244Snp		    CTLFLAG_RW, &sc->tt.tx_align, 0, "chop and align payload");
5216308311Sjhb
5217308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "timer_tick",
5218308311Sjhb		    CTLTYPE_STRING | CTLFLAG_RD, sc, 0, sysctl_tp_tick, "A",
5219308311Sjhb		    "TP timer tick (us)");
5220308311Sjhb
5221308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "timestamp_tick",
5222308311Sjhb		    CTLTYPE_STRING | CTLFLAG_RD, sc, 1, sysctl_tp_tick, "A",
5223308311Sjhb		    "TCP timestamp tick (us)");
5224308311Sjhb
5225308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dack_tick",
5226308311Sjhb		    CTLTYPE_STRING | CTLFLAG_RD, sc, 2, sysctl_tp_tick, "A",
5227308311Sjhb		    "DACK tick (us)");
5228308311Sjhb
5229308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dack_timer",
5230308311Sjhb		    CTLTYPE_UINT | CTLFLAG_RD, sc, 0, sysctl_tp_dack_timer,
5231308311Sjhb		    "IU", "DACK timer (us)");
5232308311Sjhb
5233308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rexmt_min",
5234308311Sjhb		    CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_RXT_MIN,
5235308311Sjhb		    sysctl_tp_timer, "LU", "Retransmit min (us)");
5236308311Sjhb
5237308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rexmt_max",
5238308311Sjhb		    CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_RXT_MAX,
5239308311Sjhb		    sysctl_tp_timer, "LU", "Retransmit max (us)");
5240308311Sjhb
5241308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "persist_min",
5242308311Sjhb		    CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_PERS_MIN,
5243308311Sjhb		    sysctl_tp_timer, "LU", "Persist timer min (us)");
5244308311Sjhb
5245308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "persist_max",
5246308311Sjhb		    CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_PERS_MAX,
5247308311Sjhb		    sysctl_tp_timer, "LU", "Persist timer max (us)");
5248308311Sjhb
5249308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "keepalive_idle",
5250308311Sjhb		    CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_KEEP_IDLE,
5251308311Sjhb		    sysctl_tp_timer, "LU", "Keepidle idle timer (us)");
5252308311Sjhb
5253308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "keepalive_intvl",
5254308311Sjhb		    CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_KEEP_INTVL,
5255308311Sjhb		    sysctl_tp_timer, "LU", "Keepidle interval (us)");
5256308311Sjhb
5257308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "initial_srtt",
5258308311Sjhb		    CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_INIT_SRTT,
5259308311Sjhb		    sysctl_tp_timer, "LU", "Initial SRTT (us)");
5260308311Sjhb
5261308311Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "finwait2_timer",
5262308311Sjhb		    CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_FINWAIT2_TIMER,
5263308311Sjhb		    sysctl_tp_timer, "LU", "FINWAIT2 timer (us)");
5264228561Snp	}
5265228561Snp#endif
5266218792Snp}
5267218792Snp
5268308154Sjhbvoid
5269308154Sjhbvi_sysctls(struct vi_info *vi)
5270218792Snp{
5271218792Snp	struct sysctl_ctx_list *ctx;
5272218792Snp	struct sysctl_oid *oid;
5273218792Snp	struct sysctl_oid_list *children;
5274218792Snp
5275308154Sjhb	ctx = device_get_sysctl_ctx(vi->dev);
5276218792Snp
5277218792Snp	/*
5278308154Sjhb	 * dev.v?(cxgbe|cxl).X.
5279218792Snp	 */
5280308154Sjhb	oid = device_get_sysctl_tree(vi->dev);
5281218792Snp	children = SYSCTL_CHILDREN(oid);
5282218792Snp
5283308154Sjhb	SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "viid", CTLFLAG_RD, NULL,
5284308154Sjhb	    vi->viid, "VI identifer");
5285218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD,
5286308154Sjhb	    &vi->nrxq, 0, "# of rx queues");
5287218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD,
5288308154Sjhb	    &vi->ntxq, 0, "# of tx queues");
5289218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD,
5290308154Sjhb	    &vi->first_rxq, 0, "index of first rx queue");
5291218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD,
5292308154Sjhb	    &vi->first_txq, 0, "index of first tx queue");
5293309458Sjhb	SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "rss_size", CTLFLAG_RD, NULL,
5294309458Sjhb	    vi->rss_size, "size of RSS indirection table");
5295218792Snp
5296308154Sjhb	if (IS_MAIN_VI(vi)) {
5297308154Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rsrv_noflowq",
5298308154Sjhb		    CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_noflowq, "IU",
5299308154Sjhb		    "Reserve queue 0 for non-flowid packets");
5300308154Sjhb	}
5301308154Sjhb
5302237263Snp#ifdef TCP_OFFLOAD
5303308154Sjhb	if (vi->nofldrxq != 0) {
5304228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD,
5305308154Sjhb		    &vi->nofldrxq, 0,
5306228561Snp		    "# of rx queues for offloaded TCP connections");
5307228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD,
5308308154Sjhb		    &vi->nofldtxq, 0,
5309228561Snp		    "# of tx queues for offloaded TCP connections");
5310228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq",
5311308154Sjhb		    CTLFLAG_RD, &vi->first_ofld_rxq, 0,
5312228561Snp		    "index of first TOE rx queue");
5313228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq",
5314308154Sjhb		    CTLFLAG_RD, &vi->first_ofld_txq, 0,
5315228561Snp		    "index of first TOE tx queue");
5316228561Snp	}
5317228561Snp#endif
5318270297Snp#ifdef DEV_NETMAP
5319308154Sjhb	if (vi->nnmrxq != 0) {
5320308154Sjhb		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nnmrxq", CTLFLAG_RD,
5321308154Sjhb		    &vi->nnmrxq, 0, "# of netmap rx queues");
5322308154Sjhb		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nnmtxq", CTLFLAG_RD,
5323308154Sjhb		    &vi->nnmtxq, 0, "# of netmap tx queues");
5324308154Sjhb		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_nm_rxq",
5325308154Sjhb		    CTLFLAG_RD, &vi->first_nm_rxq, 0,
5326308154Sjhb		    "index of first netmap rx queue");
5327308154Sjhb		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_nm_txq",
5328308154Sjhb		    CTLFLAG_RD, &vi->first_nm_txq, 0,
5329308154Sjhb		    "index of first netmap tx queue");
5330308154Sjhb	}
5331270297Snp#endif
5332228561Snp
5333218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx",
5334308154Sjhb	    CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_holdoff_tmr_idx, "I",
5335218792Snp	    "holdoff timer index");
5336218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx",
5337308154Sjhb	    CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_holdoff_pktc_idx, "I",
5338218792Snp	    "holdoff packet counter index");
5339218792Snp
5340218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq",
5341308154Sjhb	    CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_qsize_rxq, "I",
5342218792Snp	    "rx queue size");
5343218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq",
5344308154Sjhb	    CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_qsize_txq, "I",
5345218792Snp	    "tx queue size");
5346308154Sjhb}
5347218792Snp
5348308154Sjhbstatic void
5349308154Sjhbcxgbe_sysctls(struct port_info *pi)
5350308154Sjhb{
5351308154Sjhb	struct sysctl_ctx_list *ctx;
5352308154Sjhb	struct sysctl_oid *oid;
5353308321Sjhb	struct sysctl_oid_list *children, *children2;
5354308154Sjhb	struct adapter *sc = pi->adapter;
5355308321Sjhb	int i;
5356308321Sjhb	char name[16];
5357308154Sjhb
5358308154Sjhb	ctx = device_get_sysctl_ctx(pi->dev);
5359308154Sjhb
5360308154Sjhb	/*
5361308154Sjhb	 * dev.cxgbe.X.
5362308154Sjhb	 */
5363308154Sjhb	oid = device_get_sysctl_tree(pi->dev);
5364308154Sjhb	children = SYSCTL_CHILDREN(oid);
5365308154Sjhb
5366308154Sjhb	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkdnrc", CTLTYPE_STRING |
5367308154Sjhb	   CTLFLAG_RD, pi, 0, sysctl_linkdnrc, "A", "reason why link is down");
5368308154Sjhb	if (pi->port_type == FW_PORT_TYPE_BT_XAUI) {
5369308154Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature",
5370308154Sjhb		    CTLTYPE_INT | CTLFLAG_RD, pi, 0, sysctl_btphy, "I",
5371308154Sjhb		    "PHY temperature (in Celsius)");
5372308154Sjhb		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fw_version",
5373308154Sjhb		    CTLTYPE_INT | CTLFLAG_RD, pi, 1, sysctl_btphy, "I",
5374308154Sjhb		    "PHY firmware version");
5375308154Sjhb	}
5376308154Sjhb
5377271961Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pause_settings",
5378311261Snp	    CTLTYPE_STRING | CTLFLAG_RW, pi, 0, sysctl_pause_settings, "A",
5379311261Snp	    "PAUSE settings (bit 0 = rx_pause, bit 1 = tx_pause)");
5380311261Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fec",
5381311261Snp	    CTLTYPE_STRING | CTLFLAG_RW, pi, 0, sysctl_fec, "A",
5382311261Snp	    "Forward Error Correction (bit 0 = RS, bit 1 = BASER_RS)");
5383311261Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "autoneg",
5384311261Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_autoneg, "I",
5385311261Snp	    "autonegotiation (-1 = not supported)");
5386271961Snp
5387308311Sjhb	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "max_speed", CTLFLAG_RD, NULL,
5388308311Sjhb	    port_top_speed(pi), "max speed (in Gbps)");
5389308311Sjhb
5390309447Sjhb	if (sc->flags & IS_VF)
5391309447Sjhb		return;
5392309447Sjhb
5393218792Snp	/*
5394308321Sjhb	 * dev.(cxgbe|cxl).X.tc.
5395308321Sjhb	 */
5396308321Sjhb	oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "tc", CTLFLAG_RD, NULL,
5397318851Snp	    "Tx scheduler traffic classes (cl_rl)");
5398308321Sjhb	for (i = 0; i < sc->chip_params->nsched_cls; i++) {
5399318851Snp		struct tx_cl_rl_params *tc = &pi->sched_params->cl_rl[i];
5400308321Sjhb
5401308321Sjhb		snprintf(name, sizeof(name), "%d", i);
5402308321Sjhb		children2 = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(ctx,
5403308321Sjhb		    SYSCTL_CHILDREN(oid), OID_AUTO, name, CTLFLAG_RD, NULL,
5404308321Sjhb		    "traffic class"));
5405308321Sjhb		SYSCTL_ADD_UINT(ctx, children2, OID_AUTO, "flags", CTLFLAG_RD,
5406308321Sjhb		    &tc->flags, 0, "flags");
5407308321Sjhb		SYSCTL_ADD_UINT(ctx, children2, OID_AUTO, "refcount",
5408308321Sjhb		    CTLFLAG_RD, &tc->refcount, 0, "references to this class");
5409308321Sjhb#ifdef SBUF_DRAIN
5410308321Sjhb		SYSCTL_ADD_PROC(ctx, children2, OID_AUTO, "params",
5411308321Sjhb		    CTLTYPE_STRING | CTLFLAG_RD, sc, (pi->port_id << 16) | i,
5412308321Sjhb		    sysctl_tc_params, "A", "traffic class parameters");
5413308321Sjhb#endif
5414308321Sjhb	}
5415308321Sjhb
5416308321Sjhb	/*
5417218792Snp	 * dev.cxgbe.X.stats.
5418218792Snp	 */
5419218792Snp	oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD,
5420218792Snp	    NULL, "port statistics");
5421218792Snp	children = SYSCTL_CHILDREN(oid);
5422284052Snp	SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "tx_parse_error", CTLFLAG_RD,
5423284052Snp	    &pi->tx_parse_error, 0,
5424284052Snp	    "# of tx packets with invalid length or # of segments");
5425218792Snp
5426218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \
5427218792Snp	SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \
5428265426Snp	    CTLTYPE_U64 | CTLFLAG_RD, sc, reg, \
5429218792Snp	    sysctl_handle_t4_reg64, "QU", desc)
5430218792Snp
5431218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames",
5432218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L));
5433218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames",
5434218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L));
5435218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames",
5436218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L));
5437218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames",
5438218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L));
5439218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames",
5440218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L));
5441218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames",
5442218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L));
5443218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_64",
5444218792Snp	    "# of tx frames in this range",
5445218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L));
5446218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127",
5447218792Snp	    "# of tx frames in this range",
5448218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L));
5449218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255",
5450218792Snp	    "# of tx frames in this range",
5451218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L));
5452218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511",
5453218792Snp	    "# of tx frames in this range",
5454218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L));
5455218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023",
5456218792Snp	    "# of tx frames in this range",
5457218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L));
5458218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518",
5459218792Snp	    "# of tx frames in this range",
5460218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L));
5461218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max",
5462218792Snp	    "# of tx frames in this range",
5463218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L));
5464218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames",
5465218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L));
5466218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted",
5467218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L));
5468218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted",
5469218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L));
5470218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted",
5471218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L));
5472218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted",
5473218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L));
5474218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted",
5475218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L));
5476218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted",
5477218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L));
5478218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted",
5479218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L));
5480218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted",
5481218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L));
5482218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted",
5483218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L));
5484218792Snp
5485218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames",
5486218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L));
5487218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames",
5488218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L));
5489218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames",
5490218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L));
5491218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames",
5492218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L));
5493218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames",
5494218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L));
5495218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU",
5496218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L));
5497218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames",
5498218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L));
5499218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err",
5500218792Snp	    "# of frames received with bad FCS",
5501218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L));
5502218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_len_err",
5503218792Snp	    "# of frames received with length error",
5504218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L));
5505218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors",
5506218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L));
5507218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received",
5508218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L));
5509218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_64",
5510218792Snp	    "# of rx frames in this range",
5511218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L));
5512218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127",
5513218792Snp	    "# of rx frames in this range",
5514218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L));
5515218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255",
5516218792Snp	    "# of rx frames in this range",
5517218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L));
5518218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511",
5519218792Snp	    "# of rx frames in this range",
5520218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L));
5521218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023",
5522218792Snp	    "# of rx frames in this range",
5523218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L));
5524218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518",
5525218792Snp	    "# of rx frames in this range",
5526218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L));
5527218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max",
5528218792Snp	    "# of rx frames in this range",
5529218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L));
5530218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received",
5531218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L));
5532218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received",
5533218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L));
5534218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received",
5535218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L));
5536218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received",
5537218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L));
5538218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received",
5539218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L));
5540218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received",
5541218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L));
5542218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received",
5543218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L));
5544218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received",
5545218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L));
5546218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received",
5547218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L));
5548218792Snp
5549218792Snp#undef SYSCTL_ADD_T4_REG64
5550218792Snp
5551218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \
5552218792Snp	SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \
5553218792Snp	    &pi->stats.name, desc)
5554218792Snp
5555218792Snp	/* We get these from port_stats and they may be stale by upto 1s */
5556218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0,
5557218792Snp	    "# drops due to buffer-group 0 overflows");
5558218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1,
5559218792Snp	    "# drops due to buffer-group 1 overflows");
5560218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2,
5561218792Snp	    "# drops due to buffer-group 2 overflows");
5562218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3,
5563218792Snp	    "# drops due to buffer-group 3 overflows");
5564218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc0,
5565218792Snp	    "# of buffer-group 0 truncated packets");
5566218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc1,
5567218792Snp	    "# of buffer-group 1 truncated packets");
5568218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc2,
5569218792Snp	    "# of buffer-group 2 truncated packets");
5570218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc3,
5571218792Snp	    "# of buffer-group 3 truncated packets");
5572218792Snp
5573218792Snp#undef SYSCTL_ADD_T4_PORTSTAT
5574218792Snp}
5575218792Snp
5576218792Snpstatic int
5577219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS)
5578219436Snp{
5579281252Snp	int rc, *i, space = 0;
5580219436Snp	struct sbuf sb;
5581219436Snp
5582219436Snp	sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND);
5583281252Snp	for (i = arg1; arg2; arg2 -= sizeof(int), i++) {
5584281252Snp		if (space)
5585281252Snp			sbuf_printf(&sb, " ");
5586281252Snp		sbuf_printf(&sb, "%d", *i);
5587281252Snp		space = 1;
5588281252Snp	}
5589219436Snp	sbuf_finish(&sb);
5590219436Snp	rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
5591219436Snp	sbuf_delete(&sb);
5592219436Snp	return (rc);
5593219436Snp}
5594219436Snp
5595219436Snpstatic int
5596228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS)
5597228561Snp{
5598228561Snp	int rc;
5599228561Snp	struct sbuf *sb;
5600228561Snp
5601228561Snp	rc = sysctl_wire_old_buffer(req, 0);
5602228561Snp	if (rc != 0)
5603228561Snp		return(rc);
5604228561Snp
5605228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5606228561Snp	if (sb == NULL)
5607228561Snp		return (ENOMEM);
5608228561Snp
5609228561Snp	sbuf_printf(sb, "%b", (int)arg2, (char *)arg1);
5610228561Snp	rc = sbuf_finish(sb);
5611228561Snp	sbuf_delete(sb);
5612228561Snp
5613228561Snp	return (rc);
5614228561Snp}
5615228561Snp
5616228561Snpstatic int
5617252747Snpsysctl_btphy(SYSCTL_HANDLER_ARGS)
5618252747Snp{
5619252747Snp	struct port_info *pi = arg1;
5620252747Snp	int op = arg2;
5621252747Snp	struct adapter *sc = pi->adapter;
5622252747Snp	u_int v;
5623252747Snp	int rc;
5624252747Snp
5625308154Sjhb	rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK, "t4btt");
5626252747Snp	if (rc)
5627252747Snp		return (rc);
5628252747Snp	/* XXX: magic numbers */
5629252747Snp	rc = -t4_mdio_rd(sc, sc->mbox, pi->mdio_addr, 0x1e, op ? 0x20 : 0xc820,
5630252747Snp	    &v);
5631252747Snp	end_synchronized_op(sc, 0);
5632252747Snp	if (rc)
5633252747Snp		return (rc);
5634252747Snp	if (op == 0)
5635252747Snp		v /= 256;
5636252747Snp
5637252747Snp	rc = sysctl_handle_int(oidp, &v, 0, req);
5638252747Snp	return (rc);
5639252747Snp}
5640252747Snp
5641252747Snpstatic int
5642264493Sscottlsysctl_noflowq(SYSCTL_HANDLER_ARGS)
5643264493Sscottl{
5644308154Sjhb	struct vi_info *vi = arg1;
5645264493Sscottl	int rc, val;
5646264493Sscottl
5647308154Sjhb	val = vi->rsrv_noflowq;
5648264493Sscottl	rc = sysctl_handle_int(oidp, &val, 0, req);
5649264493Sscottl	if (rc != 0 || req->newptr == NULL)
5650264493Sscottl		return (rc);
5651264493Sscottl
5652308154Sjhb	if ((val >= 1) && (vi->ntxq > 1))
5653308154Sjhb		vi->rsrv_noflowq = 1;
5654264493Sscottl	else
5655308154Sjhb		vi->rsrv_noflowq = 0;
5656264493Sscottl
5657264493Sscottl	return (rc);
5658264493Sscottl}
5659264493Sscottl
5660264493Sscottlstatic int
5661218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS)
5662218792Snp{
5663308154Sjhb	struct vi_info *vi = arg1;
5664308154Sjhb	struct adapter *sc = vi->pi->adapter;
5665218792Snp	int idx, rc, i;
5666245274Snp	struct sge_rxq *rxq;
5667252724Snp#ifdef TCP_OFFLOAD
5668252724Snp	struct sge_ofld_rxq *ofld_rxq;
5669252724Snp#endif
5670245274Snp	uint8_t v;
5671218792Snp
5672308154Sjhb	idx = vi->tmr_idx;
5673218792Snp
5674218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
5675218792Snp	if (rc != 0 || req->newptr == NULL)
5676218792Snp		return (rc);
5677218792Snp
5678218792Snp	if (idx < 0 || idx >= SGE_NTIMERS)
5679218792Snp		return (EINVAL);
5680218792Snp
5681308154Sjhb	rc = begin_synchronized_op(sc, vi, HOLD_LOCK | SLEEP_OK | INTR_OK,
5682245274Snp	    "t4tmr");
5683245274Snp	if (rc)
5684245274Snp		return (rc);
5685228561Snp
5686308154Sjhb	v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(vi->pktc_idx != -1);
5687308154Sjhb	for_each_rxq(vi, i, rxq) {
5688228561Snp#ifdef atomic_store_rel_8
5689245274Snp		atomic_store_rel_8(&rxq->iq.intr_params, v);
5690228561Snp#else
5691245274Snp		rxq->iq.intr_params = v;
5692228561Snp#endif
5693218792Snp	}
5694252724Snp#ifdef TCP_OFFLOAD
5695308154Sjhb	for_each_ofld_rxq(vi, i, ofld_rxq) {
5696252724Snp#ifdef atomic_store_rel_8
5697252724Snp		atomic_store_rel_8(&ofld_rxq->iq.intr_params, v);
5698252724Snp#else
5699252724Snp		ofld_rxq->iq.intr_params = v;
5700252724Snp#endif
5701252724Snp	}
5702252724Snp#endif
5703308154Sjhb	vi->tmr_idx = idx;
5704218792Snp
5705245274Snp	end_synchronized_op(sc, LOCK_HELD);
5706245274Snp	return (0);
5707218792Snp}
5708218792Snp
5709218792Snpstatic int
5710218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS)
5711218792Snp{
5712308154Sjhb	struct vi_info *vi = arg1;
5713308154Sjhb	struct adapter *sc = vi->pi->adapter;
5714218792Snp	int idx, rc;
5715218792Snp
5716308154Sjhb	idx = vi->pktc_idx;
5717218792Snp
5718218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
5719218792Snp	if (rc != 0 || req->newptr == NULL)
5720218792Snp		return (rc);
5721218792Snp
5722218792Snp	if (idx < -1 || idx >= SGE_NCOUNTERS)
5723218792Snp		return (EINVAL);
5724218792Snp
5725308154Sjhb	rc = begin_synchronized_op(sc, vi, HOLD_LOCK | SLEEP_OK | INTR_OK,
5726245274Snp	    "t4pktc");
5727245274Snp	if (rc)
5728245274Snp		return (rc);
5729245274Snp
5730308154Sjhb	if (vi->flags & VI_INIT_DONE)
5731228561Snp		rc = EBUSY; /* cannot be changed once the queues are created */
5732245274Snp	else
5733308154Sjhb		vi->pktc_idx = idx;
5734218792Snp
5735245274Snp	end_synchronized_op(sc, LOCK_HELD);
5736218792Snp	return (rc);
5737218792Snp}
5738218792Snp
5739218792Snpstatic int
5740218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS)
5741218792Snp{
5742308154Sjhb	struct vi_info *vi = arg1;
5743308154Sjhb	struct adapter *sc = vi->pi->adapter;
5744218792Snp	int qsize, rc;
5745218792Snp
5746308154Sjhb	qsize = vi->qsize_rxq;
5747218792Snp
5748218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
5749218792Snp	if (rc != 0 || req->newptr == NULL)
5750218792Snp		return (rc);
5751218792Snp
5752218792Snp	if (qsize < 128 || (qsize & 7))
5753218792Snp		return (EINVAL);
5754218792Snp
5755308154Sjhb	rc = begin_synchronized_op(sc, vi, HOLD_LOCK | SLEEP_OK | INTR_OK,
5756245274Snp	    "t4rxqs");
5757245274Snp	if (rc)
5758245274Snp		return (rc);
5759245274Snp
5760308154Sjhb	if (vi->flags & VI_INIT_DONE)
5761228561Snp		rc = EBUSY; /* cannot be changed once the queues are created */
5762245274Snp	else
5763308154Sjhb		vi->qsize_rxq = qsize;
5764218792Snp
5765245274Snp	end_synchronized_op(sc, LOCK_HELD);
5766218792Snp	return (rc);
5767218792Snp}
5768218792Snp
5769218792Snpstatic int
5770218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS)
5771218792Snp{
5772308154Sjhb	struct vi_info *vi = arg1;
5773308154Sjhb	struct adapter *sc = vi->pi->adapter;
5774218792Snp	int qsize, rc;
5775218792Snp
5776308154Sjhb	qsize = vi->qsize_txq;
5777218792Snp
5778218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
5779218792Snp	if (rc != 0 || req->newptr == NULL)
5780218792Snp		return (rc);
5781218792Snp
5782284052Snp	if (qsize < 128 || qsize > 65536)
5783218792Snp		return (EINVAL);
5784218792Snp
5785308154Sjhb	rc = begin_synchronized_op(sc, vi, HOLD_LOCK | SLEEP_OK | INTR_OK,
5786245274Snp	    "t4txqs");
5787245274Snp	if (rc)
5788245274Snp		return (rc);
5789245274Snp
5790308154Sjhb	if (vi->flags & VI_INIT_DONE)
5791228561Snp		rc = EBUSY; /* cannot be changed once the queues are created */
5792245274Snp	else
5793308154Sjhb		vi->qsize_txq = qsize;
5794218792Snp
5795245274Snp	end_synchronized_op(sc, LOCK_HELD);
5796218792Snp	return (rc);
5797218792Snp}
5798218792Snp
5799218792Snpstatic int
5800271961Snpsysctl_pause_settings(SYSCTL_HANDLER_ARGS)
5801271961Snp{
5802271961Snp	struct port_info *pi = arg1;
5803271961Snp	struct adapter *sc = pi->adapter;
5804271961Snp	struct link_config *lc = &pi->link_cfg;
5805271961Snp	int rc;
5806271961Snp
5807271961Snp	if (req->newptr == NULL) {
5808271961Snp		struct sbuf *sb;
5809271961Snp		static char *bits = "\20\1PAUSE_RX\2PAUSE_TX";
5810271961Snp
5811271961Snp		rc = sysctl_wire_old_buffer(req, 0);
5812271961Snp		if (rc != 0)
5813271961Snp			return(rc);
5814271961Snp
5815271961Snp		sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5816271961Snp		if (sb == NULL)
5817271961Snp			return (ENOMEM);
5818271961Snp
5819271961Snp		sbuf_printf(sb, "%b", lc->fc & (PAUSE_TX | PAUSE_RX), bits);
5820271961Snp		rc = sbuf_finish(sb);
5821271961Snp		sbuf_delete(sb);
5822271961Snp	} else {
5823271961Snp		char s[2];
5824271961Snp		int n;
5825271961Snp
5826271961Snp		s[0] = '0' + (lc->requested_fc & (PAUSE_TX | PAUSE_RX));
5827271961Snp		s[1] = 0;
5828271961Snp
5829271961Snp		rc = sysctl_handle_string(oidp, s, sizeof(s), req);
5830271961Snp		if (rc != 0)
5831271961Snp			return(rc);
5832271961Snp
5833271961Snp		if (s[1] != 0)
5834271961Snp			return (EINVAL);
5835271961Snp		if (s[0] < '0' || s[0] > '9')
5836271961Snp			return (EINVAL);	/* not a number */
5837271961Snp		n = s[0] - '0';
5838271961Snp		if (n & ~(PAUSE_TX | PAUSE_RX))
5839271961Snp			return (EINVAL);	/* some other bit is set too */
5840271961Snp
5841308154Sjhb		rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
5842308154Sjhb		    "t4PAUSE");
5843271961Snp		if (rc)
5844271961Snp			return (rc);
5845353418Snp		PORT_LOCK(pi);
5846271961Snp		if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) {
5847271961Snp			lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
5848271961Snp			lc->requested_fc |= n;
5849308304Sjhb			rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
5850353418Snp			if (rc == 0) {
5851353418Snp				lc->fc = lc->requested_fc;
5852353418Snp				set_current_media(pi, &pi->media);
5853353418Snp			}
5854271961Snp		}
5855353418Snp		PORT_UNLOCK(pi);
5856271961Snp		end_synchronized_op(sc, 0);
5857271961Snp	}
5858271961Snp
5859271961Snp	return (rc);
5860271961Snp}
5861271961Snp
5862271961Snpstatic int
5863311261Snpsysctl_fec(SYSCTL_HANDLER_ARGS)
5864311261Snp{
5865311261Snp	struct port_info *pi = arg1;
5866311261Snp	struct adapter *sc = pi->adapter;
5867311261Snp	struct link_config *lc = &pi->link_cfg;
5868311261Snp	int rc;
5869311261Snp
5870311261Snp	if (req->newptr == NULL) {
5871311261Snp		struct sbuf *sb;
5872311261Snp		static char *bits = "\20\1RS\2BASER_RS\3RESERVED";
5873311261Snp
5874311261Snp		rc = sysctl_wire_old_buffer(req, 0);
5875311261Snp		if (rc != 0)
5876311261Snp			return(rc);
5877311261Snp
5878311261Snp		sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5879311261Snp		if (sb == NULL)
5880311261Snp			return (ENOMEM);
5881311261Snp
5882311261Snp		sbuf_printf(sb, "%b", lc->fec & M_FW_PORT_CAP_FEC, bits);
5883311261Snp		rc = sbuf_finish(sb);
5884311261Snp		sbuf_delete(sb);
5885311261Snp	} else {
5886311261Snp		char s[2];
5887311261Snp		int n;
5888311261Snp
5889311261Snp		s[0] = '0' + (lc->requested_fec & M_FW_PORT_CAP_FEC);
5890311261Snp		s[1] = 0;
5891311261Snp
5892311261Snp		rc = sysctl_handle_string(oidp, s, sizeof(s), req);
5893311261Snp		if (rc != 0)
5894311261Snp			return(rc);
5895311261Snp
5896311261Snp		if (s[1] != 0)
5897311261Snp			return (EINVAL);
5898311261Snp		if (s[0] < '0' || s[0] > '9')
5899311261Snp			return (EINVAL);	/* not a number */
5900311261Snp		n = s[0] - '0';
5901311261Snp		if (n & ~M_FW_PORT_CAP_FEC)
5902311261Snp			return (EINVAL);	/* some other bit is set too */
5903353418Snp		if (!powerof2(n))
5904353418Snp			return (EINVAL);	/* one bit can be set at most */
5905311261Snp
5906311261Snp		rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
5907311261Snp		    "t4fec");
5908311261Snp		if (rc)
5909311261Snp			return (rc);
5910353418Snp		PORT_LOCK(pi);
5911311261Snp		if ((lc->requested_fec & M_FW_PORT_CAP_FEC) != n) {
5912311261Snp			lc->requested_fec = n &
5913311261Snp			    G_FW_PORT_CAP_FEC(lc->supported);
5914311261Snp			rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
5915353418Snp			if (rc == 0) {
5916353418Snp				lc->fec = lc->requested_fec;
5917353418Snp			}
5918311261Snp		}
5919353418Snp		PORT_UNLOCK(pi);
5920311261Snp		end_synchronized_op(sc, 0);
5921311261Snp	}
5922311261Snp
5923311261Snp	return (rc);
5924311261Snp}
5925311261Snp
5926311261Snpstatic int
5927311261Snpsysctl_autoneg(SYSCTL_HANDLER_ARGS)
5928311261Snp{
5929311261Snp	struct port_info *pi = arg1;
5930311261Snp	struct adapter *sc = pi->adapter;
5931311261Snp	struct link_config *lc = &pi->link_cfg;
5932311261Snp	int rc, val, old;
5933311261Snp
5934311261Snp	if (lc->supported & FW_PORT_CAP_ANEG)
5935353418Snp		val = lc->requested_aneg == AUTONEG_ENABLE ? 1 : 0;
5936311261Snp	else
5937311261Snp		val = -1;
5938311261Snp	rc = sysctl_handle_int(oidp, &val, 0, req);
5939311261Snp	if (rc != 0 || req->newptr == NULL)
5940311261Snp		return (rc);
5941318855Snp	if (val == 0)
5942318855Snp		val = AUTONEG_DISABLE;
5943318855Snp	else if (val == 1)
5944318855Snp		val = AUTONEG_ENABLE;
5945318855Snp	else
5946318855Snp		return (EINVAL);
5947311261Snp
5948311261Snp	rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
5949311261Snp	    "t4aneg");
5950311261Snp	if (rc)
5951311261Snp		return (rc);
5952353418Snp	PORT_LOCK(pi);
5953353418Snp	if ((lc->supported & FW_PORT_CAP_ANEG) == 0) {
5954353418Snp		rc = ENOTSUP;
5955353418Snp		goto done;
5956353418Snp	}
5957353418Snp	if (lc->requested_aneg == val) {
5958353418Snp		rc = 0;	/* no change, do nothing. */
5959353418Snp		goto done;
5960353418Snp	}
5961353418Snp	old = lc->requested_aneg;
5962353418Snp	lc->requested_aneg = val;
5963311261Snp	rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
5964311261Snp	if (rc != 0)
5965353418Snp		lc->requested_aneg = old;
5966353418Snp	else
5967353418Snp		set_current_media(pi, &pi->media);
5968353418Snpdone:
5969353418Snp	PORT_UNLOCK(pi);
5970318855Snp	end_synchronized_op(sc, 0);
5971311261Snp	return (rc);
5972311261Snp}
5973311261Snp
5974311261Snpstatic int
5975218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS)
5976218792Snp{
5977218792Snp	struct adapter *sc = arg1;
5978218792Snp	int reg = arg2;
5979218792Snp	uint64_t val;
5980218792Snp
5981218792Snp	val = t4_read_reg64(sc, reg);
5982218792Snp
5983218792Snp	return (sysctl_handle_64(oidp, &val, 0, req));
5984218792Snp}
5985218792Snp
5986253890Snpstatic int
5987253890Snpsysctl_temperature(SYSCTL_HANDLER_ARGS)
5988253890Snp{
5989253890Snp	struct adapter *sc = arg1;
5990253890Snp	int rc, t;
5991253890Snp	uint32_t param, val;
5992253890Snp
5993253890Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4temp");
5994253890Snp	if (rc)
5995253890Snp		return (rc);
5996253890Snp	param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
5997253890Snp	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_DIAG) |
5998253890Snp	    V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_DIAG_TMP);
5999253890Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
6000253890Snp	end_synchronized_op(sc, 0);
6001253890Snp	if (rc)
6002253890Snp		return (rc);
6003253890Snp
6004253890Snp	/* unknown is returned as 0 but we display -1 in that case */
6005253890Snp	t = val == 0 ? -1 : val;
6006253890Snp
6007253890Snp	rc = sysctl_handle_int(oidp, &t, 0, req);
6008253890Snp	return (rc);
6009253890Snp}
6010253890Snp
6011231115Snp#ifdef SBUF_DRAIN
6012228561Snpstatic int
6013228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS)
6014228561Snp{
6015228561Snp	struct adapter *sc = arg1;
6016228561Snp	struct sbuf *sb;
6017228561Snp	int rc, i;
6018228561Snp	uint16_t incr[NMTUS][NCCTRL_WIN];
6019228561Snp	static const char *dec_fac[] = {
6020228561Snp		"0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875",
6021228561Snp		"0.9375"
6022228561Snp	};
6023228561Snp
6024228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6025228561Snp	if (rc != 0)
6026228561Snp		return (rc);
6027228561Snp
6028228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6029228561Snp	if (sb == NULL)
6030228561Snp		return (ENOMEM);
6031228561Snp
6032228561Snp	t4_read_cong_tbl(sc, incr);
6033228561Snp
6034228561Snp	for (i = 0; i < NCCTRL_WIN; ++i) {
6035228561Snp		sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i,
6036228561Snp		    incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i],
6037228561Snp		    incr[5][i], incr[6][i], incr[7][i]);
6038228561Snp		sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n",
6039228561Snp		    incr[8][i], incr[9][i], incr[10][i], incr[11][i],
6040228561Snp		    incr[12][i], incr[13][i], incr[14][i], incr[15][i],
6041228561Snp		    sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]);
6042228561Snp	}
6043228561Snp
6044228561Snp	rc = sbuf_finish(sb);
6045228561Snp	sbuf_delete(sb);
6046228561Snp
6047228561Snp	return (rc);
6048228561Snp}
6049228561Snp
6050248925Snpstatic const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ_T5] = {
6051247122Snp	"TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI",	/* ibq's */
6052248925Snp	"ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI",	/* obq's */
6053248925Snp	"SGE0-RX", "SGE1-RX"	/* additional obq's (T5 onwards) */
6054247122Snp};
6055247122Snp
6056228561Snpstatic int
6057247122Snpsysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS)
6058247122Snp{
6059247122Snp	struct adapter *sc = arg1;
6060247122Snp	struct sbuf *sb;
6061247122Snp	int rc, i, n, qid = arg2;
6062247122Snp	uint32_t *buf, *p;
6063247122Snp	char *qtype;
6064308304Sjhb	u_int cim_num_obq = sc->chip_params->cim_num_obq;
6065247122Snp
6066248925Snp	KASSERT(qid >= 0 && qid < CIM_NUM_IBQ + cim_num_obq,
6067247122Snp	    ("%s: bad qid %d\n", __func__, qid));
6068247122Snp
6069247122Snp	if (qid < CIM_NUM_IBQ) {
6070247122Snp		/* inbound queue */
6071247122Snp		qtype = "IBQ";
6072247122Snp		n = 4 * CIM_IBQ_SIZE;
6073247122Snp		buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK);
6074247122Snp		rc = t4_read_cim_ibq(sc, qid, buf, n);
6075247122Snp	} else {
6076247122Snp		/* outbound queue */
6077247122Snp		qtype = "OBQ";
6078247122Snp		qid -= CIM_NUM_IBQ;
6079248925Snp		n = 4 * cim_num_obq * CIM_OBQ_SIZE;
6080247122Snp		buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK);
6081247122Snp		rc = t4_read_cim_obq(sc, qid, buf, n);
6082247122Snp	}
6083247122Snp
6084247122Snp	if (rc < 0) {
6085247122Snp		rc = -rc;
6086247122Snp		goto done;
6087247122Snp	}
6088247122Snp	n = rc * sizeof(uint32_t);	/* rc has # of words actually read */
6089247122Snp
6090247122Snp	rc = sysctl_wire_old_buffer(req, 0);
6091247122Snp	if (rc != 0)
6092247122Snp		goto done;
6093247122Snp
6094248925Snp	sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req);
6095247122Snp	if (sb == NULL) {
6096247122Snp		rc = ENOMEM;
6097247122Snp		goto done;
6098247122Snp	}
6099247122Snp
6100247122Snp	sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]);
6101247122Snp	for (i = 0, p = buf; i < n; i += 16, p += 4)
6102247122Snp		sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1],
6103247122Snp		    p[2], p[3]);
6104247122Snp
6105247122Snp	rc = sbuf_finish(sb);
6106247122Snp	sbuf_delete(sb);
6107247122Snpdone:
6108247122Snp	free(buf, M_CXGBE);
6109247122Snp	return (rc);
6110247122Snp}
6111247122Snp
6112247122Snpstatic int
6113247122Snpsysctl_cim_la(SYSCTL_HANDLER_ARGS)
6114247122Snp{
6115247122Snp	struct adapter *sc = arg1;
6116247122Snp	u_int cfg;
6117247122Snp	struct sbuf *sb;
6118247122Snp	uint32_t *buf, *p;
6119247122Snp	int rc;
6120247122Snp
6121308304Sjhb	MPASS(chip_id(sc) <= CHELSIO_T5);
6122308304Sjhb
6123247122Snp	rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg);
6124247122Snp	if (rc != 0)
6125247122Snp		return (rc);
6126247122Snp
6127247122Snp	rc = sysctl_wire_old_buffer(req, 0);
6128247122Snp	if (rc != 0)
6129247122Snp		return (rc);
6130247122Snp
6131247122Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6132247122Snp	if (sb == NULL)
6133247122Snp		return (ENOMEM);
6134247122Snp
6135247122Snp	buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE,
6136247122Snp	    M_ZERO | M_WAITOK);
6137247122Snp
6138247122Snp	rc = -t4_cim_read_la(sc, buf, NULL);
6139247122Snp	if (rc != 0)
6140247122Snp		goto done;
6141247122Snp
6142247122Snp	sbuf_printf(sb, "Status   Data      PC%s",
6143247122Snp	    cfg & F_UPDBGLACAPTPCONLY ? "" :
6144247122Snp	    "     LS0Stat  LS0Addr             LS0Data");
6145247122Snp
6146308304Sjhb	for (p = buf; p <= &buf[sc->params.cim_la_size - 8]; p += 8) {
6147247122Snp		if (cfg & F_UPDBGLACAPTPCONLY) {
6148247122Snp			sbuf_printf(sb, "\n  %02x   %08x %08x", p[5] & 0xff,
6149247122Snp			    p[6], p[7]);
6150247122Snp			sbuf_printf(sb, "\n  %02x   %02x%06x %02x%06x",
6151247122Snp			    (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8,
6152247122Snp			    p[4] & 0xff, p[5] >> 8);
6153247122Snp			sbuf_printf(sb, "\n  %02x   %x%07x %x%07x",
6154247122Snp			    (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4,
6155247122Snp			    p[1] & 0xf, p[2] >> 4);
6156247122Snp		} else {
6157247122Snp			sbuf_printf(sb,
6158247122Snp			    "\n  %02x   %x%07x %x%07x %08x %08x "
6159247122Snp			    "%08x%08x%08x%08x",
6160247122Snp			    (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4,
6161247122Snp			    p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5],
6162247122Snp			    p[6], p[7]);
6163247122Snp		}
6164247122Snp	}
6165247122Snp
6166247122Snp	rc = sbuf_finish(sb);
6167247122Snp	sbuf_delete(sb);
6168247122Snpdone:
6169247122Snp	free(buf, M_CXGBE);
6170247122Snp	return (rc);
6171247122Snp}
6172247122Snp
6173247122Snpstatic int
6174308304Sjhbsysctl_cim_la_t6(SYSCTL_HANDLER_ARGS)
6175308304Sjhb{
6176308304Sjhb	struct adapter *sc = arg1;
6177308304Sjhb	u_int cfg;
6178308304Sjhb	struct sbuf *sb;
6179308304Sjhb	uint32_t *buf, *p;
6180308304Sjhb	int rc;
6181308304Sjhb
6182308304Sjhb	MPASS(chip_id(sc) > CHELSIO_T5);
6183308304Sjhb
6184308304Sjhb	rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg);
6185308304Sjhb	if (rc != 0)
6186308304Sjhb		return (rc);
6187308304Sjhb
6188308304Sjhb	rc = sysctl_wire_old_buffer(req, 0);
6189308304Sjhb	if (rc != 0)
6190308304Sjhb		return (rc);
6191308304Sjhb
6192308304Sjhb	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6193308304Sjhb	if (sb == NULL)
6194308304Sjhb		return (ENOMEM);
6195308304Sjhb
6196308304Sjhb	buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE,
6197308304Sjhb	    M_ZERO | M_WAITOK);
6198308304Sjhb
6199308304Sjhb	rc = -t4_cim_read_la(sc, buf, NULL);
6200308304Sjhb	if (rc != 0)
6201308304Sjhb		goto done;
6202308304Sjhb
6203308304Sjhb	sbuf_printf(sb, "Status   Inst    Data      PC%s",
6204308304Sjhb	    cfg & F_UPDBGLACAPTPCONLY ? "" :
6205308304Sjhb	    "     LS0Stat  LS0Addr  LS0Data  LS1Stat  LS1Addr  LS1Data");
6206308304Sjhb
6207308304Sjhb	for (p = buf; p <= &buf[sc->params.cim_la_size - 10]; p += 10) {
6208308304Sjhb		if (cfg & F_UPDBGLACAPTPCONLY) {
6209308304Sjhb			sbuf_printf(sb, "\n  %02x   %08x %08x %08x",
6210308304Sjhb			    p[3] & 0xff, p[2], p[1], p[0]);
6211308304Sjhb			sbuf_printf(sb, "\n  %02x   %02x%06x %02x%06x %02x%06x",
6212308304Sjhb			    (p[6] >> 8) & 0xff, p[6] & 0xff, p[5] >> 8,
6213308304Sjhb			    p[5] & 0xff, p[4] >> 8, p[4] & 0xff, p[3] >> 8);
6214308304Sjhb			sbuf_printf(sb, "\n  %02x   %04x%04x %04x%04x %04x%04x",
6215308304Sjhb			    (p[9] >> 16) & 0xff, p[9] & 0xffff, p[8] >> 16,
6216308304Sjhb			    p[8] & 0xffff, p[7] >> 16, p[7] & 0xffff,
6217308304Sjhb			    p[6] >> 16);
6218308304Sjhb		} else {
6219308304Sjhb			sbuf_printf(sb, "\n  %02x   %04x%04x %04x%04x %04x%04x "
6220308304Sjhb			    "%08x %08x %08x %08x %08x %08x",
6221308304Sjhb			    (p[9] >> 16) & 0xff,
6222308304Sjhb			    p[9] & 0xffff, p[8] >> 16,
6223308304Sjhb			    p[8] & 0xffff, p[7] >> 16,
6224308304Sjhb			    p[7] & 0xffff, p[6] >> 16,
6225308304Sjhb			    p[2], p[1], p[0], p[5], p[4], p[3]);
6226308304Sjhb		}
6227308304Sjhb	}
6228308304Sjhb
6229308304Sjhb	rc = sbuf_finish(sb);
6230308304Sjhb	sbuf_delete(sb);
6231308304Sjhbdone:
6232308304Sjhb	free(buf, M_CXGBE);
6233308304Sjhb	return (rc);
6234308304Sjhb}
6235308304Sjhb
6236308304Sjhbstatic int
6237251213Snpsysctl_cim_ma_la(SYSCTL_HANDLER_ARGS)
6238251213Snp{
6239251213Snp	struct adapter *sc = arg1;
6240251213Snp	u_int i;
6241251213Snp	struct sbuf *sb;
6242251213Snp	uint32_t *buf, *p;
6243251213Snp	int rc;
6244251213Snp
6245251213Snp	rc = sysctl_wire_old_buffer(req, 0);
6246251213Snp	if (rc != 0)
6247251213Snp		return (rc);
6248251213Snp
6249251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6250251213Snp	if (sb == NULL)
6251251213Snp		return (ENOMEM);
6252251213Snp
6253251213Snp	buf = malloc(2 * CIM_MALA_SIZE * 5 * sizeof(uint32_t), M_CXGBE,
6254251213Snp	    M_ZERO | M_WAITOK);
6255251213Snp
6256251213Snp	t4_cim_read_ma_la(sc, buf, buf + 5 * CIM_MALA_SIZE);
6257251213Snp	p = buf;
6258251213Snp
6259251213Snp	for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) {
6260251213Snp		sbuf_printf(sb, "\n%02x%08x%08x%08x%08x", p[4], p[3], p[2],
6261251213Snp		    p[1], p[0]);
6262251213Snp	}
6263251213Snp
6264251213Snp	sbuf_printf(sb, "\n\nCnt ID Tag UE       Data       RDY VLD");
6265251213Snp	for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) {
6266251213Snp		sbuf_printf(sb, "\n%3u %2u  %x   %u %08x%08x  %u   %u",
6267251213Snp		    (p[2] >> 10) & 0xff, (p[2] >> 7) & 7,
6268251213Snp		    (p[2] >> 3) & 0xf, (p[2] >> 2) & 1,
6269251213Snp		    (p[1] >> 2) | ((p[2] & 3) << 30),
6270251213Snp		    (p[0] >> 2) | ((p[1] & 3) << 30), (p[0] >> 1) & 1,
6271251213Snp		    p[0] & 1);
6272251213Snp	}
6273251213Snp
6274251213Snp	rc = sbuf_finish(sb);
6275251213Snp	sbuf_delete(sb);
6276251213Snp	free(buf, M_CXGBE);
6277251213Snp	return (rc);
6278251213Snp}
6279251213Snp
6280251213Snpstatic int
6281251213Snpsysctl_cim_pif_la(SYSCTL_HANDLER_ARGS)
6282251213Snp{
6283251213Snp	struct adapter *sc = arg1;
6284251213Snp	u_int i;
6285251213Snp	struct sbuf *sb;
6286251213Snp	uint32_t *buf, *p;
6287251213Snp	int rc;
6288251213Snp
6289251213Snp	rc = sysctl_wire_old_buffer(req, 0);
6290251213Snp	if (rc != 0)
6291251213Snp		return (rc);
6292251213Snp
6293251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6294251213Snp	if (sb == NULL)
6295251213Snp		return (ENOMEM);
6296251213Snp
6297251213Snp	buf = malloc(2 * CIM_PIFLA_SIZE * 6 * sizeof(uint32_t), M_CXGBE,
6298251213Snp	    M_ZERO | M_WAITOK);
6299251213Snp
6300251213Snp	t4_cim_read_pif_la(sc, buf, buf + 6 * CIM_PIFLA_SIZE, NULL, NULL);
6301251213Snp	p = buf;
6302251213Snp
6303251213Snp	sbuf_printf(sb, "Cntl ID DataBE   Addr                 Data");
6304308304Sjhb	for (i = 0; i < CIM_PIFLA_SIZE; i++, p += 6) {
6305251213Snp		sbuf_printf(sb, "\n %02x  %02x  %04x  %08x %08x%08x%08x%08x",
6306251213Snp		    (p[5] >> 22) & 0xff, (p[5] >> 16) & 0x3f, p[5] & 0xffff,
6307251213Snp		    p[4], p[3], p[2], p[1], p[0]);
6308251213Snp	}
6309251213Snp
6310251213Snp	sbuf_printf(sb, "\n\nCntl ID               Data");
6311308304Sjhb	for (i = 0; i < CIM_PIFLA_SIZE; i++, p += 6) {
6312251213Snp		sbuf_printf(sb, "\n %02x  %02x %08x%08x%08x%08x",
6313251213Snp		    (p[4] >> 6) & 0xff, p[4] & 0x3f, p[3], p[2], p[1], p[0]);
6314251213Snp	}
6315251213Snp
6316251213Snp	rc = sbuf_finish(sb);
6317251213Snp	sbuf_delete(sb);
6318251213Snp	free(buf, M_CXGBE);
6319251213Snp	return (rc);
6320251213Snp}
6321251213Snp
6322251213Snpstatic int
6323247122Snpsysctl_cim_qcfg(SYSCTL_HANDLER_ARGS)
6324247122Snp{
6325247122Snp	struct adapter *sc = arg1;
6326247122Snp	struct sbuf *sb;
6327247122Snp	int rc, i;
6328248925Snp	uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5];
6329248925Snp	uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5];
6330247122Snp	uint16_t thres[CIM_NUM_IBQ];
6331248925Snp	uint32_t obq_wr[2 * CIM_NUM_OBQ_T5], *wr = obq_wr;
6332248925Snp	uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)], *p = stat;
6333248925Snp	u_int cim_num_obq, ibq_rdaddr, obq_rdaddr, nq;
6334247122Snp
6335308304Sjhb	cim_num_obq = sc->chip_params->cim_num_obq;
6336248925Snp	if (is_t4(sc)) {
6337248925Snp		ibq_rdaddr = A_UP_IBQ_0_RDADDR;
6338248925Snp		obq_rdaddr = A_UP_OBQ_0_REALADDR;
6339248925Snp	} else {
6340248925Snp		ibq_rdaddr = A_UP_IBQ_0_SHADOW_RDADDR;
6341248925Snp		obq_rdaddr = A_UP_OBQ_0_SHADOW_REALADDR;
6342248925Snp	}
6343248925Snp	nq = CIM_NUM_IBQ + cim_num_obq;
6344248925Snp
6345248925Snp	rc = -t4_cim_read(sc, ibq_rdaddr, 4 * nq, stat);
6346247122Snp	if (rc == 0)
6347248925Snp		rc = -t4_cim_read(sc, obq_rdaddr, 2 * cim_num_obq, obq_wr);
6348247122Snp	if (rc != 0)
6349247122Snp		return (rc);
6350247122Snp
6351247122Snp	t4_read_cimq_cfg(sc, base, size, thres);
6352247122Snp
6353247122Snp	rc = sysctl_wire_old_buffer(req, 0);
6354247122Snp	if (rc != 0)
6355247122Snp		return (rc);
6356247122Snp
6357248925Snp	sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req);
6358247122Snp	if (sb == NULL)
6359247122Snp		return (ENOMEM);
6360247122Snp
6361309458Sjhb	sbuf_printf(sb,
6362309458Sjhb	    "  Queue  Base  Size Thres  RdPtr WrPtr  SOP  EOP Avail");
6363247122Snp
6364247122Snp	for (i = 0; i < CIM_NUM_IBQ; i++, p += 4)
6365248925Snp		sbuf_printf(sb, "\n%7s %5x %5u %5u %6x  %4x %4u %4u %5u",
6366247122Snp		    qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]),
6367247122Snp		    G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]),
6368247122Snp		    G_QUEREMFLITS(p[2]) * 16);
6369248925Snp	for ( ; i < nq; i++, p += 4, wr += 2)
6370248925Snp		sbuf_printf(sb, "\n%7s %5x %5u %12x  %4x %4u %4u %5u", qname[i],
6371247122Snp		    base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff,
6372247122Snp		    wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]),
6373247122Snp		    G_QUEREMFLITS(p[2]) * 16);
6374247122Snp
6375247122Snp	rc = sbuf_finish(sb);
6376247122Snp	sbuf_delete(sb);
6377247122Snp
6378247122Snp	return (rc);
6379247122Snp}
6380247122Snp
6381247122Snpstatic int
6382228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS)
6383228561Snp{
6384228561Snp	struct adapter *sc = arg1;
6385228561Snp	struct sbuf *sb;
6386228561Snp	int rc;
6387228561Snp	struct tp_cpl_stats stats;
6388228561Snp
6389228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6390228561Snp	if (rc != 0)
6391228561Snp		return (rc);
6392228561Snp
6393228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6394228561Snp	if (sb == NULL)
6395228561Snp		return (ENOMEM);
6396228561Snp
6397308305Sjhb	mtx_lock(&sc->reg_lock);
6398353418Snp	t4_tp_get_cpl_stats(sc, &stats, 0);
6399308305Sjhb	mtx_unlock(&sc->reg_lock);
6400228561Snp
6401308304Sjhb	if (sc->chip_params->nchan > 2) {
6402308304Sjhb		sbuf_printf(sb, "                 channel 0  channel 1"
6403308304Sjhb		    "  channel 2  channel 3");
6404308304Sjhb		sbuf_printf(sb, "\nCPL requests:   %10u %10u %10u %10u",
6405308304Sjhb		    stats.req[0], stats.req[1], stats.req[2], stats.req[3]);
6406308304Sjhb		sbuf_printf(sb, "\nCPL responses:   %10u %10u %10u %10u",
6407308304Sjhb		    stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]);
6408308304Sjhb	} else {
6409308304Sjhb		sbuf_printf(sb, "                 channel 0  channel 1");
6410308304Sjhb		sbuf_printf(sb, "\nCPL requests:   %10u %10u",
6411308304Sjhb		    stats.req[0], stats.req[1]);
6412308304Sjhb		sbuf_printf(sb, "\nCPL responses:   %10u %10u",
6413308304Sjhb		    stats.rsp[0], stats.rsp[1]);
6414308304Sjhb	}
6415228561Snp
6416228561Snp	rc = sbuf_finish(sb);
6417228561Snp	sbuf_delete(sb);
6418228561Snp
6419228561Snp	return (rc);
6420228561Snp}
6421228561Snp
6422228561Snpstatic int
6423228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS)
6424228561Snp{
6425228561Snp	struct adapter *sc = arg1;
6426228561Snp	struct sbuf *sb;
6427228561Snp	int rc;
6428228561Snp	struct tp_usm_stats stats;
6429228561Snp
6430228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6431228561Snp	if (rc != 0)
6432228561Snp		return(rc);
6433228561Snp
6434228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6435228561Snp	if (sb == NULL)
6436228561Snp		return (ENOMEM);
6437228561Snp
6438353418Snp	t4_get_usm_stats(sc, &stats, 1);
6439228561Snp
6440228561Snp	sbuf_printf(sb, "Frames: %u\n", stats.frames);
6441228561Snp	sbuf_printf(sb, "Octets: %ju\n", stats.octets);
6442228561Snp	sbuf_printf(sb, "Drops:  %u", stats.drops);
6443228561Snp
6444228561Snp	rc = sbuf_finish(sb);
6445228561Snp	sbuf_delete(sb);
6446228561Snp
6447228561Snp	return (rc);
6448228561Snp}
6449228561Snp
6450308305Sjhbstatic const char * const devlog_level_strings[] = {
6451222551Snp	[FW_DEVLOG_LEVEL_EMERG]		= "EMERG",
6452222551Snp	[FW_DEVLOG_LEVEL_CRIT]		= "CRIT",
6453222551Snp	[FW_DEVLOG_LEVEL_ERR]		= "ERR",
6454222551Snp	[FW_DEVLOG_LEVEL_NOTICE]	= "NOTICE",
6455222551Snp	[FW_DEVLOG_LEVEL_INFO]		= "INFO",
6456222551Snp	[FW_DEVLOG_LEVEL_DEBUG]		= "DEBUG"
6457222551Snp};
6458222551Snp
6459308305Sjhbstatic const char * const devlog_facility_strings[] = {
6460222551Snp	[FW_DEVLOG_FACILITY_CORE]	= "CORE",
6461268823Snp	[FW_DEVLOG_FACILITY_CF]		= "CF",
6462222551Snp	[FW_DEVLOG_FACILITY_SCHED]	= "SCHED",
6463222551Snp	[FW_DEVLOG_FACILITY_TIMER]	= "TIMER",
6464222551Snp	[FW_DEVLOG_FACILITY_RES]	= "RES",
6465222551Snp	[FW_DEVLOG_FACILITY_HW]		= "HW",
6466222551Snp	[FW_DEVLOG_FACILITY_FLR]	= "FLR",
6467222551Snp	[FW_DEVLOG_FACILITY_DMAQ]	= "DMAQ",
6468222551Snp	[FW_DEVLOG_FACILITY_PHY]	= "PHY",
6469222551Snp	[FW_DEVLOG_FACILITY_MAC]	= "MAC",
6470222551Snp	[FW_DEVLOG_FACILITY_PORT]	= "PORT",
6471222551Snp	[FW_DEVLOG_FACILITY_VI]		= "VI",
6472222551Snp	[FW_DEVLOG_FACILITY_FILTER]	= "FILTER",
6473222551Snp	[FW_DEVLOG_FACILITY_ACL]	= "ACL",
6474222551Snp	[FW_DEVLOG_FACILITY_TM]		= "TM",
6475222551Snp	[FW_DEVLOG_FACILITY_QFC]	= "QFC",
6476222551Snp	[FW_DEVLOG_FACILITY_DCB]	= "DCB",
6477222551Snp	[FW_DEVLOG_FACILITY_ETH]	= "ETH",
6478222551Snp	[FW_DEVLOG_FACILITY_OFLD]	= "OFLD",
6479222551Snp	[FW_DEVLOG_FACILITY_RI]		= "RI",
6480222551Snp	[FW_DEVLOG_FACILITY_ISCSI]	= "ISCSI",
6481222551Snp	[FW_DEVLOG_FACILITY_FCOE]	= "FCOE",
6482222551Snp	[FW_DEVLOG_FACILITY_FOISCSI]	= "FOISCSI",
6483308305Sjhb	[FW_DEVLOG_FACILITY_FOFCOE]	= "FOFCOE",
6484308305Sjhb	[FW_DEVLOG_FACILITY_CHNET]	= "CHNET",
6485222551Snp};
6486222551Snp
6487222551Snpstatic int
6488222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS)
6489222551Snp{
6490222551Snp	struct adapter *sc = arg1;
6491222551Snp	struct devlog_params *dparams = &sc->params.devlog;
6492222551Snp	struct fw_devlog_e *buf, *e;
6493308305Sjhb	int i, j, rc, nentries, first = 0;
6494222551Snp	struct sbuf *sb;
6495222551Snp	uint64_t ftstamp = UINT64_MAX;
6496222551Snp
6497308305Sjhb	if (dparams->addr == 0)
6498308305Sjhb		return (ENXIO);
6499222551Snp
6500222551Snp	buf = malloc(dparams->size, M_CXGBE, M_NOWAIT);
6501222551Snp	if (buf == NULL)
6502222551Snp		return (ENOMEM);
6503222551Snp
6504308305Sjhb	rc = read_via_memwin(sc, 1, dparams->addr, (void *)buf, dparams->size);
6505222551Snp	if (rc != 0)
6506222551Snp		goto done;
6507222551Snp
6508308305Sjhb	nentries = dparams->size / sizeof(struct fw_devlog_e);
6509222551Snp	for (i = 0; i < nentries; i++) {
6510222551Snp		e = &buf[i];
6511222551Snp
6512222551Snp		if (e->timestamp == 0)
6513222551Snp			break;	/* end */
6514222551Snp
6515222551Snp		e->timestamp = be64toh(e->timestamp);
6516222551Snp		e->seqno = be32toh(e->seqno);
6517222551Snp		for (j = 0; j < 8; j++)
6518222551Snp			e->params[j] = be32toh(e->params[j]);
6519222551Snp
6520222551Snp		if (e->timestamp < ftstamp) {
6521222551Snp			ftstamp = e->timestamp;
6522222551Snp			first = i;
6523222551Snp		}
6524222551Snp	}
6525222551Snp
6526222551Snp	if (buf[first].timestamp == 0)
6527222551Snp		goto done;	/* nothing in the log */
6528222551Snp
6529222551Snp	rc = sysctl_wire_old_buffer(req, 0);
6530222551Snp	if (rc != 0)
6531222551Snp		goto done;
6532222551Snp
6533222551Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6534228561Snp	if (sb == NULL) {
6535228561Snp		rc = ENOMEM;
6536228561Snp		goto done;
6537228561Snp	}
6538228561Snp	sbuf_printf(sb, "%10s  %15s  %8s  %8s  %s\n",
6539222551Snp	    "Seq#", "Tstamp", "Level", "Facility", "Message");
6540222551Snp
6541222551Snp	i = first;
6542222551Snp	do {
6543222551Snp		e = &buf[i];
6544222551Snp		if (e->timestamp == 0)
6545222551Snp			break;	/* end */
6546222551Snp
6547222551Snp		sbuf_printf(sb, "%10d  %15ju  %8s  %8s  ",
6548222551Snp		    e->seqno, e->timestamp,
6549240452Snp		    (e->level < nitems(devlog_level_strings) ?
6550222551Snp			devlog_level_strings[e->level] : "UNKNOWN"),
6551240452Snp		    (e->facility < nitems(devlog_facility_strings) ?
6552222551Snp			devlog_facility_strings[e->facility] : "UNKNOWN"));
6553222551Snp		sbuf_printf(sb, e->fmt, e->params[0], e->params[1],
6554222551Snp		    e->params[2], e->params[3], e->params[4],
6555222551Snp		    e->params[5], e->params[6], e->params[7]);
6556222551Snp
6557222551Snp		if (++i == nentries)
6558222551Snp			i = 0;
6559222551Snp	} while (i != first);
6560222551Snp
6561222551Snp	rc = sbuf_finish(sb);
6562222551Snp	sbuf_delete(sb);
6563222551Snpdone:
6564222551Snp	free(buf, M_CXGBE);
6565222551Snp	return (rc);
6566222551Snp}
6567222551Snp
6568228561Snpstatic int
6569228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS)
6570228561Snp{
6571228561Snp	struct adapter *sc = arg1;
6572228561Snp	struct sbuf *sb;
6573228561Snp	int rc;
6574308304Sjhb	struct tp_fcoe_stats stats[MAX_NCHAN];
6575308304Sjhb	int i, nchan = sc->chip_params->nchan;
6576228561Snp
6577228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6578228561Snp	if (rc != 0)
6579228561Snp		return (rc);
6580228561Snp
6581228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6582228561Snp	if (sb == NULL)
6583228561Snp		return (ENOMEM);
6584228561Snp
6585308304Sjhb	for (i = 0; i < nchan; i++)
6586353418Snp		t4_get_fcoe_stats(sc, i, &stats[i], 1);
6587228561Snp
6588308304Sjhb	if (nchan > 2) {
6589308304Sjhb		sbuf_printf(sb, "                   channel 0        channel 1"
6590308304Sjhb		    "        channel 2        channel 3");
6591308304Sjhb		sbuf_printf(sb, "\noctetsDDP:  %16ju %16ju %16ju %16ju",
6592308304Sjhb		    stats[0].octets_ddp, stats[1].octets_ddp,
6593308304Sjhb		    stats[2].octets_ddp, stats[3].octets_ddp);
6594308304Sjhb		sbuf_printf(sb, "\nframesDDP:  %16u %16u %16u %16u",
6595308304Sjhb		    stats[0].frames_ddp, stats[1].frames_ddp,
6596308304Sjhb		    stats[2].frames_ddp, stats[3].frames_ddp);
6597308304Sjhb		sbuf_printf(sb, "\nframesDrop: %16u %16u %16u %16u",
6598308304Sjhb		    stats[0].frames_drop, stats[1].frames_drop,
6599308304Sjhb		    stats[2].frames_drop, stats[3].frames_drop);
6600308304Sjhb	} else {
6601308304Sjhb		sbuf_printf(sb, "                   channel 0        channel 1");
6602308304Sjhb		sbuf_printf(sb, "\noctetsDDP:  %16ju %16ju",
6603308304Sjhb		    stats[0].octets_ddp, stats[1].octets_ddp);
6604308304Sjhb		sbuf_printf(sb, "\nframesDDP:  %16u %16u",
6605308304Sjhb		    stats[0].frames_ddp, stats[1].frames_ddp);
6606308304Sjhb		sbuf_printf(sb, "\nframesDrop: %16u %16u",
6607308304Sjhb		    stats[0].frames_drop, stats[1].frames_drop);
6608308304Sjhb	}
6609228561Snp
6610228561Snp	rc = sbuf_finish(sb);
6611228561Snp	sbuf_delete(sb);
6612228561Snp
6613228561Snp	return (rc);
6614228561Snp}
6615228561Snp
6616228561Snpstatic int
6617228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS)
6618228561Snp{
6619228561Snp	struct adapter *sc = arg1;
6620228561Snp	struct sbuf *sb;
6621228561Snp	int rc, i;
6622228561Snp	unsigned int map, kbps, ipg, mode;
6623228561Snp	unsigned int pace_tab[NTX_SCHED];
6624228561Snp
6625228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6626228561Snp	if (rc != 0)
6627228561Snp		return (rc);
6628228561Snp
6629228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6630228561Snp	if (sb == NULL)
6631228561Snp		return (ENOMEM);
6632228561Snp
6633228561Snp	map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP);
6634228561Snp	mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG));
6635228561Snp	t4_read_pace_tbl(sc, pace_tab);
6636228561Snp
6637228561Snp	sbuf_printf(sb, "Scheduler  Mode   Channel  Rate (Kbps)   "
6638228561Snp	    "Class IPG (0.1 ns)   Flow IPG (us)");
6639228561Snp
6640228561Snp	for (i = 0; i < NTX_SCHED; ++i, map >>= 2) {
6641353418Snp		t4_get_tx_sched(sc, i, &kbps, &ipg, 1);
6642228561Snp		sbuf_printf(sb, "\n    %u      %-5s     %u     ", i,
6643228561Snp		    (mode & (1 << i)) ? "flow" : "class", map & 3);
6644228561Snp		if (kbps)
6645228561Snp			sbuf_printf(sb, "%9u     ", kbps);
6646228561Snp		else
6647228561Snp			sbuf_printf(sb, " disabled     ");
6648228561Snp
6649228561Snp		if (ipg)
6650228561Snp			sbuf_printf(sb, "%13u        ", ipg);
6651228561Snp		else
6652228561Snp			sbuf_printf(sb, "     disabled        ");
6653228561Snp
6654228561Snp		if (pace_tab[i])
6655228561Snp			sbuf_printf(sb, "%10u", pace_tab[i]);
6656228561Snp		else
6657228561Snp			sbuf_printf(sb, "  disabled");
6658228561Snp	}
6659228561Snp
6660228561Snp	rc = sbuf_finish(sb);
6661228561Snp	sbuf_delete(sb);
6662228561Snp
6663228561Snp	return (rc);
6664228561Snp}
6665228561Snp
6666228561Snpstatic int
6667228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS)
6668228561Snp{
6669228561Snp	struct adapter *sc = arg1;
6670228561Snp	struct sbuf *sb;
6671228561Snp	int rc, i, j;
6672228561Snp	uint64_t *p0, *p1;
6673228561Snp	struct lb_port_stats s[2];
6674228561Snp	static const char *stat_name[] = {
6675228561Snp		"OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:",
6676228561Snp		"UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:",
6677228561Snp		"Frames128To255:", "Frames256To511:", "Frames512To1023:",
6678228561Snp		"Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:",
6679228561Snp		"BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:",
6680228561Snp		"BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:",
6681228561Snp		"BG2FramesTrunc:", "BG3FramesTrunc:"
6682228561Snp	};
6683228561Snp
6684228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6685228561Snp	if (rc != 0)
6686228561Snp		return (rc);
6687228561Snp
6688228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6689228561Snp	if (sb == NULL)
6690228561Snp		return (ENOMEM);
6691228561Snp
6692228561Snp	memset(s, 0, sizeof(s));
6693228561Snp
6694308304Sjhb	for (i = 0; i < sc->chip_params->nchan; i += 2) {
6695228561Snp		t4_get_lb_stats(sc, i, &s[0]);
6696228561Snp		t4_get_lb_stats(sc, i + 1, &s[1]);
6697228561Snp
6698228561Snp		p0 = &s[0].octets;
6699228561Snp		p1 = &s[1].octets;
6700228561Snp		sbuf_printf(sb, "%s                       Loopback %u"
6701228561Snp		    "           Loopback %u", i == 0 ? "" : "\n", i, i + 1);
6702228561Snp
6703240452Snp		for (j = 0; j < nitems(stat_name); j++)
6704228561Snp			sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j],
6705228561Snp				   *p0++, *p1++);
6706228561Snp	}
6707228561Snp
6708228561Snp	rc = sbuf_finish(sb);
6709228561Snp	sbuf_delete(sb);
6710228561Snp
6711228561Snp	return (rc);
6712228561Snp}
6713228561Snp
6714253701Snpstatic int
6715253701Snpsysctl_linkdnrc(SYSCTL_HANDLER_ARGS)
6716253701Snp{
6717253701Snp	int rc = 0;
6718253701Snp	struct port_info *pi = arg1;
6719311261Snp	struct link_config *lc = &pi->link_cfg;
6720253701Snp	struct sbuf *sb;
6721253701Snp
6722253701Snp	rc = sysctl_wire_old_buffer(req, 0);
6723253701Snp	if (rc != 0)
6724253701Snp		return(rc);
6725253701Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 64, req);
6726253701Snp	if (sb == NULL)
6727253701Snp		return (ENOMEM);
6728253701Snp
6729311261Snp	if (lc->link_ok || lc->link_down_rc == 255)
6730253701Snp		sbuf_printf(sb, "n/a");
6731253701Snp	else
6732311261Snp		sbuf_printf(sb, "%s", t4_link_down_rc_str(lc->link_down_rc));
6733253701Snp
6734253701Snp	rc = sbuf_finish(sb);
6735253701Snp	sbuf_delete(sb);
6736253701Snp
6737253701Snp	return (rc);
6738253701Snp}
6739253701Snp
6740228561Snpstruct mem_desc {
6741228561Snp	unsigned int base;
6742228561Snp	unsigned int limit;
6743228561Snp	unsigned int idx;
6744228561Snp};
6745228561Snp
6746228561Snpstatic int
6747228561Snpmem_desc_cmp(const void *a, const void *b)
6748228561Snp{
6749228561Snp	return ((const struct mem_desc *)a)->base -
6750228561Snp	       ((const struct mem_desc *)b)->base;
6751228561Snp}
6752228561Snp
6753228561Snpstatic void
6754228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from,
6755228561Snp    unsigned int to)
6756228561Snp{
6757228561Snp	unsigned int size;
6758228561Snp
6759308311Sjhb	if (from == to)
6760308311Sjhb		return;
6761308311Sjhb
6762228561Snp	size = to - from + 1;
6763228561Snp	if (size == 0)
6764228561Snp		return;
6765228561Snp
6766228561Snp	/* XXX: need humanize_number(3) in libkern for a more readable 'size' */
6767228561Snp	sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size);
6768228561Snp}
6769228561Snp
6770228561Snpstatic int
6771228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS)
6772228561Snp{
6773228561Snp	struct adapter *sc = arg1;
6774228561Snp	struct sbuf *sb;
6775228561Snp	int rc, i, n;
6776248925Snp	uint32_t lo, hi, used, alloc;
6777248925Snp	static const char *memory[] = {"EDC0:", "EDC1:", "MC:", "MC0:", "MC1:"};
6778228561Snp	static const char *region[] = {
6779228561Snp		"DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:",
6780228561Snp		"Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:",
6781228561Snp		"Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:",
6782228561Snp		"TDDP region:", "TPT region:", "STAG region:", "RQ region:",
6783248925Snp		"RQUDP region:", "PBL region:", "TXPBL region:",
6784248925Snp		"DBVFIFO region:", "ULPRX state:", "ULPTX state:",
6785248925Snp		"On-chip queues:"
6786228561Snp	};
6787248925Snp	struct mem_desc avail[4];
6788240452Snp	struct mem_desc mem[nitems(region) + 3];	/* up to 3 holes */
6789228561Snp	struct mem_desc *md = mem;
6790228561Snp
6791228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6792228561Snp	if (rc != 0)
6793228561Snp		return (rc);
6794228561Snp
6795228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6796228561Snp	if (sb == NULL)
6797228561Snp		return (ENOMEM);
6798228561Snp
6799240452Snp	for (i = 0; i < nitems(mem); i++) {
6800228561Snp		mem[i].limit = 0;
6801228561Snp		mem[i].idx = i;
6802228561Snp	}
6803228561Snp
6804228561Snp	/* Find and sort the populated memory ranges */
6805228561Snp	i = 0;
6806228561Snp	lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
6807228561Snp	if (lo & F_EDRAM0_ENABLE) {
6808228561Snp		hi = t4_read_reg(sc, A_MA_EDRAM0_BAR);
6809228561Snp		avail[i].base = G_EDRAM0_BASE(hi) << 20;
6810228561Snp		avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20);
6811228561Snp		avail[i].idx = 0;
6812228561Snp		i++;
6813228561Snp	}
6814228561Snp	if (lo & F_EDRAM1_ENABLE) {
6815228561Snp		hi = t4_read_reg(sc, A_MA_EDRAM1_BAR);
6816228561Snp		avail[i].base = G_EDRAM1_BASE(hi) << 20;
6817228561Snp		avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20);
6818228561Snp		avail[i].idx = 1;
6819228561Snp		i++;
6820228561Snp	}
6821228561Snp	if (lo & F_EXT_MEM_ENABLE) {
6822228561Snp		hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
6823228561Snp		avail[i].base = G_EXT_MEM_BASE(hi) << 20;
6824248925Snp		avail[i].limit = avail[i].base +
6825248925Snp		    (G_EXT_MEM_SIZE(hi) << 20);
6826308304Sjhb		avail[i].idx = is_t5(sc) ? 3 : 2;	/* Call it MC0 for T5 */
6827228561Snp		i++;
6828228561Snp	}
6829308304Sjhb	if (is_t5(sc) && lo & F_EXT_MEM1_ENABLE) {
6830248925Snp		hi = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR);
6831248925Snp		avail[i].base = G_EXT_MEM1_BASE(hi) << 20;
6832248925Snp		avail[i].limit = avail[i].base +
6833248925Snp		    (G_EXT_MEM1_SIZE(hi) << 20);
6834248925Snp		avail[i].idx = 4;
6835248925Snp		i++;
6836248925Snp	}
6837228561Snp	if (!i)                                    /* no memory available */
6838228561Snp		return 0;
6839228561Snp	qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp);
6840228561Snp
6841228561Snp	(md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR);
6842228561Snp	(md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR);
6843228561Snp	(md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR);
6844228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE);
6845228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE);
6846228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE);
6847228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE);
6848228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE);
6849228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE);
6850228561Snp
6851228561Snp	/* the next few have explicit upper bounds */
6852228561Snp	md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE);
6853228561Snp	md->limit = md->base - 1 +
6854228561Snp		    t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) *
6855228561Snp		    G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE));
6856228561Snp	md++;
6857228561Snp
6858228561Snp	md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE);
6859228561Snp	md->limit = md->base - 1 +
6860228561Snp		    t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) *
6861228561Snp		    G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE));
6862228561Snp	md++;
6863228561Snp
6864228561Snp	if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) {
6865308311Sjhb		if (chip_id(sc) <= CHELSIO_T5)
6866308304Sjhb			md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE);
6867308311Sjhb		else
6868308304Sjhb			md->base = t4_read_reg(sc, A_LE_DB_HASH_TBL_BASE_ADDR);
6869308304Sjhb		md->limit = 0;
6870228561Snp	} else {
6871228561Snp		md->base = 0;
6872240452Snp		md->idx = nitems(region);  /* hide it */
6873228561Snp	}
6874228561Snp	md++;
6875228561Snp
6876228561Snp#define ulp_region(reg) \
6877228561Snp	md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\
6878228561Snp	(md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT)
6879228561Snp
6880228561Snp	ulp_region(RX_ISCSI);
6881228561Snp	ulp_region(RX_TDDP);
6882228561Snp	ulp_region(TX_TPT);
6883228561Snp	ulp_region(RX_STAG);
6884228561Snp	ulp_region(RX_RQ);
6885228561Snp	ulp_region(RX_RQUDP);
6886228561Snp	ulp_region(RX_PBL);
6887228561Snp	ulp_region(TX_PBL);
6888228561Snp#undef ulp_region
6889228561Snp
6890248925Snp	md->base = 0;
6891248925Snp	md->idx = nitems(region);
6892308304Sjhb	if (!is_t4(sc)) {
6893308304Sjhb		uint32_t size = 0;
6894308304Sjhb		uint32_t sge_ctrl = t4_read_reg(sc, A_SGE_CONTROL2);
6895308304Sjhb		uint32_t fifo_size = t4_read_reg(sc, A_SGE_DBVFIFO_SIZE);
6896308304Sjhb
6897308304Sjhb		if (is_t5(sc)) {
6898308304Sjhb			if (sge_ctrl & F_VFIFO_ENABLE)
6899308304Sjhb				size = G_DBVFIFO_SIZE(fifo_size);
6900308304Sjhb		} else
6901308304Sjhb			size = G_T6_DBVFIFO_SIZE(fifo_size);
6902308304Sjhb
6903308304Sjhb		if (size) {
6904308304Sjhb			md->base = G_BASEADDR(t4_read_reg(sc,
6905308304Sjhb			    A_SGE_DBVFIFO_BADDR));
6906308304Sjhb			md->limit = md->base + (size << 2) - 1;
6907308304Sjhb		}
6908248925Snp	}
6909248925Snp	md++;
6910248925Snp
6911228561Snp	md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE);
6912308304Sjhb	md->limit = 0;
6913228561Snp	md++;
6914228561Snp	md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE);
6915308304Sjhb	md->limit = 0;
6916228561Snp	md++;
6917228561Snp
6918228561Snp	md->base = sc->vres.ocq.start;
6919228561Snp	if (sc->vres.ocq.size)
6920228561Snp		md->limit = md->base + sc->vres.ocq.size - 1;
6921228561Snp	else
6922240452Snp		md->idx = nitems(region);  /* hide it */
6923228561Snp	md++;
6924228561Snp
6925228561Snp	/* add any address-space holes, there can be up to 3 */
6926228561Snp	for (n = 0; n < i - 1; n++)
6927228561Snp		if (avail[n].limit < avail[n + 1].base)
6928228561Snp			(md++)->base = avail[n].limit;
6929228561Snp	if (avail[n].limit)
6930228561Snp		(md++)->base = avail[n].limit;
6931228561Snp
6932228561Snp	n = md - mem;
6933228561Snp	qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp);
6934228561Snp
6935228561Snp	for (lo = 0; lo < i; lo++)
6936228561Snp		mem_region_show(sb, memory[avail[lo].idx], avail[lo].base,
6937228561Snp				avail[lo].limit - 1);
6938228561Snp
6939228561Snp	sbuf_printf(sb, "\n");
6940228561Snp	for (i = 0; i < n; i++) {
6941240452Snp		if (mem[i].idx >= nitems(region))
6942228561Snp			continue;                        /* skip holes */
6943228561Snp		if (!mem[i].limit)
6944228561Snp			mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0;
6945228561Snp		mem_region_show(sb, region[mem[i].idx], mem[i].base,
6946228561Snp				mem[i].limit);
6947228561Snp	}
6948228561Snp
6949228561Snp	sbuf_printf(sb, "\n");
6950228561Snp	lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR);
6951228561Snp	hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1;
6952228561Snp	mem_region_show(sb, "uP RAM:", lo, hi);
6953228561Snp
6954228561Snp	lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR);
6955228561Snp	hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1;
6956228561Snp	mem_region_show(sb, "uP Extmem2:", lo, hi);
6957228561Snp
6958228561Snp	lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE);
6959228561Snp	sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n",
6960228561Snp		   G_PMRXMAXPAGE(lo),
6961228561Snp		   t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10,
6962228561Snp		   (lo & F_PMRXNUMCHN) ? 2 : 1);
6963228561Snp
6964228561Snp	lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE);
6965228561Snp	hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE);
6966228561Snp	sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n",
6967228561Snp		   G_PMTXMAXPAGE(lo),
6968228561Snp		   hi >= (1 << 20) ? (hi >> 20) : (hi >> 10),
6969228561Snp		   hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo));
6970228561Snp	sbuf_printf(sb, "%u p-structs\n",
6971228561Snp		   t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT));
6972228561Snp
6973228561Snp	for (i = 0; i < 4; i++) {
6974308304Sjhb		if (chip_id(sc) > CHELSIO_T5)
6975308304Sjhb			lo = t4_read_reg(sc, A_MPS_RX_MAC_BG_PG_CNT0 + i * 4);
6976308304Sjhb		else
6977308304Sjhb			lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4);
6978308304Sjhb		if (is_t5(sc)) {
6979308304Sjhb			used = G_T5_USED(lo);
6980308304Sjhb			alloc = G_T5_ALLOC(lo);
6981308304Sjhb		} else {
6982248925Snp			used = G_USED(lo);
6983248925Snp			alloc = G_ALLOC(lo);
6984248925Snp		}
6985308304Sjhb		/* For T6 these are MAC buffer groups */
6986228561Snp		sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated",
6987308304Sjhb		    i, used, alloc);
6988228561Snp	}
6989308304Sjhb	for (i = 0; i < sc->chip_params->nchan; i++) {
6990308304Sjhb		if (chip_id(sc) > CHELSIO_T5)
6991308304Sjhb			lo = t4_read_reg(sc, A_MPS_RX_LPBK_BG_PG_CNT0 + i * 4);
6992308304Sjhb		else
6993308304Sjhb			lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4);
6994308304Sjhb		if (is_t5(sc)) {
6995308304Sjhb			used = G_T5_USED(lo);
6996308304Sjhb			alloc = G_T5_ALLOC(lo);
6997308304Sjhb		} else {
6998248925Snp			used = G_USED(lo);
6999248925Snp			alloc = G_ALLOC(lo);
7000248925Snp		}
7001308304Sjhb		/* For T6 these are MAC buffer groups */
7002228561Snp		sbuf_printf(sb,
7003308304Sjhb		    "\nLoopback %d using %u pages out of %u allocated",
7004308304Sjhb		    i, used, alloc);
7005228561Snp	}
7006228561Snp
7007228561Snp	rc = sbuf_finish(sb);
7008228561Snp	sbuf_delete(sb);
7009228561Snp
7010228561Snp	return (rc);
7011228561Snp}
7012228561Snp
7013251213Snpstatic inline void
7014251213Snptcamxy2valmask(uint64_t x, uint64_t y, uint8_t *addr, uint64_t *mask)
7015251213Snp{
7016251213Snp	*mask = x | y;
7017251213Snp	y = htobe64(y);
7018251213Snp	memcpy(addr, (char *)&y + 2, ETHER_ADDR_LEN);
7019251213Snp}
7020251213Snp
7021228561Snpstatic int
7022251213Snpsysctl_mps_tcam(SYSCTL_HANDLER_ARGS)
7023251213Snp{
7024251213Snp	struct adapter *sc = arg1;
7025251213Snp	struct sbuf *sb;
7026308304Sjhb	int rc, i;
7027251213Snp
7028308304Sjhb	MPASS(chip_id(sc) <= CHELSIO_T5);
7029308304Sjhb
7030251213Snp	rc = sysctl_wire_old_buffer(req, 0);
7031251213Snp	if (rc != 0)
7032251213Snp		return (rc);
7033251213Snp
7034251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
7035251213Snp	if (sb == NULL)
7036251213Snp		return (ENOMEM);
7037251213Snp
7038251213Snp	sbuf_printf(sb,
7039251213Snp	    "Idx  Ethernet address     Mask     Vld Ports PF"
7040251213Snp	    "  VF              Replication             P0 P1 P2 P3  ML");
7041308304Sjhb	for (i = 0; i < sc->chip_params->mps_tcam_size; i++) {
7042251213Snp		uint64_t tcamx, tcamy, mask;
7043251213Snp		uint32_t cls_lo, cls_hi;
7044251213Snp		uint8_t addr[ETHER_ADDR_LEN];
7045251213Snp
7046251213Snp		tcamy = t4_read_reg64(sc, MPS_CLS_TCAM_Y_L(i));
7047251213Snp		tcamx = t4_read_reg64(sc, MPS_CLS_TCAM_X_L(i));
7048251213Snp		if (tcamx & tcamy)
7049251213Snp			continue;
7050251213Snp		tcamxy2valmask(tcamx, tcamy, addr, &mask);
7051308304Sjhb		cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i));
7052308304Sjhb		cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i));
7053251213Snp		sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x %012jx"
7054251213Snp			   "  %c   %#x%4u%4d", i, addr[0], addr[1], addr[2],
7055251213Snp			   addr[3], addr[4], addr[5], (uintmax_t)mask,
7056251213Snp			   (cls_lo & F_SRAM_VLD) ? 'Y' : 'N',
7057251213Snp			   G_PORTMAP(cls_hi), G_PF(cls_lo),
7058251213Snp			   (cls_lo & F_VF_VALID) ? G_VF(cls_lo) : -1);
7059251213Snp
7060251213Snp		if (cls_lo & F_REPLICATE) {
7061251213Snp			struct fw_ldst_cmd ldst_cmd;
7062251213Snp
7063251213Snp			memset(&ldst_cmd, 0, sizeof(ldst_cmd));
7064251213Snp			ldst_cmd.op_to_addrspace =
7065251213Snp			    htobe32(V_FW_CMD_OP(FW_LDST_CMD) |
7066251213Snp				F_FW_CMD_REQUEST | F_FW_CMD_READ |
7067251213Snp				V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS));
7068251213Snp			ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd));
7069286895Snp			ldst_cmd.u.mps.rplc.fid_idx =
7070251213Snp			    htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) |
7071286895Snp				V_FW_LDST_CMD_IDX(i));
7072251213Snp
7073251213Snp			rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK,
7074251213Snp			    "t4mps");
7075251213Snp			if (rc)
7076251213Snp				break;
7077251213Snp			rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd,
7078251213Snp			    sizeof(ldst_cmd), &ldst_cmd);
7079251213Snp			end_synchronized_op(sc, 0);
7080251213Snp
7081251213Snp			if (rc != 0) {
7082308304Sjhb				sbuf_printf(sb, "%36d", rc);
7083251213Snp				rc = 0;
7084251213Snp			} else {
7085251213Snp				sbuf_printf(sb, " %08x %08x %08x %08x",
7086286895Snp				    be32toh(ldst_cmd.u.mps.rplc.rplc127_96),
7087286895Snp				    be32toh(ldst_cmd.u.mps.rplc.rplc95_64),
7088286895Snp				    be32toh(ldst_cmd.u.mps.rplc.rplc63_32),
7089286895Snp				    be32toh(ldst_cmd.u.mps.rplc.rplc31_0));
7090251213Snp			}
7091251213Snp		} else
7092251213Snp			sbuf_printf(sb, "%36s", "");
7093251213Snp
7094251213Snp		sbuf_printf(sb, "%4u%3u%3u%3u %#3x", G_SRAM_PRIO0(cls_lo),
7095251213Snp		    G_SRAM_PRIO1(cls_lo), G_SRAM_PRIO2(cls_lo),
7096251213Snp		    G_SRAM_PRIO3(cls_lo), (cls_lo >> S_MULTILISTEN0) & 0xf);
7097251213Snp	}
7098251213Snp
7099251213Snp	if (rc)
7100251213Snp		(void) sbuf_finish(sb);
7101251213Snp	else
7102251213Snp		rc = sbuf_finish(sb);
7103251213Snp	sbuf_delete(sb);
7104251213Snp
7105251213Snp	return (rc);
7106251213Snp}
7107251213Snp
7108251213Snpstatic int
7109308304Sjhbsysctl_mps_tcam_t6(SYSCTL_HANDLER_ARGS)
7110308304Sjhb{
7111308304Sjhb	struct adapter *sc = arg1;
7112308304Sjhb	struct sbuf *sb;
7113308304Sjhb	int rc, i;
7114308304Sjhb
7115308304Sjhb	MPASS(chip_id(sc) > CHELSIO_T5);
7116308304Sjhb
7117308304Sjhb	rc = sysctl_wire_old_buffer(req, 0);
7118308304Sjhb	if (rc != 0)
7119308304Sjhb		return (rc);
7120308304Sjhb
7121308304Sjhb	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
7122308304Sjhb	if (sb == NULL)
7123308304Sjhb		return (ENOMEM);
7124308304Sjhb
7125308304Sjhb	sbuf_printf(sb, "Idx  Ethernet address     Mask       VNI   Mask"
7126308304Sjhb	    "   IVLAN Vld DIP_Hit   Lookup  Port Vld Ports PF  VF"
7127308304Sjhb	    "                           Replication"
7128308304Sjhb	    "                                    P0 P1 P2 P3  ML\n");
7129308304Sjhb
7130308304Sjhb	for (i = 0; i < sc->chip_params->mps_tcam_size; i++) {
7131308304Sjhb		uint8_t dip_hit, vlan_vld, lookup_type, port_num;
7132308304Sjhb		uint16_t ivlan;
7133308304Sjhb		uint64_t tcamx, tcamy, val, mask;
7134308304Sjhb		uint32_t cls_lo, cls_hi, ctl, data2, vnix, vniy;
7135308304Sjhb		uint8_t addr[ETHER_ADDR_LEN];
7136308304Sjhb
7137308304Sjhb		ctl = V_CTLREQID(1) | V_CTLCMDTYPE(0) | V_CTLXYBITSEL(0);
7138308304Sjhb		if (i < 256)
7139308304Sjhb			ctl |= V_CTLTCAMINDEX(i) | V_CTLTCAMSEL(0);
7140308304Sjhb		else
7141308304Sjhb			ctl |= V_CTLTCAMINDEX(i - 256) | V_CTLTCAMSEL(1);
7142308304Sjhb		t4_write_reg(sc, A_MPS_CLS_TCAM_DATA2_CTL, ctl);
7143308304Sjhb		val = t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA1_REQ_ID1);
7144308304Sjhb		tcamy = G_DMACH(val) << 32;
7145308304Sjhb		tcamy |= t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA0_REQ_ID1);
7146308304Sjhb		data2 = t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA2_REQ_ID1);
7147308304Sjhb		lookup_type = G_DATALKPTYPE(data2);
7148308304Sjhb		port_num = G_DATAPORTNUM(data2);
7149308304Sjhb		if (lookup_type && lookup_type != M_DATALKPTYPE) {
7150308304Sjhb			/* Inner header VNI */
7151308304Sjhb			vniy = ((data2 & F_DATAVIDH2) << 23) |
7152308304Sjhb				       (G_DATAVIDH1(data2) << 16) | G_VIDL(val);
7153308304Sjhb			dip_hit = data2 & F_DATADIPHIT;
7154308304Sjhb			vlan_vld = 0;
7155308304Sjhb		} else {
7156308304Sjhb			vniy = 0;
7157308304Sjhb			dip_hit = 0;
7158308304Sjhb			vlan_vld = data2 & F_DATAVIDH2;
7159308304Sjhb			ivlan = G_VIDL(val);
7160308304Sjhb		}
7161308304Sjhb
7162308304Sjhb		ctl |= V_CTLXYBITSEL(1);
7163308304Sjhb		t4_write_reg(sc, A_MPS_CLS_TCAM_DATA2_CTL, ctl);
7164308304Sjhb		val = t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA1_REQ_ID1);
7165308304Sjhb		tcamx = G_DMACH(val) << 32;
7166308304Sjhb		tcamx |= t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA0_REQ_ID1);
7167308304Sjhb		data2 = t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA2_REQ_ID1);
7168308304Sjhb		if (lookup_type && lookup_type != M_DATALKPTYPE) {
7169308304Sjhb			/* Inner header VNI mask */
7170308304Sjhb			vnix = ((data2 & F_DATAVIDH2) << 23) |
7171308304Sjhb			       (G_DATAVIDH1(data2) << 16) | G_VIDL(val);
7172308304Sjhb		} else
7173308304Sjhb			vnix = 0;
7174308304Sjhb
7175308304Sjhb		if (tcamx & tcamy)
7176308304Sjhb			continue;
7177308304Sjhb		tcamxy2valmask(tcamx, tcamy, addr, &mask);
7178308304Sjhb
7179308304Sjhb		cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i));
7180308304Sjhb		cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i));
7181308304Sjhb
7182308304Sjhb		if (lookup_type && lookup_type != M_DATALKPTYPE) {
7183308304Sjhb			sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x "
7184308304Sjhb			    "%012jx %06x %06x    -    -   %3c"
7185308304Sjhb			    "      'I'  %4x   %3c   %#x%4u%4d", i, addr[0],
7186308304Sjhb			    addr[1], addr[2], addr[3], addr[4], addr[5],
7187308304Sjhb			    (uintmax_t)mask, vniy, vnix, dip_hit ? 'Y' : 'N',
7188308304Sjhb			    port_num, cls_lo & F_T6_SRAM_VLD ? 'Y' : 'N',
7189308304Sjhb			    G_PORTMAP(cls_hi), G_T6_PF(cls_lo),
7190308304Sjhb			    cls_lo & F_T6_VF_VALID ? G_T6_VF(cls_lo) : -1);
7191308304Sjhb		} else {
7192308304Sjhb			sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x "
7193308304Sjhb			    "%012jx    -       -   ", i, addr[0], addr[1],
7194308304Sjhb			    addr[2], addr[3], addr[4], addr[5],
7195308304Sjhb			    (uintmax_t)mask);
7196308304Sjhb
7197308304Sjhb			if (vlan_vld)
7198308304Sjhb				sbuf_printf(sb, "%4u   Y     ", ivlan);
7199308304Sjhb			else
7200308304Sjhb				sbuf_printf(sb, "  -    N     ");
7201308304Sjhb
7202308304Sjhb			sbuf_printf(sb, "-      %3c  %4x   %3c   %#x%4u%4d",
7203308304Sjhb			    lookup_type ? 'I' : 'O', port_num,
7204308304Sjhb			    cls_lo & F_T6_SRAM_VLD ? 'Y' : 'N',
7205308304Sjhb			    G_PORTMAP(cls_hi), G_T6_PF(cls_lo),
7206308304Sjhb			    cls_lo & F_T6_VF_VALID ? G_T6_VF(cls_lo) : -1);
7207308304Sjhb		}
7208308304Sjhb
7209308304Sjhb
7210308304Sjhb		if (cls_lo & F_T6_REPLICATE) {
7211308304Sjhb			struct fw_ldst_cmd ldst_cmd;
7212308304Sjhb
7213308304Sjhb			memset(&ldst_cmd, 0, sizeof(ldst_cmd));
7214308304Sjhb			ldst_cmd.op_to_addrspace =
7215308304Sjhb			    htobe32(V_FW_CMD_OP(FW_LDST_CMD) |
7216308304Sjhb				F_FW_CMD_REQUEST | F_FW_CMD_READ |
7217308304Sjhb				V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS));
7218308304Sjhb			ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd));
7219308304Sjhb			ldst_cmd.u.mps.rplc.fid_idx =
7220308304Sjhb			    htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) |
7221308304Sjhb				V_FW_LDST_CMD_IDX(i));
7222308304Sjhb
7223308304Sjhb			rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK,
7224308304Sjhb			    "t6mps");
7225308304Sjhb			if (rc)
7226308304Sjhb				break;
7227308304Sjhb			rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd,
7228308304Sjhb			    sizeof(ldst_cmd), &ldst_cmd);
7229308304Sjhb			end_synchronized_op(sc, 0);
7230308304Sjhb
7231308304Sjhb			if (rc != 0) {
7232308304Sjhb				sbuf_printf(sb, "%72d", rc);
7233308304Sjhb				rc = 0;
7234308304Sjhb			} else {
7235308304Sjhb				sbuf_printf(sb, " %08x %08x %08x %08x"
7236308304Sjhb				    " %08x %08x %08x %08x",
7237308304Sjhb				    be32toh(ldst_cmd.u.mps.rplc.rplc255_224),
7238308304Sjhb				    be32toh(ldst_cmd.u.mps.rplc.rplc223_192),
7239308304Sjhb				    be32toh(ldst_cmd.u.mps.rplc.rplc191_160),
7240308304Sjhb				    be32toh(ldst_cmd.u.mps.rplc.rplc159_128),
7241308304Sjhb				    be32toh(ldst_cmd.u.mps.rplc.rplc127_96),
7242308304Sjhb				    be32toh(ldst_cmd.u.mps.rplc.rplc95_64),
7243308304Sjhb				    be32toh(ldst_cmd.u.mps.rplc.rplc63_32),
7244308304Sjhb				    be32toh(ldst_cmd.u.mps.rplc.rplc31_0));
7245308304Sjhb			}
7246308304Sjhb		} else
7247308304Sjhb			sbuf_printf(sb, "%72s", "");
7248308304Sjhb
7249308304Sjhb		sbuf_printf(sb, "%4u%3u%3u%3u %#x",
7250308304Sjhb		    G_T6_SRAM_PRIO0(cls_lo), G_T6_SRAM_PRIO1(cls_lo),
7251308304Sjhb		    G_T6_SRAM_PRIO2(cls_lo), G_T6_SRAM_PRIO3(cls_lo),
7252308304Sjhb		    (cls_lo >> S_T6_MULTILISTEN0) & 0xf);
7253308304Sjhb	}
7254308304Sjhb
7255308304Sjhb	if (rc)
7256308304Sjhb		(void) sbuf_finish(sb);
7257308304Sjhb	else
7258308304Sjhb		rc = sbuf_finish(sb);
7259308304Sjhb	sbuf_delete(sb);
7260308304Sjhb
7261308304Sjhb	return (rc);
7262308304Sjhb}
7263308304Sjhb
7264308304Sjhbstatic int
7265228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS)
7266228561Snp{
7267228561Snp	struct adapter *sc = arg1;
7268228561Snp	struct sbuf *sb;
7269228561Snp	int rc;
7270228561Snp	uint16_t mtus[NMTUS];
7271228561Snp
7272228561Snp	rc = sysctl_wire_old_buffer(req, 0);
7273228561Snp	if (rc != 0)
7274228561Snp		return (rc);
7275228561Snp
7276228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
7277228561Snp	if (sb == NULL)
7278228561Snp		return (ENOMEM);
7279228561Snp
7280228561Snp	t4_read_mtu_tbl(sc, mtus, NULL);
7281228561Snp
7282228561Snp	sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
7283228561Snp	    mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6],
7284228561Snp	    mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13],
7285228561Snp	    mtus[14], mtus[15]);
7286228561Snp
7287228561Snp	rc = sbuf_finish(sb);
7288228561Snp	sbuf_delete(sb);
7289228561Snp
7290228561Snp	return (rc);
7291228561Snp}
7292228561Snp
7293228561Snpstatic int
7294228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS)
7295228561Snp{
7296228561Snp	struct adapter *sc = arg1;
7297228561Snp	struct sbuf *sb;
7298228561Snp	int rc, i;
7299308304Sjhb	uint32_t tx_cnt[MAX_PM_NSTATS], rx_cnt[MAX_PM_NSTATS];
7300308304Sjhb	uint64_t tx_cyc[MAX_PM_NSTATS], rx_cyc[MAX_PM_NSTATS];
7301308304Sjhb	static const char *tx_stats[MAX_PM_NSTATS] = {
7302308304Sjhb		"Read:", "Write bypass:", "Write mem:", "Bypass + mem:",
7303308304Sjhb		"Tx FIFO wait", NULL, "Tx latency"
7304228561Snp	};
7305308304Sjhb	static const char *rx_stats[MAX_PM_NSTATS] = {
7306308304Sjhb		"Read:", "Write bypass:", "Write mem:", "Flush:",
7307309458Sjhb		"Rx FIFO wait", NULL, "Rx latency"
7308259142Snp	};
7309228561Snp
7310228561Snp	rc = sysctl_wire_old_buffer(req, 0);
7311228561Snp	if (rc != 0)
7312228561Snp		return (rc);
7313228561Snp
7314228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
7315228561Snp	if (sb == NULL)
7316228561Snp		return (ENOMEM);
7317228561Snp
7318308304Sjhb	t4_pmtx_get_stats(sc, tx_cnt, tx_cyc);
7319308304Sjhb	t4_pmrx_get_stats(sc, rx_cnt, rx_cyc);
7320308304Sjhb
7321259142Snp	sbuf_printf(sb, "                Tx pcmds             Tx bytes");
7322308304Sjhb	for (i = 0; i < 4; i++) {
7323308304Sjhb		sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], tx_cnt[i],
7324308304Sjhb		    tx_cyc[i]);
7325308304Sjhb	}
7326228561Snp
7327259142Snp	sbuf_printf(sb, "\n                Rx pcmds             Rx bytes");
7328308304Sjhb	for (i = 0; i < 4; i++) {
7329308304Sjhb		sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], rx_cnt[i],
7330308304Sjhb		    rx_cyc[i]);
7331308304Sjhb	}
7332228561Snp
7333308304Sjhb	if (chip_id(sc) > CHELSIO_T5) {
7334308304Sjhb		sbuf_printf(sb,
7335308304Sjhb		    "\n              Total wait      Total occupancy");
7336308304Sjhb		sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], tx_cnt[i],
7337308304Sjhb		    tx_cyc[i]);
7338308304Sjhb		sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], rx_cnt[i],
7339308304Sjhb		    rx_cyc[i]);
7340308304Sjhb
7341308304Sjhb		i += 2;
7342308304Sjhb		MPASS(i < nitems(tx_stats));
7343308304Sjhb
7344308304Sjhb		sbuf_printf(sb,
7345308304Sjhb		    "\n                   Reads           Total wait");
7346308304Sjhb		sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], tx_cnt[i],
7347308304Sjhb		    tx_cyc[i]);
7348308304Sjhb		sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], rx_cnt[i],
7349308304Sjhb		    rx_cyc[i]);
7350308304Sjhb	}
7351308304Sjhb
7352228561Snp	rc = sbuf_finish(sb);
7353228561Snp	sbuf_delete(sb);
7354228561Snp
7355228561Snp	return (rc);
7356228561Snp}
7357228561Snp
7358228561Snpstatic int
7359228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS)
7360228561Snp{
7361228561Snp	struct adapter *sc = arg1;
7362228561Snp	struct sbuf *sb;
7363228561Snp	int rc;
7364228561Snp	struct tp_rdma_stats stats;
7365228561Snp
7366228561Snp	rc = sysctl_wire_old_buffer(req, 0);
7367228561Snp	if (rc != 0)
7368228561Snp		return (rc);
7369228561Snp
7370228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
7371228561Snp	if (sb == NULL)
7372228561Snp		return (ENOMEM);
7373228561Snp
7374308305Sjhb	mtx_lock(&sc->reg_lock);
7375353418Snp	t4_tp_get_rdma_stats(sc, &stats, 0);
7376308305Sjhb	mtx_unlock(&sc->reg_lock);
7377308304Sjhb
7378228561Snp	sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod);
7379228561Snp	sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt);
7380228561Snp
7381228561Snp	rc = sbuf_finish(sb);
7382228561Snp	sbuf_delete(sb);
7383228561Snp
7384228561Snp	return (rc);
7385228561Snp}
7386228561Snp
7387228561Snpstatic int
7388228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS)
7389228561Snp{
7390228561Snp	struct adapter *sc = arg1;
7391228561Snp	struct sbuf *sb;
7392228561Snp	int rc;
7393228561Snp	struct tp_tcp_stats v4, v6;
7394228561Snp
7395228561Snp	rc = sysctl_wire_old_buffer(req, 0);
7396228561Snp	if (rc != 0)
7397228561Snp		return (rc);
7398228561Snp
7399228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
7400228561Snp	if (sb == NULL)
7401228561Snp		return (ENOMEM);
7402228561Snp
7403308305Sjhb	mtx_lock(&sc->reg_lock);
7404353418Snp	t4_tp_get_tcp_stats(sc, &v4, &v6, 0);
7405308305Sjhb	mtx_unlock(&sc->reg_lock);
7406308304Sjhb
7407228561Snp	sbuf_printf(sb,
7408228561Snp	    "                                IP                 IPv6\n");
7409228561Snp	sbuf_printf(sb, "OutRsts:      %20u %20u\n",
7410308304Sjhb	    v4.tcp_out_rsts, v6.tcp_out_rsts);
7411228561Snp	sbuf_printf(sb, "InSegs:       %20ju %20ju\n",
7412308304Sjhb	    v4.tcp_in_segs, v6.tcp_in_segs);
7413228561Snp	sbuf_printf(sb, "OutSegs:      %20ju %20ju\n",
7414308304Sjhb	    v4.tcp_out_segs, v6.tcp_out_segs);
7415228561Snp	sbuf_printf(sb, "RetransSegs:  %20ju %20ju",
7416308304Sjhb	    v4.tcp_retrans_segs, v6.tcp_retrans_segs);
7417228561Snp
7418228561Snp	rc = sbuf_finish(sb);
7419228561Snp	sbuf_delete(sb);
7420228561Snp
7421228561Snp	return (rc);
7422228561Snp}
7423228561Snp
7424228561Snpstatic int
7425228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS)
7426228561Snp{
7427228561Snp	struct adapter *sc = arg1;
7428228561Snp	struct sbuf *sb;
7429228561Snp	int rc;
7430228561Snp	struct tid_info *t = &sc->tids;
7431228561Snp
7432228561Snp	rc = sysctl_wire_old_buffer(req, 0);
7433228561Snp	if (rc != 0)
7434228561Snp		return (rc);
7435228561Snp
7436228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
7437228561Snp	if (sb == NULL)
7438228561Snp		return (ENOMEM);
7439228561Snp
7440228561Snp	if (t->natids) {
7441228561Snp		sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1,
7442228561Snp		    t->atids_in_use);
7443228561Snp	}
7444228561Snp
7445228561Snp	if (t->ntids) {
7446311261Snp		sbuf_printf(sb, "TID range: ");
7447228561Snp		if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) {
7448311261Snp			uint32_t b, hb;
7449228561Snp
7450311261Snp			if (chip_id(sc) <= CHELSIO_T5) {
7451309560Sjhb				b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4;
7452311261Snp				hb = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4;
7453311261Snp			} else {
7454309560Sjhb				b = t4_read_reg(sc, A_LE_DB_SRVR_START_INDEX);
7455311261Snp				hb = t4_read_reg(sc, A_T6_LE_DB_HASH_TID_BASE);
7456311261Snp			}
7457309560Sjhb
7458311261Snp			if (b)
7459311261Snp				sbuf_printf(sb, "0-%u, ", b - 1);
7460311261Snp			sbuf_printf(sb, "%u-%u", hb, t->ntids - 1);
7461228561Snp		} else
7462311261Snp			sbuf_printf(sb, "0-%u", t->ntids - 1);
7463228561Snp		sbuf_printf(sb, ", in use: %u\n",
7464228561Snp		    atomic_load_acq_int(&t->tids_in_use));
7465228561Snp	}
7466228561Snp
7467228561Snp	if (t->nstids) {
7468228561Snp		sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base,
7469228561Snp		    t->stid_base + t->nstids - 1, t->stids_in_use);
7470228561Snp	}
7471228561Snp
7472228561Snp	if (t->nftids) {
7473228561Snp		sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base,
7474228561Snp		    t->ftid_base + t->nftids - 1);
7475228561Snp	}
7476228561Snp
7477265426Snp	if (t->netids) {
7478265426Snp		sbuf_printf(sb, "ETID range: %u-%u\n", t->etid_base,
7479265426Snp		    t->etid_base + t->netids - 1);
7480265426Snp	}
7481265426Snp
7482228561Snp	sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users",
7483228561Snp	    t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4),
7484228561Snp	    t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6));
7485228561Snp
7486228561Snp	rc = sbuf_finish(sb);
7487228561Snp	sbuf_delete(sb);
7488228561Snp
7489228561Snp	return (rc);
7490228561Snp}
7491228561Snp
7492228561Snpstatic int
7493228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS)
7494228561Snp{
7495228561Snp	struct adapter *sc = arg1;
7496228561Snp	struct sbuf *sb;
7497228561Snp	int rc;
7498228561Snp	struct tp_err_stats stats;
7499228561Snp
7500228561Snp	rc = sysctl_wire_old_buffer(req, 0);
7501228561Snp	if (rc != 0)
7502228561Snp		return (rc);
7503228561Snp
7504228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
7505228561Snp	if (sb == NULL)
7506228561Snp		return (ENOMEM);
7507228561Snp
7508308305Sjhb	mtx_lock(&sc->reg_lock);
7509353418Snp	t4_tp_get_err_stats(sc, &stats, 0);
7510308305Sjhb	mtx_unlock(&sc->reg_lock);
7511228561Snp
7512308304Sjhb	if (sc->chip_params->nchan > 2) {
7513308304Sjhb		sbuf_printf(sb, "                 channel 0  channel 1"
7514308304Sjhb		    "  channel 2  channel 3\n");
7515308304Sjhb		sbuf_printf(sb, "macInErrs:      %10u %10u %10u %10u\n",
7516308304Sjhb		    stats.mac_in_errs[0], stats.mac_in_errs[1],
7517308304Sjhb		    stats.mac_in_errs[2], stats.mac_in_errs[3]);
7518308304Sjhb		sbuf_printf(sb, "hdrInErrs:      %10u %10u %10u %10u\n",
7519308304Sjhb		    stats.hdr_in_errs[0], stats.hdr_in_errs[1],
7520308304Sjhb		    stats.hdr_in_errs[2], stats.hdr_in_errs[3]);
7521308304Sjhb		sbuf_printf(sb, "tcpInErrs:      %10u %10u %10u %10u\n",
7522308304Sjhb		    stats.tcp_in_errs[0], stats.tcp_in_errs[1],
7523308304Sjhb		    stats.tcp_in_errs[2], stats.tcp_in_errs[3]);
7524308304Sjhb		sbuf_printf(sb, "tcp6InErrs:     %10u %10u %10u %10u\n",
7525308304Sjhb		    stats.tcp6_in_errs[0], stats.tcp6_in_errs[1],
7526308304Sjhb		    stats.tcp6_in_errs[2], stats.tcp6_in_errs[3]);
7527308304Sjhb		sbuf_printf(sb, "tnlCongDrops:   %10u %10u %10u %10u\n",
7528308304Sjhb		    stats.tnl_cong_drops[0], stats.tnl_cong_drops[1],
7529308304Sjhb		    stats.tnl_cong_drops[2], stats.tnl_cong_drops[3]);
7530308304Sjhb		sbuf_printf(sb, "tnlTxDrops:     %10u %10u %10u %10u\n",
7531308304Sjhb		    stats.tnl_tx_drops[0], stats.tnl_tx_drops[1],
7532308304Sjhb		    stats.tnl_tx_drops[2], stats.tnl_tx_drops[3]);
7533308304Sjhb		sbuf_printf(sb, "ofldVlanDrops:  %10u %10u %10u %10u\n",
7534308304Sjhb		    stats.ofld_vlan_drops[0], stats.ofld_vlan_drops[1],
7535308304Sjhb		    stats.ofld_vlan_drops[2], stats.ofld_vlan_drops[3]);
7536308304Sjhb		sbuf_printf(sb, "ofldChanDrops:  %10u %10u %10u %10u\n\n",
7537308304Sjhb		    stats.ofld_chan_drops[0], stats.ofld_chan_drops[1],
7538308304Sjhb		    stats.ofld_chan_drops[2], stats.ofld_chan_drops[3]);
7539308304Sjhb	} else {
7540308304Sjhb		sbuf_printf(sb, "                 channel 0  channel 1\n");
7541308304Sjhb		sbuf_printf(sb, "macInErrs:      %10u %10u\n",
7542308304Sjhb		    stats.mac_in_errs[0], stats.mac_in_errs[1]);
7543308304Sjhb		sbuf_printf(sb, "hdrInErrs:      %10u %10u\n",
7544308304Sjhb		    stats.hdr_in_errs[0], stats.hdr_in_errs[1]);
7545308304Sjhb		sbuf_printf(sb, "tcpInErrs:      %10u %10u\n",
7546308304Sjhb		    stats.tcp_in_errs[0], stats.tcp_in_errs[1]);
7547308304Sjhb		sbuf_printf(sb, "tcp6InErrs:     %10u %10u\n",
7548308304Sjhb		    stats.tcp6_in_errs[0], stats.tcp6_in_errs[1]);
7549308304Sjhb		sbuf_printf(sb, "tnlCongDrops:   %10u %10u\n",
7550308304Sjhb		    stats.tnl_cong_drops[0], stats.tnl_cong_drops[1]);
7551308304Sjhb		sbuf_printf(sb, "tnlTxDrops:     %10u %10u\n",
7552308304Sjhb		    stats.tnl_tx_drops[0], stats.tnl_tx_drops[1]);
7553308304Sjhb		sbuf_printf(sb, "ofldVlanDrops:  %10u %10u\n",
7554308304Sjhb		    stats.ofld_vlan_drops[0], stats.ofld_vlan_drops[1]);
7555308304Sjhb		sbuf_printf(sb, "ofldChanDrops:  %10u %10u\n\n",
7556308304Sjhb		    stats.ofld_chan_drops[0], stats.ofld_chan_drops[1]);
7557308304Sjhb	}
7558308304Sjhb
7559228561Snp	sbuf_printf(sb, "ofldNoNeigh:    %u\nofldCongDefer:  %u",
7560308304Sjhb	    stats.ofld_no_neigh, stats.ofld_cong_defer);
7561228561Snp
7562228561Snp	rc = sbuf_finish(sb);
7563228561Snp	sbuf_delete(sb);
7564228561Snp
7565228561Snp	return (rc);
7566228561Snp}
7567228561Snp
7568308311Sjhbstatic int
7569308311Sjhbsysctl_tp_la_mask(SYSCTL_HANDLER_ARGS)
7570308311Sjhb{
7571308311Sjhb	struct adapter *sc = arg1;
7572308311Sjhb	struct tp_params *tpp = &sc->params.tp;
7573308311Sjhb	u_int mask;
7574308311Sjhb	int rc;
7575308311Sjhb
7576308311Sjhb	mask = tpp->la_mask >> 16;
7577308311Sjhb	rc = sysctl_handle_int(oidp, &mask, 0, req);
7578308311Sjhb	if (rc != 0 || req->newptr == NULL)
7579308311Sjhb		return (rc);
7580308311Sjhb	if (mask > 0xffff)
7581308311Sjhb		return (EINVAL);
7582308311Sjhb	tpp->la_mask = mask << 16;
7583308311Sjhb	t4_set_reg_field(sc, A_TP_DBG_LA_CONFIG, 0xffff0000U, tpp->la_mask);
7584308311Sjhb
7585308311Sjhb	return (0);
7586308311Sjhb}
7587308311Sjhb
7588251213Snpstruct field_desc {
7589251213Snp	const char *name;
7590251213Snp	u_int start;
7591251213Snp	u_int width;
7592251213Snp};
7593251213Snp
7594251213Snpstatic void
7595251213Snpfield_desc_show(struct sbuf *sb, uint64_t v, const struct field_desc *f)
7596251213Snp{
7597251213Snp	char buf[32];
7598251213Snp	int line_size = 0;
7599251213Snp
7600251213Snp	while (f->name) {
7601251213Snp		uint64_t mask = (1ULL << f->width) - 1;
7602251213Snp		int len = snprintf(buf, sizeof(buf), "%s: %ju", f->name,
7603251213Snp		    ((uintmax_t)v >> f->start) & mask);
7604251213Snp
7605251213Snp		if (line_size + len >= 79) {
7606251213Snp			line_size = 8;
7607251213Snp			sbuf_printf(sb, "\n        ");
7608251213Snp		}
7609251213Snp		sbuf_printf(sb, "%s ", buf);
7610251213Snp		line_size += len + 1;
7611251213Snp		f++;
7612251213Snp	}
7613251213Snp	sbuf_printf(sb, "\n");
7614251213Snp}
7615251213Snp
7616308304Sjhbstatic const struct field_desc tp_la0[] = {
7617251213Snp	{ "RcfOpCodeOut", 60, 4 },
7618251213Snp	{ "State", 56, 4 },
7619251213Snp	{ "WcfState", 52, 4 },
7620251213Snp	{ "RcfOpcSrcOut", 50, 2 },
7621251213Snp	{ "CRxError", 49, 1 },
7622251213Snp	{ "ERxError", 48, 1 },
7623251213Snp	{ "SanityFailed", 47, 1 },
7624251213Snp	{ "SpuriousMsg", 46, 1 },
7625251213Snp	{ "FlushInputMsg", 45, 1 },
7626251213Snp	{ "FlushInputCpl", 44, 1 },
7627251213Snp	{ "RssUpBit", 43, 1 },
7628251213Snp	{ "RssFilterHit", 42, 1 },
7629251213Snp	{ "Tid", 32, 10 },
7630251213Snp	{ "InitTcb", 31, 1 },
7631251213Snp	{ "LineNumber", 24, 7 },
7632251213Snp	{ "Emsg", 23, 1 },
7633251213Snp	{ "EdataOut", 22, 1 },
7634251213Snp	{ "Cmsg", 21, 1 },
7635251213Snp	{ "CdataOut", 20, 1 },
7636251213Snp	{ "EreadPdu", 19, 1 },
7637251213Snp	{ "CreadPdu", 18, 1 },
7638251213Snp	{ "TunnelPkt", 17, 1 },
7639251213Snp	{ "RcfPeerFin", 16, 1 },
7640251213Snp	{ "RcfReasonOut", 12, 4 },
7641251213Snp	{ "TxCchannel", 10, 2 },
7642251213Snp	{ "RcfTxChannel", 8, 2 },
7643251213Snp	{ "RxEchannel", 6, 2 },
7644251213Snp	{ "RcfRxChannel", 5, 1 },
7645251213Snp	{ "RcfDataOutSrdy", 4, 1 },
7646251213Snp	{ "RxDvld", 3, 1 },
7647251213Snp	{ "RxOoDvld", 2, 1 },
7648251213Snp	{ "RxCongestion", 1, 1 },
7649251213Snp	{ "TxCongestion", 0, 1 },
7650251213Snp	{ NULL }
7651251213Snp};
7652251213Snp
7653308304Sjhbstatic const struct field_desc tp_la1[] = {
7654251213Snp	{ "CplCmdIn", 56, 8 },
7655251213Snp	{ "CplCmdOut", 48, 8 },
7656251213Snp	{ "ESynOut", 47, 1 },
7657251213Snp	{ "EAckOut", 46, 1 },
7658251213Snp	{ "EFinOut", 45, 1 },
7659251213Snp	{ "ERstOut", 44, 1 },
7660251213Snp	{ "SynIn", 43, 1 },
7661251213Snp	{ "AckIn", 42, 1 },
7662251213Snp	{ "FinIn", 41, 1 },
7663251213Snp	{ "RstIn", 40, 1 },
7664251213Snp	{ "DataIn", 39, 1 },
7665251213Snp	{ "DataInVld", 38, 1 },
7666251213Snp	{ "PadIn", 37, 1 },
7667251213Snp	{ "RxBufEmpty", 36, 1 },
7668251213Snp	{ "RxDdp", 35, 1 },
7669251213Snp	{ "RxFbCongestion", 34, 1 },
7670251213Snp	{ "TxFbCongestion", 33, 1 },
7671251213Snp	{ "TxPktSumSrdy", 32, 1 },
7672251213Snp	{ "RcfUlpType", 28, 4 },
7673251213Snp	{ "Eread", 27, 1 },
7674251213Snp	{ "Ebypass", 26, 1 },
7675251213Snp	{ "Esave", 25, 1 },
7676251213Snp	{ "Static0", 24, 1 },
7677251213Snp	{ "Cread", 23, 1 },
7678251213Snp	{ "Cbypass", 22, 1 },
7679251213Snp	{ "Csave", 21, 1 },
7680251213Snp	{ "CPktOut", 20, 1 },
7681251213Snp	{ "RxPagePoolFull", 18, 2 },
7682251213Snp	{ "RxLpbkPkt", 17, 1 },
7683251213Snp	{ "TxLpbkPkt", 16, 1 },
7684251213Snp	{ "RxVfValid", 15, 1 },
7685251213Snp	{ "SynLearned", 14, 1 },
7686251213Snp	{ "SetDelEntry", 13, 1 },
7687251213Snp	{ "SetInvEntry", 12, 1 },
7688251213Snp	{ "CpcmdDvld", 11, 1 },
7689251213Snp	{ "CpcmdSave", 10, 1 },
7690251213Snp	{ "RxPstructsFull", 8, 2 },
7691251213Snp	{ "EpcmdDvld", 7, 1 },
7692251213Snp	{ "EpcmdFlush", 6, 1 },
7693251213Snp	{ "EpcmdTrimPrefix", 5, 1 },
7694251213Snp	{ "EpcmdTrimPostfix", 4, 1 },
7695251213Snp	{ "ERssIp4Pkt", 3, 1 },
7696251213Snp	{ "ERssIp6Pkt", 2, 1 },
7697251213Snp	{ "ERssTcpUdpPkt", 1, 1 },
7698251213Snp	{ "ERssFceFipPkt", 0, 1 },
7699251213Snp	{ NULL }
7700251213Snp};
7701251213Snp
7702308304Sjhbstatic const struct field_desc tp_la2[] = {
7703251213Snp	{ "CplCmdIn", 56, 8 },
7704251213Snp	{ "MpsVfVld", 55, 1 },
7705251213Snp	{ "MpsPf", 52, 3 },
7706251213Snp	{ "MpsVf", 44, 8 },
7707251213Snp	{ "SynIn", 43, 1 },
7708251213Snp	{ "AckIn", 42, 1 },
7709251213Snp	{ "FinIn", 41, 1 },
7710251213Snp	{ "RstIn", 40, 1 },
7711251213Snp	{ "DataIn", 39, 1 },
7712251213Snp	{ "DataInVld", 38, 1 },
7713251213Snp	{ "PadIn", 37, 1 },
7714251213Snp	{ "RxBufEmpty", 36, 1 },
7715251213Snp	{ "RxDdp", 35, 1 },
7716251213Snp	{ "RxFbCongestion", 34, 1 },
7717251213Snp	{ "TxFbCongestion", 33, 1 },
7718251213Snp	{ "TxPktSumSrdy", 32, 1 },
7719251213Snp	{ "RcfUlpType", 28, 4 },
7720251213Snp	{ "Eread", 27, 1 },
7721251213Snp	{ "Ebypass", 26, 1 },
7722251213Snp	{ "Esave", 25, 1 },
7723251213Snp	{ "Static0", 24, 1 },
7724251213Snp	{ "Cread", 23, 1 },
7725251213Snp	{ "Cbypass", 22, 1 },
7726251213Snp	{ "Csave", 21, 1 },
7727251213Snp	{ "CPktOut", 20, 1 },
7728251213Snp	{ "RxPagePoolFull", 18, 2 },
7729251213Snp	{ "RxLpbkPkt", 17, 1 },
7730251213Snp	{ "TxLpbkPkt", 16, 1 },
7731251213Snp	{ "RxVfValid", 15, 1 },
7732251213Snp	{ "SynLearned", 14, 1 },
7733251213Snp	{ "SetDelEntry", 13, 1 },
7734251213Snp	{ "SetInvEntry", 12, 1 },
7735251213Snp	{ "CpcmdDvld", 11, 1 },
7736251213Snp	{ "CpcmdSave", 10, 1 },
7737251213Snp	{ "RxPstructsFull", 8, 2 },
7738251213Snp	{ "EpcmdDvld", 7, 1 },
7739251213Snp	{ "EpcmdFlush", 6, 1 },
7740251213Snp	{ "EpcmdTrimPrefix", 5, 1 },
7741251213Snp	{ "EpcmdTrimPostfix", 4, 1 },
7742251213Snp	{ "ERssIp4Pkt", 3, 1 },
7743251213Snp	{ "ERssIp6Pkt", 2, 1 },
7744251213Snp	{ "ERssTcpUdpPkt", 1, 1 },
7745251213Snp	{ "ERssFceFipPkt", 0, 1 },
7746251213Snp	{ NULL }
7747251213Snp};
7748251213Snp
7749251213Snpstatic void
7750251213Snptp_la_show(struct sbuf *sb, uint64_t *p, int idx)
7751251213Snp{
7752251213Snp
7753251213Snp	field_desc_show(sb, *p, tp_la0);
7754251213Snp}
7755251213Snp
7756251213Snpstatic void
7757251213Snptp_la_show2(struct sbuf *sb, uint64_t *p, int idx)
7758251213Snp{
7759251213Snp
7760251213Snp	if (idx)
7761251213Snp		sbuf_printf(sb, "\n");
7762251213Snp	field_desc_show(sb, p[0], tp_la0);
7763251213Snp	if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL)
7764251213Snp		field_desc_show(sb, p[1], tp_la0);
7765251213Snp}
7766251213Snp
7767251213Snpstatic void
7768251213Snptp_la_show3(struct sbuf *sb, uint64_t *p, int idx)
7769251213Snp{
7770251213Snp
7771251213Snp	if (idx)
7772251213Snp		sbuf_printf(sb, "\n");
7773251213Snp	field_desc_show(sb, p[0], tp_la0);
7774251213Snp	if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL)
7775251213Snp		field_desc_show(sb, p[1], (p[0] & (1 << 17)) ? tp_la2 : tp_la1);
7776251213Snp}
7777251213Snp
7778228561Snpstatic int
7779251213Snpsysctl_tp_la(SYSCTL_HANDLER_ARGS)
7780251213Snp{
7781251213Snp	struct adapter *sc = arg1;
7782251213Snp	struct sbuf *sb;
7783251213Snp	uint64_t *buf, *p;
7784251213Snp	int rc;
7785251213Snp	u_int i, inc;
7786251213Snp	void (*show_func)(struct sbuf *, uint64_t *, int);
7787251213Snp
7788251213Snp	rc = sysctl_wire_old_buffer(req, 0);
7789251213Snp	if (rc != 0)
7790251213Snp		return (rc);
7791251213Snp
7792251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
7793251213Snp	if (sb == NULL)
7794251213Snp		return (ENOMEM);
7795251213Snp
7796251213Snp	buf = malloc(TPLA_SIZE * sizeof(uint64_t), M_CXGBE, M_ZERO | M_WAITOK);
7797251213Snp
7798251213Snp	t4_tp_read_la(sc, buf, NULL);
7799251213Snp	p = buf;
7800251213Snp
7801251213Snp	switch (G_DBGLAMODE(t4_read_reg(sc, A_TP_DBG_LA_CONFIG))) {
7802251213Snp	case 2:
7803251213Snp		inc = 2;
7804251213Snp		show_func = tp_la_show2;
7805251213Snp		break;
7806251213Snp	case 3:
7807251213Snp		inc = 2;
7808251213Snp		show_func = tp_la_show3;
7809251213Snp		break;
7810251213Snp	default:
7811251213Snp		inc = 1;
7812251213Snp		show_func = tp_la_show;
7813251213Snp	}
7814251213Snp
7815251213Snp	for (i = 0; i < TPLA_SIZE / inc; i++, p += inc)
7816251213Snp		(*show_func)(sb, p, i);
7817251213Snp
7818251213Snp	rc = sbuf_finish(sb);
7819251213Snp	sbuf_delete(sb);
7820251213Snp	free(buf, M_CXGBE);
7821251213Snp	return (rc);
7822251213Snp}
7823251213Snp
7824251213Snpstatic int
7825228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS)
7826228561Snp{
7827228561Snp	struct adapter *sc = arg1;
7828228561Snp	struct sbuf *sb;
7829228561Snp	int rc;
7830308304Sjhb	u64 nrate[MAX_NCHAN], orate[MAX_NCHAN];
7831228561Snp
7832228561Snp	rc = sysctl_wire_old_buffer(req, 0);
7833228561Snp	if (rc != 0)
7834228561Snp		return (rc);
7835228561Snp
7836228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
7837228561Snp	if (sb == NULL)
7838228561Snp		return (ENOMEM);
7839228561Snp
7840228561Snp	t4_get_chan_txrate(sc, nrate, orate);
7841228561Snp
7842308304Sjhb	if (sc->chip_params->nchan > 2) {
7843308304Sjhb		sbuf_printf(sb, "              channel 0   channel 1"
7844308304Sjhb		    "   channel 2   channel 3\n");
7845308304Sjhb		sbuf_printf(sb, "NIC B/s:     %10ju  %10ju  %10ju  %10ju\n",
7846308304Sjhb		    nrate[0], nrate[1], nrate[2], nrate[3]);
7847308304Sjhb		sbuf_printf(sb, "Offload B/s: %10ju  %10ju  %10ju  %10ju",
7848308304Sjhb		    orate[0], orate[1], orate[2], orate[3]);
7849308304Sjhb	} else {
7850308304Sjhb		sbuf_printf(sb, "              channel 0   channel 1\n");
7851308304Sjhb		sbuf_printf(sb, "NIC B/s:     %10ju  %10ju\n",
7852308304Sjhb		    nrate[0], nrate[1]);
7853308304Sjhb		sbuf_printf(sb, "Offload B/s: %10ju  %10ju",
7854308304Sjhb		    orate[0], orate[1]);
7855308304Sjhb	}
7856308304Sjhb
7857228561Snp	rc = sbuf_finish(sb);
7858228561Snp	sbuf_delete(sb);
7859228561Snp
7860228561Snp	return (rc);
7861228561Snp}
7862248925Snp
7863248925Snpstatic int
7864251213Snpsysctl_ulprx_la(SYSCTL_HANDLER_ARGS)
7865251213Snp{
7866251213Snp	struct adapter *sc = arg1;
7867251213Snp	struct sbuf *sb;
7868251213Snp	uint32_t *buf, *p;
7869251213Snp	int rc, i;
7870251213Snp
7871251213Snp	rc = sysctl_wire_old_buffer(req, 0);
7872251213Snp	if (rc != 0)
7873251213Snp		return (rc);
7874251213Snp
7875251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
7876251213Snp	if (sb == NULL)
7877251213Snp		return (ENOMEM);
7878251213Snp
7879251213Snp	buf = malloc(ULPRX_LA_SIZE * 8 * sizeof(uint32_t), M_CXGBE,
7880251213Snp	    M_ZERO | M_WAITOK);
7881251213Snp
7882251213Snp	t4_ulprx_read_la(sc, buf);
7883251213Snp	p = buf;
7884251213Snp
7885251213Snp	sbuf_printf(sb, "      Pcmd        Type   Message"
7886251213Snp	    "                Data");
7887251213Snp	for (i = 0; i < ULPRX_LA_SIZE; i++, p += 8) {
7888251213Snp		sbuf_printf(sb, "\n%08x%08x  %4x  %08x  %08x%08x%08x%08x",
7889251213Snp		    p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]);
7890251213Snp	}
7891251213Snp
7892251213Snp	rc = sbuf_finish(sb);
7893251213Snp	sbuf_delete(sb);
7894251213Snp	free(buf, M_CXGBE);
7895251213Snp	return (rc);
7896251213Snp}
7897251213Snp
7898251213Snpstatic int
7899249392Snpsysctl_wcwr_stats(SYSCTL_HANDLER_ARGS)
7900248925Snp{
7901248925Snp	struct adapter *sc = arg1;
7902248925Snp	struct sbuf *sb;
7903248925Snp	int rc, v;
7904248925Snp
7905309560Sjhb	MPASS(chip_id(sc) >= CHELSIO_T5);
7906309560Sjhb
7907248925Snp	rc = sysctl_wire_old_buffer(req, 0);
7908248925Snp	if (rc != 0)
7909248925Snp		return (rc);
7910248925Snp
7911248925Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
7912248925Snp	if (sb == NULL)
7913248925Snp		return (ENOMEM);
7914248925Snp
7915248925Snp	v = t4_read_reg(sc, A_SGE_STAT_CFG);
7916248925Snp	if (G_STATSOURCE_T5(v) == 7) {
7917309560Sjhb		int mode;
7918309560Sjhb
7919309560Sjhb		mode = is_t5(sc) ? G_STATMODE(v) : G_T6_STATMODE(v);
7920309560Sjhb		if (mode == 0) {
7921249383Snp			sbuf_printf(sb, "total %d, incomplete %d",
7922248925Snp			    t4_read_reg(sc, A_SGE_STAT_TOTAL),
7923248925Snp			    t4_read_reg(sc, A_SGE_STAT_MATCH));
7924309560Sjhb		} else if (mode == 1) {
7925249383Snp			sbuf_printf(sb, "total %d, data overflow %d",
7926248925Snp			    t4_read_reg(sc, A_SGE_STAT_TOTAL),
7927248925Snp			    t4_read_reg(sc, A_SGE_STAT_MATCH));
7928309560Sjhb		} else {
7929309560Sjhb			sbuf_printf(sb, "unknown mode %d", mode);
7930248925Snp		}
7931248925Snp	}
7932248925Snp	rc = sbuf_finish(sb);
7933248925Snp	sbuf_delete(sb);
7934248925Snp
7935248925Snp	return (rc);
7936248925Snp}
7937308321Sjhb
7938308321Sjhbstatic int
7939308321Sjhbsysctl_tc_params(SYSCTL_HANDLER_ARGS)
7940308321Sjhb{
7941308321Sjhb	struct adapter *sc = arg1;
7942318851Snp	struct tx_cl_rl_params tc;
7943308321Sjhb	struct sbuf *sb;
7944318851Snp	int i, rc, port_id, mbps, gbps;
7945308321Sjhb
7946308321Sjhb	rc = sysctl_wire_old_buffer(req, 0);
7947308321Sjhb	if (rc != 0)
7948308321Sjhb		return (rc);
7949308321Sjhb
7950308321Sjhb	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
7951308321Sjhb	if (sb == NULL)
7952308321Sjhb		return (ENOMEM);
7953308321Sjhb
7954308321Sjhb	port_id = arg2 >> 16;
7955308321Sjhb	MPASS(port_id < sc->params.nports);
7956308321Sjhb	MPASS(sc->port[port_id] != NULL);
7957308321Sjhb	i = arg2 & 0xffff;
7958308321Sjhb	MPASS(i < sc->chip_params->nsched_cls);
7959308321Sjhb
7960318851Snp	mtx_lock(&sc->tc_lock);
7961318851Snp	tc = sc->port[port_id]->sched_params->cl_rl[i];
7962318851Snp	mtx_unlock(&sc->tc_lock);
7963308321Sjhb
7964318851Snp	if (tc.flags & TX_CLRL_ERROR) {
7965318851Snp		sbuf_printf(sb, "error");
7966308321Sjhb		goto done;
7967308321Sjhb	}
7968308321Sjhb
7969318851Snp	if (tc.ratemode == SCHED_CLASS_RATEMODE_REL) {
7970308321Sjhb		/* XXX: top speed or actual link speed? */
7971308321Sjhb		gbps = port_top_speed(sc->port[port_id]);
7972318851Snp		sbuf_printf(sb, " %u%% of %uGbps", tc.maxrate, gbps);
7973318851Snp	} else if (tc.ratemode == SCHED_CLASS_RATEMODE_ABS) {
7974318851Snp		switch (tc.rateunit) {
7975308321Sjhb		case SCHED_CLASS_RATEUNIT_BITS:
7976318851Snp			mbps = tc.maxrate / 1000;
7977318851Snp			gbps = tc.maxrate / 1000000;
7978318851Snp			if (tc.maxrate == gbps * 1000000)
7979308321Sjhb				sbuf_printf(sb, " %uGbps", gbps);
7980318851Snp			else if (tc.maxrate == mbps * 1000)
7981308321Sjhb				sbuf_printf(sb, " %uMbps", mbps);
7982308321Sjhb			else
7983318851Snp				sbuf_printf(sb, " %uKbps", tc.maxrate);
7984308321Sjhb			break;
7985308321Sjhb		case SCHED_CLASS_RATEUNIT_PKTS:
7986318851Snp			sbuf_printf(sb, " %upps", tc.maxrate);
7987308321Sjhb			break;
7988308321Sjhb		default:
7989308321Sjhb			rc = ENXIO;
7990308321Sjhb			goto done;
7991308321Sjhb		}
7992308321Sjhb	}
7993308321Sjhb
7994318851Snp	switch (tc.mode) {
7995308321Sjhb	case SCHED_CLASS_MODE_CLASS:
7996308321Sjhb		sbuf_printf(sb, " aggregate");
7997308321Sjhb		break;
7998308321Sjhb	case SCHED_CLASS_MODE_FLOW:
7999308321Sjhb		sbuf_printf(sb, " per-flow");
8000308321Sjhb		break;
8001308321Sjhb	default:
8002308321Sjhb		rc = ENXIO;
8003308321Sjhb		goto done;
8004308321Sjhb	}
8005308321Sjhb
8006308321Sjhbdone:
8007308321Sjhb	if (rc == 0)
8008308321Sjhb		rc = sbuf_finish(sb);
8009308321Sjhb	sbuf_delete(sb);
8010308321Sjhb
8011308321Sjhb	return (rc);
8012308321Sjhb}
8013231115Snp#endif
8014228561Snp
8015308311Sjhb#ifdef TCP_OFFLOAD
8016308311Sjhbstatic void
8017308311Sjhbunit_conv(char *buf, size_t len, u_int val, u_int factor)
8018308311Sjhb{
8019308311Sjhb	u_int rem = val % factor;
8020308311Sjhb
8021308311Sjhb	if (rem == 0)
8022308311Sjhb		snprintf(buf, len, "%u", val / factor);
8023308311Sjhb	else {
8024308311Sjhb		while (rem % 10 == 0)
8025308311Sjhb			rem /= 10;
8026308311Sjhb		snprintf(buf, len, "%u.%u", val / factor, rem);
8027308311Sjhb	}
8028308311Sjhb}
8029308311Sjhb
8030308311Sjhbstatic int
8031308311Sjhbsysctl_tp_tick(SYSCTL_HANDLER_ARGS)
8032308311Sjhb{
8033308311Sjhb	struct adapter *sc = arg1;
8034308311Sjhb	char buf[16];
8035308311Sjhb	u_int res, re;
8036308311Sjhb	u_int cclk_ps = 1000000000 / sc->params.vpd.cclk;
8037308311Sjhb
8038308311Sjhb	res = t4_read_reg(sc, A_TP_TIMER_RESOLUTION);
8039308311Sjhb	switch (arg2) {
8040308311Sjhb	case 0:
8041308311Sjhb		/* timer_tick */
8042308311Sjhb		re = G_TIMERRESOLUTION(res);
8043308311Sjhb		break;
8044308311Sjhb	case 1:
8045308311Sjhb		/* TCP timestamp tick */
8046308311Sjhb		re = G_TIMESTAMPRESOLUTION(res);
8047308311Sjhb		break;
8048308311Sjhb	case 2:
8049308311Sjhb		/* DACK tick */
8050308311Sjhb		re = G_DELAYEDACKRESOLUTION(res);
8051308311Sjhb		break;
8052308311Sjhb	default:
8053308311Sjhb		return (EDOOFUS);
8054308311Sjhb	}
8055308311Sjhb
8056308311Sjhb	unit_conv(buf, sizeof(buf), (cclk_ps << re), 1000000);
8057308311Sjhb
8058308311Sjhb	return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
8059308311Sjhb}
8060308311Sjhb
8061308311Sjhbstatic int
8062308311Sjhbsysctl_tp_dack_timer(SYSCTL_HANDLER_ARGS)
8063308311Sjhb{
8064308311Sjhb	struct adapter *sc = arg1;
8065308311Sjhb	u_int res, dack_re, v;
8066308311Sjhb	u_int cclk_ps = 1000000000 / sc->params.vpd.cclk;
8067308311Sjhb
8068308311Sjhb	res = t4_read_reg(sc, A_TP_TIMER_RESOLUTION);
8069308311Sjhb	dack_re = G_DELAYEDACKRESOLUTION(res);
8070308311Sjhb	v = ((cclk_ps << dack_re) / 1000000) * t4_read_reg(sc, A_TP_DACK_TIMER);
8071308311Sjhb
8072308311Sjhb	return (sysctl_handle_int(oidp, &v, 0, req));
8073308311Sjhb}
8074308311Sjhb
8075308311Sjhbstatic int
8076308311Sjhbsysctl_tp_timer(SYSCTL_HANDLER_ARGS)
8077308311Sjhb{
8078308311Sjhb	struct adapter *sc = arg1;
8079308311Sjhb	int reg = arg2;
8080308311Sjhb	u_int tre;
8081308311Sjhb	u_long tp_tick_us, v;
8082308311Sjhb	u_int cclk_ps = 1000000000 / sc->params.vpd.cclk;
8083308311Sjhb
8084308311Sjhb	MPASS(reg == A_TP_RXT_MIN || reg == A_TP_RXT_MAX ||
8085316123Snp	    reg == A_TP_PERS_MIN  || reg == A_TP_PERS_MAX ||
8086316123Snp	    reg == A_TP_KEEP_IDLE || reg == A_TP_KEEP_INTVL ||
8087316123Snp	    reg == A_TP_INIT_SRTT || reg == A_TP_FINWAIT2_TIMER);
8088308311Sjhb
8089308311Sjhb	tre = G_TIMERRESOLUTION(t4_read_reg(sc, A_TP_TIMER_RESOLUTION));
8090308311Sjhb	tp_tick_us = (cclk_ps << tre) / 1000000;
8091308311Sjhb
8092308311Sjhb	if (reg == A_TP_INIT_SRTT)
8093308311Sjhb		v = tp_tick_us * G_INITSRTT(t4_read_reg(sc, reg));
8094308311Sjhb	else
8095308311Sjhb		v = tp_tick_us * t4_read_reg(sc, reg);
8096308311Sjhb
8097308311Sjhb	return (sysctl_handle_long(oidp, &v, 0, req));
8098308311Sjhb}
8099308311Sjhb#endif
8100308311Sjhb
8101221474Snpstatic uint32_t
8102308304Sjhbfconf_iconf_to_mode(uint32_t fconf, uint32_t iconf)
8103221474Snp{
8104221474Snp	uint32_t mode;
8105221474Snp
8106221474Snp	mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR |
8107221474Snp	    T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT;
8108221474Snp
8109221474Snp	if (fconf & F_FRAGMENTATION)
8110221474Snp		mode |= T4_FILTER_IP_FRAGMENT;
8111221474Snp
8112221474Snp	if (fconf & F_MPSHITTYPE)
8113221474Snp		mode |= T4_FILTER_MPS_HIT_TYPE;
8114221474Snp
8115221474Snp	if (fconf & F_MACMATCH)
8116221474Snp		mode |= T4_FILTER_MAC_IDX;
8117221474Snp
8118221474Snp	if (fconf & F_ETHERTYPE)
8119221474Snp		mode |= T4_FILTER_ETH_TYPE;
8120221474Snp
8121221474Snp	if (fconf & F_PROTOCOL)
8122221474Snp		mode |= T4_FILTER_IP_PROTO;
8123221474Snp
8124221474Snp	if (fconf & F_TOS)
8125221474Snp		mode |= T4_FILTER_IP_TOS;
8126221474Snp
8127221474Snp	if (fconf & F_VLAN)
8128228561Snp		mode |= T4_FILTER_VLAN;
8129221474Snp
8130308304Sjhb	if (fconf & F_VNIC_ID) {
8131228561Snp		mode |= T4_FILTER_VNIC;
8132308304Sjhb		if (iconf & F_VNIC)
8133308304Sjhb			mode |= T4_FILTER_IC_VNIC;
8134308304Sjhb	}
8135221474Snp
8136221474Snp	if (fconf & F_PORT)
8137221474Snp		mode |= T4_FILTER_PORT;
8138221474Snp
8139221474Snp	if (fconf & F_FCOE)
8140221474Snp		mode |= T4_FILTER_FCoE;
8141221474Snp
8142221474Snp	return (mode);
8143221474Snp}
8144221474Snp
8145221474Snpstatic uint32_t
8146221474Snpmode_to_fconf(uint32_t mode)
8147221474Snp{
8148221474Snp	uint32_t fconf = 0;
8149221474Snp
8150221474Snp	if (mode & T4_FILTER_IP_FRAGMENT)
8151221474Snp		fconf |= F_FRAGMENTATION;
8152221474Snp
8153221474Snp	if (mode & T4_FILTER_MPS_HIT_TYPE)
8154221474Snp		fconf |= F_MPSHITTYPE;
8155221474Snp
8156221474Snp	if (mode & T4_FILTER_MAC_IDX)
8157221474Snp		fconf |= F_MACMATCH;
8158221474Snp
8159221474Snp	if (mode & T4_FILTER_ETH_TYPE)
8160221474Snp		fconf |= F_ETHERTYPE;
8161221474Snp
8162221474Snp	if (mode & T4_FILTER_IP_PROTO)
8163221474Snp		fconf |= F_PROTOCOL;
8164221474Snp
8165221474Snp	if (mode & T4_FILTER_IP_TOS)
8166221474Snp		fconf |= F_TOS;
8167221474Snp
8168228561Snp	if (mode & T4_FILTER_VLAN)
8169221474Snp		fconf |= F_VLAN;
8170221474Snp
8171228561Snp	if (mode & T4_FILTER_VNIC)
8172221474Snp		fconf |= F_VNIC_ID;
8173221474Snp
8174221474Snp	if (mode & T4_FILTER_PORT)
8175221474Snp		fconf |= F_PORT;
8176221474Snp
8177221474Snp	if (mode & T4_FILTER_FCoE)
8178221474Snp		fconf |= F_FCOE;
8179221474Snp
8180221474Snp	return (fconf);
8181221474Snp}
8182221474Snp
8183221474Snpstatic uint32_t
8184308304Sjhbmode_to_iconf(uint32_t mode)
8185221474Snp{
8186308304Sjhb
8187308304Sjhb	if (mode & T4_FILTER_IC_VNIC)
8188308304Sjhb		return (F_VNIC);
8189308304Sjhb	return (0);
8190308304Sjhb}
8191308304Sjhb
8192308304Sjhbstatic int check_fspec_against_fconf_iconf(struct adapter *sc,
8193308304Sjhb    struct t4_filter_specification *fs)
8194308304Sjhb{
8195308304Sjhb	struct tp_params *tpp = &sc->params.tp;
8196221474Snp	uint32_t fconf = 0;
8197221474Snp
8198221474Snp	if (fs->val.frag || fs->mask.frag)
8199221474Snp		fconf |= F_FRAGMENTATION;
8200221474Snp
8201221474Snp	if (fs->val.matchtype || fs->mask.matchtype)
8202221474Snp		fconf |= F_MPSHITTYPE;
8203221474Snp
8204221474Snp	if (fs->val.macidx || fs->mask.macidx)
8205221474Snp		fconf |= F_MACMATCH;
8206221474Snp
8207221474Snp	if (fs->val.ethtype || fs->mask.ethtype)
8208221474Snp		fconf |= F_ETHERTYPE;
8209221474Snp
8210221474Snp	if (fs->val.proto || fs->mask.proto)
8211221474Snp		fconf |= F_PROTOCOL;
8212221474Snp
8213221474Snp	if (fs->val.tos || fs->mask.tos)
8214221474Snp		fconf |= F_TOS;
8215221474Snp
8216228561Snp	if (fs->val.vlan_vld || fs->mask.vlan_vld)
8217221474Snp		fconf |= F_VLAN;
8218221474Snp
8219308304Sjhb	if (fs->val.ovlan_vld || fs->mask.ovlan_vld) {
8220221474Snp		fconf |= F_VNIC_ID;
8221308304Sjhb		if (tpp->ingress_config & F_VNIC)
8222308304Sjhb			return (EINVAL);
8223308304Sjhb	}
8224221474Snp
8225308304Sjhb	if (fs->val.pfvf_vld || fs->mask.pfvf_vld) {
8226308304Sjhb		fconf |= F_VNIC_ID;
8227308304Sjhb		if ((tpp->ingress_config & F_VNIC) == 0)
8228308304Sjhb			return (EINVAL);
8229308304Sjhb	}
8230308304Sjhb
8231221474Snp	if (fs->val.iport || fs->mask.iport)
8232221474Snp		fconf |= F_PORT;
8233221474Snp
8234221474Snp	if (fs->val.fcoe || fs->mask.fcoe)
8235221474Snp		fconf |= F_FCOE;
8236221474Snp
8237308304Sjhb	if ((tpp->vlan_pri_map | fconf) != tpp->vlan_pri_map)
8238308304Sjhb		return (E2BIG);
8239308304Sjhb
8240308304Sjhb	return (0);
8241221474Snp}
8242221474Snp
8243221474Snpstatic int
8244221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode)
8245221474Snp{
8246308304Sjhb	struct tp_params *tpp = &sc->params.tp;
8247221474Snp
8248308304Sjhb	/*
8249308304Sjhb	 * We trust the cached values of the relevant TP registers.  This means
8250308304Sjhb	 * things work reliably only if writes to those registers are always via
8251308304Sjhb	 * t4_set_filter_mode.
8252308304Sjhb	 */
8253308304Sjhb	*mode = fconf_iconf_to_mode(tpp->vlan_pri_map, tpp->ingress_config);
8254245274Snp
8255221474Snp	return (0);
8256221474Snp}
8257221474Snp
8258221474Snpstatic int
8259221474Snpset_filter_mode(struct adapter *sc, uint32_t mode)
8260221474Snp{
8261308304Sjhb	struct tp_params *tpp = &sc->params.tp;
8262308304Sjhb	uint32_t fconf, iconf;
8263221474Snp	int rc;
8264221474Snp
8265308304Sjhb	iconf = mode_to_iconf(mode);
8266308304Sjhb	if ((iconf ^ tpp->ingress_config) & F_VNIC) {
8267308304Sjhb		/*
8268308304Sjhb		 * For now we just complain if A_TP_INGRESS_CONFIG is not
8269308304Sjhb		 * already set to the correct value for the requested filter
8270308304Sjhb		 * mode.  It's not clear if it's safe to write to this register
8271308304Sjhb		 * on the fly.  (And we trust the cached value of the register).
8272308304Sjhb		 */
8273308304Sjhb		return (EBUSY);
8274308304Sjhb	}
8275308304Sjhb
8276221474Snp	fconf = mode_to_fconf(mode);
8277221474Snp
8278245274Snp	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
8279245274Snp	    "t4setfm");
8280245274Snp	if (rc)
8281245274Snp		return (rc);
8282221474Snp
8283221474Snp	if (sc->tids.ftids_in_use > 0) {
8284221474Snp		rc = EBUSY;
8285221474Snp		goto done;
8286221474Snp	}
8287221474Snp
8288237263Snp#ifdef TCP_OFFLOAD
8289284089Snp	if (uld_active(sc, ULD_TOM)) {
8290228561Snp		rc = EBUSY;
8291228561Snp		goto done;
8292228561Snp	}
8293228561Snp#endif
8294228561Snp
8295353418Snp	rc = -t4_set_filter_mode(sc, fconf, true);
8296221474Snpdone:
8297245274Snp	end_synchronized_op(sc, LOCK_HELD);
8298221474Snp	return (rc);
8299221474Snp}
8300221474Snp
8301222552Snpstatic inline uint64_t
8302222552Snpget_filter_hits(struct adapter *sc, uint32_t fid)
8303222552Snp{
8304308305Sjhb	uint32_t tcb_addr;
8305222552Snp
8306308305Sjhb	tcb_addr = t4_read_reg(sc, A_TP_CMM_TCB_BASE) +
8307308305Sjhb	    (fid + sc->tids.ftid_base) * TCB_SIZE;
8308308304Sjhb
8309251358Snp	if (is_t4(sc)) {
8310308305Sjhb		uint64_t hits;
8311308305Sjhb
8312308305Sjhb		read_via_memwin(sc, 0, tcb_addr + 16, (uint32_t *)&hits, 8);
8313308305Sjhb		return (be64toh(hits));
8314251358Snp	} else {
8315308305Sjhb		uint32_t hits;
8316308305Sjhb
8317308305Sjhb		read_via_memwin(sc, 0, tcb_addr + 24, &hits, 4);
8318308305Sjhb		return (be32toh(hits));
8319251358Snp	}
8320222552Snp}
8321222552Snp
8322221474Snpstatic int
8323221474Snpget_filter(struct adapter *sc, struct t4_filter *t)
8324221474Snp{
8325245274Snp	int i, rc, nfilters = sc->tids.nftids;
8326221474Snp	struct filter_entry *f;
8327221474Snp
8328245274Snp	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
8329245274Snp	    "t4getf");
8330245274Snp	if (rc)
8331245274Snp		return (rc);
8332221474Snp
8333221474Snp	if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL ||
8334221474Snp	    t->idx >= nfilters) {
8335221474Snp		t->idx = 0xffffffff;
8336245274Snp		goto done;
8337221474Snp	}
8338221474Snp
8339221474Snp	f = &sc->tids.ftid_tab[t->idx];
8340221474Snp	for (i = t->idx; i < nfilters; i++, f++) {
8341221474Snp		if (f->valid) {
8342221474Snp			t->idx = i;
8343222509Snp			t->l2tidx = f->l2t ? f->l2t->idx : 0;
8344222509Snp			t->smtidx = f->smtidx;
8345222552Snp			if (f->fs.hitcnts)
8346222552Snp				t->hits = get_filter_hits(sc, t->idx);
8347222552Snp			else
8348222552Snp				t->hits = UINT64_MAX;
8349221474Snp			t->fs = f->fs;
8350221474Snp
8351245274Snp			goto done;
8352221474Snp		}
8353221474Snp	}
8354221474Snp
8355221474Snp	t->idx = 0xffffffff;
8356245274Snpdone:
8357245274Snp	end_synchronized_op(sc, LOCK_HELD);
8358221474Snp	return (0);
8359221474Snp}
8360221474Snp
8361221474Snpstatic int
8362221474Snpset_filter(struct adapter *sc, struct t4_filter *t)
8363221474Snp{
8364221474Snp	unsigned int nfilters, nports;
8365221474Snp	struct filter_entry *f;
8366245274Snp	int i, rc;
8367221474Snp
8368245274Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf");
8369245274Snp	if (rc)
8370245274Snp		return (rc);
8371221474Snp
8372221474Snp	nfilters = sc->tids.nftids;
8373221474Snp	nports = sc->params.nports;
8374221474Snp
8375245274Snp	if (nfilters == 0) {
8376245274Snp		rc = ENOTSUP;
8377245274Snp		goto done;
8378245274Snp	}
8379221474Snp
8380245274Snp	if (t->idx >= nfilters) {
8381245274Snp		rc = EINVAL;
8382245274Snp		goto done;
8383245274Snp	}
8384221474Snp
8385308304Sjhb	/* Validate against the global filter mode and ingress config */
8386308304Sjhb	rc = check_fspec_against_fconf_iconf(sc, &t->fs);
8387308304Sjhb	if (rc != 0)
8388245274Snp		goto done;
8389221474Snp
8390245274Snp	if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) {
8391245274Snp		rc = EINVAL;
8392245274Snp		goto done;
8393245274Snp	}
8394221474Snp
8395245274Snp	if (t->fs.val.iport >= nports) {
8396245274Snp		rc = EINVAL;
8397245274Snp		goto done;
8398245274Snp	}
8399221474Snp
8400221474Snp	/* Can't specify an iq if not steering to it */
8401245274Snp	if (!t->fs.dirsteer && t->fs.iq) {
8402245274Snp		rc = EINVAL;
8403245274Snp		goto done;
8404245274Snp	}
8405221474Snp
8406221474Snp	/* IPv6 filter idx must be 4 aligned */
8407221474Snp	if (t->fs.type == 1 &&
8408245274Snp	    ((t->idx & 0x3) || t->idx + 4 >= nfilters)) {
8409245274Snp		rc = EINVAL;
8410245274Snp		goto done;
8411245274Snp	}
8412221474Snp
8413309459Sjhb	if (!(sc->flags & FULL_INIT_DONE) &&
8414309459Sjhb	    ((rc = adapter_full_init(sc)) != 0))
8415309459Sjhb		goto done;
8416309459Sjhb
8417221474Snp	if (sc->tids.ftid_tab == NULL) {
8418221474Snp		KASSERT(sc->tids.ftids_in_use == 0,
8419221474Snp		    ("%s: no memory allocated but filters_in_use > 0",
8420221474Snp		    __func__));
8421221474Snp
8422221474Snp		sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) *
8423221474Snp		    nfilters, M_CXGBE, M_NOWAIT | M_ZERO);
8424245274Snp		if (sc->tids.ftid_tab == NULL) {
8425245274Snp			rc = ENOMEM;
8426245274Snp			goto done;
8427245274Snp		}
8428245274Snp		mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF);
8429221474Snp	}
8430221474Snp
8431221474Snp	for (i = 0; i < 4; i++) {
8432221474Snp		f = &sc->tids.ftid_tab[t->idx + i];
8433221474Snp
8434245274Snp		if (f->pending || f->valid) {
8435245274Snp			rc = EBUSY;
8436245274Snp			goto done;
8437245274Snp		}
8438245274Snp		if (f->locked) {
8439245274Snp			rc = EPERM;
8440245274Snp			goto done;
8441245274Snp		}
8442221474Snp
8443221474Snp		if (t->fs.type == 0)
8444221474Snp			break;
8445221474Snp	}
8446221474Snp
8447221474Snp	f = &sc->tids.ftid_tab[t->idx];
8448221474Snp	f->fs = t->fs;
8449221474Snp
8450245274Snp	rc = set_filter_wr(sc, t->idx);
8451245274Snpdone:
8452245274Snp	end_synchronized_op(sc, 0);
8453245274Snp
8454245274Snp	if (rc == 0) {
8455245274Snp		mtx_lock(&sc->tids.ftid_lock);
8456245274Snp		for (;;) {
8457245274Snp			if (f->pending == 0) {
8458245274Snp				rc = f->valid ? 0 : EIO;
8459245274Snp				break;
8460245274Snp			}
8461245274Snp
8462245274Snp			if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock,
8463245274Snp			    PCATCH, "t4setfw", 0)) {
8464245274Snp				rc = EINPROGRESS;
8465245274Snp				break;
8466245274Snp			}
8467245274Snp		}
8468245274Snp		mtx_unlock(&sc->tids.ftid_lock);
8469245274Snp	}
8470245274Snp	return (rc);
8471221474Snp}
8472221474Snp
8473221474Snpstatic int
8474221474Snpdel_filter(struct adapter *sc, struct t4_filter *t)
8475221474Snp{
8476221474Snp	unsigned int nfilters;
8477221474Snp	struct filter_entry *f;
8478245274Snp	int rc;
8479221474Snp
8480245274Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf");
8481245274Snp	if (rc)
8482245274Snp		return (rc);
8483221474Snp
8484221474Snp	nfilters = sc->tids.nftids;
8485221474Snp
8486245274Snp	if (nfilters == 0) {
8487245274Snp		rc = ENOTSUP;
8488245274Snp		goto done;
8489245274Snp	}
8490221474Snp
8491221474Snp	if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 ||
8492245274Snp	    t->idx >= nfilters) {
8493245274Snp		rc = EINVAL;
8494245274Snp		goto done;
8495245274Snp	}
8496221474Snp
8497245274Snp	if (!(sc->flags & FULL_INIT_DONE)) {
8498245274Snp		rc = EAGAIN;
8499245274Snp		goto done;
8500245274Snp	}
8501221474Snp
8502221474Snp	f = &sc->tids.ftid_tab[t->idx];
8503221474Snp
8504245274Snp	if (f->pending) {
8505245274Snp		rc = EBUSY;
8506245274Snp		goto done;
8507245274Snp	}
8508245274Snp	if (f->locked) {
8509245274Snp		rc = EPERM;
8510245274Snp		goto done;
8511245274Snp	}
8512221474Snp
8513221474Snp	if (f->valid) {
8514221474Snp		t->fs = f->fs;	/* extra info for the caller */
8515245274Snp		rc = del_filter_wr(sc, t->idx);
8516221474Snp	}
8517221474Snp
8518245274Snpdone:
8519245274Snp	end_synchronized_op(sc, 0);
8520245274Snp
8521245274Snp	if (rc == 0) {
8522245274Snp		mtx_lock(&sc->tids.ftid_lock);
8523245274Snp		for (;;) {
8524245274Snp			if (f->pending == 0) {
8525245274Snp				rc = f->valid ? EIO : 0;
8526245274Snp				break;
8527245274Snp			}
8528245274Snp
8529245274Snp			if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock,
8530245274Snp			    PCATCH, "t4delfw", 0)) {
8531245274Snp				rc = EINPROGRESS;
8532245274Snp				break;
8533245274Snp			}
8534245274Snp		}
8535245274Snp		mtx_unlock(&sc->tids.ftid_lock);
8536245274Snp	}
8537245274Snp
8538245274Snp	return (rc);
8539221474Snp}
8540221474Snp
8541221474Snpstatic void
8542222509Snpclear_filter(struct filter_entry *f)
8543221474Snp{
8544222509Snp	if (f->l2t)
8545222509Snp		t4_l2t_release(f->l2t);
8546222509Snp
8547221474Snp	bzero(f, sizeof (*f));
8548221474Snp}
8549221474Snp
8550221474Snpstatic int
8551221474Snpset_filter_wr(struct adapter *sc, int fidx)
8552221474Snp{
8553221474Snp	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
8554221474Snp	struct fw_filter_wr *fwr;
8555308304Sjhb	unsigned int ftid, vnic_vld, vnic_vld_mask;
8556284052Snp	struct wrq_cookie cookie;
8557221474Snp
8558245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
8559221474Snp
8560222509Snp	if (f->fs.newdmac || f->fs.newvlan) {
8561222509Snp		/* This filter needs an L2T entry; allocate one. */
8562222509Snp		f->l2t = t4_l2t_alloc_switching(sc->l2t);
8563222509Snp		if (f->l2t == NULL)
8564222509Snp			return (EAGAIN);
8565222509Snp		if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport,
8566222509Snp		    f->fs.dmac)) {
8567222509Snp			t4_l2t_release(f->l2t);
8568222509Snp			f->l2t = NULL;
8569222509Snp			return (ENOMEM);
8570222509Snp		}
8571222509Snp	}
8572221474Snp
8573308304Sjhb	/* Already validated against fconf, iconf */
8574308304Sjhb	MPASS((f->fs.val.pfvf_vld & f->fs.val.ovlan_vld) == 0);
8575308304Sjhb	MPASS((f->fs.mask.pfvf_vld & f->fs.mask.ovlan_vld) == 0);
8576308304Sjhb	if (f->fs.val.pfvf_vld || f->fs.val.ovlan_vld)
8577308304Sjhb		vnic_vld = 1;
8578308304Sjhb	else
8579308304Sjhb		vnic_vld = 0;
8580308304Sjhb	if (f->fs.mask.pfvf_vld || f->fs.mask.ovlan_vld)
8581308304Sjhb		vnic_vld_mask = 1;
8582308304Sjhb	else
8583308304Sjhb		vnic_vld_mask = 0;
8584308304Sjhb
8585221474Snp	ftid = sc->tids.ftid_base + fidx;
8586221474Snp
8587284052Snp	fwr = start_wrq_wr(&sc->sge.mgmtq, howmany(sizeof(*fwr), 16), &cookie);
8588284052Snp	if (fwr == NULL)
8589221474Snp		return (ENOMEM);
8590284052Snp	bzero(fwr, sizeof(*fwr));
8591221474Snp
8592221474Snp	fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR));
8593221474Snp	fwr->len16_pkd = htobe32(FW_LEN16(*fwr));
8594221474Snp	fwr->tid_to_iq =
8595221474Snp	    htobe32(V_FW_FILTER_WR_TID(ftid) |
8596221474Snp		V_FW_FILTER_WR_RQTYPE(f->fs.type) |
8597221474Snp		V_FW_FILTER_WR_NOREPLY(0) |
8598221474Snp		V_FW_FILTER_WR_IQ(f->fs.iq));
8599221474Snp	fwr->del_filter_to_l2tix =
8600221474Snp	    htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) |
8601221474Snp		V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) |
8602221474Snp		V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) |
8603221474Snp		V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) |
8604221474Snp		V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) |
8605221474Snp		V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) |
8606221474Snp		V_FW_FILTER_WR_DMAC(f->fs.newdmac) |
8607221474Snp		V_FW_FILTER_WR_SMAC(f->fs.newsmac) |
8608221474Snp		V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT ||
8609221474Snp		    f->fs.newvlan == VLAN_REWRITE) |
8610221474Snp		V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE ||
8611221474Snp		    f->fs.newvlan == VLAN_REWRITE) |
8612221474Snp		V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) |
8613221474Snp		V_FW_FILTER_WR_TXCHAN(f->fs.eport) |
8614221474Snp		V_FW_FILTER_WR_PRIO(f->fs.prio) |
8615222509Snp		V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0));
8616221474Snp	fwr->ethtype = htobe16(f->fs.val.ethtype);
8617221474Snp	fwr->ethtypem = htobe16(f->fs.mask.ethtype);
8618221474Snp	fwr->frag_to_ovlan_vldm =
8619221474Snp	    (V_FW_FILTER_WR_FRAG(f->fs.val.frag) |
8620221474Snp		V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) |
8621228561Snp		V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) |
8622308304Sjhb		V_FW_FILTER_WR_OVLAN_VLD(vnic_vld) |
8623228561Snp		V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) |
8624308304Sjhb		V_FW_FILTER_WR_OVLAN_VLDM(vnic_vld_mask));
8625221474Snp	fwr->smac_sel = 0;
8626221474Snp	fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) |
8627228561Snp	    V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id));
8628221474Snp	fwr->maci_to_matchtypem =
8629221474Snp	    htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) |
8630221474Snp		V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) |
8631221474Snp		V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) |
8632221474Snp		V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) |
8633221474Snp		V_FW_FILTER_WR_PORT(f->fs.val.iport) |
8634221474Snp		V_FW_FILTER_WR_PORTM(f->fs.mask.iport) |
8635221474Snp		V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) |
8636221474Snp		V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype));
8637221474Snp	fwr->ptcl = f->fs.val.proto;
8638221474Snp	fwr->ptclm = f->fs.mask.proto;
8639221474Snp	fwr->ttyp = f->fs.val.tos;
8640221474Snp	fwr->ttypm = f->fs.mask.tos;
8641228561Snp	fwr->ivlan = htobe16(f->fs.val.vlan);
8642228561Snp	fwr->ivlanm = htobe16(f->fs.mask.vlan);
8643228561Snp	fwr->ovlan = htobe16(f->fs.val.vnic);
8644228561Snp	fwr->ovlanm = htobe16(f->fs.mask.vnic);
8645221474Snp	bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip));
8646221474Snp	bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm));
8647221474Snp	bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip));
8648221474Snp	bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm));
8649221474Snp	fwr->lp = htobe16(f->fs.val.dport);
8650221474Snp	fwr->lpm = htobe16(f->fs.mask.dport);
8651221474Snp	fwr->fp = htobe16(f->fs.val.sport);
8652221474Snp	fwr->fpm = htobe16(f->fs.mask.sport);
8653221474Snp	if (f->fs.newsmac)
8654221474Snp		bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma));
8655221474Snp
8656221474Snp	f->pending = 1;
8657221474Snp	sc->tids.ftids_in_use++;
8658228561Snp
8659284052Snp	commit_wrq_wr(&sc->sge.mgmtq, fwr, &cookie);
8660228561Snp	return (0);
8661221474Snp}
8662221474Snp
8663221474Snpstatic int
8664221474Snpdel_filter_wr(struct adapter *sc, int fidx)
8665221474Snp{
8666221474Snp	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
8667221474Snp	struct fw_filter_wr *fwr;
8668228561Snp	unsigned int ftid;
8669284052Snp	struct wrq_cookie cookie;
8670221474Snp
8671221474Snp	ftid = sc->tids.ftid_base + fidx;
8672221474Snp
8673284052Snp	fwr = start_wrq_wr(&sc->sge.mgmtq, howmany(sizeof(*fwr), 16), &cookie);
8674284052Snp	if (fwr == NULL)
8675221474Snp		return (ENOMEM);
8676221474Snp	bzero(fwr, sizeof (*fwr));
8677221474Snp
8678228561Snp	t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id);
8679221474Snp
8680221474Snp	f->pending = 1;
8681284052Snp	commit_wrq_wr(&sc->sge.mgmtq, fwr, &cookie);
8682228561Snp	return (0);
8683221474Snp}
8684221474Snp
8685239338Snpint
8686239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
8687221474Snp{
8688228561Snp	struct adapter *sc = iq->adapter;
8689228561Snp	const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1);
8690221474Snp	unsigned int idx = GET_TID(rpl);
8691265426Snp	unsigned int rc;
8692265426Snp	struct filter_entry *f;
8693221474Snp
8694228561Snp	KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__,
8695228561Snp	    rss->opcode));
8696309442Sjhb	MPASS(iq == &sc->sge.fwq);
8697309442Sjhb	MPASS(is_ftid(sc, idx));
8698228561Snp
8699309442Sjhb	idx -= sc->tids.ftid_base;
8700309442Sjhb	f = &sc->tids.ftid_tab[idx];
8701309442Sjhb	rc = G_COOKIE(rpl->cookie);
8702221474Snp
8703309442Sjhb	mtx_lock(&sc->tids.ftid_lock);
8704309442Sjhb	if (rc == FW_FILTER_WR_FLT_ADDED) {
8705309442Sjhb		KASSERT(f->pending, ("%s: filter[%u] isn't pending.",
8706309442Sjhb		    __func__, idx));
8707309442Sjhb		f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff;
8708309442Sjhb		f->pending = 0;  /* asynchronous setup completed */
8709309442Sjhb		f->valid = 1;
8710309442Sjhb	} else {
8711309442Sjhb		if (rc != FW_FILTER_WR_FLT_DELETED) {
8712309442Sjhb			/* Add or delete failed, display an error */
8713309442Sjhb			log(LOG_ERR,
8714309442Sjhb			    "filter %u setup failed with error %u\n",
8715309442Sjhb			    idx, rc);
8716309442Sjhb		}
8717265426Snp
8718309442Sjhb		clear_filter(f);
8719309442Sjhb		sc->tids.ftids_in_use--;
8720221474Snp	}
8721309442Sjhb	wakeup(&sc->tids.ftid_tab);
8722309442Sjhb	mtx_unlock(&sc->tids.ftid_lock);
8723228561Snp
8724228561Snp	return (0);
8725221474Snp}
8726221474Snp
8727222973Snpstatic int
8728309442Sjhbset_tcb_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
8729309442Sjhb{
8730309442Sjhb
8731309442Sjhb	MPASS(iq->set_tcb_rpl != NULL);
8732309442Sjhb	return (iq->set_tcb_rpl(iq, rss, m));
8733309442Sjhb}
8734309442Sjhb
8735309442Sjhbstatic int
8736309442Sjhbl2t_write_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
8737309442Sjhb{
8738309442Sjhb
8739309442Sjhb	MPASS(iq->l2t_write_rpl != NULL);
8740309442Sjhb	return (iq->l2t_write_rpl(iq, rss, m));
8741309442Sjhb}
8742309442Sjhb
8743309442Sjhbstatic int
8744222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt)
8745222973Snp{
8746245274Snp	int rc;
8747222973Snp
8748222973Snp	if (cntxt->cid > M_CTXTQID)
8749245274Snp		return (EINVAL);
8750222973Snp
8751222973Snp	if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS &&
8752222973Snp	    cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM)
8753245274Snp		return (EINVAL);
8754222973Snp
8755246575Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ctxt");
8756246575Snp	if (rc)
8757246575Snp		return (rc);
8758246575Snp
8759222973Snp	if (sc->flags & FW_OK) {
8760246575Snp		rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id,
8761246575Snp		    &cntxt->data[0]);
8762246575Snp		if (rc == 0)
8763246575Snp			goto done;
8764222973Snp	}
8765222973Snp
8766245274Snp	/*
8767245274Snp	 * Read via firmware failed or wasn't even attempted.  Read directly via
8768245274Snp	 * the backdoor.
8769245274Snp	 */
8770246575Snp	rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, &cntxt->data[0]);
8771246575Snpdone:
8772246575Snp	end_synchronized_op(sc, 0);
8773245274Snp	return (rc);
8774245274Snp}
8775222973Snp
8776245274Snpstatic int
8777245274Snpload_fw(struct adapter *sc, struct t4_data *fw)
8778245274Snp{
8779245274Snp	int rc;
8780245274Snp	uint8_t *fw_data;
8781245274Snp
8782245274Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw");
8783245274Snp	if (rc)
8784245274Snp		return (rc);
8785245274Snp
8786245274Snp	if (sc->flags & FULL_INIT_DONE) {
8787245274Snp		rc = EBUSY;
8788245274Snp		goto done;
8789222973Snp	}
8790222973Snp
8791245274Snp	fw_data = malloc(fw->len, M_CXGBE, M_WAITOK);
8792245274Snp	if (fw_data == NULL) {
8793245274Snp		rc = ENOMEM;
8794245274Snp		goto done;
8795245274Snp	}
8796245274Snp
8797245274Snp	rc = copyin(fw->data, fw_data, fw->len);
8798245274Snp	if (rc == 0)
8799245274Snp		rc = -t4_load_fw(sc, fw_data, fw->len);
8800245274Snp
8801245274Snp	free(fw_data, M_CXGBE);
8802245274Snpdone:
8803245274Snp	end_synchronized_op(sc, 0);
8804222973Snp	return (rc);
8805222973Snp}
8806222973Snp
8807309569Sjhbstatic int
8808309569Sjhbload_cfg(struct adapter *sc, struct t4_data *cfg)
8809309569Sjhb{
8810309569Sjhb	int rc;
8811309569Sjhb	uint8_t *cfg_data = NULL;
8812309569Sjhb
8813309569Sjhb	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldcf");
8814309569Sjhb	if (rc)
8815309569Sjhb		return (rc);
8816309569Sjhb
8817309569Sjhb	if (cfg->len == 0) {
8818309569Sjhb		/* clear */
8819309569Sjhb		rc = -t4_load_cfg(sc, NULL, 0);
8820309569Sjhb		goto done;
8821309569Sjhb	}
8822309569Sjhb
8823309569Sjhb	cfg_data = malloc(cfg->len, M_CXGBE, M_WAITOK);
8824309569Sjhb	if (cfg_data == NULL) {
8825309569Sjhb		rc = ENOMEM;
8826309569Sjhb		goto done;
8827309569Sjhb	}
8828309569Sjhb
8829309569Sjhb	rc = copyin(cfg->data, cfg_data, cfg->len);
8830309569Sjhb	if (rc == 0)
8831309569Sjhb		rc = -t4_load_cfg(sc, cfg_data, cfg->len);
8832309569Sjhb
8833309569Sjhb	free(cfg_data, M_CXGBE);
8834309569Sjhbdone:
8835309569Sjhb	end_synchronized_op(sc, 0);
8836309569Sjhb	return (rc);
8837309569Sjhb}
8838309569Sjhb
8839308305Sjhb#define MAX_READ_BUF_SIZE (128 * 1024)
8840228561Snpstatic int
8841248925Snpread_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr)
8842228561Snp{
8843308305Sjhb	uint32_t addr, remaining, n;
8844308305Sjhb	uint32_t *buf;
8845228561Snp	int rc;
8846248925Snp	uint8_t *dst;
8847228561Snp
8848248925Snp	rc = validate_mem_range(sc, mr->addr, mr->len);
8849248925Snp	if (rc != 0)
8850248925Snp		return (rc);
8851228561Snp
8852308305Sjhb	buf = malloc(min(mr->len, MAX_READ_BUF_SIZE), M_CXGBE, M_WAITOK);
8853248925Snp	addr = mr->addr;
8854228561Snp	remaining = mr->len;
8855248925Snp	dst = (void *)mr->data;
8856228561Snp
8857228561Snp	while (remaining) {
8858308305Sjhb		n = min(remaining, MAX_READ_BUF_SIZE);
8859308305Sjhb		read_via_memwin(sc, 2, addr, buf, n);
8860228561Snp
8861248925Snp		rc = copyout(buf, dst, n);
8862248925Snp		if (rc != 0)
8863248925Snp			break;
8864228561Snp
8865248925Snp		dst += n;
8866248925Snp		remaining -= n;
8867248925Snp		addr += n;
8868228561Snp	}
8869228561Snp
8870228561Snp	free(buf, M_CXGBE);
8871228561Snp	return (rc);
8872228561Snp}
8873308305Sjhb#undef MAX_READ_BUF_SIZE
8874228561Snp
8875241399Snpstatic int
8876241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd)
8877241399Snp{
8878241399Snp	int rc;
8879241399Snp
8880241399Snp	if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports)
8881241399Snp		return (EINVAL);
8882241399Snp
8883269082Snp	if (i2cd->len > sizeof(i2cd->data))
8884269082Snp		return (EFBIG);
8885241399Snp
8886245274Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd");
8887245274Snp	if (rc)
8888245274Snp		return (rc);
8889241399Snp	rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr,
8890269082Snp	    i2cd->offset, i2cd->len, &i2cd->data[0]);
8891245274Snp	end_synchronized_op(sc, 0);
8892241399Snp
8893241399Snp	return (rc);
8894241399Snp}
8895241399Snp
8896309447Sjhbint
8897218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap)
8898218792Snp{
8899222102Snp	int i;
8900218792Snp
8901222102Snp	return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0);
8902218792Snp}
8903218792Snp
8904218792Snpint
8905218792Snpt4_os_pci_save_state(struct adapter *sc)
8906218792Snp{
8907218792Snp	device_t dev;
8908218792Snp	struct pci_devinfo *dinfo;
8909218792Snp
8910218792Snp	dev = sc->dev;
8911218792Snp	dinfo = device_get_ivars(dev);
8912218792Snp
8913218792Snp	pci_cfg_save(dev, dinfo, 0);
8914218792Snp	return (0);
8915218792Snp}
8916218792Snp
8917218792Snpint
8918218792Snpt4_os_pci_restore_state(struct adapter *sc)
8919218792Snp{
8920218792Snp	device_t dev;
8921218792Snp	struct pci_devinfo *dinfo;
8922218792Snp
8923218792Snp	dev = sc->dev;
8924218792Snp	dinfo = device_get_ivars(dev);
8925218792Snp
8926218792Snp	pci_cfg_restore(dev, dinfo);
8927218792Snp	return (0);
8928218792Snp}
8929219299Snp
8930218792Snpvoid
8931353418Snpt4_os_portmod_changed(struct port_info *pi)
8932218792Snp{
8933353418Snp	struct adapter *sc = pi->adapter;
8934308154Sjhb	struct vi_info *vi;
8935308154Sjhb	struct ifnet *ifp;
8936218792Snp	static const char *mod_str[] = {
8937220232Snp		NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
8938218792Snp	};
8939218792Snp
8940353418Snp	MPASS((pi->flags & FIXED_IFMEDIA) == 0);
8941353418Snp
8942353418Snp	vi = &pi->vi[0];
8943353418Snp	if (begin_synchronized_op(sc, vi, HOLD_LOCK, "t4mod") == 0) {
8944353418Snp		PORT_LOCK(pi);
8945353418Snp		build_medialist(pi, &pi->media);
8946353418Snp		apply_l1cfg(pi);
8947353418Snp		PORT_UNLOCK(pi);
8948353418Snp		end_synchronized_op(sc, LOCK_HELD);
8949308154Sjhb	}
8950281207Snp
8951353418Snp	ifp = vi->ifp;
8952218792Snp	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
8953308154Sjhb		if_printf(ifp, "transceiver unplugged.\n");
8954220232Snp	else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
8955308154Sjhb		if_printf(ifp, "unknown transceiver inserted.\n");
8956220232Snp	else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
8957308154Sjhb		if_printf(ifp, "unsupported transceiver inserted.\n");
8958240452Snp	else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) {
8959353418Snp		if_printf(ifp, "%dGbps %s transceiver inserted.\n",
8960353418Snp		    port_top_speed(pi), mod_str[pi->mod_type]);
8961219299Snp	} else {
8962308154Sjhb		if_printf(ifp, "transceiver (type %d) inserted.\n",
8963219299Snp		    pi->mod_type);
8964219299Snp	}
8965218792Snp}
8966218792Snp
8967218792Snpvoid
8968353418Snpt4_os_link_changed(struct port_info *pi)
8969218792Snp{
8970308154Sjhb	struct vi_info *vi;
8971308154Sjhb	struct ifnet *ifp;
8972353418Snp	struct link_config *lc;
8973308154Sjhb	int v;
8974218792Snp
8975353418Snp	PORT_LOCK_ASSERT_OWNED(pi);
8976353418Snp
8977308154Sjhb	for_each_vi(pi, v, vi) {
8978308154Sjhb		ifp = vi->ifp;
8979308154Sjhb		if (ifp == NULL)
8980308154Sjhb			continue;
8981308154Sjhb
8982353418Snp		lc = &pi->link_cfg;
8983353418Snp		if (lc->link_ok) {
8984353418Snp			ifp->if_baudrate = IF_Mbps(lc->speed);
8985308154Sjhb			if_link_state_change(ifp, LINK_STATE_UP);
8986308154Sjhb		} else {
8987308154Sjhb			if_link_state_change(ifp, LINK_STATE_DOWN);
8988308154Sjhb		}
8989308154Sjhb	}
8990218792Snp}
8991218792Snp
8992228561Snpvoid
8993228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg)
8994228561Snp{
8995228561Snp	struct adapter *sc;
8996228561Snp
8997255006Snp	sx_slock(&t4_list_lock);
8998228561Snp	SLIST_FOREACH(sc, &t4_list, link) {
8999228561Snp		/*
9000228561Snp		 * func should not make any assumptions about what state sc is
9001228561Snp		 * in - the only guarantee is that sc->sc_lock is a valid lock.
9002228561Snp		 */
9003228561Snp		func(sc, arg);
9004228561Snp	}
9005255006Snp	sx_sunlock(&t4_list_lock);
9006228561Snp}
9007228561Snp
9008218792Snpstatic int
9009218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag,
9010218792Snp    struct thread *td)
9011218792Snp{
9012218792Snp	int rc;
9013218792Snp	struct adapter *sc = dev->si_drv1;
9014218792Snp
9015218792Snp	rc = priv_check(td, PRIV_DRIVER);
9016218792Snp	if (rc != 0)
9017218792Snp		return (rc);
9018218792Snp
9019218792Snp	switch (cmd) {
9020220410Snp	case CHELSIO_T4_GETREG: {
9021220410Snp		struct t4_reg *edata = (struct t4_reg *)data;
9022220410Snp
9023218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
9024218792Snp			return (EFAULT);
9025220410Snp
9026220410Snp		if (edata->size == 4)
9027220410Snp			edata->val = t4_read_reg(sc, edata->addr);
9028220410Snp		else if (edata->size == 8)
9029220410Snp			edata->val = t4_read_reg64(sc, edata->addr);
9030220410Snp		else
9031220410Snp			return (EINVAL);
9032220410Snp
9033218792Snp		break;
9034218792Snp	}
9035220410Snp	case CHELSIO_T4_SETREG: {
9036220410Snp		struct t4_reg *edata = (struct t4_reg *)data;
9037220410Snp
9038218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
9039218792Snp			return (EFAULT);
9040220410Snp
9041220410Snp		if (edata->size == 4) {
9042220410Snp			if (edata->val & 0xffffffff00000000)
9043220410Snp				return (EINVAL);
9044220410Snp			t4_write_reg(sc, edata->addr, (uint32_t) edata->val);
9045220410Snp		} else if (edata->size == 8)
9046220410Snp			t4_write_reg64(sc, edata->addr, edata->val);
9047220410Snp		else
9048220410Snp			return (EINVAL);
9049218792Snp		break;
9050218792Snp	}
9051218792Snp	case CHELSIO_T4_REGDUMP: {
9052218792Snp		struct t4_regdump *regs = (struct t4_regdump *)data;
9053309447Sjhb		int reglen = t4_get_regs_len(sc);
9054218792Snp		uint8_t *buf;
9055218792Snp
9056218792Snp		if (regs->len < reglen) {
9057218792Snp			regs->len = reglen; /* hint to the caller */
9058218792Snp			return (ENOBUFS);
9059218792Snp		}
9060218792Snp
9061218792Snp		regs->len = reglen;
9062218792Snp		buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO);
9063308304Sjhb		get_regs(sc, regs, buf);
9064218792Snp		rc = copyout(buf, regs->data, reglen);
9065218792Snp		free(buf, M_CXGBE);
9066218792Snp		break;
9067218792Snp	}
9068221474Snp	case CHELSIO_T4_GET_FILTER_MODE:
9069221474Snp		rc = get_filter_mode(sc, (uint32_t *)data);
9070221474Snp		break;
9071221474Snp	case CHELSIO_T4_SET_FILTER_MODE:
9072221474Snp		rc = set_filter_mode(sc, *(uint32_t *)data);
9073221474Snp		break;
9074221474Snp	case CHELSIO_T4_GET_FILTER:
9075221474Snp		rc = get_filter(sc, (struct t4_filter *)data);
9076221474Snp		break;
9077221474Snp	case CHELSIO_T4_SET_FILTER:
9078221474Snp		rc = set_filter(sc, (struct t4_filter *)data);
9079221474Snp		break;
9080221474Snp	case CHELSIO_T4_DEL_FILTER:
9081221474Snp		rc = del_filter(sc, (struct t4_filter *)data);
9082221474Snp		break;
9083222973Snp	case CHELSIO_T4_GET_SGE_CONTEXT:
9084222973Snp		rc = get_sge_context(sc, (struct t4_sge_context *)data);
9085222973Snp		break;
9086245274Snp	case CHELSIO_T4_LOAD_FW:
9087245274Snp		rc = load_fw(sc, (struct t4_data *)data);
9088228561Snp		break;
9089228561Snp	case CHELSIO_T4_GET_MEM:
9090248925Snp		rc = read_card_mem(sc, 2, (struct t4_mem_range *)data);
9091228561Snp		break;
9092241399Snp	case CHELSIO_T4_GET_I2C:
9093241399Snp		rc = read_i2c(sc, (struct t4_i2c_data *)data);
9094241399Snp		break;
9095241409Snp	case CHELSIO_T4_CLEAR_STATS: {
9096308154Sjhb		int i, v;
9097241409Snp		u_int port_id = *(uint32_t *)data;
9098245518Snp		struct port_info *pi;
9099308154Sjhb		struct vi_info *vi;
9100241409Snp
9101241409Snp		if (port_id >= sc->params.nports)
9102241409Snp			return (EINVAL);
9103265410Snp		pi = sc->port[port_id];
9104309559Sjhb		if (pi == NULL)
9105309559Sjhb			return (EIO);
9106241409Snp
9107245518Snp		/* MAC stats */
9108265410Snp		t4_clr_port_stats(sc, pi->tx_chan);
9109284052Snp		pi->tx_parse_error = 0;
9110308305Sjhb		mtx_lock(&sc->reg_lock);
9111308154Sjhb		for_each_vi(pi, v, vi) {
9112308154Sjhb			if (vi->flags & VI_INIT_DONE)
9113308154Sjhb				t4_clr_vi_stats(sc, vi->viid);
9114308154Sjhb		}
9115308305Sjhb		mtx_unlock(&sc->reg_lock);
9116245518Snp
9117308154Sjhb		/*
9118308154Sjhb		 * Since this command accepts a port, clear stats for
9119308154Sjhb		 * all VIs on this port.
9120308154Sjhb		 */
9121308154Sjhb		for_each_vi(pi, v, vi) {
9122308154Sjhb			if (vi->flags & VI_INIT_DONE) {
9123308154Sjhb				struct sge_rxq *rxq;
9124308154Sjhb				struct sge_txq *txq;
9125308154Sjhb				struct sge_wrq *wrq;
9126245518Snp
9127308154Sjhb				for_each_rxq(vi, i, rxq) {
9128245518Snp#if defined(INET) || defined(INET6)
9129308154Sjhb					rxq->lro.lro_queued = 0;
9130308154Sjhb					rxq->lro.lro_flushed = 0;
9131245518Snp#endif
9132308154Sjhb					rxq->rxcsum = 0;
9133308154Sjhb					rxq->vlan_extraction = 0;
9134308154Sjhb				}
9135245518Snp
9136308154Sjhb				for_each_txq(vi, i, txq) {
9137308154Sjhb					txq->txcsum = 0;
9138308154Sjhb					txq->tso_wrs = 0;
9139308154Sjhb					txq->vlan_insertion = 0;
9140308154Sjhb					txq->imm_wrs = 0;
9141308154Sjhb					txq->sgl_wrs = 0;
9142308154Sjhb					txq->txpkt_wrs = 0;
9143308154Sjhb					txq->txpkts0_wrs = 0;
9144308154Sjhb					txq->txpkts1_wrs = 0;
9145308154Sjhb					txq->txpkts0_pkts = 0;
9146308154Sjhb					txq->txpkts1_pkts = 0;
9147308154Sjhb					mp_ring_reset_stats(txq->r);
9148308154Sjhb				}
9149245518Snp
9150245518Snp#ifdef TCP_OFFLOAD
9151308154Sjhb				/* nothing to clear for each ofld_rxq */
9152245518Snp
9153308154Sjhb				for_each_ofld_txq(vi, i, wrq) {
9154308154Sjhb					wrq->tx_wrs_direct = 0;
9155308154Sjhb					wrq->tx_wrs_copied = 0;
9156308154Sjhb				}
9157308154Sjhb#endif
9158308154Sjhb
9159308154Sjhb				if (IS_MAIN_VI(vi)) {
9160308154Sjhb					wrq = &sc->sge.ctrlq[pi->port_id];
9161308154Sjhb					wrq->tx_wrs_direct = 0;
9162308154Sjhb					wrq->tx_wrs_copied = 0;
9163308154Sjhb				}
9164245518Snp			}
9165245518Snp		}
9166241409Snp		break;
9167241409Snp	}
9168259142Snp	case CHELSIO_T4_SCHED_CLASS:
9169309447Sjhb		rc = t4_set_sched_class(sc, (struct t4_sched_params *)data);
9170259142Snp		break;
9171259142Snp	case CHELSIO_T4_SCHED_QUEUE:
9172309447Sjhb		rc = t4_set_sched_queue(sc, (struct t4_sched_queue *)data);
9173259142Snp		break;
9174253691Snp	case CHELSIO_T4_GET_TRACER:
9175253691Snp		rc = t4_get_tracer(sc, (struct t4_tracer *)data);
9176253691Snp		break;
9177253691Snp	case CHELSIO_T4_SET_TRACER:
9178253691Snp		rc = t4_set_tracer(sc, (struct t4_tracer *)data);
9179253691Snp		break;
9180309569Sjhb	case CHELSIO_T4_LOAD_CFG:
9181309569Sjhb		rc = load_cfg(sc, (struct t4_data *)data);
9182309569Sjhb		break;
9183218792Snp	default:
9184309447Sjhb		rc = ENOTTY;
9185218792Snp	}
9186218792Snp
9187218792Snp	return (rc);
9188218792Snp}
9189218792Snp
9190308304Sjhbvoid
9191308304Sjhbt4_db_full(struct adapter *sc)
9192308304Sjhb{
9193308304Sjhb
9194308304Sjhb	CXGBE_UNIMPLEMENTED(__func__);
9195308304Sjhb}
9196308304Sjhb
9197308304Sjhbvoid
9198308304Sjhbt4_db_dropped(struct adapter *sc)
9199308304Sjhb{
9200308304Sjhb
9201308304Sjhb	CXGBE_UNIMPLEMENTED(__func__);
9202308304Sjhb}
9203308304Sjhb
9204237263Snp#ifdef TCP_OFFLOAD
9205270297Snpvoid
9206309440Sjhbt4_iscsi_init(struct adapter *sc, u_int tag_mask, const u_int *pgsz_order)
9207270297Snp{
9208270297Snp
9209270297Snp	t4_write_reg(sc, A_ULP_RX_ISCSI_TAGMASK, tag_mask);
9210270297Snp	t4_write_reg(sc, A_ULP_RX_ISCSI_PSZ, V_HPZ0(pgsz_order[0]) |
9211270297Snp		V_HPZ1(pgsz_order[1]) | V_HPZ2(pgsz_order[2]) |
9212270297Snp		V_HPZ3(pgsz_order[3]));
9213270297Snp}
9214270297Snp
9215219392Snpstatic int
9216308154Sjhbtoe_capability(struct vi_info *vi, int enable)
9217228561Snp{
9218228561Snp	int rc;
9219308154Sjhb	struct port_info *pi = vi->pi;
9220228561Snp	struct adapter *sc = pi->adapter;
9221228561Snp
9222245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
9223228561Snp
9224228561Snp	if (!is_offload(sc))
9225228561Snp		return (ENODEV);
9226228561Snp
9227228561Snp	if (enable) {
9228308154Sjhb		if ((vi->ifp->if_capenable & IFCAP_TOE) != 0) {
9229308154Sjhb			/* TOE is already enabled. */
9230308154Sjhb			return (0);
9231308154Sjhb		}
9232308154Sjhb
9233281248Snp		/*
9234281248Snp		 * We need the port's queues around so that we're able to send
9235281248Snp		 * and receive CPLs to/from the TOE even if the ifnet for this
9236281248Snp		 * port has never been UP'd administratively.
9237281248Snp		 */
9238308154Sjhb		if (!(vi->flags & VI_INIT_DONE)) {
9239308154Sjhb			rc = vi_full_init(vi);
9240245274Snp			if (rc)
9241245274Snp				return (rc);
9242237263Snp		}
9243308154Sjhb		if (!(pi->vi[0].flags & VI_INIT_DONE)) {
9244308154Sjhb			rc = vi_full_init(&pi->vi[0]);
9245308154Sjhb			if (rc)
9246308154Sjhb				return (rc);
9247308154Sjhb		}
9248237263Snp
9249308154Sjhb		if (isset(&sc->offload_map, pi->port_id)) {
9250308154Sjhb			/* TOE is enabled on another VI of this port. */
9251308154Sjhb			pi->uld_vis++;
9252228561Snp			return (0);
9253308154Sjhb		}
9254228561Snp
9255284089Snp		if (!uld_active(sc, ULD_TOM)) {
9256237263Snp			rc = t4_activate_uld(sc, ULD_TOM);
9257237263Snp			if (rc == EAGAIN) {
9258237263Snp				log(LOG_WARNING,
9259237263Snp				    "You must kldload t4_tom.ko before trying "
9260237263Snp				    "to enable TOE on a cxgbe interface.\n");
9261237263Snp			}
9262228561Snp			if (rc != 0)
9263228561Snp				return (rc);
9264237263Snp			KASSERT(sc->tom_softc != NULL,
9265237263Snp			    ("%s: TOM activated but softc NULL", __func__));
9266284089Snp			KASSERT(uld_active(sc, ULD_TOM),
9267237263Snp			    ("%s: TOM activated but flag not set", __func__));
9268228561Snp		}
9269228561Snp
9270284089Snp		/* Activate iWARP and iSCSI too, if the modules are loaded. */
9271284089Snp		if (!uld_active(sc, ULD_IWARP))
9272284089Snp			(void) t4_activate_uld(sc, ULD_IWARP);
9273284089Snp		if (!uld_active(sc, ULD_ISCSI))
9274284089Snp			(void) t4_activate_uld(sc, ULD_ISCSI);
9275284089Snp
9276308154Sjhb		pi->uld_vis++;
9277228561Snp		setbit(&sc->offload_map, pi->port_id);
9278228561Snp	} else {
9279308154Sjhb		pi->uld_vis--;
9280308154Sjhb
9281308154Sjhb		if (!isset(&sc->offload_map, pi->port_id) || pi->uld_vis > 0)
9282228561Snp			return (0);
9283228561Snp
9284284089Snp		KASSERT(uld_active(sc, ULD_TOM),
9285237263Snp		    ("%s: TOM never initialized?", __func__));
9286228561Snp		clrbit(&sc->offload_map, pi->port_id);
9287228561Snp	}
9288228561Snp
9289228561Snp	return (0);
9290228561Snp}
9291228561Snp
9292228561Snp/*
9293228561Snp * Add an upper layer driver to the global list.
9294228561Snp */
9295228561Snpint
9296228561Snpt4_register_uld(struct uld_info *ui)
9297228561Snp{
9298228561Snp	int rc = 0;
9299228561Snp	struct uld_info *u;
9300228561Snp
9301255006Snp	sx_xlock(&t4_uld_list_lock);
9302228561Snp	SLIST_FOREACH(u, &t4_uld_list, link) {
9303228561Snp	    if (u->uld_id == ui->uld_id) {
9304228561Snp		    rc = EEXIST;
9305228561Snp		    goto done;
9306228561Snp	    }
9307228561Snp	}
9308228561Snp
9309228561Snp	SLIST_INSERT_HEAD(&t4_uld_list, ui, link);
9310228561Snp	ui->refcount = 0;
9311228561Snpdone:
9312255006Snp	sx_xunlock(&t4_uld_list_lock);
9313228561Snp	return (rc);
9314228561Snp}
9315228561Snp
9316228561Snpint
9317228561Snpt4_unregister_uld(struct uld_info *ui)
9318228561Snp{
9319228561Snp	int rc = EINVAL;
9320228561Snp	struct uld_info *u;
9321228561Snp
9322255006Snp	sx_xlock(&t4_uld_list_lock);
9323228561Snp
9324228561Snp	SLIST_FOREACH(u, &t4_uld_list, link) {
9325228561Snp	    if (u == ui) {
9326228561Snp		    if (ui->refcount > 0) {
9327228561Snp			    rc = EBUSY;
9328228561Snp			    goto done;
9329228561Snp		    }
9330228561Snp
9331228561Snp		    SLIST_REMOVE(&t4_uld_list, ui, uld_info, link);
9332228561Snp		    rc = 0;
9333228561Snp		    goto done;
9334228561Snp	    }
9335228561Snp	}
9336228561Snpdone:
9337255006Snp	sx_xunlock(&t4_uld_list_lock);
9338228561Snp	return (rc);
9339228561Snp}
9340228561Snp
9341237263Snpint
9342237263Snpt4_activate_uld(struct adapter *sc, int id)
9343228561Snp{
9344284089Snp	int rc;
9345228561Snp	struct uld_info *ui;
9346228561Snp
9347245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
9348245274Snp
9349284089Snp	if (id < 0 || id > ULD_MAX)
9350284089Snp		return (EINVAL);
9351284089Snp	rc = EAGAIN;	/* kldoad the module with this ULD and try again. */
9352284089Snp
9353255006Snp	sx_slock(&t4_uld_list_lock);
9354228561Snp
9355228561Snp	SLIST_FOREACH(ui, &t4_uld_list, link) {
9356228561Snp		if (ui->uld_id == id) {
9357282367Snp			if (!(sc->flags & FULL_INIT_DONE)) {
9358282367Snp				rc = adapter_full_init(sc);
9359282367Snp				if (rc != 0)
9360284089Snp					break;
9361282367Snp			}
9362282367Snp
9363237263Snp			rc = ui->activate(sc);
9364284089Snp			if (rc == 0) {
9365284089Snp				setbit(&sc->active_ulds, id);
9366228561Snp				ui->refcount++;
9367284089Snp			}
9368284089Snp			break;
9369228561Snp		}
9370228561Snp	}
9371284089Snp
9372255006Snp	sx_sunlock(&t4_uld_list_lock);
9373228561Snp
9374228561Snp	return (rc);
9375228561Snp}
9376228561Snp
9377237263Snpint
9378237263Snpt4_deactivate_uld(struct adapter *sc, int id)
9379228561Snp{
9380284089Snp	int rc;
9381237263Snp	struct uld_info *ui;
9382228561Snp
9383245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
9384245274Snp
9385284089Snp	if (id < 0 || id > ULD_MAX)
9386284089Snp		return (EINVAL);
9387284089Snp	rc = ENXIO;
9388284089Snp
9389255006Snp	sx_slock(&t4_uld_list_lock);
9390228561Snp
9391237263Snp	SLIST_FOREACH(ui, &t4_uld_list, link) {
9392237263Snp		if (ui->uld_id == id) {
9393237263Snp			rc = ui->deactivate(sc);
9394284089Snp			if (rc == 0) {
9395284089Snp				clrbit(&sc->active_ulds, id);
9396237263Snp				ui->refcount--;
9397284089Snp			}
9398284089Snp			break;
9399237263Snp		}
9400228561Snp	}
9401284089Snp
9402255006Snp	sx_sunlock(&t4_uld_list_lock);
9403228561Snp
9404228561Snp	return (rc);
9405228561Snp}
9406284089Snp
9407284089Snpint
9408284089Snpuld_active(struct adapter *sc, int uld_id)
9409284089Snp{
9410284089Snp
9411284089Snp	MPASS(uld_id >= 0 && uld_id <= ULD_MAX);
9412284089Snp
9413284089Snp	return (isset(&sc->active_ulds, uld_id));
9414284089Snp}
9415228561Snp#endif
9416228561Snp
9417228561Snp/*
9418318809Snp * t  = ptr to tunable.
9419318809Snp * nc = number of CPUs.
9420318809Snp * c  = compiled in default for that tunable.
9421318809Snp */
9422318809Snpstatic void
9423318809Snpcalculate_nqueues(int *t, int nc, const int c)
9424318809Snp{
9425318809Snp	int nq;
9426318809Snp
9427318809Snp	if (*t > 0)
9428318809Snp		return;
9429318809Snp	nq = *t < 0 ? -*t : c;
9430318809Snp	*t = min(nc, nq);
9431318809Snp}
9432318809Snp
9433318809Snp/*
9434228561Snp * Come up with reasonable defaults for some of the tunables, provided they're
9435228561Snp * not set by the user (in which case we'll use the values as is).
9436228561Snp */
9437228561Snpstatic void
9438228561Snptweak_tunables(void)
9439228561Snp{
9440228561Snp	int nc = mp_ncpus;	/* our snapshot of the number of CPUs */
9441228561Snp
9442308153Sjhb	if (t4_ntxq10g < 1) {
9443308153Sjhb#ifdef RSS
9444308153Sjhb		t4_ntxq10g = rss_getnumbuckets();
9445308153Sjhb#else
9446318809Snp		calculate_nqueues(&t4_ntxq10g, nc, NTXQ_10G);
9447308153Sjhb#endif
9448308153Sjhb	}
9449228561Snp
9450308153Sjhb	if (t4_ntxq1g < 1) {
9451308153Sjhb#ifdef RSS
9452308153Sjhb		/* XXX: way too many for 1GbE? */
9453308153Sjhb		t4_ntxq1g = rss_getnumbuckets();
9454308153Sjhb#else
9455318809Snp		calculate_nqueues(&t4_ntxq1g, nc, NTXQ_1G);
9456308153Sjhb#endif
9457308153Sjhb	}
9458228561Snp
9459318809Snp	calculate_nqueues(&t4_ntxq_vi, nc, NTXQ_VI);
9460308154Sjhb
9461308153Sjhb	if (t4_nrxq10g < 1) {
9462308153Sjhb#ifdef RSS
9463308153Sjhb		t4_nrxq10g = rss_getnumbuckets();
9464308153Sjhb#else
9465318809Snp		calculate_nqueues(&t4_nrxq10g, nc, NRXQ_10G);
9466308153Sjhb#endif
9467308153Sjhb	}
9468228561Snp
9469308153Sjhb	if (t4_nrxq1g < 1) {
9470308153Sjhb#ifdef RSS
9471308153Sjhb		/* XXX: way too many for 1GbE? */
9472308153Sjhb		t4_nrxq1g = rss_getnumbuckets();
9473308153Sjhb#else
9474318809Snp		calculate_nqueues(&t4_nrxq1g, nc, NRXQ_1G);
9475308153Sjhb#endif
9476308153Sjhb	}
9477228561Snp
9478318809Snp	calculate_nqueues(&t4_nrxq_vi, nc, NRXQ_VI);
9479308154Sjhb
9480237263Snp#ifdef TCP_OFFLOAD
9481318809Snp	calculate_nqueues(&t4_nofldtxq10g, nc, NOFLDTXQ_10G);
9482318809Snp	calculate_nqueues(&t4_nofldtxq1g, nc, NOFLDTXQ_1G);
9483318809Snp	calculate_nqueues(&t4_nofldtxq_vi, nc, NOFLDTXQ_VI);
9484318809Snp	calculate_nqueues(&t4_nofldrxq10g, nc, NOFLDRXQ_10G);
9485318809Snp	calculate_nqueues(&t4_nofldrxq1g, nc, NOFLDRXQ_1G);
9486318809Snp	calculate_nqueues(&t4_nofldrxq_vi, nc, NOFLDRXQ_VI);
9487228561Snp
9488238028Snp	if (t4_toecaps_allowed == -1)
9489238028Snp		t4_toecaps_allowed = FW_CAPS_CONFIG_TOE;
9490308313Sjhb
9491308313Sjhb	if (t4_rdmacaps_allowed == -1) {
9492308313Sjhb		t4_rdmacaps_allowed = FW_CAPS_CONFIG_RDMA_RDDP |
9493308313Sjhb		    FW_CAPS_CONFIG_RDMA_RDMAC;
9494308313Sjhb	}
9495308313Sjhb
9496308313Sjhb	if (t4_iscsicaps_allowed == -1) {
9497308313Sjhb		t4_iscsicaps_allowed = FW_CAPS_CONFIG_ISCSI_INITIATOR_PDU |
9498308313Sjhb		    FW_CAPS_CONFIG_ISCSI_TARGET_PDU |
9499308313Sjhb		    FW_CAPS_CONFIG_ISCSI_T10DIF;
9500308313Sjhb	}
9501238028Snp#else
9502238028Snp	if (t4_toecaps_allowed == -1)
9503238028Snp		t4_toecaps_allowed = 0;
9504308313Sjhb
9505308313Sjhb	if (t4_rdmacaps_allowed == -1)
9506308313Sjhb		t4_rdmacaps_allowed = 0;
9507308313Sjhb
9508308313Sjhb	if (t4_iscsicaps_allowed == -1)
9509308313Sjhb		t4_iscsicaps_allowed = 0;
9510228561Snp#endif
9511228561Snp
9512270297Snp#ifdef DEV_NETMAP
9513318809Snp	calculate_nqueues(&t4_nnmtxq_vi, nc, NNMTXQ_VI);
9514318809Snp	calculate_nqueues(&t4_nnmrxq_vi, nc, NNMRXQ_VI);
9515270297Snp#endif
9516270297Snp
9517228561Snp	if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS)
9518228561Snp		t4_tmr_idx_10g = TMR_IDX_10G;
9519228561Snp
9520228561Snp	if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS)
9521228561Snp		t4_pktc_idx_10g = PKTC_IDX_10G;
9522228561Snp
9523228561Snp	if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS)
9524228561Snp		t4_tmr_idx_1g = TMR_IDX_1G;
9525228561Snp
9526228561Snp	if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS)
9527228561Snp		t4_pktc_idx_1g = PKTC_IDX_1G;
9528228561Snp
9529228561Snp	if (t4_qsize_txq < 128)
9530228561Snp		t4_qsize_txq = 128;
9531228561Snp
9532228561Snp	if (t4_qsize_rxq < 128)
9533228561Snp		t4_qsize_rxq = 128;
9534228561Snp	while (t4_qsize_rxq & 7)
9535228561Snp		t4_qsize_rxq++;
9536228561Snp
9537228561Snp	t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX;
9538228561Snp}
9539228561Snp
9540308318Sjhb#ifdef DDB
9541308318Sjhbstatic void
9542308318Sjhbt4_dump_tcb(struct adapter *sc, int tid)
9543308318Sjhb{
9544308318Sjhb	uint32_t base, i, j, off, pf, reg, save, tcb_addr, win_pos;
9545308318Sjhb
9546308318Sjhb	reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2);
9547308318Sjhb	save = t4_read_reg(sc, reg);
9548308318Sjhb	base = sc->memwin[2].mw_base;
9549308318Sjhb
9550308318Sjhb	/* Dump TCB for the tid */
9551308318Sjhb	tcb_addr = t4_read_reg(sc, A_TP_CMM_TCB_BASE);
9552308318Sjhb	tcb_addr += tid * TCB_SIZE;
9553308318Sjhb
9554308318Sjhb	if (is_t4(sc)) {
9555308318Sjhb		pf = 0;
9556308318Sjhb		win_pos = tcb_addr & ~0xf;	/* start must be 16B aligned */
9557308318Sjhb	} else {
9558308318Sjhb		pf = V_PFNUM(sc->pf);
9559308318Sjhb		win_pos = tcb_addr & ~0x7f;	/* start must be 128B aligned */
9560308318Sjhb	}
9561308318Sjhb	t4_write_reg(sc, reg, win_pos | pf);
9562308318Sjhb	t4_read_reg(sc, reg);
9563308318Sjhb
9564308318Sjhb	off = tcb_addr - win_pos;
9565308318Sjhb	for (i = 0; i < 4; i++) {
9566308318Sjhb		uint32_t buf[8];
9567308318Sjhb		for (j = 0; j < 8; j++, off += 4)
9568308318Sjhb			buf[j] = htonl(t4_read_reg(sc, base + off));
9569308318Sjhb
9570308318Sjhb		db_printf("%08x %08x %08x %08x %08x %08x %08x %08x\n",
9571308318Sjhb		    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
9572308318Sjhb		    buf[7]);
9573308318Sjhb	}
9574308318Sjhb
9575308318Sjhb	t4_write_reg(sc, reg, save);
9576308318Sjhb	t4_read_reg(sc, reg);
9577308318Sjhb}
9578308318Sjhb
9579308318Sjhbstatic void
9580308318Sjhbt4_dump_devlog(struct adapter *sc)
9581308318Sjhb{
9582308318Sjhb	struct devlog_params *dparams = &sc->params.devlog;
9583308318Sjhb	struct fw_devlog_e e;
9584308318Sjhb	int i, first, j, m, nentries, rc;
9585308318Sjhb	uint64_t ftstamp = UINT64_MAX;
9586308318Sjhb
9587308318Sjhb	if (dparams->start == 0) {
9588308318Sjhb		db_printf("devlog params not valid\n");
9589308318Sjhb		return;
9590308318Sjhb	}
9591308318Sjhb
9592308318Sjhb	nentries = dparams->size / sizeof(struct fw_devlog_e);
9593308318Sjhb	m = fwmtype_to_hwmtype(dparams->memtype);
9594308318Sjhb
9595308318Sjhb	/* Find the first entry. */
9596308318Sjhb	first = -1;
9597308318Sjhb	for (i = 0; i < nentries && !db_pager_quit; i++) {
9598308318Sjhb		rc = -t4_mem_read(sc, m, dparams->start + i * sizeof(e),
9599308318Sjhb		    sizeof(e), (void *)&e);
9600308318Sjhb		if (rc != 0)
9601308318Sjhb			break;
9602308318Sjhb
9603308318Sjhb		if (e.timestamp == 0)
9604308318Sjhb			break;
9605308318Sjhb
9606308318Sjhb		e.timestamp = be64toh(e.timestamp);
9607308318Sjhb		if (e.timestamp < ftstamp) {
9608308318Sjhb			ftstamp = e.timestamp;
9609308318Sjhb			first = i;
9610308318Sjhb		}
9611308318Sjhb	}
9612308318Sjhb
9613308318Sjhb	if (first == -1)
9614308318Sjhb		return;
9615308318Sjhb
9616308318Sjhb	i = first;
9617308318Sjhb	do {
9618308318Sjhb		rc = -t4_mem_read(sc, m, dparams->start + i * sizeof(e),
9619308318Sjhb		    sizeof(e), (void *)&e);
9620308318Sjhb		if (rc != 0)
9621308318Sjhb			return;
9622308318Sjhb
9623308318Sjhb		if (e.timestamp == 0)
9624308318Sjhb			return;
9625308318Sjhb
9626308318Sjhb		e.timestamp = be64toh(e.timestamp);
9627308318Sjhb		e.seqno = be32toh(e.seqno);
9628308318Sjhb		for (j = 0; j < 8; j++)
9629308318Sjhb			e.params[j] = be32toh(e.params[j]);
9630308318Sjhb
9631308318Sjhb		db_printf("%10d  %15ju  %8s  %8s  ",
9632308318Sjhb		    e.seqno, e.timestamp,
9633308318Sjhb		    (e.level < nitems(devlog_level_strings) ?
9634308318Sjhb			devlog_level_strings[e.level] : "UNKNOWN"),
9635308318Sjhb		    (e.facility < nitems(devlog_facility_strings) ?
9636308318Sjhb			devlog_facility_strings[e.facility] : "UNKNOWN"));
9637308318Sjhb		db_printf(e.fmt, e.params[0], e.params[1], e.params[2],
9638308318Sjhb		    e.params[3], e.params[4], e.params[5], e.params[6],
9639308318Sjhb		    e.params[7]);
9640308318Sjhb
9641308318Sjhb		if (++i == nentries)
9642308318Sjhb			i = 0;
9643308318Sjhb	} while (i != first && !db_pager_quit);
9644308318Sjhb}
9645308318Sjhb
9646308318Sjhbstatic struct command_table db_t4_table = LIST_HEAD_INITIALIZER(db_t4_table);
9647308318Sjhb_DB_SET(_show, t4, NULL, db_show_table, 0, &db_t4_table);
9648308318Sjhb
9649308318SjhbDB_FUNC(devlog, db_show_devlog, db_t4_table, CS_OWN, NULL)
9650308318Sjhb{
9651308318Sjhb	device_t dev;
9652308318Sjhb	int t;
9653308318Sjhb	bool valid;
9654308318Sjhb
9655308318Sjhb	valid = false;
9656308318Sjhb	t = db_read_token();
9657308318Sjhb	if (t == tIDENT) {
9658308318Sjhb		dev = device_lookup_by_name(db_tok_string);
9659308318Sjhb		valid = true;
9660308318Sjhb	}
9661308318Sjhb	db_skip_to_eol();
9662308318Sjhb	if (!valid) {
9663308318Sjhb		db_printf("usage: show t4 devlog <nexus>\n");
9664308318Sjhb		return;
9665308318Sjhb	}
9666308318Sjhb
9667308318Sjhb	if (dev == NULL) {
9668308318Sjhb		db_printf("device not found\n");
9669308318Sjhb		return;
9670308318Sjhb	}
9671308318Sjhb
9672308318Sjhb	t4_dump_devlog(device_get_softc(dev));
9673308318Sjhb}
9674308318Sjhb
9675308318SjhbDB_FUNC(tcb, db_show_t4tcb, db_t4_table, CS_OWN, NULL)
9676308318Sjhb{
9677308318Sjhb	device_t dev;
9678308318Sjhb	int radix, tid, t;
9679308318Sjhb	bool valid;
9680308318Sjhb
9681308318Sjhb	valid = false;
9682308318Sjhb	radix = db_radix;
9683308318Sjhb	db_radix = 10;
9684308318Sjhb	t = db_read_token();
9685308318Sjhb	if (t == tIDENT) {
9686308318Sjhb		dev = device_lookup_by_name(db_tok_string);
9687308318Sjhb		t = db_read_token();
9688308318Sjhb		if (t == tNUMBER) {
9689308318Sjhb			tid = db_tok_number;
9690308318Sjhb			valid = true;
9691308318Sjhb		}
9692308318Sjhb	}
9693308318Sjhb	db_radix = radix;
9694308318Sjhb	db_skip_to_eol();
9695308318Sjhb	if (!valid) {
9696308318Sjhb		db_printf("usage: show t4 tcb <nexus> <tid>\n");
9697308318Sjhb		return;
9698308318Sjhb	}
9699308318Sjhb
9700308318Sjhb	if (dev == NULL) {
9701308318Sjhb		db_printf("device not found\n");
9702308318Sjhb		return;
9703308318Sjhb	}
9704308318Sjhb	if (tid < 0) {
9705308318Sjhb		db_printf("invalid tid\n");
9706308318Sjhb		return;
9707308318Sjhb	}
9708308318Sjhb
9709308318Sjhb	t4_dump_tcb(device_get_softc(dev), tid);
9710308318Sjhb}
9711308318Sjhb#endif
9712308318Sjhb
9713269356Snpstatic struct sx mlu;	/* mod load unload */
9714269356SnpSX_SYSINIT(cxgbe_mlu, &mlu, "cxgbe mod load/unload");
9715269356Snp
9716228561Snpstatic int
9717249370Snpmod_event(module_t mod, int cmd, void *arg)
9718219392Snp{
9719228561Snp	int rc = 0;
9720249370Snp	static int loaded = 0;
9721219392Snp
9722228561Snp	switch (cmd) {
9723228561Snp	case MOD_LOAD:
9724269356Snp		sx_xlock(&mlu);
9725269356Snp		if (loaded++ == 0) {
9726269356Snp			t4_sge_modload();
9727309442Sjhb			t4_register_cpl_handler(CPL_SET_TCB_RPL, set_tcb_rpl);
9728309442Sjhb			t4_register_cpl_handler(CPL_L2T_WRITE_RPL, l2t_write_rpl);
9729309442Sjhb			t4_register_cpl_handler(CPL_TRACE_PKT, t4_trace_pkt);
9730309442Sjhb			t4_register_cpl_handler(CPL_T5_TRACE_PKT, t5_trace_pkt);
9731269356Snp			sx_init(&t4_list_lock, "T4/T5 adapters");
9732269356Snp			SLIST_INIT(&t4_list);
9733237263Snp#ifdef TCP_OFFLOAD
9734269356Snp			sx_init(&t4_uld_list_lock, "T4/T5 ULDs");
9735269356Snp			SLIST_INIT(&t4_uld_list);
9736228561Snp#endif
9737269356Snp			t4_tracer_modload();
9738269356Snp			tweak_tunables();
9739269356Snp		}
9740269356Snp		sx_xunlock(&mlu);
9741228561Snp		break;
9742219392Snp
9743228561Snp	case MOD_UNLOAD:
9744269356Snp		sx_xlock(&mlu);
9745269356Snp		if (--loaded == 0) {
9746269356Snp			int tries;
9747269356Snp
9748269356Snp			sx_slock(&t4_list_lock);
9749269356Snp			if (!SLIST_EMPTY(&t4_list)) {
9750269356Snp				rc = EBUSY;
9751269356Snp				sx_sunlock(&t4_list_lock);
9752269356Snp				goto done_unload;
9753269356Snp			}
9754237263Snp#ifdef TCP_OFFLOAD
9755269356Snp			sx_slock(&t4_uld_list_lock);
9756269356Snp			if (!SLIST_EMPTY(&t4_uld_list)) {
9757269356Snp				rc = EBUSY;
9758269356Snp				sx_sunlock(&t4_uld_list_lock);
9759269356Snp				sx_sunlock(&t4_list_lock);
9760269356Snp				goto done_unload;
9761269356Snp			}
9762269356Snp#endif
9763269356Snp			tries = 0;
9764269356Snp			while (tries++ < 5 && t4_sge_extfree_refs() != 0) {
9765269356Snp				uprintf("%ju clusters with custom free routine "
9766269356Snp				    "still is use.\n", t4_sge_extfree_refs());
9767269356Snp				pause("t4unload", 2 * hz);
9768269356Snp			}
9769269356Snp#ifdef TCP_OFFLOAD
9770255006Snp			sx_sunlock(&t4_uld_list_lock);
9771228561Snp#endif
9772255006Snp			sx_sunlock(&t4_list_lock);
9773269356Snp
9774269356Snp			if (t4_sge_extfree_refs() == 0) {
9775269356Snp				t4_tracer_modunload();
9776269356Snp#ifdef TCP_OFFLOAD
9777269356Snp				sx_destroy(&t4_uld_list_lock);
9778269356Snp#endif
9779269356Snp				sx_destroy(&t4_list_lock);
9780269356Snp				t4_sge_modunload();
9781269356Snp				loaded = 0;
9782269356Snp			} else {
9783269356Snp				rc = EBUSY;
9784269356Snp				loaded++;	/* undo earlier decrement */
9785269356Snp			}
9786228561Snp		}
9787269356Snpdone_unload:
9788269356Snp		sx_xunlock(&mlu);
9789228561Snp		break;
9790228561Snp	}
9791228561Snp
9792228561Snp	return (rc);
9793219392Snp}
9794219392Snp
9795309560Sjhbstatic devclass_t t4_devclass, t5_devclass, t6_devclass;
9796309560Sjhbstatic devclass_t cxgbe_devclass, cxl_devclass, cc_devclass;
9797309560Sjhbstatic devclass_t vcxgbe_devclass, vcxl_devclass, vcc_devclass;
9798218792Snp
9799249370SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, mod_event, 0);
9800218792SnpMODULE_VERSION(t4nex, 1);
9801250697SkibMODULE_DEPEND(t4nex, firmware, 1, 1, 1);
9802218792Snp
9803249370SnpDRIVER_MODULE(t5nex, pci, t5_driver, t5_devclass, mod_event, 0);
9804248925SnpMODULE_VERSION(t5nex, 1);
9805250697SkibMODULE_DEPEND(t5nex, firmware, 1, 1, 1);
9806248925Snp
9807309560SjhbDRIVER_MODULE(t6nex, pci, t6_driver, t6_devclass, mod_event, 0);
9808309560SjhbMODULE_VERSION(t6nex, 1);
9809309560SjhbMODULE_DEPEND(t6nex, firmware, 1, 1, 1);
9810309560Sjhb#ifdef DEV_NETMAP
9811309560SjhbMODULE_DEPEND(t6nex, netmap, 1, 1, 1);
9812309560Sjhb#endif /* DEV_NETMAP */
9813309560Sjhb
9814218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0);
9815218792SnpMODULE_VERSION(cxgbe, 1);
9816248925Snp
9817248925SnpDRIVER_MODULE(cxl, t5nex, cxl_driver, cxl_devclass, 0, 0);
9818248925SnpMODULE_VERSION(cxl, 1);
9819308154Sjhb
9820309560SjhbDRIVER_MODULE(cc, t6nex, cc_driver, cc_devclass, 0, 0);
9821309560SjhbMODULE_VERSION(cc, 1);
9822309560Sjhb
9823308154SjhbDRIVER_MODULE(vcxgbe, cxgbe, vcxgbe_driver, vcxgbe_devclass, 0, 0);
9824308154SjhbMODULE_VERSION(vcxgbe, 1);
9825308154Sjhb
9826308154SjhbDRIVER_MODULE(vcxl, cxl, vcxl_driver, vcxl_devclass, 0, 0);
9827308154SjhbMODULE_VERSION(vcxl, 1);
9828309560Sjhb
9829309560SjhbDRIVER_MODULE(vcc, cc, vcc_driver, vcc_devclass, 0, 0);
9830309560SjhbMODULE_VERSION(vcc, 1);
9831