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$");
30218792Snp
31218792Snp#include "opt_inet.h"
32237819Snp#include "opt_inet6.h"
33218792Snp
34218792Snp#include <sys/param.h>
35218792Snp#include <sys/conf.h>
36218792Snp#include <sys/priv.h>
37218792Snp#include <sys/kernel.h>
38218792Snp#include <sys/bus.h>
39218792Snp#include <sys/module.h>
40219286Snp#include <sys/malloc.h>
41219286Snp#include <sys/queue.h>
42219286Snp#include <sys/taskqueue.h>
43218792Snp#include <sys/pciio.h>
44218792Snp#include <dev/pci/pcireg.h>
45218792Snp#include <dev/pci/pcivar.h>
46218792Snp#include <dev/pci/pci_private.h>
47218792Snp#include <sys/firmware.h>
48219436Snp#include <sys/sbuf.h>
49218792Snp#include <sys/smp.h>
50218792Snp#include <sys/socket.h>
51218792Snp#include <sys/sockio.h>
52218792Snp#include <sys/sysctl.h>
53218792Snp#include <net/ethernet.h>
54218792Snp#include <net/if.h>
55218792Snp#include <net/if_types.h>
56218792Snp#include <net/if_dl.h>
57222003Snp#include <net/if_vlan_var.h>
58248925Snp#if defined(__i386__) || defined(__amd64__)
59248925Snp#include <vm/vm.h>
60248925Snp#include <vm/pmap.h>
61248925Snp#endif
62218792Snp
63218792Snp#include "common/common.h"
64221474Snp#include "common/t4_msg.h"
65218792Snp#include "common/t4_regs.h"
66218792Snp#include "common/t4_regs_values.h"
67218792Snp#include "t4_ioctl.h"
68222509Snp#include "t4_l2t.h"
69218792Snp
70218792Snp/* T4 bus driver interface */
71218792Snpstatic int t4_probe(device_t);
72218792Snpstatic int t4_attach(device_t);
73218792Snpstatic int t4_detach(device_t);
74218792Snpstatic device_method_t t4_methods[] = {
75218792Snp	DEVMETHOD(device_probe,		t4_probe),
76218792Snp	DEVMETHOD(device_attach,	t4_attach),
77218792Snp	DEVMETHOD(device_detach,	t4_detach),
78218792Snp
79227843Smarius	DEVMETHOD_END
80218792Snp};
81218792Snpstatic driver_t t4_driver = {
82218792Snp	"t4nex",
83218792Snp	t4_methods,
84218792Snp	sizeof(struct adapter)
85218792Snp};
86218792Snp
87218792Snp
88218792Snp/* T4 port (cxgbe) interface */
89218792Snpstatic int cxgbe_probe(device_t);
90218792Snpstatic int cxgbe_attach(device_t);
91218792Snpstatic int cxgbe_detach(device_t);
92218792Snpstatic device_method_t cxgbe_methods[] = {
93218792Snp	DEVMETHOD(device_probe,		cxgbe_probe),
94218792Snp	DEVMETHOD(device_attach,	cxgbe_attach),
95218792Snp	DEVMETHOD(device_detach,	cxgbe_detach),
96218792Snp	{ 0, 0 }
97218792Snp};
98218792Snpstatic driver_t cxgbe_driver = {
99218792Snp	"cxgbe",
100218792Snp	cxgbe_methods,
101218792Snp	sizeof(struct port_info)
102218792Snp};
103218792Snp
104218792Snpstatic d_ioctl_t t4_ioctl;
105218792Snpstatic d_open_t t4_open;
106218792Snpstatic d_close_t t4_close;
107218792Snp
108218792Snpstatic struct cdevsw t4_cdevsw = {
109218792Snp       .d_version = D_VERSION,
110218792Snp       .d_flags = 0,
111218792Snp       .d_open = t4_open,
112218792Snp       .d_close = t4_close,
113218792Snp       .d_ioctl = t4_ioctl,
114218792Snp       .d_name = "t4nex",
115218792Snp};
116218792Snp
117248925Snp/* T5 bus driver interface */
118248925Snpstatic int t5_probe(device_t);
119248925Snpstatic device_method_t t5_methods[] = {
120248925Snp	DEVMETHOD(device_probe,		t5_probe),
121248925Snp	DEVMETHOD(device_attach,	t4_attach),
122248925Snp	DEVMETHOD(device_detach,	t4_detach),
123248925Snp
124248925Snp	DEVMETHOD_END
125248925Snp};
126248925Snpstatic driver_t t5_driver = {
127248925Snp	"t5nex",
128248925Snp	t5_methods,
129248925Snp	sizeof(struct adapter)
130248925Snp};
131248925Snp
132248925Snp
133248925Snp/* T5 port (cxl) interface */
134248925Snpstatic driver_t cxl_driver = {
135248925Snp	"cxl",
136248925Snp	cxgbe_methods,
137248925Snp	sizeof(struct port_info)
138248925Snp};
139248925Snp
140248925Snpstatic struct cdevsw t5_cdevsw = {
141248925Snp       .d_version = D_VERSION,
142248925Snp       .d_flags = 0,
143248925Snp       .d_open = t4_open,
144248925Snp       .d_close = t4_close,
145248925Snp       .d_ioctl = t4_ioctl,
146248925Snp       .d_name = "t5nex",
147248925Snp};
148248925Snp
149218792Snp/* ifnet + media interface */
150218792Snpstatic void cxgbe_init(void *);
151218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t);
152218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *);
153218792Snpstatic void cxgbe_qflush(struct ifnet *);
154218792Snpstatic int cxgbe_media_change(struct ifnet *);
155218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *);
156218792Snp
157248925SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4/T5 Ethernet driver and services");
158218792Snp
159237263Snp/*
160237263Snp * Correct lock order when you need to acquire multiple locks is t4_list_lock,
161237263Snp * then ADAPTER_LOCK, then t4_uld_list_lock.
162237263Snp */
163255006Snpstatic struct sx t4_list_lock;
164259241SnpSLIST_HEAD(, adapter) t4_list;
165237263Snp#ifdef TCP_OFFLOAD
166255006Snpstatic struct sx t4_uld_list_lock;
167259241SnpSLIST_HEAD(, uld_info) t4_uld_list;
168228561Snp#endif
169218792Snp
170218792Snp/*
171228561Snp * Tunables.  See tweak_tunables() too.
172248925Snp *
173248925Snp * Each tunable is set to a default value here if it's known at compile-time.
174248925Snp * Otherwise it is set to -1 as an indication to tweak_tunables() that it should
175248925Snp * provide a reasonable default when the driver is loaded.
176248925Snp *
177248925Snp * Tunables applicable to both T4 and T5 are under hw.cxgbe.  Those specific to
178248925Snp * T5 are under hw.cxl.
179218792Snp */
180218792Snp
181218792Snp/*
182228561Snp * Number of queues for tx and rx, 10G and 1G, NIC and offload.
183218792Snp */
184228561Snp#define NTXQ_10G 16
185228561Snpstatic int t4_ntxq10g = -1;
186228561SnpTUNABLE_INT("hw.cxgbe.ntxq10g", &t4_ntxq10g);
187218792Snp
188228561Snp#define NRXQ_10G 8
189228561Snpstatic int t4_nrxq10g = -1;
190228561SnpTUNABLE_INT("hw.cxgbe.nrxq10g", &t4_nrxq10g);
191218792Snp
192228561Snp#define NTXQ_1G 4
193228561Snpstatic int t4_ntxq1g = -1;
194228561SnpTUNABLE_INT("hw.cxgbe.ntxq1g", &t4_ntxq1g);
195218792Snp
196228561Snp#define NRXQ_1G 2
197228561Snpstatic int t4_nrxq1g = -1;
198228561SnpTUNABLE_INT("hw.cxgbe.nrxq1g", &t4_nrxq1g);
199218792Snp
200264493Sscottlstatic int t4_rsrv_noflowq = 0;
201264493SscottlTUNABLE_INT("hw.cxgbe.rsrv_noflowq", &t4_rsrv_noflowq);
202264493Sscottl
203237263Snp#ifdef TCP_OFFLOAD
204228561Snp#define NOFLDTXQ_10G 8
205228561Snpstatic int t4_nofldtxq10g = -1;
206228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq10g", &t4_nofldtxq10g);
207228561Snp
208228561Snp#define NOFLDRXQ_10G 2
209228561Snpstatic int t4_nofldrxq10g = -1;
210228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq10g", &t4_nofldrxq10g);
211228561Snp
212228561Snp#define NOFLDTXQ_1G 2
213228561Snpstatic int t4_nofldtxq1g = -1;
214228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq1g", &t4_nofldtxq1g);
215228561Snp
216228561Snp#define NOFLDRXQ_1G 1
217228561Snpstatic int t4_nofldrxq1g = -1;
218228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq1g", &t4_nofldrxq1g);
219228561Snp#endif
220228561Snp
221270297Snp#ifdef DEV_NETMAP
222270297Snp#define NNMTXQ_10G 2
223270297Snpstatic int t4_nnmtxq10g = -1;
224270297SnpTUNABLE_INT("hw.cxgbe.nnmtxq10g", &t4_nnmtxq10g);
225270297Snp
226270297Snp#define NNMRXQ_10G 2
227270297Snpstatic int t4_nnmrxq10g = -1;
228270297SnpTUNABLE_INT("hw.cxgbe.nnmrxq10g", &t4_nnmrxq10g);
229270297Snp
230270297Snp#define NNMTXQ_1G 1
231270297Snpstatic int t4_nnmtxq1g = -1;
232270297SnpTUNABLE_INT("hw.cxgbe.nnmtxq1g", &t4_nnmtxq1g);
233270297Snp
234270297Snp#define NNMRXQ_1G 1
235270297Snpstatic int t4_nnmrxq1g = -1;
236270297SnpTUNABLE_INT("hw.cxgbe.nnmrxq1g", &t4_nnmrxq1g);
237270297Snp#endif
238270297Snp
239218792Snp/*
240218792Snp * Holdoff parameters for 10G and 1G ports.
241218792Snp */
242228561Snp#define TMR_IDX_10G 1
243228561Snpstatic int t4_tmr_idx_10g = TMR_IDX_10G;
244228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &t4_tmr_idx_10g);
245218792Snp
246234833Snp#define PKTC_IDX_10G (-1)
247228561Snpstatic int t4_pktc_idx_10g = PKTC_IDX_10G;
248228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &t4_pktc_idx_10g);
249218792Snp
250228561Snp#define TMR_IDX_1G 1
251228561Snpstatic int t4_tmr_idx_1g = TMR_IDX_1G;
252228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &t4_tmr_idx_1g);
253218792Snp
254234833Snp#define PKTC_IDX_1G (-1)
255228561Snpstatic int t4_pktc_idx_1g = PKTC_IDX_1G;
256228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &t4_pktc_idx_1g);
257218792Snp
258218792Snp/*
259218792Snp * Size (# of entries) of each tx and rx queue.
260218792Snp */
261228561Snpstatic unsigned int t4_qsize_txq = TX_EQ_QSIZE;
262228561SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &t4_qsize_txq);
263218792Snp
264228561Snpstatic unsigned int t4_qsize_rxq = RX_IQ_QSIZE;
265228561SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &t4_qsize_rxq);
266218792Snp
267218792Snp/*
268228561Snp * Interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively).
269218792Snp */
270228561Snpstatic int t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX;
271228561SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types);
272218792Snp
273218792Snp/*
274228561Snp * Configuration file.
275218792Snp */
276248925Snp#define DEFAULT_CF	"default"
277248925Snp#define FLASH_CF	"flash"
278248925Snp#define UWIRE_CF	"uwire"
279249376Snp#define FPGA_CF		"fpga"
280248925Snpstatic char t4_cfg_file[32] = DEFAULT_CF;
281228561SnpTUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file));
282218792Snp
283228561Snp/*
284271961Snp * PAUSE settings (bit 0, 1 = rx_pause, tx_pause respectively).
285271961Snp * rx_pause = 1 to heed incoming PAUSE frames, 0 to ignore them.
286271961Snp * tx_pause = 1 to emit PAUSE frames when the rx FIFO reaches its high water
287271961Snp *            mark or when signalled to do so, 0 to never emit PAUSE.
288271961Snp */
289271961Snpstatic int t4_pause_settings = PAUSE_TX | PAUSE_RX;
290271961SnpTUNABLE_INT("hw.cxgbe.pause_settings", &t4_pause_settings);
291271961Snp
292271961Snp/*
293247347Snp * Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed,
294247347Snp * encouraged respectively).
295247347Snp */
296247347Snpstatic unsigned int t4_fw_install = 1;
297247347SnpTUNABLE_INT("hw.cxgbe.fw_install", &t4_fw_install);
298247347Snp
299247347Snp/*
300228561Snp * ASIC features that will be used.  Disable the ones you don't want so that the
301228561Snp * chip resources aren't wasted on features that will not be used.
302228561Snp */
303228561Snpstatic int t4_linkcaps_allowed = 0;	/* No DCBX, PPP, etc. by default */
304228561SnpTUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed);
305221474Snp
306228561Snpstatic int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC;
307228561SnpTUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed);
308228561Snp
309238028Snpstatic int t4_toecaps_allowed = -1;
310228561SnpTUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed);
311228561Snp
312228561Snpstatic int t4_rdmacaps_allowed = 0;
313228561SnpTUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed);
314228561Snp
315228561Snpstatic int t4_iscsicaps_allowed = 0;
316228561SnpTUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed);
317228561Snp
318228561Snpstatic int t4_fcoecaps_allowed = 0;
319228561SnpTUNABLE_INT("hw.cxgbe.fcoecaps_allowed", &t4_fcoecaps_allowed);
320228561Snp
321248925Snpstatic int t5_write_combine = 0;
322248925SnpTUNABLE_INT("hw.cxl.write_combine", &t5_write_combine);
323248925Snp
324218792Snpstruct intrs_and_queues {
325270297Snp	uint16_t intr_type;	/* INTx, MSI, or MSI-X */
326270297Snp	uint16_t nirq;		/* Total # of vectors */
327270297Snp	uint16_t intr_flags_10g;/* Interrupt flags for each 10G port */
328270297Snp	uint16_t intr_flags_1g;	/* Interrupt flags for each 1G port */
329270297Snp	uint16_t ntxq10g;	/* # of NIC txq's for each 10G port */
330270297Snp	uint16_t nrxq10g;	/* # of NIC rxq's for each 10G port */
331270297Snp	uint16_t ntxq1g;	/* # of NIC txq's for each 1G port */
332270297Snp	uint16_t nrxq1g;	/* # of NIC rxq's for each 1G port */
333270297Snp	uint16_t rsrv_noflowq;	/* Flag whether to reserve queue 0 */
334237263Snp#ifdef TCP_OFFLOAD
335270297Snp	uint16_t nofldtxq10g;	/* # of TOE txq's for each 10G port */
336270297Snp	uint16_t nofldrxq10g;	/* # of TOE rxq's for each 10G port */
337270297Snp	uint16_t nofldtxq1g;	/* # of TOE txq's for each 1G port */
338270297Snp	uint16_t nofldrxq1g;	/* # of TOE rxq's for each 1G port */
339228561Snp#endif
340270297Snp#ifdef DEV_NETMAP
341270297Snp	uint16_t nnmtxq10g;	/* # of netmap txq's for each 10G port */
342270297Snp	uint16_t nnmrxq10g;	/* # of netmap rxq's for each 10G port */
343270297Snp	uint16_t nnmtxq1g;	/* # of netmap txq's for each 1G port */
344270297Snp	uint16_t nnmrxq1g;	/* # of netmap rxq's for each 1G port */
345270297Snp#endif
346218792Snp};
347218792Snp
348221474Snpstruct filter_entry {
349221474Snp        uint32_t valid:1;	/* filter allocated and valid */
350221474Snp        uint32_t locked:1;	/* filter is administratively locked */
351221474Snp        uint32_t pending:1;	/* filter action is pending firmware reply */
352221474Snp	uint32_t smtidx:8;	/* Source MAC Table index for smac */
353222509Snp	struct l2t_entry *l2t;	/* Layer Two Table entry for dmac */
354221474Snp
355221474Snp        struct t4_filter_specification fs;
356221474Snp};
357221474Snp
358248925Snpstatic int map_bars_0_and_4(struct adapter *);
359248925Snpstatic int map_bar_2(struct adapter *);
360218792Snpstatic void setup_memwin(struct adapter *);
361248925Snpstatic int validate_mem_range(struct adapter *, uint32_t, int);
362256791Snpstatic int fwmtype_to_hwmtype(int);
363248925Snpstatic int validate_mt_off_len(struct adapter *, int, uint32_t, int,
364248925Snp    uint32_t *);
365248925Snpstatic void memwin_info(struct adapter *, int, uint32_t *, uint32_t *);
366248925Snpstatic uint32_t position_memwin(struct adapter *, int, uint32_t);
367218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int,
368218792Snp    struct intrs_and_queues *);
369218792Snpstatic int prep_firmware(struct adapter *);
370248925Snpstatic int partition_resources(struct adapter *, const struct firmware *,
371248925Snp    const char *);
372228561Snpstatic int get_params__pre_init(struct adapter *);
373228561Snpstatic int get_params__post_init(struct adapter *);
374247291Snpstatic int set_params__post_init(struct adapter *);
375218792Snpstatic void t4_set_desc(struct adapter *);
376270297Snpstatic void build_medialist(struct port_info *, struct ifmedia *);
377218792Snpstatic int cxgbe_init_synchronized(struct port_info *);
378218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *);
379240453Snpstatic int setup_intr_handlers(struct adapter *);
380228561Snpstatic void quiesce_eq(struct adapter *, struct sge_eq *);
381228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *);
382228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *);
383218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid,
384228561Snp    driver_intr_t *, void *, char *);
385218792Snpstatic int t4_free_irq(struct adapter *, struct irq *);
386218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int,
387218792Snp    unsigned int);
388218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *);
389218792Snpstatic void cxgbe_tick(void *);
390237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t);
391228561Snpstatic int cpl_not_handled(struct sge_iq *, const struct rss_header *,
392228561Snp    struct mbuf *);
393237263Snpstatic int an_not_handled(struct sge_iq *, const struct rsp_ctrl *);
394239336Snpstatic int fw_msg_not_handled(struct adapter *, const __be64 *);
395218792Snpstatic int t4_sysctls(struct adapter *);
396218792Snpstatic int cxgbe_sysctls(struct port_info *);
397219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS);
398228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS);
399252747Snpstatic int sysctl_btphy(SYSCTL_HANDLER_ARGS);
400264493Sscottlstatic int sysctl_noflowq(SYSCTL_HANDLER_ARGS);
401218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS);
402218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS);
403218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS);
404218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS);
405271961Snpstatic int sysctl_pause_settings(SYSCTL_HANDLER_ARGS);
406218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS);
407253890Snpstatic int sysctl_temperature(SYSCTL_HANDLER_ARGS);
408231115Snp#ifdef SBUF_DRAIN
409228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS);
410247122Snpstatic int sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS);
411247122Snpstatic int sysctl_cim_la(SYSCTL_HANDLER_ARGS);
412251213Snpstatic int sysctl_cim_ma_la(SYSCTL_HANDLER_ARGS);
413251213Snpstatic int sysctl_cim_pif_la(SYSCTL_HANDLER_ARGS);
414247122Snpstatic int sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS);
415228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS);
416228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS);
417222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS);
418228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS);
419228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS);
420228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS);
421253701Snpstatic int sysctl_linkdnrc(SYSCTL_HANDLER_ARGS);
422228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS);
423251213Snpstatic int sysctl_mps_tcam(SYSCTL_HANDLER_ARGS);
424228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS);
425228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS);
426228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS);
427228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS);
428228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS);
429228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS);
430251213Snpstatic int sysctl_tp_la(SYSCTL_HANDLER_ARGS);
431228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS);
432251213Snpstatic int sysctl_ulprx_la(SYSCTL_HANDLER_ARGS);
433249392Snpstatic int sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS);
434231115Snp#endif
435219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *);
436221474Snpstatic uint32_t fconf_to_mode(uint32_t);
437221474Snpstatic uint32_t mode_to_fconf(uint32_t);
438221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *);
439221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *);
440221474Snpstatic int set_filter_mode(struct adapter *, uint32_t);
441222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t);
442221474Snpstatic int get_filter(struct adapter *, struct t4_filter *);
443221474Snpstatic int set_filter(struct adapter *, struct t4_filter *);
444221474Snpstatic int del_filter(struct adapter *, struct t4_filter *);
445222509Snpstatic void clear_filter(struct filter_entry *);
446221474Snpstatic int set_filter_wr(struct adapter *, int);
447221474Snpstatic int del_filter_wr(struct adapter *, int);
448222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *);
449245274Snpstatic int load_fw(struct adapter *, struct t4_data *);
450248925Snpstatic int read_card_mem(struct adapter *, int, struct t4_mem_range *);
451241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *);
452259142Snpstatic int set_sched_class(struct adapter *, struct t4_sched_params *);
453259142Snpstatic int set_sched_queue(struct adapter *, struct t4_sched_queue *);
454237263Snp#ifdef TCP_OFFLOAD
455228561Snpstatic int toe_capability(struct port_info *, int);
456228561Snp#endif
457249370Snpstatic int mod_event(module_t, int, void *);
458218792Snp
459248925Snpstruct {
460218792Snp	uint16_t device;
461218792Snp	char *desc;
462218792Snp} t4_pciids[] = {
463237587Snp	{0xa000, "Chelsio Terminator 4 FPGA"},
464237587Snp	{0x4400, "Chelsio T440-dbg"},
465237587Snp	{0x4401, "Chelsio T420-CR"},
466237587Snp	{0x4402, "Chelsio T422-CR"},
467237587Snp	{0x4403, "Chelsio T440-CR"},
468237587Snp	{0x4404, "Chelsio T420-BCH"},
469237587Snp	{0x4405, "Chelsio T440-BCH"},
470237587Snp	{0x4406, "Chelsio T440-CH"},
471237587Snp	{0x4407, "Chelsio T420-SO"},
472237587Snp	{0x4408, "Chelsio T420-CX"},
473237587Snp	{0x4409, "Chelsio T420-BT"},
474237587Snp	{0x440a, "Chelsio T404-BT"},
475244580Snp	{0x440e, "Chelsio T440-LP-CR"},
476248925Snp}, t5_pciids[] = {
477248925Snp	{0xb000, "Chelsio Terminator 5 FPGA"},
478248925Snp	{0x5400, "Chelsio T580-dbg"},
479253699Snp	{0x5401,  "Chelsio T520-CR"},		/* 2 x 10G */
480253699Snp	{0x5402,  "Chelsio T522-CR"},		/* 2 x 10G, 2 X 1G */
481253217Snp	{0x5403,  "Chelsio T540-CR"},		/* 4 x 10G */
482253699Snp	{0x5407,  "Chelsio T520-SO"},		/* 2 x 10G, nomem */
483253699Snp	{0x5409,  "Chelsio T520-BT"},		/* 2 x 10GBaseT */
484253699Snp	{0x540a,  "Chelsio T504-BT"},		/* 4 x 1G */
485253699Snp	{0x540d,  "Chelsio T580-CR"},		/* 2 x 40G */
486253699Snp	{0x540e,  "Chelsio T540-LP-CR"},	/* 4 x 10G */
487250093Snp	{0x5410,  "Chelsio T580-LP-CR"},	/* 2 x 40G */
488253699Snp	{0x5411,  "Chelsio T520-LL-CR"},	/* 2 x 10G */
489253699Snp	{0x5412,  "Chelsio T560-CR"},		/* 1 x 40G, 2 x 10G */
490253699Snp	{0x5414,  "Chelsio T580-LP-SO-CR"},	/* 2 x 40G, nomem */
491249393Snp#ifdef notyet
492249393Snp	{0x5404,  "Chelsio T520-BCH"},
493249393Snp	{0x5405,  "Chelsio T540-BCH"},
494249393Snp	{0x5406,  "Chelsio T540-CH"},
495253699Snp	{0x5408,  "Chelsio T520-CX"},
496249393Snp	{0x540b,  "Chelsio B520-SR"},
497249393Snp	{0x540c,  "Chelsio B504-BT"},
498249393Snp	{0x540f,  "Chelsio Amsterdam"},
499253699Snp	{0x5413,  "Chelsio T580-CHR"},
500249393Snp#endif
501218792Snp};
502218792Snp
503237263Snp#ifdef TCP_OFFLOAD
504237263Snp/*
505237263Snp * service_iq() has an iq and needs the fl.  Offset of fl from the iq should be
506237263Snp * exactly the same for both rxq and ofld_rxq.
507237263Snp */
508237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq));
509228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl));
510228561Snp#endif
511228561Snp
512239336Snp/* No easy way to include t4_msg.h before adapter.h so we check this way */
513240452SnpCTASSERT(nitems(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS);
514240452SnpCTASSERT(nitems(((struct adapter *)0)->fw_msg_handler) == NUM_FW6_TYPES);
515239336Snp
516265425SnpCTASSERT(sizeof(struct cluster_metadata) <= CL_METADATA_SIZE);
517265425Snp
518218792Snpstatic int
519218792Snpt4_probe(device_t dev)
520218792Snp{
521218792Snp	int i;
522218792Snp	uint16_t v = pci_get_vendor(dev);
523218792Snp	uint16_t d = pci_get_device(dev);
524237587Snp	uint8_t f = pci_get_function(dev);
525218792Snp
526218792Snp	if (v != PCI_VENDOR_ID_CHELSIO)
527218792Snp		return (ENXIO);
528218792Snp
529237587Snp	/* Attach only to PF0 of the FPGA */
530237587Snp	if (d == 0xa000 && f != 0)
531237587Snp		return (ENXIO);
532237587Snp
533240452Snp	for (i = 0; i < nitems(t4_pciids); i++) {
534237587Snp		if (d == t4_pciids[i].device) {
535218792Snp			device_set_desc(dev, t4_pciids[i].desc);
536218792Snp			return (BUS_PROBE_DEFAULT);
537218792Snp		}
538218792Snp	}
539218792Snp
540218792Snp	return (ENXIO);
541218792Snp}
542218792Snp
543218792Snpstatic int
544248925Snpt5_probe(device_t dev)
545248925Snp{
546248925Snp	int i;
547248925Snp	uint16_t v = pci_get_vendor(dev);
548248925Snp	uint16_t d = pci_get_device(dev);
549248925Snp	uint8_t f = pci_get_function(dev);
550248925Snp
551248925Snp	if (v != PCI_VENDOR_ID_CHELSIO)
552248925Snp		return (ENXIO);
553248925Snp
554248925Snp	/* Attach only to PF0 of the FPGA */
555248925Snp	if (d == 0xb000 && f != 0)
556248925Snp		return (ENXIO);
557248925Snp
558248925Snp	for (i = 0; i < nitems(t5_pciids); i++) {
559248925Snp		if (d == t5_pciids[i].device) {
560248925Snp			device_set_desc(dev, t5_pciids[i].desc);
561248925Snp			return (BUS_PROBE_DEFAULT);
562248925Snp		}
563248925Snp	}
564248925Snp
565248925Snp	return (ENXIO);
566248925Snp}
567248925Snp
568248925Snpstatic int
569218792Snpt4_attach(device_t dev)
570218792Snp{
571218792Snp	struct adapter *sc;
572218792Snp	int rc = 0, i, n10g, n1g, rqidx, tqidx;
573218792Snp	struct intrs_and_queues iaq;
574218792Snp	struct sge *s;
575237263Snp#ifdef TCP_OFFLOAD
576228561Snp	int ofld_rqidx, ofld_tqidx;
577228561Snp#endif
578270297Snp#ifdef DEV_NETMAP
579270297Snp	int nm_rqidx, nm_tqidx;
580270297Snp#endif
581218792Snp
582218792Snp	sc = device_get_softc(dev);
583218792Snp	sc->dev = dev;
584218792Snp
585218792Snp	pci_enable_busmaster(dev);
586222085Snp	if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) {
587228561Snp		uint32_t v;
588228561Snp
589222085Snp		pci_set_max_read_req(dev, 4096);
590240680Sgavin		v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2);
591240680Sgavin		v |= PCIEM_CTL_RELAXED_ORD_ENABLE;
592240680Sgavin		pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2);
593222085Snp	}
594222085Snp
595253691Snp	sc->traceq = -1;
596253691Snp	mtx_init(&sc->ifp_lock, sc->ifp_lockname, 0, MTX_DEF);
597253691Snp	snprintf(sc->ifp_lockname, sizeof(sc->ifp_lockname), "%s tracer",
598253691Snp	    device_get_nameunit(dev));
599253691Snp
600218792Snp	snprintf(sc->lockname, sizeof(sc->lockname), "%s",
601218792Snp	    device_get_nameunit(dev));
602218792Snp	mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF);
603255006Snp	sx_xlock(&t4_list_lock);
604228561Snp	SLIST_INSERT_HEAD(&t4_list, sc, link);
605255006Snp	sx_xunlock(&t4_list_lock);
606218792Snp
607228561Snp	mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF);
608228561Snp	TAILQ_INIT(&sc->sfl);
609228561Snp	callout_init(&sc->sfl_callout, CALLOUT_MPSAFE);
610228561Snp
611248925Snp	rc = map_bars_0_and_4(sc);
612218792Snp	if (rc != 0)
613218792Snp		goto done; /* error message displayed already */
614218792Snp
615237587Snp	/*
616237587Snp	 * This is the real PF# to which we're attaching.  Works from within PCI
617237587Snp	 * passthrough environments too, where pci_get_function() could return a
618237587Snp	 * different PF# depending on the passthrough configuration.  We need to
619237587Snp	 * use the real PF# in all our communication with the firmware.
620237587Snp	 */
621237587Snp	sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI));
622237587Snp	sc->mbox = sc->pf;
623237587Snp
624218792Snp	memset(sc->chan_map, 0xff, sizeof(sc->chan_map));
625237263Snp	sc->an_handler = an_not_handled;
626240452Snp	for (i = 0; i < nitems(sc->cpl_handler); i++)
627228561Snp		sc->cpl_handler[i] = cpl_not_handled;
628240452Snp	for (i = 0; i < nitems(sc->fw_msg_handler); i++)
629239336Snp		sc->fw_msg_handler[i] = fw_msg_not_handled;
630239338Snp	t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, t4_filter_rpl);
631253691Snp	t4_register_cpl_handler(sc, CPL_TRACE_PKT, t4_trace_pkt);
632253691Snp	t4_register_cpl_handler(sc, CPL_TRACE_PKT_T5, t5_trace_pkt);
633248925Snp	t4_init_sge_cpl_handlers(sc);
634218792Snp
635218792Snp	/* Prepare the adapter for operation */
636218792Snp	rc = -t4_prep_adapter(sc);
637218792Snp	if (rc != 0) {
638218792Snp		device_printf(dev, "failed to prepare adapter: %d.\n", rc);
639218792Snp		goto done;
640218792Snp	}
641218792Snp
642228561Snp	/*
643228561Snp	 * Do this really early, with the memory windows set up even before the
644228561Snp	 * character device.  The userland tool's register i/o and mem read
645228561Snp	 * will work even in "recovery mode".
646228561Snp	 */
647228561Snp	setup_memwin(sc);
648248925Snp	sc->cdev = make_dev(is_t4(sc) ? &t4_cdevsw : &t5_cdevsw,
649248925Snp	    device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "%s",
650248925Snp	    device_get_nameunit(dev));
651248925Snp	if (sc->cdev == NULL)
652248925Snp		device_printf(dev, "failed to create nexus char device.\n");
653248925Snp	else
654248925Snp		sc->cdev->si_drv1 = sc;
655218792Snp
656228561Snp	/* Go no further if recovery mode has been requested. */
657228561Snp	if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) {
658228561Snp		device_printf(dev, "recovery mode.\n");
659228561Snp		goto done;
660228561Snp	}
661228561Snp
662218792Snp	/* Prepare the firmware for operation */
663218792Snp	rc = prep_firmware(sc);
664218792Snp	if (rc != 0)
665218792Snp		goto done; /* error message displayed already */
666218792Snp
667248925Snp	rc = get_params__post_init(sc);
668228561Snp	if (rc != 0)
669228561Snp		goto done; /* error message displayed already */
670222551Snp
671248925Snp	rc = set_params__post_init(sc);
672228561Snp	if (rc != 0)
673228561Snp		goto done; /* error message displayed already */
674218792Snp
675248925Snp	rc = map_bar_2(sc);
676228561Snp	if (rc != 0)
677228561Snp		goto done; /* error message displayed already */
678218792Snp
679218792Snp	rc = t4_create_dma_tag(sc);
680218792Snp	if (rc != 0)
681218792Snp		goto done; /* error message displayed already */
682218792Snp
683218792Snp	/*
684218792Snp	 * First pass over all the ports - allocate VIs and initialize some
685218792Snp	 * basic parameters like mac address, port type, etc.  We also figure
686218792Snp	 * out whether a port is 10G or 1G and use that information when
687218792Snp	 * calculating how many interrupts to attempt to allocate.
688218792Snp	 */
689218792Snp	n10g = n1g = 0;
690218792Snp	for_each_port(sc, i) {
691218792Snp		struct port_info *pi;
692218792Snp
693218792Snp		pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK);
694218792Snp		sc->port[i] = pi;
695218792Snp
696218792Snp		/* These must be set before t4_port_init */
697218792Snp		pi->adapter = sc;
698218792Snp		pi->port_id = i;
699218792Snp
700218792Snp		/* Allocate the vi and initialize parameters like mac addr */
701218792Snp		rc = -t4_port_init(pi, sc->mbox, sc->pf, 0);
702218792Snp		if (rc != 0) {
703218792Snp			device_printf(dev, "unable to initialize port %d: %d\n",
704218792Snp			    i, rc);
705218792Snp			free(pi, M_CXGBE);
706222510Snp			sc->port[i] = NULL;
707222510Snp			goto done;
708218792Snp		}
709271961Snp
710271961Snp		pi->link_cfg.requested_fc &= ~(PAUSE_TX | PAUSE_RX);
711271961Snp		pi->link_cfg.requested_fc |= t4_pause_settings;
712271961Snp		pi->link_cfg.fc &= ~(PAUSE_TX | PAUSE_RX);
713271961Snp		pi->link_cfg.fc |= t4_pause_settings;
714271961Snp
715270297Snp		rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg);
716270297Snp		if (rc != 0) {
717270297Snp			device_printf(dev, "port %d l1cfg failed: %d\n", i, rc);
718270297Snp			free(pi, M_CXGBE);
719270297Snp			sc->port[i] = NULL;
720270297Snp			goto done;
721270297Snp		}
722218792Snp
723218792Snp		snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d",
724218792Snp		    device_get_nameunit(dev), i);
725218792Snp		mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
726253691Snp		sc->chan_map[pi->tx_chan] = i;
727218792Snp
728250092Snp		if (is_10G_port(pi) || is_40G_port(pi)) {
729218792Snp			n10g++;
730228561Snp			pi->tmr_idx = t4_tmr_idx_10g;
731228561Snp			pi->pktc_idx = t4_pktc_idx_10g;
732218792Snp		} else {
733218792Snp			n1g++;
734228561Snp			pi->tmr_idx = t4_tmr_idx_1g;
735228561Snp			pi->pktc_idx = t4_pktc_idx_1g;
736218792Snp		}
737218792Snp
738218792Snp		pi->xact_addr_filt = -1;
739252747Snp		pi->linkdnrc = -1;
740218792Snp
741228561Snp		pi->qsize_rxq = t4_qsize_rxq;
742228561Snp		pi->qsize_txq = t4_qsize_txq;
743218792Snp
744248925Snp		pi->dev = device_add_child(dev, is_t4(sc) ? "cxgbe" : "cxl", -1);
745218792Snp		if (pi->dev == NULL) {
746218792Snp			device_printf(dev,
747218792Snp			    "failed to add device for port %d.\n", i);
748218792Snp			rc = ENXIO;
749218792Snp			goto done;
750218792Snp		}
751218792Snp		device_set_softc(pi->dev, pi);
752218792Snp	}
753218792Snp
754218792Snp	/*
755218792Snp	 * Interrupt type, # of interrupts, # of rx/tx queues, etc.
756218792Snp	 */
757218792Snp	rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq);
758218792Snp	if (rc != 0)
759218792Snp		goto done; /* error message displayed already */
760218792Snp
761218792Snp	sc->intr_type = iaq.intr_type;
762218792Snp	sc->intr_count = iaq.nirq;
763218792Snp
764218792Snp	s = &sc->sge;
765218792Snp	s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g;
766218792Snp	s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g;
767220873Snp	s->neq = s->ntxq + s->nrxq;	/* the free list in an rxq is an eq */
768228561Snp	s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */
769218792Snp	s->niq = s->nrxq + 1;		/* 1 extra for firmware event queue */
770237263Snp#ifdef TCP_OFFLOAD
771228561Snp	if (is_offload(sc)) {
772228561Snp		s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g;
773228561Snp		s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g;
774228561Snp		s->neq += s->nofldtxq + s->nofldrxq;
775228561Snp		s->niq += s->nofldrxq;
776228561Snp
777228561Snp		s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq),
778228561Snp		    M_CXGBE, M_ZERO | M_WAITOK);
779228561Snp		s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq),
780228561Snp		    M_CXGBE, M_ZERO | M_WAITOK);
781228561Snp	}
782228561Snp#endif
783270297Snp#ifdef DEV_NETMAP
784270297Snp	s->nnmrxq = n10g * iaq.nnmrxq10g + n1g * iaq.nnmrxq1g;
785270297Snp	s->nnmtxq = n10g * iaq.nnmtxq10g + n1g * iaq.nnmtxq1g;
786270297Snp	s->neq += s->nnmtxq + s->nnmrxq;
787270297Snp	s->niq += s->nnmrxq;
788228561Snp
789270297Snp	s->nm_rxq = malloc(s->nnmrxq * sizeof(struct sge_nm_rxq),
790270297Snp	    M_CXGBE, M_ZERO | M_WAITOK);
791270297Snp	s->nm_txq = malloc(s->nnmtxq * sizeof(struct sge_nm_txq),
792270297Snp	    M_CXGBE, M_ZERO | M_WAITOK);
793270297Snp#endif
794270297Snp
795228561Snp	s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE,
796220873Snp	    M_ZERO | M_WAITOK);
797218792Snp	s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE,
798218792Snp	    M_ZERO | M_WAITOK);
799218792Snp	s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE,
800218792Snp	    M_ZERO | M_WAITOK);
801218792Snp	s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE,
802218792Snp	    M_ZERO | M_WAITOK);
803218792Snp	s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE,
804218792Snp	    M_ZERO | M_WAITOK);
805218792Snp
806218792Snp	sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE,
807218792Snp	    M_ZERO | M_WAITOK);
808218792Snp
809228561Snp	t4_init_l2t(sc, M_WAITOK);
810222509Snp
811218792Snp	/*
812218792Snp	 * Second pass over the ports.  This time we know the number of rx and
813218792Snp	 * tx queues that each port should get.
814218792Snp	 */
815218792Snp	rqidx = tqidx = 0;
816237263Snp#ifdef TCP_OFFLOAD
817228561Snp	ofld_rqidx = ofld_tqidx = 0;
818228561Snp#endif
819270297Snp#ifdef DEV_NETMAP
820270297Snp	nm_rqidx = nm_tqidx = 0;
821270297Snp#endif
822218792Snp	for_each_port(sc, i) {
823218792Snp		struct port_info *pi = sc->port[i];
824218792Snp
825218792Snp		if (pi == NULL)
826218792Snp			continue;
827218792Snp
828218792Snp		pi->first_rxq = rqidx;
829218792Snp		pi->first_txq = tqidx;
830250092Snp		if (is_10G_port(pi) || is_40G_port(pi)) {
831270297Snp			pi->flags |= iaq.intr_flags_10g;
832228561Snp			pi->nrxq = iaq.nrxq10g;
833228561Snp			pi->ntxq = iaq.ntxq10g;
834228561Snp		} else {
835270297Snp			pi->flags |= iaq.intr_flags_1g;
836228561Snp			pi->nrxq = iaq.nrxq1g;
837228561Snp			pi->ntxq = iaq.ntxq1g;
838228561Snp		}
839218792Snp
840264493Sscottl		if (pi->ntxq > 1)
841264493Sscottl			pi->rsrv_noflowq = iaq.rsrv_noflowq ? 1 : 0;
842264493Sscottl		else
843264493Sscottl			pi->rsrv_noflowq = 0;
844264493Sscottl
845218792Snp		rqidx += pi->nrxq;
846218792Snp		tqidx += pi->ntxq;
847237263Snp#ifdef TCP_OFFLOAD
848228561Snp		if (is_offload(sc)) {
849228561Snp			pi->first_ofld_rxq = ofld_rqidx;
850228561Snp			pi->first_ofld_txq = ofld_tqidx;
851250092Snp			if (is_10G_port(pi) || is_40G_port(pi)) {
852228561Snp				pi->nofldrxq = iaq.nofldrxq10g;
853228561Snp				pi->nofldtxq = iaq.nofldtxq10g;
854228561Snp			} else {
855228561Snp				pi->nofldrxq = iaq.nofldrxq1g;
856228561Snp				pi->nofldtxq = iaq.nofldtxq1g;
857228561Snp			}
858228561Snp			ofld_rqidx += pi->nofldrxq;
859228561Snp			ofld_tqidx += pi->nofldtxq;
860228561Snp		}
861228561Snp#endif
862270297Snp#ifdef DEV_NETMAP
863270297Snp		pi->first_nm_rxq = nm_rqidx;
864270297Snp		pi->first_nm_txq = nm_tqidx;
865270297Snp		if (is_10G_port(pi) || is_40G_port(pi)) {
866270297Snp			pi->nnmrxq = iaq.nnmrxq10g;
867270297Snp			pi->nnmtxq = iaq.nnmtxq10g;
868270297Snp		} else {
869270297Snp			pi->nnmrxq = iaq.nnmrxq1g;
870270297Snp			pi->nnmtxq = iaq.nnmtxq1g;
871270297Snp		}
872270297Snp		nm_rqidx += pi->nnmrxq;
873270297Snp		nm_tqidx += pi->nnmtxq;
874270297Snp#endif
875218792Snp	}
876218792Snp
877240453Snp	rc = setup_intr_handlers(sc);
878240453Snp	if (rc != 0) {
879240453Snp		device_printf(dev,
880240453Snp		    "failed to setup interrupt handlers: %d\n", rc);
881240453Snp		goto done;
882240453Snp	}
883240453Snp
884218792Snp	rc = bus_generic_attach(dev);
885218792Snp	if (rc != 0) {
886218792Snp		device_printf(dev,
887218792Snp		    "failed to attach all child ports: %d\n", rc);
888218792Snp		goto done;
889218792Snp	}
890218792Snp
891218792Snp	device_printf(dev,
892228561Snp	    "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n",
893228561Snp	    sc->params.pci.width, sc->params.nports, sc->intr_count,
894228561Snp	    sc->intr_type == INTR_MSIX ? "MSI-X" :
895228561Snp	    (sc->intr_type == INTR_MSI ? "MSI" : "INTx"),
896228561Snp	    sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq);
897228561Snp
898218792Snp	t4_set_desc(sc);
899218792Snp
900218792Snpdone:
901228561Snp	if (rc != 0 && sc->cdev) {
902228561Snp		/* cdev was created and so cxgbetool works; recover that way. */
903228561Snp		device_printf(dev,
904228561Snp		    "error during attach, adapter is now in recovery mode.\n");
905228561Snp		rc = 0;
906228561Snp	}
907228561Snp
908218792Snp	if (rc != 0)
909218792Snp		t4_detach(dev);
910228561Snp	else
911228561Snp		t4_sysctls(sc);
912218792Snp
913218792Snp	return (rc);
914218792Snp}
915218792Snp
916218792Snp/*
917218792Snp * Idempotent
918218792Snp */
919218792Snpstatic int
920218792Snpt4_detach(device_t dev)
921218792Snp{
922218792Snp	struct adapter *sc;
923218792Snp	struct port_info *pi;
924228561Snp	int i, rc;
925218792Snp
926218792Snp	sc = device_get_softc(dev);
927218792Snp
928228561Snp	if (sc->flags & FULL_INIT_DONE)
929228561Snp		t4_intr_disable(sc);
930228561Snp
931228561Snp	if (sc->cdev) {
932218792Snp		destroy_dev(sc->cdev);
933228561Snp		sc->cdev = NULL;
934228561Snp	}
935218792Snp
936228561Snp	rc = bus_generic_detach(dev);
937228561Snp	if (rc) {
938228561Snp		device_printf(dev,
939228561Snp		    "failed to detach child devices: %d\n", rc);
940228561Snp		return (rc);
941228561Snp	}
942228561Snp
943240453Snp	for (i = 0; i < sc->intr_count; i++)
944240453Snp		t4_free_irq(sc, &sc->irq[i]);
945240453Snp
946218792Snp	for (i = 0; i < MAX_NPORTS; i++) {
947218792Snp		pi = sc->port[i];
948218792Snp		if (pi) {
949270297Snp			t4_free_vi(sc, sc->mbox, sc->pf, 0, pi->viid);
950218792Snp			if (pi->dev)
951218792Snp				device_delete_child(dev, pi->dev);
952218792Snp
953218792Snp			mtx_destroy(&pi->pi_lock);
954218792Snp			free(pi, M_CXGBE);
955218792Snp		}
956218792Snp	}
957218792Snp
958228561Snp	if (sc->flags & FULL_INIT_DONE)
959228561Snp		adapter_full_uninit(sc);
960228561Snp
961218792Snp	if (sc->flags & FW_OK)
962218792Snp		t4_fw_bye(sc, sc->mbox);
963218792Snp
964219944Snp	if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX)
965218792Snp		pci_release_msi(dev);
966218792Snp
967218792Snp	if (sc->regs_res)
968218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid,
969218792Snp		    sc->regs_res);
970218792Snp
971248925Snp	if (sc->udbs_res)
972248925Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->udbs_rid,
973248925Snp		    sc->udbs_res);
974248925Snp
975218792Snp	if (sc->msix_res)
976218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid,
977218792Snp		    sc->msix_res);
978218792Snp
979222509Snp	if (sc->l2t)
980222509Snp		t4_free_l2t(sc->l2t);
981222509Snp
982237263Snp#ifdef TCP_OFFLOAD
983228561Snp	free(sc->sge.ofld_rxq, M_CXGBE);
984228561Snp	free(sc->sge.ofld_txq, M_CXGBE);
985228561Snp#endif
986270297Snp#ifdef DEV_NETMAP
987270297Snp	free(sc->sge.nm_rxq, M_CXGBE);
988270297Snp	free(sc->sge.nm_txq, M_CXGBE);
989270297Snp#endif
990218792Snp	free(sc->irq, M_CXGBE);
991218792Snp	free(sc->sge.rxq, M_CXGBE);
992218792Snp	free(sc->sge.txq, M_CXGBE);
993220873Snp	free(sc->sge.ctrlq, M_CXGBE);
994218792Snp	free(sc->sge.iqmap, M_CXGBE);
995218792Snp	free(sc->sge.eqmap, M_CXGBE);
996221474Snp	free(sc->tids.ftid_tab, M_CXGBE);
997218792Snp	t4_destroy_dma_tag(sc);
998228561Snp	if (mtx_initialized(&sc->sc_lock)) {
999255006Snp		sx_xlock(&t4_list_lock);
1000228561Snp		SLIST_REMOVE(&t4_list, sc, adapter, link);
1001255006Snp		sx_xunlock(&t4_list_lock);
1002228561Snp		mtx_destroy(&sc->sc_lock);
1003228561Snp	}
1004218792Snp
1005245274Snp	if (mtx_initialized(&sc->tids.ftid_lock))
1006245274Snp		mtx_destroy(&sc->tids.ftid_lock);
1007228561Snp	if (mtx_initialized(&sc->sfl_lock))
1008228561Snp		mtx_destroy(&sc->sfl_lock);
1009253691Snp	if (mtx_initialized(&sc->ifp_lock))
1010253691Snp		mtx_destroy(&sc->ifp_lock);
1011228561Snp
1012218792Snp	bzero(sc, sizeof(*sc));
1013218792Snp
1014218792Snp	return (0);
1015218792Snp}
1016218792Snp
1017218792Snpstatic int
1018218792Snpcxgbe_probe(device_t dev)
1019218792Snp{
1020218792Snp	char buf[128];
1021218792Snp	struct port_info *pi = device_get_softc(dev);
1022218792Snp
1023228561Snp	snprintf(buf, sizeof(buf), "port %d", pi->port_id);
1024218792Snp	device_set_desc_copy(dev, buf);
1025218792Snp
1026218792Snp	return (BUS_PROBE_DEFAULT);
1027218792Snp}
1028218792Snp
1029218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \
1030218792Snp    IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \
1031256218Sglebius    IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6 | IFCAP_HWSTATS)
1032237819Snp#define T4_CAP_ENABLE (T4_CAP)
1033218792Snp
1034218792Snpstatic int
1035218792Snpcxgbe_attach(device_t dev)
1036218792Snp{
1037218792Snp	struct port_info *pi = device_get_softc(dev);
1038218792Snp	struct ifnet *ifp;
1039270297Snp	char *s;
1040270297Snp	int n, o;
1041218792Snp
1042218792Snp	/* Allocate an ifnet and set it up */
1043218792Snp	ifp = if_alloc(IFT_ETHER);
1044218792Snp	if (ifp == NULL) {
1045218792Snp		device_printf(dev, "Cannot allocate ifnet\n");
1046218792Snp		return (ENOMEM);
1047218792Snp	}
1048218792Snp	pi->ifp = ifp;
1049218792Snp	ifp->if_softc = pi;
1050218792Snp
1051218792Snp	callout_init(&pi->tick, CALLOUT_MPSAFE);
1052218792Snp
1053218792Snp	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1054218792Snp	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1055218792Snp
1056218792Snp	ifp->if_init = cxgbe_init;
1057218792Snp	ifp->if_ioctl = cxgbe_ioctl;
1058218792Snp	ifp->if_transmit = cxgbe_transmit;
1059218792Snp	ifp->if_qflush = cxgbe_qflush;
1060218792Snp
1061218792Snp	ifp->if_capabilities = T4_CAP;
1062237263Snp#ifdef TCP_OFFLOAD
1063228561Snp	if (is_offload(pi->adapter))
1064245933Snp		ifp->if_capabilities |= IFCAP_TOE;
1065228561Snp#endif
1066218792Snp	ifp->if_capenable = T4_CAP_ENABLE;
1067237799Snp	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO |
1068237799Snp	    CSUM_UDP_IPV6 | CSUM_TCP_IPV6;
1069218792Snp
1070218792Snp	/* Initialize ifmedia for this port */
1071218792Snp	ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change,
1072218792Snp	    cxgbe_media_status);
1073270297Snp	build_medialist(pi, &pi->media);
1074218792Snp
1075237263Snp	pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp,
1076237263Snp	    EVENTHANDLER_PRI_ANY);
1077237263Snp
1078218792Snp	ether_ifattach(ifp, pi->hw_addr);
1079218792Snp
1080270297Snp	n = 128;
1081270297Snp	s = malloc(n, M_CXGBE, M_WAITOK);
1082270297Snp	o = snprintf(s, n, "%d txq, %d rxq (NIC)", pi->ntxq, pi->nrxq);
1083270297Snp	MPASS(n > o);
1084237263Snp#ifdef TCP_OFFLOAD
1085228561Snp	if (is_offload(pi->adapter)) {
1086270297Snp		o += snprintf(s + o, n - o, "; %d txq, %d rxq (TOE)",
1087270297Snp		    pi->nofldtxq, pi->nofldrxq);
1088270297Snp		MPASS(n > o);
1089270297Snp	}
1090218792Snp#endif
1091270297Snp#ifdef DEV_NETMAP
1092270297Snp	o += snprintf(s + o, n - o, "; %d txq, %d rxq (netmap)", pi->nnmtxq,
1093270297Snp	    pi->nnmrxq);
1094270297Snp	MPASS(n > o);
1095270297Snp#endif
1096270297Snp	device_printf(dev, "%s\n", s);
1097270297Snp	free(s, M_CXGBE);
1098218792Snp
1099270297Snp#ifdef DEV_NETMAP
1100270297Snp	/* nm_media handled here to keep implementation private to this file */
1101270297Snp	ifmedia_init(&pi->nm_media, IFM_IMASK, cxgbe_media_change,
1102270297Snp	    cxgbe_media_status);
1103270297Snp	build_medialist(pi, &pi->nm_media);
1104270297Snp	create_netmap_ifnet(pi);	/* logs errors it something fails */
1105270297Snp#endif
1106218792Snp	cxgbe_sysctls(pi);
1107218792Snp
1108218792Snp	return (0);
1109218792Snp}
1110218792Snp
1111218792Snpstatic int
1112218792Snpcxgbe_detach(device_t dev)
1113218792Snp{
1114218792Snp	struct port_info *pi = device_get_softc(dev);
1115218792Snp	struct adapter *sc = pi->adapter;
1116228561Snp	struct ifnet *ifp = pi->ifp;
1117218792Snp
1118218792Snp	/* Tell if_ioctl and if_init that the port is going away */
1119218792Snp	ADAPTER_LOCK(sc);
1120218792Snp	SET_DOOMED(pi);
1121218792Snp	wakeup(&sc->flags);
1122218792Snp	while (IS_BUSY(sc))
1123218792Snp		mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0);
1124218792Snp	SET_BUSY(sc);
1125245274Snp#ifdef INVARIANTS
1126245274Snp	sc->last_op = "t4detach";
1127245274Snp	sc->last_op_thr = curthread;
1128245274Snp#endif
1129218792Snp	ADAPTER_UNLOCK(sc);
1130218792Snp
1131253691Snp	if (pi->flags & HAS_TRACEQ) {
1132253691Snp		sc->traceq = -1;	/* cloner should not create ifnet */
1133253691Snp		t4_tracer_port_detach(sc);
1134253691Snp	}
1135253691Snp
1136237263Snp	if (pi->vlan_c)
1137237263Snp		EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c);
1138237263Snp
1139228561Snp	PORT_LOCK(pi);
1140228561Snp	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1141228561Snp	callout_stop(&pi->tick);
1142228561Snp	PORT_UNLOCK(pi);
1143228561Snp	callout_drain(&pi->tick);
1144218792Snp
1145228561Snp	/* Let detach proceed even if these fail. */
1146228561Snp	cxgbe_uninit_synchronized(pi);
1147228561Snp	port_full_uninit(pi);
1148219286Snp
1149218792Snp	ifmedia_removeall(&pi->media);
1150218792Snp	ether_ifdetach(pi->ifp);
1151218792Snp	if_free(pi->ifp);
1152218792Snp
1153270297Snp#ifdef DEV_NETMAP
1154270297Snp	/* XXXNM: equivalent of cxgbe_uninit_synchronized to ifdown nm_ifp */
1155270297Snp	destroy_netmap_ifnet(pi);
1156270297Snp#endif
1157270297Snp
1158218792Snp	ADAPTER_LOCK(sc);
1159218792Snp	CLR_BUSY(sc);
1160245274Snp	wakeup(&sc->flags);
1161218792Snp	ADAPTER_UNLOCK(sc);
1162218792Snp
1163218792Snp	return (0);
1164218792Snp}
1165218792Snp
1166218792Snpstatic void
1167218792Snpcxgbe_init(void *arg)
1168218792Snp{
1169218792Snp	struct port_info *pi = arg;
1170218792Snp	struct adapter *sc = pi->adapter;
1171218792Snp
1172245274Snp	if (begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4init") != 0)
1173245274Snp		return;
1174245274Snp	cxgbe_init_synchronized(pi);
1175245274Snp	end_synchronized_op(sc, 0);
1176218792Snp}
1177218792Snp
1178218792Snpstatic int
1179218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
1180218792Snp{
1181270297Snp	int rc = 0, mtu, flags, can_sleep;
1182218792Snp	struct port_info *pi = ifp->if_softc;
1183218792Snp	struct adapter *sc = pi->adapter;
1184218792Snp	struct ifreq *ifr = (struct ifreq *)data;
1185218792Snp	uint32_t mask;
1186218792Snp
1187218792Snp	switch (cmd) {
1188218792Snp	case SIOCSIFMTU:
1189245274Snp		mtu = ifr->ifr_mtu;
1190245274Snp		if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO))
1191245274Snp			return (EINVAL);
1192245274Snp
1193245274Snp		rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4mtu");
1194245274Snp		if (rc)
1195218792Snp			return (rc);
1196245274Snp		ifp->if_mtu = mtu;
1197252728Snp		if (pi->flags & PORT_INIT_DONE) {
1198245274Snp			t4_update_fl_bufsize(ifp);
1199252728Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1200270297Snp				rc = update_mac_settings(ifp, XGMAC_MTU);
1201218792Snp		}
1202245274Snp		end_synchronized_op(sc, 0);
1203218792Snp		break;
1204218792Snp
1205218792Snp	case SIOCSIFFLAGS:
1206270297Snp		can_sleep = 0;
1207270297Snpredo_sifflags:
1208270297Snp		rc = begin_synchronized_op(sc, pi,
1209270297Snp		    can_sleep ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4flg");
1210245274Snp		if (rc)
1211245274Snp			return (rc);
1212245274Snp
1213218792Snp		if (ifp->if_flags & IFF_UP) {
1214218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1215218792Snp				flags = pi->if_flags;
1216218792Snp				if ((ifp->if_flags ^ flags) &
1217218792Snp				    (IFF_PROMISC | IFF_ALLMULTI)) {
1218270297Snp					if (can_sleep == 1) {
1219270297Snp						end_synchronized_op(sc, 0);
1220270297Snp						can_sleep = 0;
1221270297Snp						goto redo_sifflags;
1222270297Snp					}
1223270297Snp					rc = update_mac_settings(ifp,
1224218792Snp					    XGMAC_PROMISC | XGMAC_ALLMULTI);
1225218792Snp				}
1226270297Snp			} else {
1227270297Snp				if (can_sleep == 0) {
1228270297Snp					end_synchronized_op(sc, LOCK_HELD);
1229270297Snp					can_sleep = 1;
1230270297Snp					goto redo_sifflags;
1231270297Snp				}
1232245274Snp				rc = cxgbe_init_synchronized(pi);
1233270297Snp			}
1234218792Snp			pi->if_flags = ifp->if_flags;
1235270297Snp		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1236270297Snp			if (can_sleep == 0) {
1237270297Snp				end_synchronized_op(sc, LOCK_HELD);
1238270297Snp				can_sleep = 1;
1239270297Snp				goto redo_sifflags;
1240270297Snp			}
1241245274Snp			rc = cxgbe_uninit_synchronized(pi);
1242270297Snp		}
1243270297Snp		end_synchronized_op(sc, can_sleep ? 0 : LOCK_HELD);
1244218792Snp		break;
1245218792Snp
1246270297Snp	case SIOCADDMULTI:
1247245274Snp	case SIOCDELMULTI: /* these two are called with a mutex held :-( */
1248245274Snp		rc = begin_synchronized_op(sc, pi, HOLD_LOCK, "t4multi");
1249218792Snp		if (rc)
1250245274Snp			return (rc);
1251245274Snp		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1252270297Snp			rc = update_mac_settings(ifp, XGMAC_MCADDRS);
1253245274Snp		end_synchronized_op(sc, LOCK_HELD);
1254218792Snp		break;
1255218792Snp
1256218792Snp	case SIOCSIFCAP:
1257245274Snp		rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4cap");
1258218792Snp		if (rc)
1259245274Snp			return (rc);
1260218792Snp
1261218792Snp		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1262218792Snp		if (mask & IFCAP_TXCSUM) {
1263218792Snp			ifp->if_capenable ^= IFCAP_TXCSUM;
1264218792Snp			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
1265218792Snp
1266237831Snp			if (IFCAP_TSO4 & ifp->if_capenable &&
1267218792Snp			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
1268237799Snp				ifp->if_capenable &= ~IFCAP_TSO4;
1269218792Snp				if_printf(ifp,
1270237831Snp				    "tso4 disabled due to -txcsum.\n");
1271218792Snp			}
1272218792Snp		}
1273237799Snp		if (mask & IFCAP_TXCSUM_IPV6) {
1274237799Snp			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
1275237799Snp			ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
1276237799Snp
1277237799Snp			if (IFCAP_TSO6 & ifp->if_capenable &&
1278237799Snp			    !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) {
1279237799Snp				ifp->if_capenable &= ~IFCAP_TSO6;
1280237799Snp				if_printf(ifp,
1281237799Snp				    "tso6 disabled due to -txcsum6.\n");
1282237799Snp			}
1283237799Snp		}
1284218792Snp		if (mask & IFCAP_RXCSUM)
1285218792Snp			ifp->if_capenable ^= IFCAP_RXCSUM;
1286237799Snp		if (mask & IFCAP_RXCSUM_IPV6)
1287237799Snp			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
1288237799Snp
1289237799Snp		/*
1290237799Snp		 * Note that we leave CSUM_TSO alone (it is always set).  The
1291237799Snp		 * kernel takes both IFCAP_TSOx and CSUM_TSO into account before
1292237799Snp		 * sending a TSO request our way, so it's sufficient to toggle
1293237799Snp		 * IFCAP_TSOx only.
1294237799Snp		 */
1295218792Snp		if (mask & IFCAP_TSO4) {
1296237799Snp			if (!(IFCAP_TSO4 & ifp->if_capenable) &&
1297237799Snp			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
1298237799Snp				if_printf(ifp, "enable txcsum first.\n");
1299237799Snp				rc = EAGAIN;
1300237799Snp				goto fail;
1301237799Snp			}
1302218792Snp			ifp->if_capenable ^= IFCAP_TSO4;
1303218792Snp		}
1304237799Snp		if (mask & IFCAP_TSO6) {
1305237799Snp			if (!(IFCAP_TSO6 & ifp->if_capenable) &&
1306237799Snp			    !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) {
1307237799Snp				if_printf(ifp, "enable txcsum6 first.\n");
1308237799Snp				rc = EAGAIN;
1309237799Snp				goto fail;
1310237799Snp			}
1311237799Snp			ifp->if_capenable ^= IFCAP_TSO6;
1312237799Snp		}
1313218792Snp		if (mask & IFCAP_LRO) {
1314237819Snp#if defined(INET) || defined(INET6)
1315218792Snp			int i;
1316218792Snp			struct sge_rxq *rxq;
1317218792Snp
1318218792Snp			ifp->if_capenable ^= IFCAP_LRO;
1319218792Snp			for_each_rxq(pi, i, rxq) {
1320218792Snp				if (ifp->if_capenable & IFCAP_LRO)
1321228561Snp					rxq->iq.flags |= IQ_LRO_ENABLED;
1322218792Snp				else
1323228561Snp					rxq->iq.flags &= ~IQ_LRO_ENABLED;
1324218792Snp			}
1325218792Snp#endif
1326218792Snp		}
1327237263Snp#ifdef TCP_OFFLOAD
1328228561Snp		if (mask & IFCAP_TOE) {
1329228561Snp			int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE;
1330228561Snp
1331228561Snp			rc = toe_capability(pi, enable);
1332228561Snp			if (rc != 0)
1333228561Snp				goto fail;
1334228561Snp
1335228561Snp			ifp->if_capenable ^= mask;
1336218792Snp		}
1337218792Snp#endif
1338218792Snp		if (mask & IFCAP_VLAN_HWTAGGING) {
1339218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1340245274Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1341270297Snp				rc = update_mac_settings(ifp, XGMAC_VLANEX);
1342218792Snp		}
1343218792Snp		if (mask & IFCAP_VLAN_MTU) {
1344218792Snp			ifp->if_capenable ^= IFCAP_VLAN_MTU;
1345218792Snp
1346218792Snp			/* Need to find out how to disable auto-mtu-inflation */
1347218792Snp		}
1348218792Snp		if (mask & IFCAP_VLAN_HWTSO)
1349218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
1350218792Snp		if (mask & IFCAP_VLAN_HWCSUM)
1351218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
1352218792Snp
1353218792Snp#ifdef VLAN_CAPABILITIES
1354218792Snp		VLAN_CAPABILITIES(ifp);
1355218792Snp#endif
1356245274Snpfail:
1357245274Snp		end_synchronized_op(sc, 0);
1358218792Snp		break;
1359218792Snp
1360218792Snp	case SIOCSIFMEDIA:
1361218792Snp	case SIOCGIFMEDIA:
1362218792Snp		ifmedia_ioctl(ifp, ifr, &pi->media, cmd);
1363218792Snp		break;
1364218792Snp
1365218792Snp	default:
1366218792Snp		rc = ether_ioctl(ifp, cmd, data);
1367218792Snp	}
1368218792Snp
1369218792Snp	return (rc);
1370218792Snp}
1371218792Snp
1372218792Snpstatic int
1373218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m)
1374218792Snp{
1375218792Snp	struct port_info *pi = ifp->if_softc;
1376218792Snp	struct adapter *sc = pi->adapter;
1377218792Snp	struct sge_txq *txq = &sc->sge.txq[pi->first_txq];
1378218792Snp	struct buf_ring *br;
1379218792Snp	int rc;
1380218792Snp
1381218792Snp	M_ASSERTPKTHDR(m);
1382218792Snp
1383228561Snp	if (__predict_false(pi->link_cfg.link_ok == 0)) {
1384218792Snp		m_freem(m);
1385228561Snp		return (ENETDOWN);
1386218792Snp	}
1387218792Snp
1388218792Snp	if (m->m_flags & M_FLOWID)
1389264493Sscottl		txq += ((m->m_pkthdr.flowid % (pi->ntxq - pi->rsrv_noflowq))
1390264493Sscottl		    + pi->rsrv_noflowq);
1391220873Snp	br = txq->br;
1392218792Snp
1393218792Snp	if (TXQ_TRYLOCK(txq) == 0) {
1394228561Snp		struct sge_eq *eq = &txq->eq;
1395228561Snp
1396218792Snp		/*
1397228561Snp		 * It is possible that t4_eth_tx finishes up and releases the
1398228561Snp		 * lock between the TRYLOCK above and the drbr_enqueue here.  We
1399228561Snp		 * need to make sure that this mbuf doesn't just sit there in
1400228561Snp		 * the drbr.
1401218792Snp		 */
1402218792Snp
1403228561Snp		rc = drbr_enqueue(ifp, br, m);
1404228561Snp		if (rc == 0 && callout_pending(&eq->tx_callout) == 0 &&
1405228561Snp		    !(eq->flags & EQ_DOOMED))
1406228561Snp			callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq);
1407228561Snp		return (rc);
1408218792Snp	}
1409218792Snp
1410218792Snp	/*
1411218792Snp	 * txq->m is the mbuf that is held up due to a temporary shortage of
1412218792Snp	 * resources and it should be put on the wire first.  Then what's in
1413218792Snp	 * drbr and finally the mbuf that was just passed in to us.
1414218792Snp	 *
1415218792Snp	 * Return code should indicate the fate of the mbuf that was passed in
1416218792Snp	 * this time.
1417218792Snp	 */
1418218792Snp
1419218792Snp	TXQ_LOCK_ASSERT_OWNED(txq);
1420218792Snp	if (drbr_needs_enqueue(ifp, br) || txq->m) {
1421218792Snp
1422218792Snp		/* Queued for transmission. */
1423218792Snp
1424218792Snp		rc = drbr_enqueue(ifp, br, m);
1425218792Snp		m = txq->m ? txq->m : drbr_dequeue(ifp, br);
1426218792Snp		(void) t4_eth_tx(ifp, txq, m);
1427218792Snp		TXQ_UNLOCK(txq);
1428218792Snp		return (rc);
1429218792Snp	}
1430218792Snp
1431218792Snp	/* Direct transmission. */
1432218792Snp	rc = t4_eth_tx(ifp, txq, m);
1433218792Snp	if (rc != 0 && txq->m)
1434218792Snp		rc = 0;	/* held, will be transmitted soon (hopefully) */
1435218792Snp
1436218792Snp	TXQ_UNLOCK(txq);
1437218792Snp	return (rc);
1438218792Snp}
1439218792Snp
1440218792Snpstatic void
1441218792Snpcxgbe_qflush(struct ifnet *ifp)
1442218792Snp{
1443218792Snp	struct port_info *pi = ifp->if_softc;
1444220649Snp	struct sge_txq *txq;
1445220649Snp	int i;
1446220649Snp	struct mbuf *m;
1447218792Snp
1448228561Snp	/* queues do not exist if !PORT_INIT_DONE. */
1449228561Snp	if (pi->flags & PORT_INIT_DONE) {
1450220649Snp		for_each_txq(pi, i, txq) {
1451220649Snp			TXQ_LOCK(txq);
1452220649Snp			m_freem(txq->m);
1453228561Snp			txq->m = NULL;
1454220873Snp			while ((m = buf_ring_dequeue_sc(txq->br)) != NULL)
1455220649Snp				m_freem(m);
1456220649Snp			TXQ_UNLOCK(txq);
1457220649Snp		}
1458220649Snp	}
1459220649Snp	if_qflush(ifp);
1460218792Snp}
1461218792Snp
1462218792Snpstatic int
1463218792Snpcxgbe_media_change(struct ifnet *ifp)
1464218792Snp{
1465218792Snp	struct port_info *pi = ifp->if_softc;
1466218792Snp
1467218792Snp	device_printf(pi->dev, "%s unimplemented.\n", __func__);
1468218792Snp
1469218792Snp	return (EOPNOTSUPP);
1470218792Snp}
1471218792Snp
1472218792Snpstatic void
1473218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1474218792Snp{
1475218792Snp	struct port_info *pi = ifp->if_softc;
1476270297Snp	struct ifmedia *media = NULL;
1477270297Snp	struct ifmedia_entry *cur;
1478218792Snp	int speed = pi->link_cfg.speed;
1479218792Snp	int data = (pi->port_type << 8) | pi->mod_type;
1480218792Snp
1481270297Snp	if (ifp == pi->ifp)
1482270297Snp		media = &pi->media;
1483270297Snp#ifdef DEV_NETMAP
1484270297Snp	else if (ifp == pi->nm_ifp)
1485270297Snp		media = &pi->nm_media;
1486270297Snp#endif
1487270297Snp	MPASS(media != NULL);
1488270297Snp
1489270297Snp	cur = media->ifm_cur;
1490218792Snp	if (cur->ifm_data != data) {
1491270297Snp		build_medialist(pi, media);
1492270297Snp		cur = media->ifm_cur;
1493218792Snp	}
1494218792Snp
1495218792Snp	ifmr->ifm_status = IFM_AVALID;
1496218792Snp	if (!pi->link_cfg.link_ok)
1497218792Snp		return;
1498218792Snp
1499218792Snp	ifmr->ifm_status |= IFM_ACTIVE;
1500218792Snp
1501218792Snp	/* active and current will differ iff current media is autoselect. */
1502218792Snp	if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
1503218792Snp		return;
1504218792Snp
1505218792Snp	ifmr->ifm_active = IFM_ETHER | IFM_FDX;
1506218792Snp	if (speed == SPEED_10000)
1507218792Snp		ifmr->ifm_active |= IFM_10G_T;
1508218792Snp	else if (speed == SPEED_1000)
1509218792Snp		ifmr->ifm_active |= IFM_1000_T;
1510218792Snp	else if (speed == SPEED_100)
1511218792Snp		ifmr->ifm_active |= IFM_100_TX;
1512218792Snp	else if (speed == SPEED_10)
1513218792Snp		ifmr->ifm_active |= IFM_10_T;
1514218792Snp	else
1515218792Snp		KASSERT(0, ("%s: link up but speed unknown (%u)", __func__,
1516218792Snp			    speed));
1517218792Snp}
1518218792Snp
1519218792Snpvoid
1520218792Snpt4_fatal_err(struct adapter *sc)
1521218792Snp{
1522218792Snp	t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0);
1523218792Snp	t4_intr_disable(sc);
1524218792Snp	log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n",
1525218792Snp	    device_get_nameunit(sc->dev));
1526218792Snp}
1527218792Snp
1528218792Snpstatic int
1529248925Snpmap_bars_0_and_4(struct adapter *sc)
1530218792Snp{
1531218792Snp	sc->regs_rid = PCIR_BAR(0);
1532218792Snp	sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1533218792Snp	    &sc->regs_rid, RF_ACTIVE);
1534218792Snp	if (sc->regs_res == NULL) {
1535218792Snp		device_printf(sc->dev, "cannot map registers.\n");
1536218792Snp		return (ENXIO);
1537218792Snp	}
1538218792Snp	sc->bt = rman_get_bustag(sc->regs_res);
1539218792Snp	sc->bh = rman_get_bushandle(sc->regs_res);
1540218792Snp	sc->mmio_len = rman_get_size(sc->regs_res);
1541248925Snp	setbit(&sc->doorbells, DOORBELL_KDB);
1542218792Snp
1543218792Snp	sc->msix_rid = PCIR_BAR(4);
1544218792Snp	sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1545218792Snp	    &sc->msix_rid, RF_ACTIVE);
1546218792Snp	if (sc->msix_res == NULL) {
1547218792Snp		device_printf(sc->dev, "cannot map MSI-X BAR.\n");
1548218792Snp		return (ENXIO);
1549218792Snp	}
1550218792Snp
1551218792Snp	return (0);
1552218792Snp}
1553218792Snp
1554248925Snpstatic int
1555248925Snpmap_bar_2(struct adapter *sc)
1556248925Snp{
1557248925Snp
1558248925Snp	/*
1559248925Snp	 * T4: only iWARP driver uses the userspace doorbells.  There is no need
1560248925Snp	 * to map it if RDMA is disabled.
1561248925Snp	 */
1562248925Snp	if (is_t4(sc) && sc->rdmacaps == 0)
1563248925Snp		return (0);
1564248925Snp
1565248925Snp	sc->udbs_rid = PCIR_BAR(2);
1566248925Snp	sc->udbs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1567248925Snp	    &sc->udbs_rid, RF_ACTIVE);
1568248925Snp	if (sc->udbs_res == NULL) {
1569248925Snp		device_printf(sc->dev, "cannot map doorbell BAR.\n");
1570248925Snp		return (ENXIO);
1571248925Snp	}
1572248925Snp	sc->udbs_base = rman_get_virtual(sc->udbs_res);
1573248925Snp
1574248925Snp	if (is_t5(sc)) {
1575248925Snp		setbit(&sc->doorbells, DOORBELL_UDB);
1576248925Snp#if defined(__i386__) || defined(__amd64__)
1577248925Snp		if (t5_write_combine) {
1578248925Snp			int rc;
1579248925Snp
1580248925Snp			/*
1581248925Snp			 * Enable write combining on BAR2.  This is the
1582248925Snp			 * userspace doorbell BAR and is split into 128B
1583248925Snp			 * (UDBS_SEG_SIZE) doorbell regions, each associated
1584248925Snp			 * with an egress queue.  The first 64B has the doorbell
1585248925Snp			 * and the second 64B can be used to submit a tx work
1586248925Snp			 * request with an implicit doorbell.
1587248925Snp			 */
1588248925Snp
1589248925Snp			rc = pmap_change_attr((vm_offset_t)sc->udbs_base,
1590248925Snp			    rman_get_size(sc->udbs_res), PAT_WRITE_COMBINING);
1591248925Snp			if (rc == 0) {
1592248925Snp				clrbit(&sc->doorbells, DOORBELL_UDB);
1593249392Snp				setbit(&sc->doorbells, DOORBELL_WCWR);
1594248925Snp				setbit(&sc->doorbells, DOORBELL_UDBWC);
1595248925Snp			} else {
1596248925Snp				device_printf(sc->dev,
1597248925Snp				    "couldn't enable write combining: %d\n",
1598248925Snp				    rc);
1599248925Snp			}
1600248925Snp
1601248925Snp			t4_write_reg(sc, A_SGE_STAT_CFG,
1602248925Snp			    V_STATSOURCE_T5(7) | V_STATMODE(0));
1603248925Snp		}
1604248925Snp#endif
1605248925Snp	}
1606248925Snp
1607248925Snp	return (0);
1608248925Snp}
1609248925Snp
1610248925Snpstatic const struct memwin t4_memwin[] = {
1611248925Snp	{ MEMWIN0_BASE, MEMWIN0_APERTURE },
1612248925Snp	{ MEMWIN1_BASE, MEMWIN1_APERTURE },
1613248925Snp	{ MEMWIN2_BASE_T4, MEMWIN2_APERTURE_T4 }
1614248925Snp};
1615248925Snp
1616248925Snpstatic const struct memwin t5_memwin[] = {
1617248925Snp	{ MEMWIN0_BASE, MEMWIN0_APERTURE },
1618248925Snp	{ MEMWIN1_BASE, MEMWIN1_APERTURE },
1619248925Snp	{ MEMWIN2_BASE_T5, MEMWIN2_APERTURE_T5 },
1620248925Snp};
1621248925Snp
1622218792Snpstatic void
1623218792Snpsetup_memwin(struct adapter *sc)
1624218792Snp{
1625248925Snp	const struct memwin *mw;
1626248925Snp	int i, n;
1627237587Snp	uint32_t bar0;
1628218792Snp
1629248925Snp	if (is_t4(sc)) {
1630248925Snp		/*
1631248925Snp		 * Read low 32b of bar0 indirectly via the hardware backdoor
1632248925Snp		 * mechanism.  Works from within PCI passthrough environments
1633248925Snp		 * too, where rman_get_start() can return a different value.  We
1634248925Snp		 * need to program the T4 memory window decoders with the actual
1635248925Snp		 * addresses that will be coming across the PCIe link.
1636248925Snp		 */
1637248925Snp		bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0));
1638248925Snp		bar0 &= (uint32_t) PCIM_BAR_MEM_BASE;
1639218792Snp
1640248925Snp		mw = &t4_memwin[0];
1641248925Snp		n = nitems(t4_memwin);
1642248925Snp	} else {
1643248925Snp		/* T5 uses the relative offset inside the PCIe BAR */
1644248925Snp		bar0 = 0;
1645218792Snp
1646248925Snp		mw = &t5_memwin[0];
1647248925Snp		n = nitems(t5_memwin);
1648248925Snp	}
1649218792Snp
1650248925Snp	for (i = 0; i < n; i++, mw++) {
1651248925Snp		t4_write_reg(sc,
1652248925Snp		    PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, i),
1653248925Snp		    (mw->base + bar0) | V_BIR(0) |
1654248925Snp		    V_WINDOW(ilog2(mw->aperture) - 10));
1655248925Snp	}
1656237587Snp
1657237587Snp	/* flush */
1658237587Snp	t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2));
1659218792Snp}
1660218792Snp
1661248925Snp/*
1662248925Snp * Verify that the memory range specified by the addr/len pair is valid and lies
1663248925Snp * entirely within a single region (EDCx or MCx).
1664248925Snp */
1665218792Snpstatic int
1666248925Snpvalidate_mem_range(struct adapter *sc, uint32_t addr, int len)
1667248925Snp{
1668248925Snp	uint32_t em, addr_len, maddr, mlen;
1669248925Snp
1670248925Snp	/* Memory can only be accessed in naturally aligned 4 byte units */
1671248925Snp	if (addr & 3 || len & 3 || len == 0)
1672248925Snp		return (EINVAL);
1673248925Snp
1674248925Snp	/* Enabled memories */
1675248925Snp	em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
1676248925Snp	if (em & F_EDRAM0_ENABLE) {
1677248925Snp		addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR);
1678248925Snp		maddr = G_EDRAM0_BASE(addr_len) << 20;
1679248925Snp		mlen = G_EDRAM0_SIZE(addr_len) << 20;
1680248925Snp		if (mlen > 0 && addr >= maddr && addr < maddr + mlen &&
1681248925Snp		    addr + len <= maddr + mlen)
1682248925Snp			return (0);
1683248925Snp	}
1684248925Snp	if (em & F_EDRAM1_ENABLE) {
1685248925Snp		addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR);
1686248925Snp		maddr = G_EDRAM1_BASE(addr_len) << 20;
1687248925Snp		mlen = G_EDRAM1_SIZE(addr_len) << 20;
1688248925Snp		if (mlen > 0 && addr >= maddr && addr < maddr + mlen &&
1689248925Snp		    addr + len <= maddr + mlen)
1690248925Snp			return (0);
1691248925Snp	}
1692248925Snp	if (em & F_EXT_MEM_ENABLE) {
1693248925Snp		addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
1694248925Snp		maddr = G_EXT_MEM_BASE(addr_len) << 20;
1695248925Snp		mlen = G_EXT_MEM_SIZE(addr_len) << 20;
1696248925Snp		if (mlen > 0 && addr >= maddr && addr < maddr + mlen &&
1697248925Snp		    addr + len <= maddr + mlen)
1698248925Snp			return (0);
1699248925Snp	}
1700248925Snp	if (!is_t4(sc) && em & F_EXT_MEM1_ENABLE) {
1701248925Snp		addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR);
1702248925Snp		maddr = G_EXT_MEM1_BASE(addr_len) << 20;
1703248925Snp		mlen = G_EXT_MEM1_SIZE(addr_len) << 20;
1704248925Snp		if (mlen > 0 && addr >= maddr && addr < maddr + mlen &&
1705248925Snp		    addr + len <= maddr + mlen)
1706248925Snp			return (0);
1707248925Snp	}
1708248925Snp
1709248925Snp	return (EFAULT);
1710248925Snp}
1711248925Snp
1712256791Snpstatic int
1713256791Snpfwmtype_to_hwmtype(int mtype)
1714256791Snp{
1715256791Snp
1716256791Snp	switch (mtype) {
1717256791Snp	case FW_MEMTYPE_EDC0:
1718256791Snp		return (MEM_EDC0);
1719256791Snp	case FW_MEMTYPE_EDC1:
1720256791Snp		return (MEM_EDC1);
1721256791Snp	case FW_MEMTYPE_EXTMEM:
1722256791Snp		return (MEM_MC0);
1723256791Snp	case FW_MEMTYPE_EXTMEM1:
1724256791Snp		return (MEM_MC1);
1725256791Snp	default:
1726256791Snp		panic("%s: cannot translate fw mtype %d.", __func__, mtype);
1727256791Snp	}
1728256791Snp}
1729256791Snp
1730248925Snp/*
1731248925Snp * Verify that the memory range specified by the memtype/offset/len pair is
1732248925Snp * valid and lies entirely within the memtype specified.  The global address of
1733248925Snp * the start of the range is returned in addr.
1734248925Snp */
1735248925Snpstatic int
1736248925Snpvalidate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len,
1737248925Snp    uint32_t *addr)
1738248925Snp{
1739248925Snp	uint32_t em, addr_len, maddr, mlen;
1740248925Snp
1741248925Snp	/* Memory can only be accessed in naturally aligned 4 byte units */
1742248925Snp	if (off & 3 || len & 3 || len == 0)
1743248925Snp		return (EINVAL);
1744248925Snp
1745248925Snp	em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
1746256791Snp	switch (fwmtype_to_hwmtype(mtype)) {
1747248925Snp	case MEM_EDC0:
1748248925Snp		if (!(em & F_EDRAM0_ENABLE))
1749248925Snp			return (EINVAL);
1750248925Snp		addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR);
1751248925Snp		maddr = G_EDRAM0_BASE(addr_len) << 20;
1752248925Snp		mlen = G_EDRAM0_SIZE(addr_len) << 20;
1753248925Snp		break;
1754248925Snp	case MEM_EDC1:
1755248925Snp		if (!(em & F_EDRAM1_ENABLE))
1756248925Snp			return (EINVAL);
1757248925Snp		addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR);
1758248925Snp		maddr = G_EDRAM1_BASE(addr_len) << 20;
1759248925Snp		mlen = G_EDRAM1_SIZE(addr_len) << 20;
1760248925Snp		break;
1761248925Snp	case MEM_MC:
1762248925Snp		if (!(em & F_EXT_MEM_ENABLE))
1763248925Snp			return (EINVAL);
1764248925Snp		addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
1765248925Snp		maddr = G_EXT_MEM_BASE(addr_len) << 20;
1766248925Snp		mlen = G_EXT_MEM_SIZE(addr_len) << 20;
1767248925Snp		break;
1768248925Snp	case MEM_MC1:
1769248925Snp		if (is_t4(sc) || !(em & F_EXT_MEM1_ENABLE))
1770248925Snp			return (EINVAL);
1771248925Snp		addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR);
1772248925Snp		maddr = G_EXT_MEM1_BASE(addr_len) << 20;
1773248925Snp		mlen = G_EXT_MEM1_SIZE(addr_len) << 20;
1774248925Snp		break;
1775248925Snp	default:
1776248925Snp		return (EINVAL);
1777248925Snp	}
1778248925Snp
1779248925Snp	if (mlen > 0 && off < mlen && off + len <= mlen) {
1780248925Snp		*addr = maddr + off;	/* global address */
1781248925Snp		return (0);
1782248925Snp	}
1783248925Snp
1784248925Snp	return (EFAULT);
1785248925Snp}
1786248925Snp
1787248925Snpstatic void
1788248925Snpmemwin_info(struct adapter *sc, int win, uint32_t *base, uint32_t *aperture)
1789248925Snp{
1790248925Snp	const struct memwin *mw;
1791248925Snp
1792248925Snp	if (is_t4(sc)) {
1793248925Snp		KASSERT(win >= 0 && win < nitems(t4_memwin),
1794248925Snp		    ("%s: incorrect memwin# (%d)", __func__, win));
1795248925Snp		mw = &t4_memwin[win];
1796248925Snp	} else {
1797248925Snp		KASSERT(win >= 0 && win < nitems(t5_memwin),
1798248925Snp		    ("%s: incorrect memwin# (%d)", __func__, win));
1799248925Snp		mw = &t5_memwin[win];
1800248925Snp	}
1801248925Snp
1802248925Snp	if (base != NULL)
1803248925Snp		*base = mw->base;
1804248925Snp	if (aperture != NULL)
1805248925Snp		*aperture = mw->aperture;
1806248925Snp}
1807248925Snp
1808248925Snp/*
1809248925Snp * Positions the memory window such that it can be used to access the specified
1810248925Snp * address in the chip's address space.  The return value is the offset of addr
1811248925Snp * from the start of the window.
1812248925Snp */
1813248925Snpstatic uint32_t
1814248925Snpposition_memwin(struct adapter *sc, int n, uint32_t addr)
1815248925Snp{
1816248925Snp	uint32_t start, pf;
1817248925Snp	uint32_t reg;
1818248925Snp
1819248925Snp	KASSERT(n >= 0 && n <= 3,
1820248925Snp	    ("%s: invalid window %d.", __func__, n));
1821248925Snp	KASSERT((addr & 3) == 0,
1822248925Snp	    ("%s: addr (0x%x) is not at a 4B boundary.", __func__, addr));
1823248925Snp
1824248925Snp	if (is_t4(sc)) {
1825248925Snp		pf = 0;
1826248925Snp		start = addr & ~0xf;	/* start must be 16B aligned */
1827248925Snp	} else {
1828248925Snp		pf = V_PFNUM(sc->pf);
1829248925Snp		start = addr & ~0x7f;	/* start must be 128B aligned */
1830248925Snp	}
1831248925Snp	reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, n);
1832248925Snp
1833248925Snp	t4_write_reg(sc, reg, start | pf);
1834248925Snp	t4_read_reg(sc, reg);
1835248925Snp
1836248925Snp	return (addr - start);
1837248925Snp}
1838248925Snp
1839248925Snpstatic int
1840218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g,
1841218792Snp    struct intrs_and_queues *iaq)
1842218792Snp{
1843228561Snp	int rc, itype, navail, nrxq10g, nrxq1g, n;
1844228561Snp	int nofldrxq10g = 0, nofldrxq1g = 0;
1845270297Snp	int nnmrxq10g = 0, nnmrxq1g = 0;
1846218792Snp
1847218792Snp	bzero(iaq, sizeof(*iaq));
1848218792Snp
1849228561Snp	iaq->ntxq10g = t4_ntxq10g;
1850228561Snp	iaq->ntxq1g = t4_ntxq1g;
1851228561Snp	iaq->nrxq10g = nrxq10g = t4_nrxq10g;
1852228561Snp	iaq->nrxq1g = nrxq1g = t4_nrxq1g;
1853264493Sscottl	iaq->rsrv_noflowq = t4_rsrv_noflowq;
1854237263Snp#ifdef TCP_OFFLOAD
1855237463Snp	if (is_offload(sc)) {
1856237463Snp		iaq->nofldtxq10g = t4_nofldtxq10g;
1857237463Snp		iaq->nofldtxq1g = t4_nofldtxq1g;
1858237463Snp		iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g;
1859237463Snp		iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g;
1860237463Snp	}
1861228561Snp#endif
1862270297Snp#ifdef DEV_NETMAP
1863270297Snp	iaq->nnmtxq10g = t4_nnmtxq10g;
1864270297Snp	iaq->nnmtxq1g = t4_nnmtxq1g;
1865270297Snp	iaq->nnmrxq10g = nnmrxq10g = t4_nnmrxq10g;
1866270297Snp	iaq->nnmrxq1g = nnmrxq1g = t4_nnmrxq1g;
1867270297Snp#endif
1868228561Snp
1869219944Snp	for (itype = INTR_MSIX; itype; itype >>= 1) {
1870218792Snp
1871228561Snp		if ((itype & t4_intr_types) == 0)
1872218792Snp			continue;	/* not allowed */
1873218792Snp
1874219944Snp		if (itype == INTR_MSIX)
1875218792Snp			navail = pci_msix_count(sc->dev);
1876219944Snp		else if (itype == INTR_MSI)
1877218792Snp			navail = pci_msi_count(sc->dev);
1878218792Snp		else
1879218792Snp			navail = 1;
1880228561Snprestart:
1881218792Snp		if (navail == 0)
1882218792Snp			continue;
1883218792Snp
1884218792Snp		iaq->intr_type = itype;
1885270297Snp		iaq->intr_flags_10g = 0;
1886270297Snp		iaq->intr_flags_1g = 0;
1887218792Snp
1888228561Snp		/*
1889228561Snp		 * Best option: an interrupt vector for errors, one for the
1890270297Snp		 * firmware event queue, and one for every rxq (NIC, TOE, and
1891270297Snp		 * netmap).
1892228561Snp		 */
1893228561Snp		iaq->nirq = T4_EXTRA_INTR;
1894270297Snp		iaq->nirq += n10g * (nrxq10g + nofldrxq10g + nnmrxq10g);
1895270297Snp		iaq->nirq += n1g * (nrxq1g + nofldrxq1g + nnmrxq1g);
1896228561Snp		if (iaq->nirq <= navail &&
1897228561Snp		    (itype != INTR_MSI || powerof2(iaq->nirq))) {
1898270297Snp			iaq->intr_flags_10g = INTR_ALL;
1899270297Snp			iaq->intr_flags_1g = INTR_ALL;
1900228561Snp			goto allocate;
1901228561Snp		}
1902218792Snp
1903228561Snp		/*
1904270297Snp		 * Second best option: a vector for errors, one for the firmware
1905270297Snp		 * event queue, and vectors for either all the NIC rx queues or
1906270297Snp		 * all the TOE rx queues.  The queues that don't get vectors
1907270297Snp		 * will forward their interrupts to those that do.
1908270297Snp		 *
1909270297Snp		 * Note: netmap rx queues cannot be created early and so they
1910270297Snp		 * can't be setup to receive forwarded interrupts for others.
1911228561Snp		 */
1912228561Snp		iaq->nirq = T4_EXTRA_INTR;
1913270297Snp		if (nrxq10g >= nofldrxq10g) {
1914270297Snp			iaq->intr_flags_10g = INTR_RXQ;
1915270297Snp			iaq->nirq += n10g * nrxq10g;
1916270297Snp#ifdef DEV_NETMAP
1917270297Snp			iaq->nnmrxq10g = min(nnmrxq10g, nrxq10g);
1918270297Snp#endif
1919270297Snp		} else {
1920270297Snp			iaq->intr_flags_10g = INTR_OFLD_RXQ;
1921270297Snp			iaq->nirq += n10g * nofldrxq10g;
1922270297Snp#ifdef DEV_NETMAP
1923270297Snp			iaq->nnmrxq10g = min(nnmrxq10g, nofldrxq10g);
1924270297Snp#endif
1925270297Snp		}
1926270297Snp		if (nrxq1g >= nofldrxq1g) {
1927270297Snp			iaq->intr_flags_1g = INTR_RXQ;
1928270297Snp			iaq->nirq += n1g * nrxq1g;
1929270297Snp#ifdef DEV_NETMAP
1930270297Snp			iaq->nnmrxq1g = min(nnmrxq1g, nrxq1g);
1931270297Snp#endif
1932270297Snp		} else {
1933270297Snp			iaq->intr_flags_1g = INTR_OFLD_RXQ;
1934270297Snp			iaq->nirq += n1g * nofldrxq1g;
1935270297Snp#ifdef DEV_NETMAP
1936270297Snp			iaq->nnmrxq1g = min(nnmrxq1g, nofldrxq1g);
1937270297Snp#endif
1938270297Snp		}
1939228561Snp		if (iaq->nirq <= navail &&
1940228561Snp		    (itype != INTR_MSI || powerof2(iaq->nirq)))
1941228561Snp			goto allocate;
1942218792Snp
1943228561Snp		/*
1944228561Snp		 * Next best option: an interrupt vector for errors, one for the
1945228561Snp		 * firmware event queue, and at least one per port.  At this
1946270297Snp		 * point we know we'll have to downsize nrxq and/or nofldrxq
1947270297Snp		 * and/or nnmrxq to fit what's available to us.
1948228561Snp		 */
1949228561Snp		iaq->nirq = T4_EXTRA_INTR;
1950228561Snp		iaq->nirq += n10g + n1g;
1951228561Snp		if (iaq->nirq <= navail) {
1952228561Snp			int leftover = navail - iaq->nirq;
1953218792Snp
1954228561Snp			if (n10g > 0) {
1955228561Snp				int target = max(nrxq10g, nofldrxq10g);
1956219944Snp
1957270297Snp				iaq->intr_flags_10g = nrxq10g >= nofldrxq10g ?
1958270297Snp				    INTR_RXQ : INTR_OFLD_RXQ;
1959270297Snp
1960228561Snp				n = 1;
1961228561Snp				while (n < target && leftover >= n10g) {
1962228561Snp					leftover -= n10g;
1963228561Snp					iaq->nirq += n10g;
1964228561Snp					n++;
1965228561Snp				}
1966228561Snp				iaq->nrxq10g = min(n, nrxq10g);
1967237263Snp#ifdef TCP_OFFLOAD
1968270297Snp				iaq->nofldrxq10g = min(n, nofldrxq10g);
1969228561Snp#endif
1970270297Snp#ifdef DEV_NETMAP
1971270297Snp				iaq->nnmrxq10g = min(n, nnmrxq10g);
1972270297Snp#endif
1973228561Snp			}
1974218792Snp
1975228561Snp			if (n1g > 0) {
1976228561Snp				int target = max(nrxq1g, nofldrxq1g);
1977219944Snp
1978270297Snp				iaq->intr_flags_1g = nrxq1g >= nofldrxq1g ?
1979270297Snp				    INTR_RXQ : INTR_OFLD_RXQ;
1980270297Snp
1981228561Snp				n = 1;
1982228561Snp				while (n < target && leftover >= n1g) {
1983228561Snp					leftover -= n1g;
1984228561Snp					iaq->nirq += n1g;
1985228561Snp					n++;
1986219944Snp				}
1987228561Snp				iaq->nrxq1g = min(n, nrxq1g);
1988237263Snp#ifdef TCP_OFFLOAD
1989270297Snp				iaq->nofldrxq1g = min(n, nofldrxq1g);
1990228561Snp#endif
1991270297Snp#ifdef DEV_NETMAP
1992270297Snp				iaq->nnmrxq1g = min(n, nnmrxq1g);
1993270297Snp#endif
1994219944Snp			}
1995219944Snp
1996228561Snp			if (itype != INTR_MSI || powerof2(iaq->nirq))
1997228561Snp				goto allocate;
1998218792Snp		}
1999218792Snp
2000228561Snp		/*
2001228561Snp		 * Least desirable option: one interrupt vector for everything.
2002228561Snp		 */
2003228561Snp		iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1;
2004270297Snp		iaq->intr_flags_10g = iaq->intr_flags_1g = 0;
2005237263Snp#ifdef TCP_OFFLOAD
2006237463Snp		if (is_offload(sc))
2007237463Snp			iaq->nofldrxq10g = iaq->nofldrxq1g = 1;
2008228561Snp#endif
2009270297Snp#ifdef DEV_NETMAP
2010270297Snp		iaq->nnmrxq10g = iaq->nnmrxq1g = 1;
2011270297Snp#endif
2012228561Snp
2013228561Snpallocate:
2014218792Snp		navail = iaq->nirq;
2015218792Snp		rc = 0;
2016219944Snp		if (itype == INTR_MSIX)
2017218792Snp			rc = pci_alloc_msix(sc->dev, &navail);
2018219944Snp		else if (itype == INTR_MSI)
2019218792Snp			rc = pci_alloc_msi(sc->dev, &navail);
2020218792Snp
2021218792Snp		if (rc == 0) {
2022218792Snp			if (navail == iaq->nirq)
2023218792Snp				return (0);
2024218792Snp
2025218792Snp			/*
2026218792Snp			 * Didn't get the number requested.  Use whatever number
2027218792Snp			 * the kernel is willing to allocate (it's in navail).
2028218792Snp			 */
2029228561Snp			device_printf(sc->dev, "fewer vectors than requested, "
2030228561Snp			    "type=%d, req=%d, rcvd=%d; will downshift req.\n",
2031228561Snp			    itype, iaq->nirq, navail);
2032218792Snp			pci_release_msi(sc->dev);
2033228561Snp			goto restart;
2034218792Snp		}
2035218792Snp
2036218792Snp		device_printf(sc->dev,
2037218792Snp		    "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n",
2038218792Snp		    itype, rc, iaq->nirq, navail);
2039218792Snp	}
2040218792Snp
2041218792Snp	device_printf(sc->dev,
2042218792Snp	    "failed to find a usable interrupt type.  "
2043228561Snp	    "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types,
2044218792Snp	    pci_msix_count(sc->dev), pci_msi_count(sc->dev));
2045218792Snp
2046218792Snp	return (ENXIO);
2047218792Snp}
2048218792Snp
2049248925Snp#define FW_VERSION(chip) ( \
2050252661Snp    V_FW_HDR_FW_VER_MAJOR(chip##FW_VERSION_MAJOR) | \
2051252661Snp    V_FW_HDR_FW_VER_MINOR(chip##FW_VERSION_MINOR) | \
2052252661Snp    V_FW_HDR_FW_VER_MICRO(chip##FW_VERSION_MICRO) | \
2053252661Snp    V_FW_HDR_FW_VER_BUILD(chip##FW_VERSION_BUILD))
2054252661Snp#define FW_INTFVER(chip, intf) (chip##FW_HDR_INTFVER_##intf)
2055248925Snp
2056248925Snpstruct fw_info {
2057248925Snp	uint8_t chip;
2058248925Snp	char *kld_name;
2059248925Snp	char *fw_mod_name;
2060248925Snp	struct fw_hdr fw_hdr;	/* XXX: waste of space, need a sparse struct */
2061248925Snp} fw_info[] = {
2062248925Snp	{
2063248925Snp		.chip = CHELSIO_T4,
2064248925Snp		.kld_name = "t4fw_cfg",
2065248925Snp		.fw_mod_name = "t4fw",
2066248925Snp		.fw_hdr = {
2067248925Snp			.chip = FW_HDR_CHIP_T4,
2068248925Snp			.fw_ver = htobe32_const(FW_VERSION(T4)),
2069248925Snp			.intfver_nic = FW_INTFVER(T4, NIC),
2070248925Snp			.intfver_vnic = FW_INTFVER(T4, VNIC),
2071248925Snp			.intfver_ofld = FW_INTFVER(T4, OFLD),
2072248925Snp			.intfver_ri = FW_INTFVER(T4, RI),
2073248925Snp			.intfver_iscsipdu = FW_INTFVER(T4, ISCSIPDU),
2074248925Snp			.intfver_iscsi = FW_INTFVER(T4, ISCSI),
2075248925Snp			.intfver_fcoepdu = FW_INTFVER(T4, FCOEPDU),
2076248925Snp			.intfver_fcoe = FW_INTFVER(T4, FCOE),
2077248925Snp		},
2078248925Snp	}, {
2079248925Snp		.chip = CHELSIO_T5,
2080248925Snp		.kld_name = "t5fw_cfg",
2081248925Snp		.fw_mod_name = "t5fw",
2082248925Snp		.fw_hdr = {
2083248925Snp			.chip = FW_HDR_CHIP_T5,
2084248925Snp			.fw_ver = htobe32_const(FW_VERSION(T5)),
2085248925Snp			.intfver_nic = FW_INTFVER(T5, NIC),
2086248925Snp			.intfver_vnic = FW_INTFVER(T5, VNIC),
2087248925Snp			.intfver_ofld = FW_INTFVER(T5, OFLD),
2088248925Snp			.intfver_ri = FW_INTFVER(T5, RI),
2089248925Snp			.intfver_iscsipdu = FW_INTFVER(T5, ISCSIPDU),
2090248925Snp			.intfver_iscsi = FW_INTFVER(T5, ISCSI),
2091248925Snp			.intfver_fcoepdu = FW_INTFVER(T5, FCOEPDU),
2092248925Snp			.intfver_fcoe = FW_INTFVER(T5, FCOE),
2093248925Snp		},
2094248925Snp	}
2095248925Snp};
2096248925Snp
2097248925Snpstatic struct fw_info *
2098248925Snpfind_fw_info(int chip)
2099248925Snp{
2100248925Snp	int i;
2101248925Snp
2102248925Snp	for (i = 0; i < nitems(fw_info); i++) {
2103248925Snp		if (fw_info[i].chip == chip)
2104248925Snp			return (&fw_info[i]);
2105248925Snp	}
2106248925Snp	return (NULL);
2107248925Snp}
2108248925Snp
2109218792Snp/*
2110248925Snp * Is the given firmware API compatible with the one the driver was compiled
2111248925Snp * with?
2112247347Snp */
2113247347Snpstatic int
2114248925Snpfw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2)
2115247347Snp{
2116247347Snp
2117248925Snp	/* short circuit if it's the exact same firmware version */
2118248925Snp	if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver)
2119247347Snp		return (1);
2120247347Snp
2121247347Snp	/*
2122247347Snp	 * XXX: Is this too conservative?  Perhaps I should limit this to the
2123247347Snp	 * features that are supported in the driver.
2124247347Snp	 */
2125248925Snp#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x)
2126248925Snp	if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) &&
2127248925Snp	    SAME_INTF(ofld) && SAME_INTF(ri) && SAME_INTF(iscsipdu) &&
2128248925Snp	    SAME_INTF(iscsi) && SAME_INTF(fcoepdu) && SAME_INTF(fcoe))
2129247347Snp		return (1);
2130248925Snp#undef SAME_INTF
2131247347Snp
2132247347Snp	return (0);
2133247347Snp}
2134247347Snp
2135247347Snp/*
2136251434Snp * The firmware in the KLD is usable, but should it be installed?  This routine
2137251434Snp * explains itself in detail if it indicates the KLD firmware should be
2138251434Snp * installed.
2139249376Snp */
2140249376Snpstatic int
2141249376Snpshould_install_kld_fw(struct adapter *sc, int card_fw_usable, int k, int c)
2142249376Snp{
2143249376Snp	const char *reason;
2144249376Snp
2145249376Snp	if (!card_fw_usable) {
2146249376Snp		reason = "incompatible or unusable";
2147249376Snp		goto install;
2148249376Snp	}
2149249376Snp
2150249376Snp	if (k > c) {
2151249376Snp		reason = "older than the version bundled with this driver";
2152249376Snp		goto install;
2153249376Snp	}
2154249376Snp
2155249376Snp	if (t4_fw_install == 2 && k != c) {
2156249376Snp		reason = "different than the version bundled with this driver";
2157249376Snp		goto install;
2158249376Snp	}
2159249376Snp
2160249376Snp	return (0);
2161249376Snp
2162249376Snpinstall:
2163251434Snp	if (t4_fw_install == 0) {
2164251434Snp		device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, "
2165251434Snp		    "but the driver is prohibited from installing a different "
2166251434Snp		    "firmware on the card.\n",
2167251434Snp		    G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c),
2168251434Snp		    G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason);
2169251434Snp
2170251434Snp		return (0);
2171251434Snp	}
2172251434Snp
2173249376Snp	device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, "
2174249376Snp	    "installing firmware %u.%u.%u.%u on card.\n",
2175249376Snp	    G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c),
2176249376Snp	    G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason,
2177249376Snp	    G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k),
2178249376Snp	    G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k));
2179249376Snp
2180249376Snp	return (1);
2181249376Snp}
2182249376Snp/*
2183248925Snp * Establish contact with the firmware and determine if we are the master driver
2184248925Snp * or not, and whether we are responsible for chip initialization.
2185218792Snp */
2186218792Snpstatic int
2187218792Snpprep_firmware(struct adapter *sc)
2188218792Snp{
2189248925Snp	const struct firmware *fw = NULL, *default_cfg;
2190248925Snp	int rc, pf, card_fw_usable, kld_fw_usable, need_fw_reset = 1;
2191218792Snp	enum dev_state state;
2192248925Snp	struct fw_info *fw_info;
2193248925Snp	struct fw_hdr *card_fw;		/* fw on the card */
2194248925Snp	const struct fw_hdr *kld_fw;	/* fw in the KLD */
2195248925Snp	const struct fw_hdr *drv_fw;	/* fw header the driver was compiled
2196248925Snp					   against */
2197218792Snp
2198248925Snp	/* Contact firmware. */
2199248925Snp	rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state);
2200248925Snp	if (rc < 0 || state == DEV_STATE_ERR) {
2201248925Snp		rc = -rc;
2202248925Snp		device_printf(sc->dev,
2203248925Snp		    "failed to connect to the firmware: %d, %d.\n", rc, state);
2204248925Snp		return (rc);
2205248925Snp	}
2206248925Snp	pf = rc;
2207248925Snp	if (pf == sc->mbox)
2208248925Snp		sc->flags |= MASTER_PF;
2209248925Snp	else if (state == DEV_STATE_UNINIT) {
2210248925Snp		/*
2211248925Snp		 * We didn't get to be the master so we definitely won't be
2212248925Snp		 * configuring the chip.  It's a bug if someone else hasn't
2213248925Snp		 * configured it already.
2214248925Snp		 */
2215248925Snp		device_printf(sc->dev, "couldn't be master(%d), "
2216248925Snp		    "device not already initialized either(%d).\n", rc, state);
2217248925Snp		return (EDOOFUS);
2218248925Snp	}
2219228561Snp
2220248925Snp	/* This is the firmware whose headers the driver was compiled against */
2221248925Snp	fw_info = find_fw_info(chip_id(sc));
2222248925Snp	if (fw_info == NULL) {
2223248925Snp		device_printf(sc->dev,
2224248925Snp		    "unable to look up firmware information for chip %d.\n",
2225248925Snp		    chip_id(sc));
2226248925Snp		return (EINVAL);
2227248925Snp	}
2228248925Snp	drv_fw = &fw_info->fw_hdr;
2229248925Snp
2230248925Snp	/*
2231248925Snp	 * The firmware KLD contains many modules.  The KLD name is also the
2232248925Snp	 * name of the module that contains the default config file.
2233248925Snp	 */
2234248925Snp	default_cfg = firmware_get(fw_info->kld_name);
2235248925Snp
2236247347Snp	/* Read the header of the firmware on the card */
2237247347Snp	card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK);
2238247347Snp	rc = -t4_read_flash(sc, FLASH_FW_START,
2239247347Snp	    sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1);
2240247347Snp	if (rc == 0)
2241248925Snp		card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw);
2242247347Snp	else {
2243247347Snp		device_printf(sc->dev,
2244247347Snp		    "Unable to read card's firmware header: %d\n", rc);
2245247347Snp		card_fw_usable = 0;
2246247347Snp	}
2247218792Snp
2248247347Snp	/* This is the firmware in the KLD */
2249248925Snp	fw = firmware_get(fw_info->fw_mod_name);
2250247347Snp	if (fw != NULL) {
2251247347Snp		kld_fw = (const void *)fw->data;
2252248925Snp		kld_fw_usable = fw_compatible(drv_fw, kld_fw);
2253247347Snp	} else {
2254247347Snp		kld_fw = NULL;
2255247347Snp		kld_fw_usable = 0;
2256247347Snp	}
2257219287Snp
2258248925Snp	if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver &&
2259251434Snp	    (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver)) {
2260248925Snp		/*
2261248925Snp		 * Common case: the firmware on the card is an exact match and
2262248925Snp		 * the KLD is an exact match too, or the KLD is
2263251434Snp		 * absent/incompatible.  Note that t4_fw_install = 2 is ignored
2264251434Snp		 * here -- use cxgbetool loadfw if you want to reinstall the
2265251434Snp		 * same firmware as the one on the card.
2266248925Snp		 */
2267248925Snp	} else if (kld_fw_usable && state == DEV_STATE_UNINIT &&
2268249376Snp	    should_install_kld_fw(sc, card_fw_usable, be32toh(kld_fw->fw_ver),
2269249376Snp	    be32toh(card_fw->fw_ver))) {
2270219287Snp
2271250221Snp		rc = -t4_fw_upgrade(sc, sc->mbox, fw->data, fw->datasize, 0);
2272247347Snp		if (rc != 0) {
2273247347Snp			device_printf(sc->dev,
2274247347Snp			    "failed to install firmware: %d\n", rc);
2275228561Snp			goto done;
2276219287Snp		}
2277219287Snp
2278247347Snp		/* Installed successfully, update the cached header too. */
2279247347Snp		memcpy(card_fw, kld_fw, sizeof(*card_fw));
2280247347Snp		card_fw_usable = 1;
2281248925Snp		need_fw_reset = 0;	/* already reset as part of load_fw */
2282247347Snp	}
2283219287Snp
2284247347Snp	if (!card_fw_usable) {
2285248925Snp		uint32_t d, c, k;
2286247347Snp
2287248925Snp		d = ntohl(drv_fw->fw_ver);
2288247347Snp		c = ntohl(card_fw->fw_ver);
2289247347Snp		k = kld_fw ? ntohl(kld_fw->fw_ver) : 0;
2290247347Snp
2291247347Snp		device_printf(sc->dev, "Cannot find a usable firmware: "
2292248925Snp		    "fw_install %d, chip state %d, "
2293248925Snp		    "driver compiled with %d.%d.%d.%d, "
2294247347Snp		    "card has %d.%d.%d.%d, KLD has %d.%d.%d.%d\n",
2295248925Snp		    t4_fw_install, state,
2296248925Snp		    G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d),
2297248925Snp		    G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d),
2298247347Snp		    G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c),
2299247347Snp		    G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c),
2300247347Snp		    G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k),
2301247347Snp		    G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k));
2302248925Snp		rc = EINVAL;
2303247347Snp		goto done;
2304218792Snp	}
2305218792Snp
2306247347Snp	/* We're using whatever's on the card and it's known to be good. */
2307247347Snp	sc->params.fw_vers = ntohl(card_fw->fw_ver);
2308247347Snp	snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u",
2309247347Snp	    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
2310247347Snp	    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
2311247347Snp	    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
2312247347Snp	    G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers));
2313252705Snp	t4_get_tp_version(sc, &sc->params.tp_vers);
2314247347Snp
2315218792Snp	/* Reset device */
2316248925Snp	if (need_fw_reset &&
2317248925Snp	    (rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST)) != 0) {
2318218792Snp		device_printf(sc->dev, "firmware reset failed: %d.\n", rc);
2319218792Snp		if (rc != ETIMEDOUT && rc != EIO)
2320218792Snp			t4_fw_bye(sc, sc->mbox);
2321228561Snp		goto done;
2322218792Snp	}
2323248925Snp	sc->flags |= FW_OK;
2324218792Snp
2325248925Snp	rc = get_params__pre_init(sc);
2326248925Snp	if (rc != 0)
2327248925Snp		goto done; /* error message displayed already */
2328248925Snp
2329228561Snp	/* Partition adapter resources as specified in the config file. */
2330248925Snp	if (state == DEV_STATE_UNINIT) {
2331228561Snp
2332248925Snp		KASSERT(sc->flags & MASTER_PF,
2333248925Snp		    ("%s: trying to change chip settings when not master.",
2334248925Snp		    __func__));
2335228561Snp
2336248925Snp		rc = partition_resources(sc, default_cfg, fw_info->kld_name);
2337228561Snp		if (rc != 0)
2338228561Snp			goto done;	/* error message displayed already */
2339248925Snp
2340248925Snp		t4_tweak_chip_settings(sc);
2341248925Snp
2342248925Snp		/* get basic stuff going */
2343248925Snp		rc = -t4_fw_initialize(sc, sc->mbox);
2344248925Snp		if (rc != 0) {
2345248925Snp			device_printf(sc->dev, "fw init failed: %d.\n", rc);
2346248925Snp			goto done;
2347248925Snp		}
2348245936Snp	} else {
2349248925Snp		snprintf(sc->cfg_file, sizeof(sc->cfg_file), "pf%d", pf);
2350248925Snp		sc->cfcsum = 0;
2351228561Snp	}
2352228561Snp
2353228561Snpdone:
2354247347Snp	free(card_fw, M_CXGBE);
2355228561Snp	if (fw != NULL)
2356228561Snp		firmware_put(fw, FIRMWARE_UNLOAD);
2357228561Snp	if (default_cfg != NULL)
2358228561Snp		firmware_put(default_cfg, FIRMWARE_UNLOAD);
2359228561Snp
2360228561Snp	return (rc);
2361218792Snp}
2362218792Snp
2363228561Snp#define FW_PARAM_DEV(param) \
2364228561Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
2365228561Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
2366228561Snp#define FW_PARAM_PFVF(param) \
2367228561Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
2368228561Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param))
2369228561Snp
2370228561Snp/*
2371248925Snp * Partition chip resources for use between various PFs, VFs, etc.
2372228561Snp */
2373218792Snpstatic int
2374248925Snppartition_resources(struct adapter *sc, const struct firmware *default_cfg,
2375248925Snp    const char *name_prefix)
2376222551Snp{
2377248925Snp	const struct firmware *cfg = NULL;
2378248925Snp	int rc = 0;
2379248925Snp	struct fw_caps_config_cmd caps;
2380248925Snp	uint32_t mtype, moff, finicsum, cfcsum;
2381222551Snp
2382248925Snp	/*
2383248925Snp	 * Figure out what configuration file to use.  Pick the default config
2384248925Snp	 * file for the card if the user hasn't specified one explicitly.
2385248925Snp	 */
2386248925Snp	snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", t4_cfg_file);
2387248925Snp	if (strncmp(t4_cfg_file, DEFAULT_CF, sizeof(t4_cfg_file)) == 0) {
2388248925Snp		/* Card specific overrides go here. */
2389248925Snp		if (pci_get_device(sc->dev) == 0x440a)
2390248925Snp			snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF);
2391249376Snp		if (is_fpga(sc))
2392249376Snp			snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF);
2393222551Snp	}
2394222551Snp
2395248925Snp	/*
2396248925Snp	 * We need to load another module if the profile is anything except
2397248925Snp	 * "default" or "flash".
2398248925Snp	 */
2399248925Snp	if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) != 0 &&
2400248925Snp	    strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) {
2401248925Snp		char s[32];
2402248925Snp
2403248925Snp		snprintf(s, sizeof(s), "%s_%s", name_prefix, sc->cfg_file);
2404248925Snp		cfg = firmware_get(s);
2405248925Snp		if (cfg == NULL) {
2406248925Snp			if (default_cfg != NULL) {
2407249376Snp				device_printf(sc->dev,
2408249376Snp				    "unable to load module \"%s\" for "
2409249376Snp				    "configuration profile \"%s\", will use "
2410249376Snp				    "the default config file instead.\n",
2411249376Snp				    s, sc->cfg_file);
2412248925Snp				snprintf(sc->cfg_file, sizeof(sc->cfg_file),
2413248925Snp				    "%s", DEFAULT_CF);
2414248925Snp			} else {
2415249376Snp				device_printf(sc->dev,
2416249376Snp				    "unable to load module \"%s\" for "
2417249376Snp				    "configuration profile \"%s\", will use "
2418249376Snp				    "the config file on the card's flash "
2419249376Snp				    "instead.\n", s, sc->cfg_file);
2420248925Snp				snprintf(sc->cfg_file, sizeof(sc->cfg_file),
2421248925Snp				    "%s", FLASH_CF);
2422248925Snp			}
2423248925Snp		}
2424228561Snp	}
2425222551Snp
2426248925Snp	if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) == 0 &&
2427248925Snp	    default_cfg == NULL) {
2428228561Snp		device_printf(sc->dev,
2429248925Snp		    "default config file not available, will use the config "
2430248925Snp		    "file on the card's flash instead.\n");
2431248925Snp		snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", FLASH_CF);
2432228561Snp	}
2433228561Snp
2434248925Snp	if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) {
2435248925Snp		u_int cflen, i, n;
2436248925Snp		const uint32_t *cfdata;
2437248925Snp		uint32_t param, val, addr, off, mw_base, mw_aperture;
2438228561Snp
2439248925Snp		KASSERT(cfg != NULL || default_cfg != NULL,
2440248925Snp		    ("%s: no config to upload", __func__));
2441228561Snp
2442248925Snp		/*
2443248925Snp		 * Ask the firmware where it wants us to upload the config file.
2444248925Snp		 */
2445248925Snp		param = FW_PARAM_DEV(CF);
2446248925Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
2447248925Snp		if (rc != 0) {
2448248925Snp			/* No support for config file?  Shouldn't happen. */
2449248925Snp			device_printf(sc->dev,
2450248925Snp			    "failed to query config file location: %d.\n", rc);
2451248925Snp			goto done;
2452248925Snp		}
2453248925Snp		mtype = G_FW_PARAMS_PARAM_Y(val);
2454248925Snp		moff = G_FW_PARAMS_PARAM_Z(val) << 16;
2455228561Snp
2456248925Snp		/*
2457248925Snp		 * XXX: sheer laziness.  We deliberately added 4 bytes of
2458248925Snp		 * useless stuffing/comments at the end of the config file so
2459248925Snp		 * it's ok to simply throw away the last remaining bytes when
2460248925Snp		 * the config file is not an exact multiple of 4.  This also
2461248925Snp		 * helps with the validate_mt_off_len check.
2462248925Snp		 */
2463248925Snp		if (cfg != NULL) {
2464248925Snp			cflen = cfg->datasize & ~3;
2465248925Snp			cfdata = cfg->data;
2466248925Snp		} else {
2467248925Snp			cflen = default_cfg->datasize & ~3;
2468248925Snp			cfdata = default_cfg->data;
2469248925Snp		}
2470222551Snp
2471248925Snp		if (cflen > FLASH_CFG_MAX_SIZE) {
2472248925Snp			device_printf(sc->dev,
2473248925Snp			    "config file too long (%d, max allowed is %d).  "
2474248925Snp			    "Will try to use the config on the card, if any.\n",
2475248925Snp			    cflen, FLASH_CFG_MAX_SIZE);
2476248925Snp			goto use_config_on_flash;
2477248925Snp		}
2478218792Snp
2479248925Snp		rc = validate_mt_off_len(sc, mtype, moff, cflen, &addr);
2480248925Snp		if (rc != 0) {
2481248925Snp			device_printf(sc->dev,
2482248925Snp			    "%s: addr (%d/0x%x) or len %d is not valid: %d.  "
2483248925Snp			    "Will try to use the config on the card, if any.\n",
2484248925Snp			    __func__, mtype, moff, cflen, rc);
2485248925Snp			goto use_config_on_flash;
2486248925Snp		}
2487248925Snp
2488248925Snp		memwin_info(sc, 2, &mw_base, &mw_aperture);
2489248925Snp		while (cflen) {
2490248925Snp			off = position_memwin(sc, 2, addr);
2491248925Snp			n = min(cflen, mw_aperture - off);
2492248925Snp			for (i = 0; i < n; i += 4)
2493248925Snp				t4_write_reg(sc, mw_base + off + i, *cfdata++);
2494248925Snp			cflen -= n;
2495248925Snp			addr += n;
2496248925Snp		}
2497248925Snp	} else {
2498248925Snpuse_config_on_flash:
2499256791Snp		mtype = FW_MEMTYPE_FLASH;
2500248925Snp		moff = t4_flash_cfg_addr(sc);
2501228561Snp	}
2502228561Snp
2503228561Snp	bzero(&caps, sizeof(caps));
2504228561Snp	caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
2505218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
2506228561Snp	caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID |
2507228561Snp	    V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
2508248925Snp	    V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(moff >> 16) | FW_LEN16(caps));
2509228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps);
2510228561Snp	if (rc != 0) {
2511228561Snp		device_printf(sc->dev,
2512249376Snp		    "failed to pre-process config file: %d "
2513249376Snp		    "(mtype %d, moff 0x%x).\n", rc, mtype, moff);
2514248925Snp		goto done;
2515228561Snp	}
2516218792Snp
2517228561Snp	finicsum = be32toh(caps.finicsum);
2518228561Snp	cfcsum = be32toh(caps.cfcsum);
2519228561Snp	if (finicsum != cfcsum) {
2520228561Snp		device_printf(sc->dev,
2521228561Snp		    "WARNING: config file checksum mismatch: %08x %08x\n",
2522228561Snp		    finicsum, cfcsum);
2523228561Snp	}
2524228561Snp	sc->cfcsum = cfcsum;
2525218792Snp
2526228561Snp#define LIMIT_CAPS(x) do { \
2527228561Snp	caps.x &= htobe16(t4_##x##_allowed); \
2528228561Snp} while (0)
2529228561Snp
2530228561Snp	/*
2531228561Snp	 * Let the firmware know what features will (not) be used so it can tune
2532228561Snp	 * things accordingly.
2533228561Snp	 */
2534228561Snp	LIMIT_CAPS(linkcaps);
2535228561Snp	LIMIT_CAPS(niccaps);
2536228561Snp	LIMIT_CAPS(toecaps);
2537228561Snp	LIMIT_CAPS(rdmacaps);
2538228561Snp	LIMIT_CAPS(iscsicaps);
2539228561Snp	LIMIT_CAPS(fcoecaps);
2540228561Snp#undef LIMIT_CAPS
2541228561Snp
2542228561Snp	caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
2543218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
2544228561Snp	caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps));
2545228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL);
2546228561Snp	if (rc != 0) {
2547228561Snp		device_printf(sc->dev,
2548228561Snp		    "failed to process config file: %d.\n", rc);
2549228561Snp	}
2550248925Snpdone:
2551248925Snp	if (cfg != NULL)
2552248925Snp		firmware_put(cfg, FIRMWARE_UNLOAD);
2553248925Snp	return (rc);
2554218792Snp}
2555218792Snp
2556228561Snp/*
2557248925Snp * Retrieve parameters that are needed (or nice to have) very early.
2558228561Snp */
2559218792Snpstatic int
2560228561Snpget_params__pre_init(struct adapter *sc)
2561218792Snp{
2562218792Snp	int rc;
2563228561Snp	uint32_t param[2], val[2];
2564228561Snp	struct fw_devlog_cmd cmd;
2565228561Snp	struct devlog_params *dlog = &sc->params.devlog;
2566218792Snp
2567228561Snp	param[0] = FW_PARAM_DEV(PORTVEC);
2568228561Snp	param[1] = FW_PARAM_DEV(CCLK);
2569228561Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val);
2570218792Snp	if (rc != 0) {
2571218792Snp		device_printf(sc->dev,
2572228561Snp		    "failed to query parameters (pre_init): %d.\n", rc);
2573228561Snp		return (rc);
2574218792Snp	}
2575218792Snp
2576218792Snp	sc->params.portvec = val[0];
2577240452Snp	sc->params.nports = bitcount32(val[0]);
2578228561Snp	sc->params.vpd.cclk = val[1];
2579218792Snp
2580228561Snp	/* Read device log parameters. */
2581228561Snp	bzero(&cmd, sizeof(cmd));
2582228561Snp	cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) |
2583228561Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
2584228561Snp	cmd.retval_len16 = htobe32(FW_LEN16(cmd));
2585228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd);
2586228561Snp	if (rc != 0) {
2587228561Snp		device_printf(sc->dev,
2588228561Snp		    "failed to get devlog parameters: %d.\n", rc);
2589228561Snp		bzero(dlog, sizeof (*dlog));
2590228561Snp		rc = 0;	/* devlog isn't critical for device operation */
2591228561Snp	} else {
2592228561Snp		val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog);
2593228561Snp		dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]);
2594228561Snp		dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4;
2595228561Snp		dlog->size = be32toh(cmd.memsize_devlog);
2596228561Snp	}
2597228561Snp
2598228561Snp	return (rc);
2599228561Snp}
2600228561Snp
2601228561Snp/*
2602228561Snp * Retrieve various parameters that are of interest to the driver.  The device
2603228561Snp * has been initialized by the firmware at this point.
2604228561Snp */
2605228561Snpstatic int
2606228561Snpget_params__post_init(struct adapter *sc)
2607228561Snp{
2608228561Snp	int rc;
2609228561Snp	uint32_t param[7], val[7];
2610228561Snp	struct fw_caps_config_cmd caps;
2611228561Snp
2612228561Snp	param[0] = FW_PARAM_PFVF(IQFLINT_START);
2613228561Snp	param[1] = FW_PARAM_PFVF(EQ_START);
2614228561Snp	param[2] = FW_PARAM_PFVF(FILTER_START);
2615228561Snp	param[3] = FW_PARAM_PFVF(FILTER_END);
2616245434Snp	param[4] = FW_PARAM_PFVF(L2T_START);
2617245434Snp	param[5] = FW_PARAM_PFVF(L2T_END);
2618245434Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
2619228561Snp	if (rc != 0) {
2620228561Snp		device_printf(sc->dev,
2621228561Snp		    "failed to query parameters (post_init): %d.\n", rc);
2622228561Snp		return (rc);
2623228561Snp	}
2624228561Snp
2625228561Snp	sc->sge.iq_start = val[0];
2626228561Snp	sc->sge.eq_start = val[1];
2627228561Snp	sc->tids.ftid_base = val[2];
2628228561Snp	sc->tids.nftids = val[3] - val[2] + 1;
2629265426Snp	sc->params.ftid_min = val[2];
2630265426Snp	sc->params.ftid_max = val[3];
2631245434Snp	sc->vres.l2t.start = val[4];
2632245434Snp	sc->vres.l2t.size = val[5] - val[4] + 1;
2633245434Snp	KASSERT(sc->vres.l2t.size <= L2T_SIZE,
2634245434Snp	    ("%s: L2 table size (%u) larger than expected (%u)",
2635245434Snp	    __func__, sc->vres.l2t.size, L2T_SIZE));
2636228561Snp
2637228561Snp	/* get capabilites */
2638228561Snp	bzero(&caps, sizeof(caps));
2639228561Snp	caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
2640228561Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
2641228561Snp	caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps));
2642228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps);
2643228561Snp	if (rc != 0) {
2644228561Snp		device_printf(sc->dev,
2645228561Snp		    "failed to get card capabilities: %d.\n", rc);
2646228561Snp		return (rc);
2647228561Snp	}
2648228561Snp
2649265426Snp#define READ_CAPS(x) do { \
2650265426Snp	sc->x = htobe16(caps.x); \
2651265426Snp} while (0)
2652265426Snp	READ_CAPS(linkcaps);
2653265426Snp	READ_CAPS(niccaps);
2654265426Snp	READ_CAPS(toecaps);
2655265426Snp	READ_CAPS(rdmacaps);
2656265426Snp	READ_CAPS(iscsicaps);
2657265426Snp	READ_CAPS(fcoecaps);
2658265426Snp
2659265426Snp	if (sc->niccaps & FW_CAPS_CONFIG_NIC_ETHOFLD) {
2660265426Snp		param[0] = FW_PARAM_PFVF(ETHOFLD_START);
2661265426Snp		param[1] = FW_PARAM_PFVF(ETHOFLD_END);
2662265426Snp		param[2] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
2663265426Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 3, param, val);
2664265426Snp		if (rc != 0) {
2665265426Snp			device_printf(sc->dev,
2666265426Snp			    "failed to query NIC parameters: %d.\n", rc);
2667265426Snp			return (rc);
2668265426Snp		}
2669265426Snp		sc->tids.etid_base = val[0];
2670265426Snp		sc->params.etid_min = val[0];
2671265426Snp		sc->tids.netids = val[1] - val[0] + 1;
2672265426Snp		sc->params.netids = sc->tids.netids;
2673265426Snp		sc->params.eo_wr_cred = val[2];
2674265426Snp		sc->params.ethoffload = 1;
2675265426Snp	}
2676265426Snp
2677265426Snp	if (sc->toecaps) {
2678218792Snp		/* query offload-related parameters */
2679228561Snp		param[0] = FW_PARAM_DEV(NTID);
2680228561Snp		param[1] = FW_PARAM_PFVF(SERVER_START);
2681228561Snp		param[2] = FW_PARAM_PFVF(SERVER_END);
2682228561Snp		param[3] = FW_PARAM_PFVF(TDDP_START);
2683228561Snp		param[4] = FW_PARAM_PFVF(TDDP_END);
2684228561Snp		param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
2685228561Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
2686218792Snp		if (rc != 0) {
2687218792Snp			device_printf(sc->dev,
2688218792Snp			    "failed to query TOE parameters: %d.\n", rc);
2689228561Snp			return (rc);
2690218792Snp		}
2691218792Snp		sc->tids.ntids = val[0];
2692218792Snp		sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS);
2693218792Snp		sc->tids.stid_base = val[1];
2694218792Snp		sc->tids.nstids = val[2] - val[1] + 1;
2695218792Snp		sc->vres.ddp.start = val[3];
2696218792Snp		sc->vres.ddp.size = val[4] - val[3] + 1;
2697218792Snp		sc->params.ofldq_wr_cred = val[5];
2698218792Snp		sc->params.offload = 1;
2699218792Snp	}
2700265426Snp	if (sc->rdmacaps) {
2701228561Snp		param[0] = FW_PARAM_PFVF(STAG_START);
2702228561Snp		param[1] = FW_PARAM_PFVF(STAG_END);
2703228561Snp		param[2] = FW_PARAM_PFVF(RQ_START);
2704228561Snp		param[3] = FW_PARAM_PFVF(RQ_END);
2705228561Snp		param[4] = FW_PARAM_PFVF(PBL_START);
2706228561Snp		param[5] = FW_PARAM_PFVF(PBL_END);
2707228561Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
2708218792Snp		if (rc != 0) {
2709218792Snp			device_printf(sc->dev,
2710228561Snp			    "failed to query RDMA parameters(1): %d.\n", rc);
2711228561Snp			return (rc);
2712218792Snp		}
2713218792Snp		sc->vres.stag.start = val[0];
2714218792Snp		sc->vres.stag.size = val[1] - val[0] + 1;
2715218792Snp		sc->vres.rq.start = val[2];
2716218792Snp		sc->vres.rq.size = val[3] - val[2] + 1;
2717218792Snp		sc->vres.pbl.start = val[4];
2718218792Snp		sc->vres.pbl.size = val[5] - val[4] + 1;
2719228561Snp
2720228561Snp		param[0] = FW_PARAM_PFVF(SQRQ_START);
2721228561Snp		param[1] = FW_PARAM_PFVF(SQRQ_END);
2722228561Snp		param[2] = FW_PARAM_PFVF(CQ_START);
2723228561Snp		param[3] = FW_PARAM_PFVF(CQ_END);
2724228561Snp		param[4] = FW_PARAM_PFVF(OCQ_START);
2725228561Snp		param[5] = FW_PARAM_PFVF(OCQ_END);
2726254933Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
2727228561Snp		if (rc != 0) {
2728228561Snp			device_printf(sc->dev,
2729228561Snp			    "failed to query RDMA parameters(2): %d.\n", rc);
2730228561Snp			return (rc);
2731228561Snp		}
2732228561Snp		sc->vres.qp.start = val[0];
2733228561Snp		sc->vres.qp.size = val[1] - val[0] + 1;
2734228561Snp		sc->vres.cq.start = val[2];
2735228561Snp		sc->vres.cq.size = val[3] - val[2] + 1;
2736228561Snp		sc->vres.ocq.start = val[4];
2737228561Snp		sc->vres.ocq.size = val[5] - val[4] + 1;
2738218792Snp	}
2739265426Snp	if (sc->iscsicaps) {
2740228561Snp		param[0] = FW_PARAM_PFVF(ISCSI_START);
2741228561Snp		param[1] = FW_PARAM_PFVF(ISCSI_END);
2742228561Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val);
2743218792Snp		if (rc != 0) {
2744218792Snp			device_printf(sc->dev,
2745218792Snp			    "failed to query iSCSI parameters: %d.\n", rc);
2746228561Snp			return (rc);
2747218792Snp		}
2748218792Snp		sc->vres.iscsi.start = val[0];
2749218792Snp		sc->vres.iscsi.size = val[1] - val[0] + 1;
2750218792Snp	}
2751218792Snp
2752248925Snp	/*
2753248925Snp	 * We've got the params we wanted to query via the firmware.  Now grab
2754248925Snp	 * some others directly from the chip.
2755248925Snp	 */
2756248925Snp	rc = t4_read_chip_settings(sc);
2757228561Snp
2758218792Snp	return (rc);
2759218792Snp}
2760218792Snp
2761247291Snpstatic int
2762247291Snpset_params__post_init(struct adapter *sc)
2763247291Snp{
2764247291Snp	uint32_t param, val;
2765247291Snp
2766249382Snp	/* ask for encapsulated CPLs */
2767247291Snp	param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP);
2768249382Snp	val = 1;
2769249382Snp	(void)t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
2770247291Snp
2771249382Snp	return (0);
2772247291Snp}
2773247291Snp
2774228561Snp#undef FW_PARAM_PFVF
2775228561Snp#undef FW_PARAM_DEV
2776228561Snp
2777218792Snpstatic void
2778218792Snpt4_set_desc(struct adapter *sc)
2779218792Snp{
2780218792Snp	char buf[128];
2781218792Snp	struct adapter_params *p = &sc->params;
2782218792Snp
2783254577Snp	snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, "
2784254577Snp	    "P/N:%s, E/C:%s", p->vpd.id, is_offload(sc) ? "R" : "",
2785254577Snp	    chip_rev(sc), p->vpd.sn, p->vpd.pn, p->vpd.ec);
2786218792Snp
2787218792Snp	device_set_desc_copy(sc->dev, buf);
2788218792Snp}
2789218792Snp
2790218792Snpstatic void
2791270297Snpbuild_medialist(struct port_info *pi, struct ifmedia *media)
2792218792Snp{
2793218792Snp	int data, m;
2794218792Snp
2795218792Snp	PORT_LOCK(pi);
2796218792Snp
2797218792Snp	ifmedia_removeall(media);
2798218792Snp
2799218792Snp	m = IFM_ETHER | IFM_FDX;
2800218792Snp	data = (pi->port_type << 8) | pi->mod_type;
2801218792Snp
2802218792Snp	switch(pi->port_type) {
2803218792Snp	case FW_PORT_TYPE_BT_XFI:
2804218792Snp		ifmedia_add(media, m | IFM_10G_T, data, NULL);
2805218792Snp		break;
2806218792Snp
2807218792Snp	case FW_PORT_TYPE_BT_XAUI:
2808218792Snp		ifmedia_add(media, m | IFM_10G_T, data, NULL);
2809218792Snp		/* fall through */
2810218792Snp
2811218792Snp	case FW_PORT_TYPE_BT_SGMII:
2812218792Snp		ifmedia_add(media, m | IFM_1000_T, data, NULL);
2813218792Snp		ifmedia_add(media, m | IFM_100_TX, data, NULL);
2814218792Snp		ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL);
2815218792Snp		ifmedia_set(media, IFM_ETHER | IFM_AUTO);
2816218792Snp		break;
2817218792Snp
2818218792Snp	case FW_PORT_TYPE_CX4:
2819218792Snp		ifmedia_add(media, m | IFM_10G_CX4, data, NULL);
2820218792Snp		ifmedia_set(media, m | IFM_10G_CX4);
2821218792Snp		break;
2822218792Snp
2823265410Snp	case FW_PORT_TYPE_QSFP_10G:
2824218792Snp	case FW_PORT_TYPE_SFP:
2825218792Snp	case FW_PORT_TYPE_FIBER_XFI:
2826218792Snp	case FW_PORT_TYPE_FIBER_XAUI:
2827218792Snp		switch (pi->mod_type) {
2828218792Snp
2829218792Snp		case FW_PORT_MOD_TYPE_LR:
2830218792Snp			ifmedia_add(media, m | IFM_10G_LR, data, NULL);
2831218792Snp			ifmedia_set(media, m | IFM_10G_LR);
2832218792Snp			break;
2833218792Snp
2834218792Snp		case FW_PORT_MOD_TYPE_SR:
2835218792Snp			ifmedia_add(media, m | IFM_10G_SR, data, NULL);
2836218792Snp			ifmedia_set(media, m | IFM_10G_SR);
2837218792Snp			break;
2838218792Snp
2839218792Snp		case FW_PORT_MOD_TYPE_LRM:
2840218792Snp			ifmedia_add(media, m | IFM_10G_LRM, data, NULL);
2841218792Snp			ifmedia_set(media, m | IFM_10G_LRM);
2842218792Snp			break;
2843218792Snp
2844218792Snp		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
2845218792Snp		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
2846218792Snp			ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL);
2847218792Snp			ifmedia_set(media, m | IFM_10G_TWINAX);
2848218792Snp			break;
2849218792Snp
2850218792Snp		case FW_PORT_MOD_TYPE_NONE:
2851218792Snp			m &= ~IFM_FDX;
2852218792Snp			ifmedia_add(media, m | IFM_NONE, data, NULL);
2853218792Snp			ifmedia_set(media, m | IFM_NONE);
2854218792Snp			break;
2855218792Snp
2856218792Snp		case FW_PORT_MOD_TYPE_NA:
2857218792Snp		case FW_PORT_MOD_TYPE_ER:
2858218792Snp		default:
2859250092Snp			device_printf(pi->dev,
2860250092Snp			    "unknown port_type (%d), mod_type (%d)\n",
2861250092Snp			    pi->port_type, pi->mod_type);
2862218792Snp			ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
2863218792Snp			ifmedia_set(media, m | IFM_UNKNOWN);
2864218792Snp			break;
2865218792Snp		}
2866218792Snp		break;
2867218792Snp
2868250092Snp	case FW_PORT_TYPE_QSFP:
2869250092Snp		switch (pi->mod_type) {
2870250092Snp
2871250092Snp		case FW_PORT_MOD_TYPE_LR:
2872250092Snp			ifmedia_add(media, m | IFM_40G_LR4, data, NULL);
2873250092Snp			ifmedia_set(media, m | IFM_40G_LR4);
2874250092Snp			break;
2875250092Snp
2876250092Snp		case FW_PORT_MOD_TYPE_SR:
2877250092Snp			ifmedia_add(media, m | IFM_40G_SR4, data, NULL);
2878250092Snp			ifmedia_set(media, m | IFM_40G_SR4);
2879250092Snp			break;
2880250614Snp
2881250092Snp		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
2882250092Snp		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
2883250092Snp			ifmedia_add(media, m | IFM_40G_CR4, data, NULL);
2884250092Snp			ifmedia_set(media, m | IFM_40G_CR4);
2885250092Snp			break;
2886250092Snp
2887250614Snp		case FW_PORT_MOD_TYPE_NONE:
2888250614Snp			m &= ~IFM_FDX;
2889250614Snp			ifmedia_add(media, m | IFM_NONE, data, NULL);
2890250614Snp			ifmedia_set(media, m | IFM_NONE);
2891250614Snp			break;
2892250614Snp
2893250092Snp		default:
2894250092Snp			device_printf(pi->dev,
2895250092Snp			    "unknown port_type (%d), mod_type (%d)\n",
2896250092Snp			    pi->port_type, pi->mod_type);
2897250092Snp			ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
2898250092Snp			ifmedia_set(media, m | IFM_UNKNOWN);
2899250092Snp			break;
2900250092Snp		}
2901250092Snp		break;
2902250092Snp
2903218792Snp	default:
2904250092Snp		device_printf(pi->dev,
2905250092Snp		    "unknown port_type (%d), mod_type (%d)\n", pi->port_type,
2906250092Snp		    pi->mod_type);
2907218792Snp		ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
2908218792Snp		ifmedia_set(media, m | IFM_UNKNOWN);
2909218792Snp		break;
2910218792Snp	}
2911218792Snp
2912218792Snp	PORT_UNLOCK(pi);
2913218792Snp}
2914218792Snp
2915231172Snp#define FW_MAC_EXACT_CHUNK	7
2916231172Snp
2917218792Snp/*
2918218792Snp * Program the port's XGMAC based on parameters in ifnet.  The caller also
2919218792Snp * indicates which parameters should be programmed (the rest are left alone).
2920218792Snp */
2921270297Snpint
2922270297Snpupdate_mac_settings(struct ifnet *ifp, int flags)
2923218792Snp{
2924270297Snp	int rc = 0;
2925270297Snp	struct port_info *pi = ifp->if_softc;
2926218792Snp	struct adapter *sc = pi->adapter;
2927218792Snp	int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1;
2928270297Snp	uint16_t viid = 0xffff;
2929270297Snp	int16_t *xact_addr_filt = NULL;
2930218792Snp
2931245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
2932218792Snp	KASSERT(flags, ("%s: not told what to update.", __func__));
2933218792Snp
2934270297Snp	if (ifp == pi->ifp) {
2935270297Snp		viid = pi->viid;
2936270297Snp		xact_addr_filt = &pi->xact_addr_filt;
2937270297Snp	}
2938270297Snp#ifdef DEV_NETMAP
2939270297Snp	else if (ifp == pi->nm_ifp) {
2940270297Snp		viid = pi->nm_viid;
2941270297Snp		xact_addr_filt = &pi->nm_xact_addr_filt;
2942270297Snp	}
2943270297Snp#endif
2944218792Snp	if (flags & XGMAC_MTU)
2945218792Snp		mtu = ifp->if_mtu;
2946218792Snp
2947218792Snp	if (flags & XGMAC_PROMISC)
2948218792Snp		promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0;
2949218792Snp
2950218792Snp	if (flags & XGMAC_ALLMULTI)
2951218792Snp		allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0;
2952218792Snp
2953218792Snp	if (flags & XGMAC_VLANEX)
2954218792Snp		vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0;
2955218792Snp
2956270297Snp	if (flags & (XGMAC_MTU|XGMAC_PROMISC|XGMAC_ALLMULTI|XGMAC_VLANEX)) {
2957270297Snp		rc = -t4_set_rxmode(sc, sc->mbox, viid, mtu, promisc, allmulti,
2958270297Snp		    1, vlanex, false);
2959270297Snp		if (rc) {
2960270297Snp			if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags,
2961270297Snp			    rc);
2962270297Snp			return (rc);
2963270297Snp		}
2964218792Snp	}
2965218792Snp
2966218792Snp	if (flags & XGMAC_UCADDR) {
2967218792Snp		uint8_t ucaddr[ETHER_ADDR_LEN];
2968218792Snp
2969218792Snp		bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr));
2970270297Snp		rc = t4_change_mac(sc, sc->mbox, viid, *xact_addr_filt, ucaddr,
2971270297Snp		    true, true);
2972218792Snp		if (rc < 0) {
2973218792Snp			rc = -rc;
2974218792Snp			if_printf(ifp, "change_mac failed: %d\n", rc);
2975218792Snp			return (rc);
2976218792Snp		} else {
2977270297Snp			*xact_addr_filt = rc;
2978218792Snp			rc = 0;
2979218792Snp		}
2980218792Snp	}
2981218792Snp
2982218792Snp	if (flags & XGMAC_MCADDRS) {
2983231172Snp		const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK];
2984218792Snp		int del = 1;
2985218792Snp		uint64_t hash = 0;
2986218792Snp		struct ifmultiaddr *ifma;
2987231172Snp		int i = 0, j;
2988218792Snp
2989218792Snp		if_maddr_rlock(ifp);
2990218792Snp		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2991238054Snp			if (ifma->ifma_addr->sa_family != AF_LINK)
2992218792Snp				continue;
2993231172Snp			mcaddr[i++] =
2994231172Snp			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2995218792Snp
2996231172Snp			if (i == FW_MAC_EXACT_CHUNK) {
2997270297Snp				rc = t4_alloc_mac_filt(sc, sc->mbox, viid, del,
2998270297Snp				    i, mcaddr, NULL, &hash, 0);
2999231172Snp				if (rc < 0) {
3000231172Snp					rc = -rc;
3001231172Snp					for (j = 0; j < i; j++) {
3002231172Snp						if_printf(ifp,
3003231172Snp						    "failed to add mc address"
3004231172Snp						    " %02x:%02x:%02x:"
3005231172Snp						    "%02x:%02x:%02x rc=%d\n",
3006231172Snp						    mcaddr[j][0], mcaddr[j][1],
3007231172Snp						    mcaddr[j][2], mcaddr[j][3],
3008231172Snp						    mcaddr[j][4], mcaddr[j][5],
3009231172Snp						    rc);
3010231172Snp					}
3011231172Snp					goto mcfail;
3012231172Snp				}
3013231172Snp				del = 0;
3014231172Snp				i = 0;
3015231172Snp			}
3016231172Snp		}
3017231172Snp		if (i > 0) {
3018270297Snp			rc = t4_alloc_mac_filt(sc, sc->mbox, viid, del, i,
3019270297Snp			    mcaddr, NULL, &hash, 0);
3020218792Snp			if (rc < 0) {
3021218792Snp				rc = -rc;
3022231172Snp				for (j = 0; j < i; j++) {
3023231172Snp					if_printf(ifp,
3024231172Snp					    "failed to add mc address"
3025231172Snp					    " %02x:%02x:%02x:"
3026231172Snp					    "%02x:%02x:%02x rc=%d\n",
3027231172Snp					    mcaddr[j][0], mcaddr[j][1],
3028231172Snp					    mcaddr[j][2], mcaddr[j][3],
3029231172Snp					    mcaddr[j][4], mcaddr[j][5],
3030231172Snp					    rc);
3031231172Snp				}
3032218792Snp				goto mcfail;
3033218792Snp			}
3034218792Snp		}
3035218792Snp
3036270297Snp		rc = -t4_set_addr_hash(sc, sc->mbox, viid, 0, hash, 0);
3037218792Snp		if (rc != 0)
3038218792Snp			if_printf(ifp, "failed to set mc address hash: %d", rc);
3039218792Snpmcfail:
3040218792Snp		if_maddr_runlock(ifp);
3041218792Snp	}
3042218792Snp
3043218792Snp	return (rc);
3044218792Snp}
3045218792Snp
3046245274Snpint
3047245274Snpbegin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags,
3048245274Snp    char *wmesg)
3049218792Snp{
3050245274Snp	int rc, pri;
3051218792Snp
3052245274Snp#ifdef WITNESS
3053245274Snp	/* the caller thinks it's ok to sleep, but is it really? */
3054245274Snp	if (flags & SLEEP_OK)
3055245274Snp		pause("t4slptst", 1);
3056245274Snp#endif
3057218792Snp
3058245274Snp	if (INTR_OK)
3059245274Snp		pri = PCATCH;
3060245274Snp	else
3061245274Snp		pri = 0;
3062245274Snp
3063245274Snp	ADAPTER_LOCK(sc);
3064245274Snp	for (;;) {
3065245274Snp
3066245274Snp		if (pi && IS_DOOMED(pi)) {
3067245274Snp			rc = ENXIO;
3068245274Snp			goto done;
3069245274Snp		}
3070245274Snp
3071245274Snp		if (!IS_BUSY(sc)) {
3072245274Snp			rc = 0;
3073245274Snp			break;
3074245274Snp		}
3075245274Snp
3076245274Snp		if (!(flags & SLEEP_OK)) {
3077245274Snp			rc = EBUSY;
3078245274Snp			goto done;
3079245274Snp		}
3080245274Snp
3081245274Snp		if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) {
3082218792Snp			rc = EINTR;
3083218792Snp			goto done;
3084218792Snp		}
3085218792Snp	}
3086245274Snp
3087218792Snp	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
3088218792Snp	SET_BUSY(sc);
3089245274Snp#ifdef INVARIANTS
3090245274Snp	sc->last_op = wmesg;
3091245274Snp	sc->last_op_thr = curthread;
3092245274Snp#endif
3093218792Snp
3094245274Snpdone:
3095245274Snp	if (!(flags & HOLD_LOCK) || rc)
3096245274Snp		ADAPTER_UNLOCK(sc);
3097218792Snp
3098245274Snp	return (rc);
3099245274Snp}
3100245274Snp
3101245274Snpvoid
3102245274Snpend_synchronized_op(struct adapter *sc, int flags)
3103245274Snp{
3104245274Snp
3105245274Snp	if (flags & LOCK_HELD)
3106245274Snp		ADAPTER_LOCK_ASSERT_OWNED(sc);
3107245274Snp	else
3108245274Snp		ADAPTER_LOCK(sc);
3109245274Snp
3110218792Snp	KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
3111218792Snp	CLR_BUSY(sc);
3112245274Snp	wakeup(&sc->flags);
3113218792Snp	ADAPTER_UNLOCK(sc);
3114218792Snp}
3115218792Snp
3116218792Snpstatic int
3117218792Snpcxgbe_init_synchronized(struct port_info *pi)
3118218792Snp{
3119218792Snp	struct adapter *sc = pi->adapter;
3120218792Snp	struct ifnet *ifp = pi->ifp;
3121228561Snp	int rc = 0;
3122218792Snp
3123245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
3124218792Snp
3125218792Snp	if (isset(&sc->open_device_map, pi->port_id)) {
3126218792Snp		KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING,
3127218792Snp		    ("mismatch between open_device_map and if_drv_flags"));
3128218792Snp		return (0);	/* already running */
3129218792Snp	}
3130218792Snp
3131228561Snp	if (!(sc->flags & FULL_INIT_DONE) &&
3132228561Snp	    ((rc = adapter_full_init(sc)) != 0))
3133218792Snp		return (rc);	/* error message displayed already */
3134218792Snp
3135228561Snp	if (!(pi->flags & PORT_INIT_DONE) &&
3136228561Snp	    ((rc = port_full_init(pi)) != 0))
3137228561Snp		return (rc); /* error message displayed already */
3138218792Snp
3139270297Snp	rc = update_mac_settings(ifp, XGMAC_ALL);
3140218792Snp	if (rc)
3141218792Snp		goto done;	/* error message displayed already */
3142218792Snp
3143218792Snp	rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true);
3144218792Snp	if (rc != 0) {
3145218792Snp		if_printf(ifp, "enable_vi failed: %d\n", rc);
3146218792Snp		goto done;
3147218792Snp	}
3148218792Snp
3149253691Snp	/*
3150253691Snp	 * The first iq of the first port to come up is used for tracing.
3151253691Snp	 */
3152253691Snp	if (sc->traceq < 0) {
3153253691Snp		sc->traceq = sc->sge.rxq[pi->first_rxq].iq.abs_id;
3154253691Snp		t4_write_reg(sc, is_t4(sc) ?  A_MPS_TRC_RSS_CONTROL :
3155253691Snp		    A_MPS_T5_TRC_RSS_CONTROL, V_RSSCONTROL(pi->tx_chan) |
3156253691Snp		    V_QUEUENUMBER(sc->traceq));
3157253691Snp		pi->flags |= HAS_TRACEQ;
3158253691Snp	}
3159253691Snp
3160218792Snp	/* all ok */
3161218792Snp	setbit(&sc->open_device_map, pi->port_id);
3162245274Snp	PORT_LOCK(pi);
3163218792Snp	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3164245274Snp	PORT_UNLOCK(pi);
3165218792Snp
3166218792Snp	callout_reset(&pi->tick, hz, cxgbe_tick, pi);
3167218792Snpdone:
3168218792Snp	if (rc != 0)
3169218792Snp		cxgbe_uninit_synchronized(pi);
3170218792Snp
3171218792Snp	return (rc);
3172218792Snp}
3173218792Snp
3174218792Snp/*
3175218792Snp * Idempotent.
3176218792Snp */
3177218792Snpstatic int
3178218792Snpcxgbe_uninit_synchronized(struct port_info *pi)
3179218792Snp{
3180218792Snp	struct adapter *sc = pi->adapter;
3181218792Snp	struct ifnet *ifp = pi->ifp;
3182218792Snp	int rc;
3183218792Snp
3184245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
3185218792Snp
3186218792Snp	/*
3187228561Snp	 * Disable the VI so that all its data in either direction is discarded
3188228561Snp	 * by the MPS.  Leave everything else (the queues, interrupts, and 1Hz
3189228561Snp	 * tick) intact as the TP can deliver negative advice or data that it's
3190228561Snp	 * holding in its RAM (for an offloaded connection) even after the VI is
3191228561Snp	 * disabled.
3192218792Snp	 */
3193228561Snp	rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false);
3194228561Snp	if (rc) {
3195228561Snp		if_printf(ifp, "disable_vi failed: %d\n", rc);
3196228561Snp		return (rc);
3197228561Snp	}
3198228561Snp
3199218792Snp	clrbit(&sc->open_device_map, pi->port_id);
3200245274Snp	PORT_LOCK(pi);
3201228561Snp	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
3202245274Snp	PORT_UNLOCK(pi);
3203218792Snp
3204218792Snp	pi->link_cfg.link_ok = 0;
3205218792Snp	pi->link_cfg.speed = 0;
3206252747Snp	pi->linkdnrc = -1;
3207252747Snp	t4_os_link_changed(sc, pi->port_id, 0, -1);
3208218792Snp
3209218792Snp	return (0);
3210218792Snp}
3211218792Snp
3212240453Snp/*
3213240453Snp * It is ok for this function to fail midway and return right away.  t4_detach
3214240453Snp * will walk the entire sc->irq list and clean up whatever is valid.
3215240453Snp */
3216218792Snpstatic int
3217240453Snpsetup_intr_handlers(struct adapter *sc)
3218218792Snp{
3219240453Snp	int rc, rid, p, q;
3220222510Snp	char s[8];
3221222510Snp	struct irq *irq;
3222228561Snp	struct port_info *pi;
3223228561Snp	struct sge_rxq *rxq;
3224237263Snp#ifdef TCP_OFFLOAD
3225228561Snp	struct sge_ofld_rxq *ofld_rxq;
3226228561Snp#endif
3227270297Snp#ifdef DEV_NETMAP
3228270297Snp	struct sge_nm_rxq *nm_rxq;
3229270297Snp#endif
3230218792Snp
3231218792Snp	/*
3232218792Snp	 * Setup interrupts.
3233218792Snp	 */
3234222510Snp	irq = &sc->irq[0];
3235222510Snp	rid = sc->intr_type == INTR_INTX ? 0 : 1;
3236270297Snp	if (sc->intr_count == 1)
3237270297Snp		return (t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all"));
3238222510Snp
3239270297Snp	/* Multiple interrupts. */
3240270297Snp	KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports,
3241270297Snp	    ("%s: too few intr.", __func__));
3242228561Snp
3243270297Snp	/* The first one is always error intr */
3244270297Snp	rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err");
3245270297Snp	if (rc != 0)
3246270297Snp		return (rc);
3247270297Snp	irq++;
3248270297Snp	rid++;
3249218792Snp
3250270297Snp	/* The second one is always the firmware event queue */
3251270297Snp	rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, "evt");
3252270297Snp	if (rc != 0)
3253270297Snp		return (rc);
3254270297Snp	irq++;
3255270297Snp	rid++;
3256222510Snp
3257270297Snp	for_each_port(sc, p) {
3258270297Snp		pi = sc->port[p];
3259222510Snp
3260270297Snp		if (pi->flags & INTR_RXQ) {
3261270297Snp			for_each_rxq(pi, q, rxq) {
3262228561Snp				snprintf(s, sizeof(s), "%d.%d", p, q);
3263240453Snp				rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq,
3264240453Snp				    s);
3265240453Snp				if (rc != 0)
3266240453Snp					return (rc);
3267222510Snp				irq++;
3268222510Snp				rid++;
3269218792Snp			}
3270270297Snp		}
3271237263Snp#ifdef TCP_OFFLOAD
3272270297Snp		if (pi->flags & INTR_OFLD_RXQ) {
3273270297Snp			for_each_ofld_rxq(pi, q, ofld_rxq) {
3274228561Snp				snprintf(s, sizeof(s), "%d,%d", p, q);
3275240453Snp				rc = t4_alloc_irq(sc, irq, rid, t4_intr,
3276240453Snp				    ofld_rxq, s);
3277240453Snp				if (rc != 0)
3278240453Snp					return (rc);
3279228561Snp				irq++;
3280228561Snp				rid++;
3281218792Snp			}
3282270297Snp		}
3283228561Snp#endif
3284270297Snp#ifdef DEV_NETMAP
3285270297Snp		if (pi->flags & INTR_NM_RXQ) {
3286270297Snp			for_each_nm_rxq(pi, q, nm_rxq) {
3287270297Snp				snprintf(s, sizeof(s), "%d-%d", p, q);
3288270297Snp				rc = t4_alloc_irq(sc, irq, rid, t4_nm_intr,
3289270297Snp				    nm_rxq, s);
3290270297Snp				if (rc != 0)
3291270297Snp					return (rc);
3292270297Snp				irq++;
3293270297Snp				rid++;
3294270297Snp			}
3295218792Snp		}
3296270297Snp#endif
3297218792Snp	}
3298270297Snp	MPASS(irq == &sc->irq[sc->intr_count]);
3299218792Snp
3300240453Snp	return (0);
3301240453Snp}
3302240453Snp
3303270297Snpint
3304240453Snpadapter_full_init(struct adapter *sc)
3305240453Snp{
3306240453Snp	int rc, i;
3307240453Snp
3308240453Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
3309240453Snp	KASSERT((sc->flags & FULL_INIT_DONE) == 0,
3310240453Snp	    ("%s: FULL_INIT_DONE already", __func__));
3311240453Snp
3312240453Snp	/*
3313240453Snp	 * queues that belong to the adapter (not any particular port).
3314240453Snp	 */
3315240453Snp	rc = t4_setup_adapter_queues(sc);
3316240453Snp	if (rc != 0)
3317240453Snp		goto done;
3318240453Snp
3319240453Snp	for (i = 0; i < nitems(sc->tq); i++) {
3320240453Snp		sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT,
3321240453Snp		    taskqueue_thread_enqueue, &sc->tq[i]);
3322240453Snp		if (sc->tq[i] == NULL) {
3323240453Snp			device_printf(sc->dev,
3324240453Snp			    "failed to allocate task queue %d\n", i);
3325240453Snp			rc = ENOMEM;
3326240453Snp			goto done;
3327240453Snp		}
3328240453Snp		taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d",
3329240453Snp		    device_get_nameunit(sc->dev), i);
3330240453Snp	}
3331240453Snp
3332218792Snp	t4_intr_enable(sc);
3333218792Snp	sc->flags |= FULL_INIT_DONE;
3334218792Snpdone:
3335218792Snp	if (rc != 0)
3336228561Snp		adapter_full_uninit(sc);
3337218792Snp
3338218792Snp	return (rc);
3339218792Snp}
3340218792Snp
3341270297Snpint
3342228561Snpadapter_full_uninit(struct adapter *sc)
3343218792Snp{
3344218792Snp	int i;
3345218792Snp
3346218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
3347218792Snp
3348220873Snp	t4_teardown_adapter_queues(sc);
3349218792Snp
3350240452Snp	for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) {
3351228561Snp		taskqueue_free(sc->tq[i]);
3352228561Snp		sc->tq[i] = NULL;
3353228561Snp	}
3354228561Snp
3355218792Snp	sc->flags &= ~FULL_INIT_DONE;
3356218792Snp
3357218792Snp	return (0);
3358218792Snp}
3359218792Snp
3360270297Snpint
3361228561Snpport_full_init(struct port_info *pi)
3362228561Snp{
3363228561Snp	struct adapter *sc = pi->adapter;
3364228561Snp	struct ifnet *ifp = pi->ifp;
3365228561Snp	uint16_t *rss;
3366228561Snp	struct sge_rxq *rxq;
3367259142Snp	int rc, i, j;
3368228561Snp
3369245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
3370228561Snp	KASSERT((pi->flags & PORT_INIT_DONE) == 0,
3371228561Snp	    ("%s: PORT_INIT_DONE already", __func__));
3372228561Snp
3373228561Snp	sysctl_ctx_init(&pi->ctx);
3374228561Snp	pi->flags |= PORT_SYSCTL_CTX;
3375228561Snp
3376228561Snp	/*
3377228561Snp	 * Allocate tx/rx/fl queues for this port.
3378228561Snp	 */
3379228561Snp	rc = t4_setup_port_queues(pi);
3380228561Snp	if (rc != 0)
3381228561Snp		goto done;	/* error message displayed already */
3382228561Snp
3383228561Snp	/*
3384259142Snp	 * Setup RSS for this port.  Save a copy of the RSS table for later use.
3385228561Snp	 */
3386259142Snp	rss = malloc(pi->rss_size * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK);
3387259142Snp	for (i = 0; i < pi->rss_size;) {
3388259142Snp		for_each_rxq(pi, j, rxq) {
3389259142Snp			rss[i++] = rxq->iq.abs_id;
3390259142Snp			if (i == pi->rss_size)
3391259142Snp				break;
3392259142Snp		}
3393228561Snp	}
3394259142Snp
3395259142Snp	rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, pi->rss_size, rss,
3396259142Snp	    pi->rss_size);
3397228561Snp	if (rc != 0) {
3398228561Snp		if_printf(ifp, "rss_config failed: %d\n", rc);
3399228561Snp		goto done;
3400228561Snp	}
3401228561Snp
3402259142Snp	pi->rss = rss;
3403228561Snp	pi->flags |= PORT_INIT_DONE;
3404228561Snpdone:
3405228561Snp	if (rc != 0)
3406228561Snp		port_full_uninit(pi);
3407228561Snp
3408228561Snp	return (rc);
3409228561Snp}
3410228561Snp
3411228561Snp/*
3412228561Snp * Idempotent.
3413228561Snp */
3414270297Snpint
3415228561Snpport_full_uninit(struct port_info *pi)
3416228561Snp{
3417228561Snp	struct adapter *sc = pi->adapter;
3418228561Snp	int i;
3419228561Snp	struct sge_rxq *rxq;
3420228561Snp	struct sge_txq *txq;
3421237263Snp#ifdef TCP_OFFLOAD
3422228561Snp	struct sge_ofld_rxq *ofld_rxq;
3423228561Snp	struct sge_wrq *ofld_txq;
3424228561Snp#endif
3425228561Snp
3426228561Snp	if (pi->flags & PORT_INIT_DONE) {
3427228561Snp
3428228561Snp		/* Need to quiesce queues.  XXX: ctrl queues? */
3429228561Snp
3430228561Snp		for_each_txq(pi, i, txq) {
3431228561Snp			quiesce_eq(sc, &txq->eq);
3432228561Snp		}
3433228561Snp
3434237263Snp#ifdef TCP_OFFLOAD
3435228561Snp		for_each_ofld_txq(pi, i, ofld_txq) {
3436228561Snp			quiesce_eq(sc, &ofld_txq->eq);
3437228561Snp		}
3438228561Snp#endif
3439228561Snp
3440228561Snp		for_each_rxq(pi, i, rxq) {
3441228561Snp			quiesce_iq(sc, &rxq->iq);
3442228561Snp			quiesce_fl(sc, &rxq->fl);
3443228561Snp		}
3444228561Snp
3445237263Snp#ifdef TCP_OFFLOAD
3446228561Snp		for_each_ofld_rxq(pi, i, ofld_rxq) {
3447228561Snp			quiesce_iq(sc, &ofld_rxq->iq);
3448228561Snp			quiesce_fl(sc, &ofld_rxq->fl);
3449228561Snp		}
3450228561Snp#endif
3451259142Snp		free(pi->rss, M_CXGBE);
3452228561Snp	}
3453228561Snp
3454228561Snp	t4_teardown_port_queues(pi);
3455228561Snp	pi->flags &= ~PORT_INIT_DONE;
3456228561Snp
3457228561Snp	return (0);
3458228561Snp}
3459228561Snp
3460228561Snpstatic void
3461228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq)
3462228561Snp{
3463228561Snp	EQ_LOCK(eq);
3464228561Snp	eq->flags |= EQ_DOOMED;
3465228561Snp
3466228561Snp	/*
3467228561Snp	 * Wait for the response to a credit flush if one's
3468228561Snp	 * pending.
3469228561Snp	 */
3470228561Snp	while (eq->flags & EQ_CRFLUSHED)
3471228561Snp		mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0);
3472228561Snp	EQ_UNLOCK(eq);
3473228561Snp
3474228561Snp	callout_drain(&eq->tx_callout);	/* XXX: iffy */
3475228561Snp	pause("callout", 10);		/* Still iffy */
3476228561Snp
3477228561Snp	taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task);
3478228561Snp}
3479228561Snp
3480228561Snpstatic void
3481228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq)
3482228561Snp{
3483228561Snp	(void) sc;	/* unused */
3484228561Snp
3485228561Snp	/* Synchronize with the interrupt handler */
3486228561Snp	while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED))
3487228561Snp		pause("iqfree", 1);
3488228561Snp}
3489228561Snp
3490228561Snpstatic void
3491228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl)
3492228561Snp{
3493228561Snp	mtx_lock(&sc->sfl_lock);
3494228561Snp	FL_LOCK(fl);
3495228561Snp	fl->flags |= FL_DOOMED;
3496228561Snp	FL_UNLOCK(fl);
3497228561Snp	mtx_unlock(&sc->sfl_lock);
3498228561Snp
3499228561Snp	callout_drain(&sc->sfl_callout);
3500228561Snp	KASSERT((fl->flags & FL_STARVING) == 0,
3501228561Snp	    ("%s: still starving", __func__));
3502228561Snp}
3503228561Snp
3504228561Snpstatic int
3505218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid,
3506228561Snp    driver_intr_t *handler, void *arg, char *name)
3507218792Snp{
3508218792Snp	int rc;
3509218792Snp
3510218792Snp	irq->rid = rid;
3511218792Snp	irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid,
3512218792Snp	    RF_SHAREABLE | RF_ACTIVE);
3513218792Snp	if (irq->res == NULL) {
3514218792Snp		device_printf(sc->dev,
3515218792Snp		    "failed to allocate IRQ for rid %d, name %s.\n", rid, name);
3516218792Snp		return (ENOMEM);
3517218792Snp	}
3518218792Snp
3519218792Snp	rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET,
3520218792Snp	    NULL, handler, arg, &irq->tag);
3521218792Snp	if (rc != 0) {
3522218792Snp		device_printf(sc->dev,
3523218792Snp		    "failed to setup interrupt for rid %d, name %s: %d\n",
3524218792Snp		    rid, name, rc);
3525218792Snp	} else if (name)
3526218792Snp		bus_describe_intr(sc->dev, irq->res, irq->tag, name);
3527218792Snp
3528218792Snp	return (rc);
3529218792Snp}
3530218792Snp
3531218792Snpstatic int
3532218792Snpt4_free_irq(struct adapter *sc, struct irq *irq)
3533218792Snp{
3534218792Snp	if (irq->tag)
3535218792Snp		bus_teardown_intr(sc->dev, irq->res, irq->tag);
3536218792Snp	if (irq->res)
3537218792Snp		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res);
3538218792Snp
3539218792Snp	bzero(irq, sizeof(*irq));
3540218792Snp
3541218792Snp	return (0);
3542218792Snp}
3543218792Snp
3544218792Snpstatic void
3545218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start,
3546218792Snp    unsigned int end)
3547218792Snp{
3548218792Snp	uint32_t *p = (uint32_t *)(buf + start);
3549218792Snp
3550218792Snp	for ( ; start <= end; start += sizeof(uint32_t))
3551218792Snp		*p++ = t4_read_reg(sc, start);
3552218792Snp}
3553218792Snp
3554218792Snpstatic void
3555218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf)
3556218792Snp{
3557248925Snp	int i, n;
3558248925Snp	const unsigned int *reg_ranges;
3559248925Snp	static const unsigned int t4_reg_ranges[] = {
3560218792Snp		0x1008, 0x1108,
3561218792Snp		0x1180, 0x11b4,
3562218792Snp		0x11fc, 0x123c,
3563218792Snp		0x1300, 0x173c,
3564218792Snp		0x1800, 0x18fc,
3565218792Snp		0x3000, 0x30d8,
3566218792Snp		0x30e0, 0x5924,
3567218792Snp		0x5960, 0x59d4,
3568218792Snp		0x5a00, 0x5af8,
3569218792Snp		0x6000, 0x6098,
3570218792Snp		0x6100, 0x6150,
3571218792Snp		0x6200, 0x6208,
3572218792Snp		0x6240, 0x6248,
3573218792Snp		0x6280, 0x6338,
3574218792Snp		0x6370, 0x638c,
3575218792Snp		0x6400, 0x643c,
3576218792Snp		0x6500, 0x6524,
3577218792Snp		0x6a00, 0x6a38,
3578218792Snp		0x6a60, 0x6a78,
3579218792Snp		0x6b00, 0x6b84,
3580218792Snp		0x6bf0, 0x6c84,
3581218792Snp		0x6cf0, 0x6d84,
3582218792Snp		0x6df0, 0x6e84,
3583218792Snp		0x6ef0, 0x6f84,
3584218792Snp		0x6ff0, 0x7084,
3585218792Snp		0x70f0, 0x7184,
3586218792Snp		0x71f0, 0x7284,
3587218792Snp		0x72f0, 0x7384,
3588218792Snp		0x73f0, 0x7450,
3589218792Snp		0x7500, 0x7530,
3590218792Snp		0x7600, 0x761c,
3591218792Snp		0x7680, 0x76cc,
3592218792Snp		0x7700, 0x7798,
3593218792Snp		0x77c0, 0x77fc,
3594218792Snp		0x7900, 0x79fc,
3595218792Snp		0x7b00, 0x7c38,
3596218792Snp		0x7d00, 0x7efc,
3597218792Snp		0x8dc0, 0x8e1c,
3598218792Snp		0x8e30, 0x8e78,
3599218792Snp		0x8ea0, 0x8f6c,
3600218792Snp		0x8fc0, 0x9074,
3601218792Snp		0x90fc, 0x90fc,
3602218792Snp		0x9400, 0x9458,
3603218792Snp		0x9600, 0x96bc,
3604218792Snp		0x9800, 0x9808,
3605218792Snp		0x9820, 0x983c,
3606218792Snp		0x9850, 0x9864,
3607218792Snp		0x9c00, 0x9c6c,
3608218792Snp		0x9c80, 0x9cec,
3609218792Snp		0x9d00, 0x9d6c,
3610218792Snp		0x9d80, 0x9dec,
3611218792Snp		0x9e00, 0x9e6c,
3612218792Snp		0x9e80, 0x9eec,
3613218792Snp		0x9f00, 0x9f6c,
3614218792Snp		0x9f80, 0x9fec,
3615218792Snp		0xd004, 0xd03c,
3616218792Snp		0xdfc0, 0xdfe0,
3617218792Snp		0xe000, 0xea7c,
3618259142Snp		0xf000, 0x11110,
3619259142Snp		0x11118, 0x11190,
3620237439Snp		0x19040, 0x1906c,
3621237439Snp		0x19078, 0x19080,
3622237439Snp		0x1908c, 0x19124,
3623218792Snp		0x19150, 0x191b0,
3624218792Snp		0x191d0, 0x191e8,
3625218792Snp		0x19238, 0x1924c,
3626218792Snp		0x193f8, 0x19474,
3627218792Snp		0x19490, 0x194f8,
3628218792Snp		0x19800, 0x19f30,
3629218792Snp		0x1a000, 0x1a06c,
3630218792Snp		0x1a0b0, 0x1a120,
3631218792Snp		0x1a128, 0x1a138,
3632218792Snp		0x1a190, 0x1a1c4,
3633218792Snp		0x1a1fc, 0x1a1fc,
3634218792Snp		0x1e040, 0x1e04c,
3635237439Snp		0x1e284, 0x1e28c,
3636218792Snp		0x1e2c0, 0x1e2c0,
3637218792Snp		0x1e2e0, 0x1e2e0,
3638218792Snp		0x1e300, 0x1e384,
3639218792Snp		0x1e3c0, 0x1e3c8,
3640218792Snp		0x1e440, 0x1e44c,
3641237439Snp		0x1e684, 0x1e68c,
3642218792Snp		0x1e6c0, 0x1e6c0,
3643218792Snp		0x1e6e0, 0x1e6e0,
3644218792Snp		0x1e700, 0x1e784,
3645218792Snp		0x1e7c0, 0x1e7c8,
3646218792Snp		0x1e840, 0x1e84c,
3647237439Snp		0x1ea84, 0x1ea8c,
3648218792Snp		0x1eac0, 0x1eac0,
3649218792Snp		0x1eae0, 0x1eae0,
3650218792Snp		0x1eb00, 0x1eb84,
3651218792Snp		0x1ebc0, 0x1ebc8,
3652218792Snp		0x1ec40, 0x1ec4c,
3653237439Snp		0x1ee84, 0x1ee8c,
3654218792Snp		0x1eec0, 0x1eec0,
3655218792Snp		0x1eee0, 0x1eee0,
3656218792Snp		0x1ef00, 0x1ef84,
3657218792Snp		0x1efc0, 0x1efc8,
3658218792Snp		0x1f040, 0x1f04c,
3659237439Snp		0x1f284, 0x1f28c,
3660218792Snp		0x1f2c0, 0x1f2c0,
3661218792Snp		0x1f2e0, 0x1f2e0,
3662218792Snp		0x1f300, 0x1f384,
3663218792Snp		0x1f3c0, 0x1f3c8,
3664218792Snp		0x1f440, 0x1f44c,
3665237439Snp		0x1f684, 0x1f68c,
3666218792Snp		0x1f6c0, 0x1f6c0,
3667218792Snp		0x1f6e0, 0x1f6e0,
3668218792Snp		0x1f700, 0x1f784,
3669218792Snp		0x1f7c0, 0x1f7c8,
3670218792Snp		0x1f840, 0x1f84c,
3671237439Snp		0x1fa84, 0x1fa8c,
3672218792Snp		0x1fac0, 0x1fac0,
3673218792Snp		0x1fae0, 0x1fae0,
3674218792Snp		0x1fb00, 0x1fb84,
3675218792Snp		0x1fbc0, 0x1fbc8,
3676218792Snp		0x1fc40, 0x1fc4c,
3677237439Snp		0x1fe84, 0x1fe8c,
3678218792Snp		0x1fec0, 0x1fec0,
3679218792Snp		0x1fee0, 0x1fee0,
3680218792Snp		0x1ff00, 0x1ff84,
3681218792Snp		0x1ffc0, 0x1ffc8,
3682218792Snp		0x20000, 0x2002c,
3683218792Snp		0x20100, 0x2013c,
3684218792Snp		0x20190, 0x201c8,
3685218792Snp		0x20200, 0x20318,
3686218792Snp		0x20400, 0x20528,
3687218792Snp		0x20540, 0x20614,
3688218792Snp		0x21000, 0x21040,
3689218792Snp		0x2104c, 0x21060,
3690218792Snp		0x210c0, 0x210ec,
3691218792Snp		0x21200, 0x21268,
3692218792Snp		0x21270, 0x21284,
3693218792Snp		0x212fc, 0x21388,
3694218792Snp		0x21400, 0x21404,
3695218792Snp		0x21500, 0x21518,
3696218792Snp		0x2152c, 0x2153c,
3697218792Snp		0x21550, 0x21554,
3698218792Snp		0x21600, 0x21600,
3699218792Snp		0x21608, 0x21628,
3700218792Snp		0x21630, 0x2163c,
3701218792Snp		0x21700, 0x2171c,
3702218792Snp		0x21780, 0x2178c,
3703218792Snp		0x21800, 0x21c38,
3704218792Snp		0x21c80, 0x21d7c,
3705218792Snp		0x21e00, 0x21e04,
3706218792Snp		0x22000, 0x2202c,
3707218792Snp		0x22100, 0x2213c,
3708218792Snp		0x22190, 0x221c8,
3709218792Snp		0x22200, 0x22318,
3710218792Snp		0x22400, 0x22528,
3711218792Snp		0x22540, 0x22614,
3712218792Snp		0x23000, 0x23040,
3713218792Snp		0x2304c, 0x23060,
3714218792Snp		0x230c0, 0x230ec,
3715218792Snp		0x23200, 0x23268,
3716218792Snp		0x23270, 0x23284,
3717218792Snp		0x232fc, 0x23388,
3718218792Snp		0x23400, 0x23404,
3719218792Snp		0x23500, 0x23518,
3720218792Snp		0x2352c, 0x2353c,
3721218792Snp		0x23550, 0x23554,
3722218792Snp		0x23600, 0x23600,
3723218792Snp		0x23608, 0x23628,
3724218792Snp		0x23630, 0x2363c,
3725218792Snp		0x23700, 0x2371c,
3726218792Snp		0x23780, 0x2378c,
3727218792Snp		0x23800, 0x23c38,
3728218792Snp		0x23c80, 0x23d7c,
3729218792Snp		0x23e00, 0x23e04,
3730218792Snp		0x24000, 0x2402c,
3731218792Snp		0x24100, 0x2413c,
3732218792Snp		0x24190, 0x241c8,
3733218792Snp		0x24200, 0x24318,
3734218792Snp		0x24400, 0x24528,
3735218792Snp		0x24540, 0x24614,
3736218792Snp		0x25000, 0x25040,
3737218792Snp		0x2504c, 0x25060,
3738218792Snp		0x250c0, 0x250ec,
3739218792Snp		0x25200, 0x25268,
3740218792Snp		0x25270, 0x25284,
3741218792Snp		0x252fc, 0x25388,
3742218792Snp		0x25400, 0x25404,
3743218792Snp		0x25500, 0x25518,
3744218792Snp		0x2552c, 0x2553c,
3745218792Snp		0x25550, 0x25554,
3746218792Snp		0x25600, 0x25600,
3747218792Snp		0x25608, 0x25628,
3748218792Snp		0x25630, 0x2563c,
3749218792Snp		0x25700, 0x2571c,
3750218792Snp		0x25780, 0x2578c,
3751218792Snp		0x25800, 0x25c38,
3752218792Snp		0x25c80, 0x25d7c,
3753218792Snp		0x25e00, 0x25e04,
3754218792Snp		0x26000, 0x2602c,
3755218792Snp		0x26100, 0x2613c,
3756218792Snp		0x26190, 0x261c8,
3757218792Snp		0x26200, 0x26318,
3758218792Snp		0x26400, 0x26528,
3759218792Snp		0x26540, 0x26614,
3760218792Snp		0x27000, 0x27040,
3761218792Snp		0x2704c, 0x27060,
3762218792Snp		0x270c0, 0x270ec,
3763218792Snp		0x27200, 0x27268,
3764218792Snp		0x27270, 0x27284,
3765218792Snp		0x272fc, 0x27388,
3766218792Snp		0x27400, 0x27404,
3767218792Snp		0x27500, 0x27518,
3768218792Snp		0x2752c, 0x2753c,
3769218792Snp		0x27550, 0x27554,
3770218792Snp		0x27600, 0x27600,
3771218792Snp		0x27608, 0x27628,
3772218792Snp		0x27630, 0x2763c,
3773218792Snp		0x27700, 0x2771c,
3774218792Snp		0x27780, 0x2778c,
3775218792Snp		0x27800, 0x27c38,
3776218792Snp		0x27c80, 0x27d7c,
3777218792Snp		0x27e00, 0x27e04
3778218792Snp	};
3779248925Snp	static const unsigned int t5_reg_ranges[] = {
3780248925Snp		0x1008, 0x1148,
3781248925Snp		0x1180, 0x11b4,
3782248925Snp		0x11fc, 0x123c,
3783248925Snp		0x1280, 0x173c,
3784248925Snp		0x1800, 0x18fc,
3785248925Snp		0x3000, 0x3028,
3786248925Snp		0x3060, 0x30d8,
3787248925Snp		0x30e0, 0x30fc,
3788248925Snp		0x3140, 0x357c,
3789248925Snp		0x35a8, 0x35cc,
3790248925Snp		0x35ec, 0x35ec,
3791248925Snp		0x3600, 0x5624,
3792248925Snp		0x56cc, 0x575c,
3793248925Snp		0x580c, 0x5814,
3794248925Snp		0x5890, 0x58bc,
3795248925Snp		0x5940, 0x59dc,
3796248925Snp		0x59fc, 0x5a18,
3797248925Snp		0x5a60, 0x5a9c,
3798248925Snp		0x5b94, 0x5bfc,
3799248925Snp		0x6000, 0x6040,
3800248925Snp		0x6058, 0x614c,
3801248925Snp		0x7700, 0x7798,
3802248925Snp		0x77c0, 0x78fc,
3803248925Snp		0x7b00, 0x7c54,
3804248925Snp		0x7d00, 0x7efc,
3805248925Snp		0x8dc0, 0x8de0,
3806248925Snp		0x8df8, 0x8e84,
3807248925Snp		0x8ea0, 0x8f84,
3808248925Snp		0x8fc0, 0x90f8,
3809248925Snp		0x9400, 0x9470,
3810248925Snp		0x9600, 0x96f4,
3811248925Snp		0x9800, 0x9808,
3812248925Snp		0x9820, 0x983c,
3813248925Snp		0x9850, 0x9864,
3814248925Snp		0x9c00, 0x9c6c,
3815248925Snp		0x9c80, 0x9cec,
3816248925Snp		0x9d00, 0x9d6c,
3817248925Snp		0x9d80, 0x9dec,
3818248925Snp		0x9e00, 0x9e6c,
3819248925Snp		0x9e80, 0x9eec,
3820248925Snp		0x9f00, 0x9f6c,
3821248925Snp		0x9f80, 0xa020,
3822248925Snp		0xd004, 0xd03c,
3823248925Snp		0xdfc0, 0xdfe0,
3824248925Snp		0xe000, 0x11088,
3825259142Snp		0x1109c, 0x11110,
3826259142Snp		0x11118, 0x1117c,
3827248925Snp		0x11190, 0x11204,
3828248925Snp		0x19040, 0x1906c,
3829248925Snp		0x19078, 0x19080,
3830248925Snp		0x1908c, 0x19124,
3831248925Snp		0x19150, 0x191b0,
3832248925Snp		0x191d0, 0x191e8,
3833248925Snp		0x19238, 0x19290,
3834248925Snp		0x193f8, 0x19474,
3835248925Snp		0x19490, 0x194cc,
3836248925Snp		0x194f0, 0x194f8,
3837248925Snp		0x19c00, 0x19c60,
3838248925Snp		0x19c94, 0x19e10,
3839248925Snp		0x19e50, 0x19f34,
3840248925Snp		0x19f40, 0x19f50,
3841248925Snp		0x19f90, 0x19fe4,
3842248925Snp		0x1a000, 0x1a06c,
3843248925Snp		0x1a0b0, 0x1a120,
3844248925Snp		0x1a128, 0x1a138,
3845248925Snp		0x1a190, 0x1a1c4,
3846248925Snp		0x1a1fc, 0x1a1fc,
3847248925Snp		0x1e008, 0x1e00c,
3848248925Snp		0x1e040, 0x1e04c,
3849248925Snp		0x1e284, 0x1e290,
3850248925Snp		0x1e2c0, 0x1e2c0,
3851248925Snp		0x1e2e0, 0x1e2e0,
3852248925Snp		0x1e300, 0x1e384,
3853248925Snp		0x1e3c0, 0x1e3c8,
3854248925Snp		0x1e408, 0x1e40c,
3855248925Snp		0x1e440, 0x1e44c,
3856248925Snp		0x1e684, 0x1e690,
3857248925Snp		0x1e6c0, 0x1e6c0,
3858248925Snp		0x1e6e0, 0x1e6e0,
3859248925Snp		0x1e700, 0x1e784,
3860248925Snp		0x1e7c0, 0x1e7c8,
3861248925Snp		0x1e808, 0x1e80c,
3862248925Snp		0x1e840, 0x1e84c,
3863248925Snp		0x1ea84, 0x1ea90,
3864248925Snp		0x1eac0, 0x1eac0,
3865248925Snp		0x1eae0, 0x1eae0,
3866248925Snp		0x1eb00, 0x1eb84,
3867248925Snp		0x1ebc0, 0x1ebc8,
3868248925Snp		0x1ec08, 0x1ec0c,
3869248925Snp		0x1ec40, 0x1ec4c,
3870248925Snp		0x1ee84, 0x1ee90,
3871248925Snp		0x1eec0, 0x1eec0,
3872248925Snp		0x1eee0, 0x1eee0,
3873248925Snp		0x1ef00, 0x1ef84,
3874248925Snp		0x1efc0, 0x1efc8,
3875248925Snp		0x1f008, 0x1f00c,
3876248925Snp		0x1f040, 0x1f04c,
3877248925Snp		0x1f284, 0x1f290,
3878248925Snp		0x1f2c0, 0x1f2c0,
3879248925Snp		0x1f2e0, 0x1f2e0,
3880248925Snp		0x1f300, 0x1f384,
3881248925Snp		0x1f3c0, 0x1f3c8,
3882248925Snp		0x1f408, 0x1f40c,
3883248925Snp		0x1f440, 0x1f44c,
3884248925Snp		0x1f684, 0x1f690,
3885248925Snp		0x1f6c0, 0x1f6c0,
3886248925Snp		0x1f6e0, 0x1f6e0,
3887248925Snp		0x1f700, 0x1f784,
3888248925Snp		0x1f7c0, 0x1f7c8,
3889248925Snp		0x1f808, 0x1f80c,
3890248925Snp		0x1f840, 0x1f84c,
3891248925Snp		0x1fa84, 0x1fa90,
3892248925Snp		0x1fac0, 0x1fac0,
3893248925Snp		0x1fae0, 0x1fae0,
3894248925Snp		0x1fb00, 0x1fb84,
3895248925Snp		0x1fbc0, 0x1fbc8,
3896248925Snp		0x1fc08, 0x1fc0c,
3897248925Snp		0x1fc40, 0x1fc4c,
3898248925Snp		0x1fe84, 0x1fe90,
3899248925Snp		0x1fec0, 0x1fec0,
3900248925Snp		0x1fee0, 0x1fee0,
3901248925Snp		0x1ff00, 0x1ff84,
3902248925Snp		0x1ffc0, 0x1ffc8,
3903252312Snp		0x30000, 0x30030,
3904248925Snp		0x30100, 0x30144,
3905248925Snp		0x30190, 0x301d0,
3906248925Snp		0x30200, 0x30318,
3907248925Snp		0x30400, 0x3052c,
3908248925Snp		0x30540, 0x3061c,
3909248925Snp		0x30800, 0x30834,
3910248925Snp		0x308c0, 0x30908,
3911248925Snp		0x30910, 0x309ac,
3912252312Snp		0x30a00, 0x30a2c,
3913248925Snp		0x30a44, 0x30a50,
3914248925Snp		0x30a74, 0x30c24,
3915252312Snp		0x30d00, 0x30d00,
3916248925Snp		0x30d08, 0x30d14,
3917248925Snp		0x30d1c, 0x30d20,
3918248925Snp		0x30d3c, 0x30d50,
3919248925Snp		0x31200, 0x3120c,
3920248925Snp		0x31220, 0x31220,
3921248925Snp		0x31240, 0x31240,
3922252312Snp		0x31600, 0x3160c,
3923248925Snp		0x31a00, 0x31a1c,
3924252312Snp		0x31e00, 0x31e20,
3925248925Snp		0x31e38, 0x31e3c,
3926248925Snp		0x31e80, 0x31e80,
3927248925Snp		0x31e88, 0x31ea8,
3928248925Snp		0x31eb0, 0x31eb4,
3929248925Snp		0x31ec8, 0x31ed4,
3930248925Snp		0x31fb8, 0x32004,
3931252312Snp		0x32200, 0x32200,
3932252312Snp		0x32208, 0x32240,
3933252312Snp		0x32248, 0x32280,
3934252312Snp		0x32288, 0x322c0,
3935248925Snp		0x322c8, 0x322fc,
3936248925Snp		0x32600, 0x32630,
3937248925Snp		0x32a00, 0x32abc,
3938248925Snp		0x32b00, 0x32b70,
3939248925Snp		0x33000, 0x33048,
3940248925Snp		0x33060, 0x3309c,
3941248925Snp		0x330f0, 0x33148,
3942248925Snp		0x33160, 0x3319c,
3943248925Snp		0x331f0, 0x332e4,
3944248925Snp		0x332f8, 0x333e4,
3945248925Snp		0x333f8, 0x33448,
3946248925Snp		0x33460, 0x3349c,
3947248925Snp		0x334f0, 0x33548,
3948248925Snp		0x33560, 0x3359c,
3949248925Snp		0x335f0, 0x336e4,
3950248925Snp		0x336f8, 0x337e4,
3951248925Snp		0x337f8, 0x337fc,
3952248925Snp		0x33814, 0x33814,
3953248925Snp		0x3382c, 0x3382c,
3954248925Snp		0x33880, 0x3388c,
3955248925Snp		0x338e8, 0x338ec,
3956248925Snp		0x33900, 0x33948,
3957248925Snp		0x33960, 0x3399c,
3958248925Snp		0x339f0, 0x33ae4,
3959248925Snp		0x33af8, 0x33b10,
3960248925Snp		0x33b28, 0x33b28,
3961248925Snp		0x33b3c, 0x33b50,
3962248925Snp		0x33bf0, 0x33c10,
3963248925Snp		0x33c28, 0x33c28,
3964248925Snp		0x33c3c, 0x33c50,
3965248925Snp		0x33cf0, 0x33cfc,
3966252312Snp		0x34000, 0x34030,
3967248925Snp		0x34100, 0x34144,
3968248925Snp		0x34190, 0x341d0,
3969248925Snp		0x34200, 0x34318,
3970248925Snp		0x34400, 0x3452c,
3971248925Snp		0x34540, 0x3461c,
3972248925Snp		0x34800, 0x34834,
3973248925Snp		0x348c0, 0x34908,
3974248925Snp		0x34910, 0x349ac,
3975252312Snp		0x34a00, 0x34a2c,
3976248925Snp		0x34a44, 0x34a50,
3977248925Snp		0x34a74, 0x34c24,
3978252312Snp		0x34d00, 0x34d00,
3979248925Snp		0x34d08, 0x34d14,
3980248925Snp		0x34d1c, 0x34d20,
3981248925Snp		0x34d3c, 0x34d50,
3982248925Snp		0x35200, 0x3520c,
3983248925Snp		0x35220, 0x35220,
3984248925Snp		0x35240, 0x35240,
3985252312Snp		0x35600, 0x3560c,
3986248925Snp		0x35a00, 0x35a1c,
3987252312Snp		0x35e00, 0x35e20,
3988248925Snp		0x35e38, 0x35e3c,
3989248925Snp		0x35e80, 0x35e80,
3990248925Snp		0x35e88, 0x35ea8,
3991248925Snp		0x35eb0, 0x35eb4,
3992248925Snp		0x35ec8, 0x35ed4,
3993248925Snp		0x35fb8, 0x36004,
3994252312Snp		0x36200, 0x36200,
3995252312Snp		0x36208, 0x36240,
3996252312Snp		0x36248, 0x36280,
3997252312Snp		0x36288, 0x362c0,
3998248925Snp		0x362c8, 0x362fc,
3999248925Snp		0x36600, 0x36630,
4000248925Snp		0x36a00, 0x36abc,
4001248925Snp		0x36b00, 0x36b70,
4002248925Snp		0x37000, 0x37048,
4003248925Snp		0x37060, 0x3709c,
4004248925Snp		0x370f0, 0x37148,
4005248925Snp		0x37160, 0x3719c,
4006248925Snp		0x371f0, 0x372e4,
4007248925Snp		0x372f8, 0x373e4,
4008248925Snp		0x373f8, 0x37448,
4009248925Snp		0x37460, 0x3749c,
4010248925Snp		0x374f0, 0x37548,
4011248925Snp		0x37560, 0x3759c,
4012248925Snp		0x375f0, 0x376e4,
4013248925Snp		0x376f8, 0x377e4,
4014248925Snp		0x377f8, 0x377fc,
4015248925Snp		0x37814, 0x37814,
4016248925Snp		0x3782c, 0x3782c,
4017248925Snp		0x37880, 0x3788c,
4018248925Snp		0x378e8, 0x378ec,
4019248925Snp		0x37900, 0x37948,
4020248925Snp		0x37960, 0x3799c,
4021248925Snp		0x379f0, 0x37ae4,
4022248925Snp		0x37af8, 0x37b10,
4023248925Snp		0x37b28, 0x37b28,
4024248925Snp		0x37b3c, 0x37b50,
4025248925Snp		0x37bf0, 0x37c10,
4026248925Snp		0x37c28, 0x37c28,
4027248925Snp		0x37c3c, 0x37c50,
4028248925Snp		0x37cf0, 0x37cfc,
4029252312Snp		0x38000, 0x38030,
4030248925Snp		0x38100, 0x38144,
4031248925Snp		0x38190, 0x381d0,
4032248925Snp		0x38200, 0x38318,
4033248925Snp		0x38400, 0x3852c,
4034248925Snp		0x38540, 0x3861c,
4035248925Snp		0x38800, 0x38834,
4036248925Snp		0x388c0, 0x38908,
4037248925Snp		0x38910, 0x389ac,
4038252312Snp		0x38a00, 0x38a2c,
4039248925Snp		0x38a44, 0x38a50,
4040248925Snp		0x38a74, 0x38c24,
4041252312Snp		0x38d00, 0x38d00,
4042248925Snp		0x38d08, 0x38d14,
4043248925Snp		0x38d1c, 0x38d20,
4044248925Snp		0x38d3c, 0x38d50,
4045248925Snp		0x39200, 0x3920c,
4046248925Snp		0x39220, 0x39220,
4047248925Snp		0x39240, 0x39240,
4048252312Snp		0x39600, 0x3960c,
4049248925Snp		0x39a00, 0x39a1c,
4050252312Snp		0x39e00, 0x39e20,
4051248925Snp		0x39e38, 0x39e3c,
4052248925Snp		0x39e80, 0x39e80,
4053248925Snp		0x39e88, 0x39ea8,
4054248925Snp		0x39eb0, 0x39eb4,
4055248925Snp		0x39ec8, 0x39ed4,
4056248925Snp		0x39fb8, 0x3a004,
4057252312Snp		0x3a200, 0x3a200,
4058252312Snp		0x3a208, 0x3a240,
4059252312Snp		0x3a248, 0x3a280,
4060252312Snp		0x3a288, 0x3a2c0,
4061248925Snp		0x3a2c8, 0x3a2fc,
4062248925Snp		0x3a600, 0x3a630,
4063248925Snp		0x3aa00, 0x3aabc,
4064248925Snp		0x3ab00, 0x3ab70,
4065248925Snp		0x3b000, 0x3b048,
4066248925Snp		0x3b060, 0x3b09c,
4067248925Snp		0x3b0f0, 0x3b148,
4068248925Snp		0x3b160, 0x3b19c,
4069248925Snp		0x3b1f0, 0x3b2e4,
4070248925Snp		0x3b2f8, 0x3b3e4,
4071248925Snp		0x3b3f8, 0x3b448,
4072248925Snp		0x3b460, 0x3b49c,
4073248925Snp		0x3b4f0, 0x3b548,
4074248925Snp		0x3b560, 0x3b59c,
4075248925Snp		0x3b5f0, 0x3b6e4,
4076248925Snp		0x3b6f8, 0x3b7e4,
4077248925Snp		0x3b7f8, 0x3b7fc,
4078248925Snp		0x3b814, 0x3b814,
4079248925Snp		0x3b82c, 0x3b82c,
4080248925Snp		0x3b880, 0x3b88c,
4081248925Snp		0x3b8e8, 0x3b8ec,
4082248925Snp		0x3b900, 0x3b948,
4083248925Snp		0x3b960, 0x3b99c,
4084248925Snp		0x3b9f0, 0x3bae4,
4085248925Snp		0x3baf8, 0x3bb10,
4086248925Snp		0x3bb28, 0x3bb28,
4087248925Snp		0x3bb3c, 0x3bb50,
4088248925Snp		0x3bbf0, 0x3bc10,
4089248925Snp		0x3bc28, 0x3bc28,
4090248925Snp		0x3bc3c, 0x3bc50,
4091248925Snp		0x3bcf0, 0x3bcfc,
4092252312Snp		0x3c000, 0x3c030,
4093248925Snp		0x3c100, 0x3c144,
4094248925Snp		0x3c190, 0x3c1d0,
4095248925Snp		0x3c200, 0x3c318,
4096248925Snp		0x3c400, 0x3c52c,
4097248925Snp		0x3c540, 0x3c61c,
4098248925Snp		0x3c800, 0x3c834,
4099248925Snp		0x3c8c0, 0x3c908,
4100248925Snp		0x3c910, 0x3c9ac,
4101252312Snp		0x3ca00, 0x3ca2c,
4102248925Snp		0x3ca44, 0x3ca50,
4103248925Snp		0x3ca74, 0x3cc24,
4104252312Snp		0x3cd00, 0x3cd00,
4105248925Snp		0x3cd08, 0x3cd14,
4106248925Snp		0x3cd1c, 0x3cd20,
4107248925Snp		0x3cd3c, 0x3cd50,
4108248925Snp		0x3d200, 0x3d20c,
4109248925Snp		0x3d220, 0x3d220,
4110248925Snp		0x3d240, 0x3d240,
4111252312Snp		0x3d600, 0x3d60c,
4112248925Snp		0x3da00, 0x3da1c,
4113252312Snp		0x3de00, 0x3de20,
4114248925Snp		0x3de38, 0x3de3c,
4115248925Snp		0x3de80, 0x3de80,
4116248925Snp		0x3de88, 0x3dea8,
4117248925Snp		0x3deb0, 0x3deb4,
4118248925Snp		0x3dec8, 0x3ded4,
4119248925Snp		0x3dfb8, 0x3e004,
4120252312Snp		0x3e200, 0x3e200,
4121252312Snp		0x3e208, 0x3e240,
4122252312Snp		0x3e248, 0x3e280,
4123252312Snp		0x3e288, 0x3e2c0,
4124248925Snp		0x3e2c8, 0x3e2fc,
4125248925Snp		0x3e600, 0x3e630,
4126248925Snp		0x3ea00, 0x3eabc,
4127248925Snp		0x3eb00, 0x3eb70,
4128248925Snp		0x3f000, 0x3f048,
4129248925Snp		0x3f060, 0x3f09c,
4130248925Snp		0x3f0f0, 0x3f148,
4131248925Snp		0x3f160, 0x3f19c,
4132248925Snp		0x3f1f0, 0x3f2e4,
4133248925Snp		0x3f2f8, 0x3f3e4,
4134248925Snp		0x3f3f8, 0x3f448,
4135248925Snp		0x3f460, 0x3f49c,
4136248925Snp		0x3f4f0, 0x3f548,
4137248925Snp		0x3f560, 0x3f59c,
4138248925Snp		0x3f5f0, 0x3f6e4,
4139248925Snp		0x3f6f8, 0x3f7e4,
4140248925Snp		0x3f7f8, 0x3f7fc,
4141248925Snp		0x3f814, 0x3f814,
4142248925Snp		0x3f82c, 0x3f82c,
4143248925Snp		0x3f880, 0x3f88c,
4144248925Snp		0x3f8e8, 0x3f8ec,
4145248925Snp		0x3f900, 0x3f948,
4146248925Snp		0x3f960, 0x3f99c,
4147248925Snp		0x3f9f0, 0x3fae4,
4148248925Snp		0x3faf8, 0x3fb10,
4149248925Snp		0x3fb28, 0x3fb28,
4150248925Snp		0x3fb3c, 0x3fb50,
4151248925Snp		0x3fbf0, 0x3fc10,
4152248925Snp		0x3fc28, 0x3fc28,
4153248925Snp		0x3fc3c, 0x3fc50,
4154248925Snp		0x3fcf0, 0x3fcfc,
4155248925Snp		0x40000, 0x4000c,
4156248925Snp		0x40040, 0x40068,
4157248925Snp		0x4007c, 0x40144,
4158248925Snp		0x40180, 0x4018c,
4159248925Snp		0x40200, 0x40298,
4160248925Snp		0x402ac, 0x4033c,
4161248925Snp		0x403f8, 0x403fc,
4162252312Snp		0x41304, 0x413c4,
4163248925Snp		0x41400, 0x4141c,
4164248925Snp		0x41480, 0x414d0,
4165248925Snp		0x44000, 0x44078,
4166248925Snp		0x440c0, 0x44278,
4167248925Snp		0x442c0, 0x44478,
4168248925Snp		0x444c0, 0x44678,
4169248925Snp		0x446c0, 0x44878,
4170248925Snp		0x448c0, 0x449fc,
4171248925Snp		0x45000, 0x45068,
4172248925Snp		0x45080, 0x45084,
4173248925Snp		0x450a0, 0x450b0,
4174248925Snp		0x45200, 0x45268,
4175248925Snp		0x45280, 0x45284,
4176248925Snp		0x452a0, 0x452b0,
4177248925Snp		0x460c0, 0x460e4,
4178248925Snp		0x47000, 0x4708c,
4179248925Snp		0x47200, 0x47250,
4180248925Snp		0x47400, 0x47420,
4181248925Snp		0x47600, 0x47618,
4182248925Snp		0x47800, 0x47814,
4183248925Snp		0x48000, 0x4800c,
4184248925Snp		0x48040, 0x48068,
4185248925Snp		0x4807c, 0x48144,
4186248925Snp		0x48180, 0x4818c,
4187248925Snp		0x48200, 0x48298,
4188248925Snp		0x482ac, 0x4833c,
4189248925Snp		0x483f8, 0x483fc,
4190252312Snp		0x49304, 0x493c4,
4191248925Snp		0x49400, 0x4941c,
4192248925Snp		0x49480, 0x494d0,
4193248925Snp		0x4c000, 0x4c078,
4194248925Snp		0x4c0c0, 0x4c278,
4195248925Snp		0x4c2c0, 0x4c478,
4196248925Snp		0x4c4c0, 0x4c678,
4197248925Snp		0x4c6c0, 0x4c878,
4198248925Snp		0x4c8c0, 0x4c9fc,
4199248925Snp		0x4d000, 0x4d068,
4200248925Snp		0x4d080, 0x4d084,
4201248925Snp		0x4d0a0, 0x4d0b0,
4202248925Snp		0x4d200, 0x4d268,
4203248925Snp		0x4d280, 0x4d284,
4204248925Snp		0x4d2a0, 0x4d2b0,
4205248925Snp		0x4e0c0, 0x4e0e4,
4206248925Snp		0x4f000, 0x4f08c,
4207248925Snp		0x4f200, 0x4f250,
4208248925Snp		0x4f400, 0x4f420,
4209248925Snp		0x4f600, 0x4f618,
4210248925Snp		0x4f800, 0x4f814,
4211248925Snp		0x50000, 0x500cc,
4212248925Snp		0x50400, 0x50400,
4213248925Snp		0x50800, 0x508cc,
4214248925Snp		0x50c00, 0x50c00,
4215248925Snp		0x51000, 0x5101c,
4216248925Snp		0x51300, 0x51308,
4217248925Snp	};
4218218792Snp
4219248925Snp	if (is_t4(sc)) {
4220248925Snp		reg_ranges = &t4_reg_ranges[0];
4221248925Snp		n = nitems(t4_reg_ranges);
4222248925Snp	} else {
4223248925Snp		reg_ranges = &t5_reg_ranges[0];
4224248925Snp		n = nitems(t5_reg_ranges);
4225248925Snp	}
4226248925Snp
4227248925Snp	regs->version = chip_id(sc) | chip_rev(sc) << 10;
4228248925Snp	for (i = 0; i < n; i += 2)
4229218792Snp		reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]);
4230218792Snp}
4231218792Snp
4232218792Snpstatic void
4233218792Snpcxgbe_tick(void *arg)
4234218792Snp{
4235218792Snp	struct port_info *pi = arg;
4236265425Snp	struct adapter *sc = pi->adapter;
4237218792Snp	struct ifnet *ifp = pi->ifp;
4238218792Snp	struct sge_txq *txq;
4239218792Snp	int i, drops;
4240218792Snp	struct port_stats *s = &pi->stats;
4241218792Snp
4242218792Snp	PORT_LOCK(pi);
4243218792Snp	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
4244218792Snp		PORT_UNLOCK(pi);
4245218792Snp		return;	/* without scheduling another callout */
4246218792Snp	}
4247218792Snp
4248265425Snp	t4_get_port_stats(sc, pi->tx_chan, s);
4249218792Snp
4250228561Snp	ifp->if_opackets = s->tx_frames - s->tx_pause;
4251228561Snp	ifp->if_ipackets = s->rx_frames - s->rx_pause;
4252228561Snp	ifp->if_obytes = s->tx_octets - s->tx_pause * 64;
4253228561Snp	ifp->if_ibytes = s->rx_octets - s->rx_pause * 64;
4254228561Snp	ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause;
4255228561Snp	ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause;
4256218792Snp	ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 +
4257239259Snp	    s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 +
4258239259Snp	    s->rx_trunc3;
4259265425Snp	for (i = 0; i < 4; i++) {
4260265425Snp		if (pi->rx_chan_map & (1 << i)) {
4261265425Snp			uint32_t v;
4262218792Snp
4263265425Snp			/*
4264265425Snp			 * XXX: indirect reads from the same ADDR/DATA pair can
4265265425Snp			 * race with each other.
4266265425Snp			 */
4267265425Snp			t4_read_indirect(sc, A_TP_MIB_INDEX, A_TP_MIB_DATA, &v,
4268265425Snp			    1, A_TP_MIB_TNL_CNG_DROP_0 + i);
4269265425Snp			ifp->if_iqdrops += v;
4270265425Snp		}
4271265425Snp	}
4272265425Snp
4273218792Snp	drops = s->tx_drop;
4274218792Snp	for_each_txq(pi, i, txq)
4275220873Snp		drops += txq->br->br_drops;
4276218792Snp	ifp->if_snd.ifq_drops = drops;
4277218792Snp
4278218792Snp	ifp->if_oerrors = s->tx_error_frames;
4279218792Snp	ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long +
4280218792Snp	    s->rx_fcs_err + s->rx_len_err;
4281218792Snp
4282218792Snp	callout_schedule(&pi->tick, hz);
4283218792Snp	PORT_UNLOCK(pi);
4284218792Snp}
4285218792Snp
4286237263Snpstatic void
4287237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid)
4288237263Snp{
4289237263Snp	struct ifnet *vlan;
4290237263Snp
4291241494Snp	if (arg != ifp || ifp->if_type != IFT_ETHER)
4292237263Snp		return;
4293237263Snp
4294237263Snp	vlan = VLAN_DEVAT(ifp, vid);
4295237263Snp	VLAN_SETCOOKIE(vlan, ifp);
4296237263Snp}
4297237263Snp
4298218792Snpstatic int
4299228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
4300228561Snp{
4301237263Snp
4302228561Snp#ifdef INVARIANTS
4303237263Snp	panic("%s: opcode 0x%02x on iq %p with payload %p",
4304228561Snp	    __func__, rss->opcode, iq, m);
4305228561Snp#else
4306239336Snp	log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n",
4307228561Snp	    __func__, rss->opcode, iq, m);
4308228561Snp	m_freem(m);
4309228561Snp#endif
4310228561Snp	return (EDOOFUS);
4311228561Snp}
4312228561Snp
4313228561Snpint
4314228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h)
4315228561Snp{
4316228561Snp	uintptr_t *loc, new;
4317228561Snp
4318240452Snp	if (opcode >= nitems(sc->cpl_handler))
4319228561Snp		return (EINVAL);
4320228561Snp
4321228561Snp	new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled;
4322228561Snp	loc = (uintptr_t *) &sc->cpl_handler[opcode];
4323228561Snp	atomic_store_rel_ptr(loc, new);
4324228561Snp
4325228561Snp	return (0);
4326228561Snp}
4327228561Snp
4328228561Snpstatic int
4329237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl)
4330237263Snp{
4331237263Snp
4332237263Snp#ifdef INVARIANTS
4333237263Snp	panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl);
4334237263Snp#else
4335239336Snp	log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n",
4336237263Snp	    __func__, iq, ctrl);
4337237263Snp#endif
4338237263Snp	return (EDOOFUS);
4339237263Snp}
4340237263Snp
4341237263Snpint
4342237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h)
4343237263Snp{
4344237263Snp	uintptr_t *loc, new;
4345237263Snp
4346237263Snp	new = h ? (uintptr_t)h : (uintptr_t)an_not_handled;
4347237263Snp	loc = (uintptr_t *) &sc->an_handler;
4348237263Snp	atomic_store_rel_ptr(loc, new);
4349237263Snp
4350237263Snp	return (0);
4351237263Snp}
4352237263Snp
4353237263Snpstatic int
4354239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl)
4355239336Snp{
4356241733Sed	const struct cpl_fw6_msg *cpl =
4357241733Sed	    __containerof(rpl, struct cpl_fw6_msg, data[0]);
4358239336Snp
4359239336Snp#ifdef INVARIANTS
4360239336Snp	panic("%s: fw_msg type %d", __func__, cpl->type);
4361239336Snp#else
4362239336Snp	log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type);
4363239336Snp#endif
4364239336Snp	return (EDOOFUS);
4365239336Snp}
4366239336Snp
4367239336Snpint
4368239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h)
4369239336Snp{
4370239336Snp	uintptr_t *loc, new;
4371239336Snp
4372240452Snp	if (type >= nitems(sc->fw_msg_handler))
4373239336Snp		return (EINVAL);
4374239336Snp
4375247291Snp	/*
4376247291Snp	 * These are dispatched by the handler for FW{4|6}_CPL_MSG using the CPL
4377247291Snp	 * handler dispatch table.  Reject any attempt to install a handler for
4378247291Snp	 * this subtype.
4379247291Snp	 */
4380247291Snp	if (type == FW_TYPE_RSSCPL || type == FW6_TYPE_RSSCPL)
4381247291Snp		return (EINVAL);
4382247291Snp
4383239336Snp	new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled;
4384239336Snp	loc = (uintptr_t *) &sc->fw_msg_handler[type];
4385239336Snp	atomic_store_rel_ptr(loc, new);
4386239336Snp
4387239336Snp	return (0);
4388239336Snp}
4389239336Snp
4390239336Snpstatic int
4391218792Snpt4_sysctls(struct adapter *sc)
4392218792Snp{
4393218792Snp	struct sysctl_ctx_list *ctx;
4394218792Snp	struct sysctl_oid *oid;
4395228561Snp	struct sysctl_oid_list *children, *c0;
4396228561Snp	static char *caps[] = {
4397228561Snp		"\20\1PPP\2QFC\3DCBX",			/* caps[0] linkcaps */
4398259142Snp		"\20\1NIC\2VM\3IDS\4UM\5UM_ISGL"	/* caps[1] niccaps */
4399259142Snp		    "\6HASHFILTER\7ETHOFLD",
4400228561Snp		"\20\1TOE",				/* caps[2] toecaps */
4401228561Snp		"\20\1RDDP\2RDMAC",			/* caps[3] rdmacaps */
4402228561Snp		"\20\1INITIATOR_PDU\2TARGET_PDU"	/* caps[4] iscsicaps */
4403228561Snp		    "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD"
4404228561Snp		    "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD",
4405228561Snp		"\20\1INITIATOR\2TARGET\3CTRL_OFLD"	/* caps[5] fcoecaps */
4406259142Snp		    "\4PO_INITIAOR\5PO_TARGET"
4407228561Snp	};
4408249392Snp	static char *doorbells = {"\20\1UDB\2WCWR\3UDBWC\4KDB"};
4409218792Snp
4410218792Snp	ctx = device_get_sysctl_ctx(sc->dev);
4411228561Snp
4412228561Snp	/*
4413228561Snp	 * dev.t4nex.X.
4414228561Snp	 */
4415218792Snp	oid = device_get_sysctl_tree(sc->dev);
4416228561Snp	c0 = children = SYSCTL_CHILDREN(oid);
4417218792Snp
4418265421Snp	sc->sc_do_rxcopy = 1;
4419265421Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "do_rx_copy", CTLFLAG_RW,
4420265421Snp	    &sc->sc_do_rxcopy, 1, "Do RX copy of small frames");
4421265421Snp
4422248925Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, NULL,
4423248925Snp	    sc->params.nports, "# of ports");
4424218792Snp
4425218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD,
4426248925Snp	    NULL, chip_rev(sc), "chip hardware revision");
4427218792Snp
4428218792Snp	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version",
4429218792Snp	    CTLFLAG_RD, &sc->fw_version, 0, "firmware version");
4430218792Snp
4431228561Snp	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf",
4432245936Snp	    CTLFLAG_RD, &sc->cfg_file, 0, "configuration file");
4433218792Snp
4434248925Snp	SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, NULL,
4435248925Snp	    sc->cfcsum, "config file checksum");
4436228561Snp
4437248925Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "doorbells",
4438248925Snp	    CTLTYPE_STRING | CTLFLAG_RD, doorbells, sc->doorbells,
4439248925Snp	    sysctl_bitfield, "A", "available doorbells");
4440248925Snp
4441228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps",
4442228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps,
4443228561Snp	    sysctl_bitfield, "A", "available link capabilities");
4444228561Snp
4445228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps",
4446228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps,
4447228561Snp	    sysctl_bitfield, "A", "available NIC capabilities");
4448228561Snp
4449228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps",
4450228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps,
4451228561Snp	    sysctl_bitfield, "A", "available TCP offload capabilities");
4452228561Snp
4453228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps",
4454228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps,
4455228561Snp	    sysctl_bitfield, "A", "available RDMA capabilities");
4456228561Snp
4457228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps",
4458228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps,
4459228561Snp	    sysctl_bitfield, "A", "available iSCSI capabilities");
4460228561Snp
4461228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps",
4462228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps,
4463228561Snp	    sysctl_bitfield, "A", "available FCoE capabilities");
4464228561Snp
4465248925Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, NULL,
4466248925Snp	    sc->params.vpd.cclk, "core clock frequency (in KHz)");
4467218792Snp
4468219436Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers",
4469228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val,
4470228561Snp	    sizeof(sc->sge.timer_val), sysctl_int_array, "A",
4471228561Snp	    "interrupt holdoff timer values (us)");
4472218792Snp
4473219436Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts",
4474228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val,
4475228561Snp	    sizeof(sc->sge.counter_val), sysctl_int_array, "A",
4476228561Snp	    "interrupt holdoff packet counter values");
4477218792Snp
4478252469Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nfilters", CTLFLAG_RD,
4479252469Snp	    NULL, sc->tids.nftids, "number of filters");
4480252469Snp
4481253890Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature", CTLTYPE_INT |
4482264736Semax	    CTLFLAG_RD, sc, 0, sysctl_temperature, "I",
4483253890Snp	    "chip temperature (in Celsius)");
4484253890Snp
4485253829Snp	t4_sge_sysctls(sc, ctx, children);
4486253829Snp
4487255015Snp	sc->lro_timeout = 100;
4488255015Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "lro_timeout", CTLFLAG_RW,
4489255015Snp	    &sc->lro_timeout, 0, "lro inactive-flush timeout (in us)");
4490255015Snp
4491231115Snp#ifdef SBUF_DRAIN
4492228561Snp	/*
4493228561Snp	 * dev.t4nex.X.misc.  Marked CTLFLAG_SKIP to avoid information overload.
4494228561Snp	 */
4495228561Snp	oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc",
4496228561Snp	    CTLFLAG_RD | CTLFLAG_SKIP, NULL,
4497228561Snp	    "logs and miscellaneous information");
4498228561Snp	children = SYSCTL_CHILDREN(oid);
4499228561Snp
4500228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl",
4501228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4502228561Snp	    sysctl_cctrl, "A", "congestion control");
4503228561Snp
4504247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0",
4505247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4506247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)");
4507247122Snp
4508247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1",
4509247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 1,
4510247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)");
4511247122Snp
4512247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp",
4513247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 2,
4514247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)");
4515247122Snp
4516247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0",
4517247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 3,
4518247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)");
4519247122Snp
4520247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1",
4521247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 4,
4522247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)");
4523247122Snp
4524247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi",
4525247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 5,
4526247122Snp	    sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)");
4527247122Snp
4528247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la",
4529247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4530247122Snp	    sysctl_cim_la, "A", "CIM logic analyzer");
4531247122Snp
4532251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ma_la",
4533251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4534251213Snp	    sysctl_cim_ma_la, "A", "CIM MA logic analyzer");
4535251213Snp
4536247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0",
4537247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ,
4538247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)");
4539247122Snp
4540247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1",
4541247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ,
4542247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)");
4543247122Snp
4544247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2",
4545247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ,
4546247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)");
4547247122Snp
4548247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3",
4549247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ,
4550247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)");
4551247122Snp
4552247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge",
4553247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ,
4554247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)");
4555247122Snp
4556247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi",
4557247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ,
4558247122Snp	    sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)");
4559247122Snp
4560248925Snp	if (is_t5(sc)) {
4561248925Snp		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge0_rx",
4562248925Snp		    CTLTYPE_STRING | CTLFLAG_RD, sc, 6 + CIM_NUM_IBQ,
4563248925Snp		    sysctl_cim_ibq_obq, "A", "CIM OBQ 6 (SGE0-RX)");
4564248925Snp
4565248925Snp		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge1_rx",
4566248925Snp		    CTLTYPE_STRING | CTLFLAG_RD, sc, 7 + CIM_NUM_IBQ,
4567248925Snp		    sysctl_cim_ibq_obq, "A", "CIM OBQ 7 (SGE1-RX)");
4568248925Snp	}
4569248925Snp
4570251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_pif_la",
4571251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4572251213Snp	    sysctl_cim_pif_la, "A", "CIM PIF logic analyzer");
4573251213Snp
4574247122Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg",
4575247122Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4576247122Snp	    sysctl_cim_qcfg, "A", "CIM queue configuration");
4577247122Snp
4578228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats",
4579228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4580228561Snp	    sysctl_cpl_stats, "A", "CPL statistics");
4581228561Snp
4582228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats",
4583228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4584228561Snp	    sysctl_ddp_stats, "A", "DDP statistics");
4585228561Snp
4586222551Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog",
4587222551Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4588228561Snp	    sysctl_devlog, "A", "firmware's device log");
4589222551Snp
4590228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats",
4591228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4592228561Snp	    sysctl_fcoe_stats, "A", "FCoE statistics");
4593228561Snp
4594228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched",
4595228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4596228561Snp	    sysctl_hw_sched, "A", "hardware scheduler ");
4597228561Snp
4598228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t",
4599228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4600228561Snp	    sysctl_l2t, "A", "hardware L2 table");
4601228561Snp
4602228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats",
4603228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4604228561Snp	    sysctl_lb_stats, "A", "loopback statistics");
4605228561Snp
4606228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo",
4607228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4608228561Snp	    sysctl_meminfo, "A", "memory regions");
4609228561Snp
4610251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mps_tcam",
4611251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4612251213Snp	    sysctl_mps_tcam, "A", "MPS TCAM entries");
4613251213Snp
4614228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus",
4615228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4616228561Snp	    sysctl_path_mtus, "A", "path MTUs");
4617228561Snp
4618228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats",
4619228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4620228561Snp	    sysctl_pm_stats, "A", "PM statistics");
4621228561Snp
4622228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats",
4623228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4624228561Snp	    sysctl_rdma_stats, "A", "RDMA statistics");
4625228561Snp
4626228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats",
4627228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4628228561Snp	    sysctl_tcp_stats, "A", "TCP statistics");
4629228561Snp
4630228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids",
4631228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4632228561Snp	    sysctl_tids, "A", "TID information");
4633228561Snp
4634228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats",
4635228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4636228561Snp	    sysctl_tp_err_stats, "A", "TP error statistics");
4637228561Snp
4638251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la",
4639251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4640251213Snp	    sysctl_tp_la, "A", "TP logic analyzer");
4641251213Snp
4642228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate",
4643228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4644228561Snp	    sysctl_tx_rate, "A", "Tx rate");
4645248925Snp
4646251213Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ulprx_la",
4647251213Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4648251213Snp	    sysctl_ulprx_la, "A", "ULPRX logic analyzer");
4649251213Snp
4650248925Snp	if (is_t5(sc)) {
4651249392Snp		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "wcwr_stats",
4652248925Snp		    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
4653249392Snp		    sysctl_wcwr_stats, "A", "write combined work requests");
4654248925Snp	}
4655231115Snp#endif
4656228561Snp
4657237263Snp#ifdef TCP_OFFLOAD
4658228561Snp	if (is_offload(sc)) {
4659228561Snp		/*
4660228561Snp		 * dev.t4nex.X.toe.
4661228561Snp		 */
4662228561Snp		oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD,
4663228561Snp		    NULL, "TOE parameters");
4664228561Snp		children = SYSCTL_CHILDREN(oid);
4665228561Snp
4666228561Snp		sc->tt.sndbuf = 256 * 1024;
4667228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW,
4668228561Snp		    &sc->tt.sndbuf, 0, "max hardware send buffer size");
4669228561Snp
4670228561Snp		sc->tt.ddp = 0;
4671228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW,
4672228561Snp		    &sc->tt.ddp, 0, "DDP allowed");
4673239341Snp
4674239341Snp		sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5));
4675228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW,
4676228561Snp		    &sc->tt.indsz, 0, "DDP max indicate size allowed");
4677239341Snp
4678239341Snp		sc->tt.ddp_thres =
4679239341Snp		    G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2));
4680228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW,
4681228561Snp		    &sc->tt.ddp_thres, 0, "DDP threshold");
4682252728Snp
4683252728Snp		sc->tt.rx_coalesce = 1;
4684252728Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_coalesce",
4685252728Snp		    CTLFLAG_RW, &sc->tt.rx_coalesce, 0, "receive coalescing");
4686228561Snp	}
4687228561Snp#endif
4688228561Snp
4689228561Snp
4690218792Snp	return (0);
4691218792Snp}
4692218792Snp
4693218792Snpstatic int
4694218792Snpcxgbe_sysctls(struct port_info *pi)
4695218792Snp{
4696218792Snp	struct sysctl_ctx_list *ctx;
4697218792Snp	struct sysctl_oid *oid;
4698218792Snp	struct sysctl_oid_list *children;
4699265426Snp	struct adapter *sc = pi->adapter;
4700218792Snp
4701218792Snp	ctx = device_get_sysctl_ctx(pi->dev);
4702218792Snp
4703218792Snp	/*
4704218792Snp	 * dev.cxgbe.X.
4705218792Snp	 */
4706218792Snp	oid = device_get_sysctl_tree(pi->dev);
4707218792Snp	children = SYSCTL_CHILDREN(oid);
4708218792Snp
4709253701Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkdnrc", CTLTYPE_STRING |
4710253701Snp	   CTLFLAG_RD, pi, 0, sysctl_linkdnrc, "A", "reason why link is down");
4711252747Snp	if (pi->port_type == FW_PORT_TYPE_BT_XAUI) {
4712252747Snp		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature",
4713252747Snp		    CTLTYPE_INT | CTLFLAG_RD, pi, 0, sysctl_btphy, "I",
4714252747Snp		    "PHY temperature (in Celsius)");
4715252747Snp		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fw_version",
4716252747Snp		    CTLTYPE_INT | CTLFLAG_RD, pi, 1, sysctl_btphy, "I",
4717252747Snp		    "PHY firmware version");
4718252747Snp	}
4719218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD,
4720218792Snp	    &pi->nrxq, 0, "# of rx queues");
4721218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD,
4722218792Snp	    &pi->ntxq, 0, "# of tx queues");
4723218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD,
4724218792Snp	    &pi->first_rxq, 0, "index of first rx queue");
4725218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD,
4726218792Snp	    &pi->first_txq, 0, "index of first tx queue");
4727264493Sscottl	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rsrv_noflowq", CTLTYPE_INT |
4728264493Sscottl	    CTLFLAG_RW, pi, 0, sysctl_noflowq, "IU",
4729264493Sscottl	    "Reserve queue 0 for non-flowid packets");
4730218792Snp
4731237263Snp#ifdef TCP_OFFLOAD
4732265426Snp	if (is_offload(sc)) {
4733228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD,
4734228561Snp		    &pi->nofldrxq, 0,
4735228561Snp		    "# of rx queues for offloaded TCP connections");
4736228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD,
4737228561Snp		    &pi->nofldtxq, 0,
4738228561Snp		    "# of tx queues for offloaded TCP connections");
4739228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq",
4740228561Snp		    CTLFLAG_RD, &pi->first_ofld_rxq, 0,
4741228561Snp		    "index of first TOE rx queue");
4742228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq",
4743228561Snp		    CTLFLAG_RD, &pi->first_ofld_txq, 0,
4744228561Snp		    "index of first TOE tx queue");
4745228561Snp	}
4746228561Snp#endif
4747270297Snp#ifdef DEV_NETMAP
4748270297Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nnmrxq", CTLFLAG_RD,
4749270297Snp	    &pi->nnmrxq, 0, "# of rx queues for netmap");
4750270297Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nnmtxq", CTLFLAG_RD,
4751270297Snp	    &pi->nnmtxq, 0, "# of tx queues for netmap");
4752270297Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_nm_rxq",
4753270297Snp	    CTLFLAG_RD, &pi->first_nm_rxq, 0,
4754270297Snp	    "index of first netmap rx queue");
4755270297Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_nm_txq",
4756270297Snp	    CTLFLAG_RD, &pi->first_nm_txq, 0,
4757270297Snp	    "index of first netmap tx queue");
4758270297Snp#endif
4759228561Snp
4760218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx",
4761218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I",
4762218792Snp	    "holdoff timer index");
4763218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx",
4764218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I",
4765218792Snp	    "holdoff packet counter index");
4766218792Snp
4767218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq",
4768218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I",
4769218792Snp	    "rx queue size");
4770218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq",
4771218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I",
4772218792Snp	    "tx queue size");
4773218792Snp
4774271961Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pause_settings",
4775271961Snp	    CTLTYPE_STRING | CTLFLAG_RW, pi, PAUSE_TX, sysctl_pause_settings,
4776271961Snp	    "A", "PAUSE settings (bit 0 = rx_pause, bit 1 = tx_pause)");
4777271961Snp
4778218792Snp	/*
4779218792Snp	 * dev.cxgbe.X.stats.
4780218792Snp	 */
4781218792Snp	oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD,
4782218792Snp	    NULL, "port statistics");
4783218792Snp	children = SYSCTL_CHILDREN(oid);
4784218792Snp
4785218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \
4786218792Snp	SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \
4787265426Snp	    CTLTYPE_U64 | CTLFLAG_RD, sc, reg, \
4788218792Snp	    sysctl_handle_t4_reg64, "QU", desc)
4789218792Snp
4790218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames",
4791218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L));
4792218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames",
4793218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L));
4794218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames",
4795218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L));
4796218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames",
4797218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L));
4798218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames",
4799218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L));
4800218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames",
4801218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L));
4802218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_64",
4803218792Snp	    "# of tx frames in this range",
4804218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L));
4805218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127",
4806218792Snp	    "# of tx frames in this range",
4807218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L));
4808218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255",
4809218792Snp	    "# of tx frames in this range",
4810218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L));
4811218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511",
4812218792Snp	    "# of tx frames in this range",
4813218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L));
4814218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023",
4815218792Snp	    "# of tx frames in this range",
4816218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L));
4817218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518",
4818218792Snp	    "# of tx frames in this range",
4819218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L));
4820218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max",
4821218792Snp	    "# of tx frames in this range",
4822218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L));
4823218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames",
4824218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L));
4825218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted",
4826218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L));
4827218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted",
4828218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L));
4829218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted",
4830218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L));
4831218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted",
4832218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L));
4833218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted",
4834218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L));
4835218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted",
4836218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L));
4837218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted",
4838218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L));
4839218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted",
4840218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L));
4841218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted",
4842218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L));
4843218792Snp
4844218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames",
4845218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L));
4846218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames",
4847218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L));
4848218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames",
4849218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L));
4850218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames",
4851218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L));
4852218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames",
4853218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L));
4854218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU",
4855218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L));
4856218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames",
4857218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L));
4858218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err",
4859218792Snp	    "# of frames received with bad FCS",
4860218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L));
4861218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_len_err",
4862218792Snp	    "# of frames received with length error",
4863218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L));
4864218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors",
4865218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L));
4866218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received",
4867218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L));
4868218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_64",
4869218792Snp	    "# of rx frames in this range",
4870218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L));
4871218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127",
4872218792Snp	    "# of rx frames in this range",
4873218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L));
4874218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255",
4875218792Snp	    "# of rx frames in this range",
4876218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L));
4877218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511",
4878218792Snp	    "# of rx frames in this range",
4879218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L));
4880218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023",
4881218792Snp	    "# of rx frames in this range",
4882218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L));
4883218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518",
4884218792Snp	    "# of rx frames in this range",
4885218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L));
4886218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max",
4887218792Snp	    "# of rx frames in this range",
4888218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L));
4889218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received",
4890218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L));
4891218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received",
4892218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L));
4893218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received",
4894218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L));
4895218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received",
4896218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L));
4897218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received",
4898218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L));
4899218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received",
4900218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L));
4901218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received",
4902218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L));
4903218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received",
4904218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L));
4905218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received",
4906218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L));
4907218792Snp
4908218792Snp#undef SYSCTL_ADD_T4_REG64
4909218792Snp
4910218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \
4911218792Snp	SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \
4912218792Snp	    &pi->stats.name, desc)
4913218792Snp
4914218792Snp	/* We get these from port_stats and they may be stale by upto 1s */
4915218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0,
4916218792Snp	    "# drops due to buffer-group 0 overflows");
4917218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1,
4918218792Snp	    "# drops due to buffer-group 1 overflows");
4919218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2,
4920218792Snp	    "# drops due to buffer-group 2 overflows");
4921218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3,
4922218792Snp	    "# drops due to buffer-group 3 overflows");
4923218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc0,
4924218792Snp	    "# of buffer-group 0 truncated packets");
4925218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc1,
4926218792Snp	    "# of buffer-group 1 truncated packets");
4927218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc2,
4928218792Snp	    "# of buffer-group 2 truncated packets");
4929218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc3,
4930218792Snp	    "# of buffer-group 3 truncated packets");
4931218792Snp
4932218792Snp#undef SYSCTL_ADD_T4_PORTSTAT
4933218792Snp
4934218792Snp	return (0);
4935218792Snp}
4936218792Snp
4937218792Snpstatic int
4938219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS)
4939219436Snp{
4940219436Snp	int rc, *i;
4941219436Snp	struct sbuf sb;
4942219436Snp
4943219436Snp	sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND);
4944219436Snp	for (i = arg1; arg2; arg2 -= sizeof(int), i++)
4945219436Snp		sbuf_printf(&sb, "%d ", *i);
4946219436Snp	sbuf_trim(&sb);
4947219436Snp	sbuf_finish(&sb);
4948219436Snp	rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
4949219436Snp	sbuf_delete(&sb);
4950219436Snp	return (rc);
4951219436Snp}
4952219436Snp
4953219436Snpstatic int
4954228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS)
4955228561Snp{
4956228561Snp	int rc;
4957228561Snp	struct sbuf *sb;
4958228561Snp
4959228561Snp	rc = sysctl_wire_old_buffer(req, 0);
4960228561Snp	if (rc != 0)
4961228561Snp		return(rc);
4962228561Snp
4963228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4964228561Snp	if (sb == NULL)
4965228561Snp		return (ENOMEM);
4966228561Snp
4967228561Snp	sbuf_printf(sb, "%b", (int)arg2, (char *)arg1);
4968228561Snp	rc = sbuf_finish(sb);
4969228561Snp	sbuf_delete(sb);
4970228561Snp
4971228561Snp	return (rc);
4972228561Snp}
4973228561Snp
4974228561Snpstatic int
4975252747Snpsysctl_btphy(SYSCTL_HANDLER_ARGS)
4976252747Snp{
4977252747Snp	struct port_info *pi = arg1;
4978252747Snp	int op = arg2;
4979252747Snp	struct adapter *sc = pi->adapter;
4980252747Snp	u_int v;
4981252747Snp	int rc;
4982252747Snp
4983252747Snp	rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4btt");
4984252747Snp	if (rc)
4985252747Snp		return (rc);
4986252747Snp	/* XXX: magic numbers */
4987252747Snp	rc = -t4_mdio_rd(sc, sc->mbox, pi->mdio_addr, 0x1e, op ? 0x20 : 0xc820,
4988252747Snp	    &v);
4989252747Snp	end_synchronized_op(sc, 0);
4990252747Snp	if (rc)
4991252747Snp		return (rc);
4992252747Snp	if (op == 0)
4993252747Snp		v /= 256;
4994252747Snp
4995252747Snp	rc = sysctl_handle_int(oidp, &v, 0, req);
4996252747Snp	return (rc);
4997252747Snp}
4998252747Snp
4999252747Snpstatic int
5000264493Sscottlsysctl_noflowq(SYSCTL_HANDLER_ARGS)
5001264493Sscottl{
5002264493Sscottl	struct port_info *pi = arg1;
5003264493Sscottl	int rc, val;
5004264493Sscottl
5005264493Sscottl	val = pi->rsrv_noflowq;
5006264493Sscottl	rc = sysctl_handle_int(oidp, &val, 0, req);
5007264493Sscottl	if (rc != 0 || req->newptr == NULL)
5008264493Sscottl		return (rc);
5009264493Sscottl
5010264493Sscottl	if ((val >= 1) && (pi->ntxq > 1))
5011264493Sscottl		pi->rsrv_noflowq = 1;
5012264493Sscottl	else
5013264493Sscottl		pi->rsrv_noflowq = 0;
5014264493Sscottl
5015264493Sscottl	return (rc);
5016264493Sscottl}
5017264493Sscottl
5018264493Sscottlstatic int
5019218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS)
5020218792Snp{
5021218792Snp	struct port_info *pi = arg1;
5022218792Snp	struct adapter *sc = pi->adapter;
5023218792Snp	int idx, rc, i;
5024245274Snp	struct sge_rxq *rxq;
5025252724Snp#ifdef TCP_OFFLOAD
5026252724Snp	struct sge_ofld_rxq *ofld_rxq;
5027252724Snp#endif
5028245274Snp	uint8_t v;
5029218792Snp
5030218792Snp	idx = pi->tmr_idx;
5031218792Snp
5032218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
5033218792Snp	if (rc != 0 || req->newptr == NULL)
5034218792Snp		return (rc);
5035218792Snp
5036218792Snp	if (idx < 0 || idx >= SGE_NTIMERS)
5037218792Snp		return (EINVAL);
5038218792Snp
5039245274Snp	rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK,
5040245274Snp	    "t4tmr");
5041245274Snp	if (rc)
5042245274Snp		return (rc);
5043228561Snp
5044245274Snp	v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1);
5045245274Snp	for_each_rxq(pi, i, rxq) {
5046228561Snp#ifdef atomic_store_rel_8
5047245274Snp		atomic_store_rel_8(&rxq->iq.intr_params, v);
5048228561Snp#else
5049245274Snp		rxq->iq.intr_params = v;
5050228561Snp#endif
5051218792Snp	}
5052252724Snp#ifdef TCP_OFFLOAD
5053252724Snp	for_each_ofld_rxq(pi, i, ofld_rxq) {
5054252724Snp#ifdef atomic_store_rel_8
5055252724Snp		atomic_store_rel_8(&ofld_rxq->iq.intr_params, v);
5056252724Snp#else
5057252724Snp		ofld_rxq->iq.intr_params = v;
5058252724Snp#endif
5059252724Snp	}
5060252724Snp#endif
5061245274Snp	pi->tmr_idx = idx;
5062218792Snp
5063245274Snp	end_synchronized_op(sc, LOCK_HELD);
5064245274Snp	return (0);
5065218792Snp}
5066218792Snp
5067218792Snpstatic int
5068218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS)
5069218792Snp{
5070218792Snp	struct port_info *pi = arg1;
5071218792Snp	struct adapter *sc = pi->adapter;
5072218792Snp	int idx, rc;
5073218792Snp
5074218792Snp	idx = pi->pktc_idx;
5075218792Snp
5076218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
5077218792Snp	if (rc != 0 || req->newptr == NULL)
5078218792Snp		return (rc);
5079218792Snp
5080218792Snp	if (idx < -1 || idx >= SGE_NCOUNTERS)
5081218792Snp		return (EINVAL);
5082218792Snp
5083245274Snp	rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK,
5084245274Snp	    "t4pktc");
5085245274Snp	if (rc)
5086245274Snp		return (rc);
5087245274Snp
5088245274Snp	if (pi->flags & PORT_INIT_DONE)
5089228561Snp		rc = EBUSY; /* cannot be changed once the queues are created */
5090245274Snp	else
5091218792Snp		pi->pktc_idx = idx;
5092218792Snp
5093245274Snp	end_synchronized_op(sc, LOCK_HELD);
5094218792Snp	return (rc);
5095218792Snp}
5096218792Snp
5097218792Snpstatic int
5098218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS)
5099218792Snp{
5100218792Snp	struct port_info *pi = arg1;
5101218792Snp	struct adapter *sc = pi->adapter;
5102218792Snp	int qsize, rc;
5103218792Snp
5104218792Snp	qsize = pi->qsize_rxq;
5105218792Snp
5106218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
5107218792Snp	if (rc != 0 || req->newptr == NULL)
5108218792Snp		return (rc);
5109218792Snp
5110218792Snp	if (qsize < 128 || (qsize & 7))
5111218792Snp		return (EINVAL);
5112218792Snp
5113245274Snp	rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK,
5114245274Snp	    "t4rxqs");
5115245274Snp	if (rc)
5116245274Snp		return (rc);
5117245274Snp
5118245274Snp	if (pi->flags & PORT_INIT_DONE)
5119228561Snp		rc = EBUSY; /* cannot be changed once the queues are created */
5120245274Snp	else
5121218792Snp		pi->qsize_rxq = qsize;
5122218792Snp
5123245274Snp	end_synchronized_op(sc, LOCK_HELD);
5124218792Snp	return (rc);
5125218792Snp}
5126218792Snp
5127218792Snpstatic int
5128218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS)
5129218792Snp{
5130218792Snp	struct port_info *pi = arg1;
5131218792Snp	struct adapter *sc = pi->adapter;
5132218792Snp	int qsize, rc;
5133218792Snp
5134218792Snp	qsize = pi->qsize_txq;
5135218792Snp
5136218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
5137218792Snp	if (rc != 0 || req->newptr == NULL)
5138218792Snp		return (rc);
5139218792Snp
5140245274Snp	/* bufring size must be powerof2 */
5141245274Snp	if (qsize < 128 || !powerof2(qsize))
5142218792Snp		return (EINVAL);
5143218792Snp
5144245274Snp	rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK,
5145245274Snp	    "t4txqs");
5146245274Snp	if (rc)
5147245274Snp		return (rc);
5148245274Snp
5149245274Snp	if (pi->flags & PORT_INIT_DONE)
5150228561Snp		rc = EBUSY; /* cannot be changed once the queues are created */
5151245274Snp	else
5152218792Snp		pi->qsize_txq = qsize;
5153218792Snp
5154245274Snp	end_synchronized_op(sc, LOCK_HELD);
5155218792Snp	return (rc);
5156218792Snp}
5157218792Snp
5158218792Snpstatic int
5159271961Snpsysctl_pause_settings(SYSCTL_HANDLER_ARGS)
5160271961Snp{
5161271961Snp	struct port_info *pi = arg1;
5162271961Snp	struct adapter *sc = pi->adapter;
5163271961Snp	struct link_config *lc = &pi->link_cfg;
5164271961Snp	int rc;
5165271961Snp
5166271961Snp	if (req->newptr == NULL) {
5167271961Snp		struct sbuf *sb;
5168271961Snp		static char *bits = "\20\1PAUSE_RX\2PAUSE_TX";
5169271961Snp
5170271961Snp		rc = sysctl_wire_old_buffer(req, 0);
5171271961Snp		if (rc != 0)
5172271961Snp			return(rc);
5173271961Snp
5174271961Snp		sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5175271961Snp		if (sb == NULL)
5176271961Snp			return (ENOMEM);
5177271961Snp
5178271961Snp		sbuf_printf(sb, "%b", lc->fc & (PAUSE_TX | PAUSE_RX), bits);
5179271961Snp		rc = sbuf_finish(sb);
5180271961Snp		sbuf_delete(sb);
5181271961Snp	} else {
5182271961Snp		char s[2];
5183271961Snp		int n;
5184271961Snp
5185271961Snp		s[0] = '0' + (lc->requested_fc & (PAUSE_TX | PAUSE_RX));
5186271961Snp		s[1] = 0;
5187271961Snp
5188271961Snp		rc = sysctl_handle_string(oidp, s, sizeof(s), req);
5189271961Snp		if (rc != 0)
5190271961Snp			return(rc);
5191271961Snp
5192271961Snp		if (s[1] != 0)
5193271961Snp			return (EINVAL);
5194271961Snp		if (s[0] < '0' || s[0] > '9')
5195271961Snp			return (EINVAL);	/* not a number */
5196271961Snp		n = s[0] - '0';
5197271961Snp		if (n & ~(PAUSE_TX | PAUSE_RX))
5198271961Snp			return (EINVAL);	/* some other bit is set too */
5199271961Snp
5200271961Snp		rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4PAUSE");
5201271961Snp		if (rc)
5202271961Snp			return (rc);
5203271961Snp		if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) {
5204271961Snp			int link_ok = lc->link_ok;
5205271961Snp
5206271961Snp			lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
5207271961Snp			lc->requested_fc |= n;
5208271961Snp			rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, lc);
5209271961Snp			lc->link_ok = link_ok;	/* restore */
5210271961Snp		}
5211271961Snp		end_synchronized_op(sc, 0);
5212271961Snp	}
5213271961Snp
5214271961Snp	return (rc);
5215271961Snp}
5216271961Snp
5217271961Snpstatic int
5218218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS)
5219218792Snp{
5220218792Snp	struct adapter *sc = arg1;
5221218792Snp	int reg = arg2;
5222218792Snp	uint64_t val;
5223218792Snp
5224218792Snp	val = t4_read_reg64(sc, reg);
5225218792Snp
5226218792Snp	return (sysctl_handle_64(oidp, &val, 0, req));
5227218792Snp}
5228218792Snp
5229253890Snpstatic int
5230253890Snpsysctl_temperature(SYSCTL_HANDLER_ARGS)
5231253890Snp{
5232253890Snp	struct adapter *sc = arg1;
5233253890Snp	int rc, t;
5234253890Snp	uint32_t param, val;
5235253890Snp
5236253890Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4temp");
5237253890Snp	if (rc)
5238253890Snp		return (rc);
5239253890Snp	param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
5240253890Snp	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_DIAG) |
5241253890Snp	    V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_DIAG_TMP);
5242253890Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
5243253890Snp	end_synchronized_op(sc, 0);
5244253890Snp	if (rc)
5245253890Snp		return (rc);
5246253890Snp
5247253890Snp	/* unknown is returned as 0 but we display -1 in that case */
5248253890Snp	t = val == 0 ? -1 : val;
5249253890Snp
5250253890Snp	rc = sysctl_handle_int(oidp, &t, 0, req);
5251253890Snp	return (rc);
5252253890Snp}
5253253890Snp
5254231115Snp#ifdef SBUF_DRAIN
5255228561Snpstatic int
5256228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS)
5257228561Snp{
5258228561Snp	struct adapter *sc = arg1;
5259228561Snp	struct sbuf *sb;
5260228561Snp	int rc, i;
5261228561Snp	uint16_t incr[NMTUS][NCCTRL_WIN];
5262228561Snp	static const char *dec_fac[] = {
5263228561Snp		"0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875",
5264228561Snp		"0.9375"
5265228561Snp	};
5266228561Snp
5267228561Snp	rc = sysctl_wire_old_buffer(req, 0);
5268228561Snp	if (rc != 0)
5269228561Snp		return (rc);
5270228561Snp
5271228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
5272228561Snp	if (sb == NULL)
5273228561Snp		return (ENOMEM);
5274228561Snp
5275228561Snp	t4_read_cong_tbl(sc, incr);
5276228561Snp
5277228561Snp	for (i = 0; i < NCCTRL_WIN; ++i) {
5278228561Snp		sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i,
5279228561Snp		    incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i],
5280228561Snp		    incr[5][i], incr[6][i], incr[7][i]);
5281228561Snp		sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n",
5282228561Snp		    incr[8][i], incr[9][i], incr[10][i], incr[11][i],
5283228561Snp		    incr[12][i], incr[13][i], incr[14][i], incr[15][i],
5284228561Snp		    sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]);
5285228561Snp	}
5286228561Snp
5287228561Snp	rc = sbuf_finish(sb);
5288228561Snp	sbuf_delete(sb);
5289228561Snp
5290228561Snp	return (rc);
5291228561Snp}
5292228561Snp
5293248925Snpstatic const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ_T5] = {
5294247122Snp	"TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI",	/* ibq's */
5295248925Snp	"ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI",	/* obq's */
5296248925Snp	"SGE0-RX", "SGE1-RX"	/* additional obq's (T5 onwards) */
5297247122Snp};
5298247122Snp
5299228561Snpstatic int
5300247122Snpsysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS)
5301247122Snp{
5302247122Snp	struct adapter *sc = arg1;
5303247122Snp	struct sbuf *sb;
5304247122Snp	int rc, i, n, qid = arg2;
5305247122Snp	uint32_t *buf, *p;
5306247122Snp	char *qtype;
5307248925Snp	u_int cim_num_obq = is_t4(sc) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
5308247122Snp
5309248925Snp	KASSERT(qid >= 0 && qid < CIM_NUM_IBQ + cim_num_obq,
5310247122Snp	    ("%s: bad qid %d\n", __func__, qid));
5311247122Snp
5312247122Snp	if (qid < CIM_NUM_IBQ) {
5313247122Snp		/* inbound queue */
5314247122Snp		qtype = "IBQ";
5315247122Snp		n = 4 * CIM_IBQ_SIZE;
5316247122Snp		buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK);
5317247122Snp		rc = t4_read_cim_ibq(sc, qid, buf, n);
5318247122Snp	} else {
5319247122Snp		/* outbound queue */
5320247122Snp		qtype = "OBQ";
5321247122Snp		qid -= CIM_NUM_IBQ;
5322248925Snp		n = 4 * cim_num_obq * CIM_OBQ_SIZE;
5323247122Snp		buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK);
5324247122Snp		rc = t4_read_cim_obq(sc, qid, buf, n);
5325247122Snp	}
5326247122Snp
5327247122Snp	if (rc < 0) {
5328247122Snp		rc = -rc;
5329247122Snp		goto done;
5330247122Snp	}
5331247122Snp	n = rc * sizeof(uint32_t);	/* rc has # of words actually read */
5332247122Snp
5333247122Snp	rc = sysctl_wire_old_buffer(req, 0);
5334247122Snp	if (rc != 0)
5335247122Snp		goto done;
5336247122Snp
5337248925Snp	sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req);
5338247122Snp	if (sb == NULL) {
5339247122Snp		rc = ENOMEM;
5340247122Snp		goto done;
5341247122Snp	}
5342247122Snp
5343247122Snp	sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]);
5344247122Snp	for (i = 0, p = buf; i < n; i += 16, p += 4)
5345247122Snp		sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1],
5346247122Snp		    p[2], p[3]);
5347247122Snp
5348247122Snp	rc = sbuf_finish(sb);
5349247122Snp	sbuf_delete(sb);
5350247122Snpdone:
5351247122Snp	free(buf, M_CXGBE);
5352247122Snp	return (rc);
5353247122Snp}
5354247122Snp
5355247122Snpstatic int
5356247122Snpsysctl_cim_la(SYSCTL_HANDLER_ARGS)
5357247122Snp{
5358247122Snp	struct adapter *sc = arg1;
5359247122Snp	u_int cfg;
5360247122Snp	struct sbuf *sb;
5361247122Snp	uint32_t *buf, *p;
5362247122Snp	int rc;
5363247122Snp
5364247122Snp	rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg);
5365247122Snp	if (rc != 0)
5366247122Snp		return (rc);
5367247122Snp
5368247122Snp	rc = sysctl_wire_old_buffer(req, 0);
5369247122Snp	if (rc != 0)
5370247122Snp		return (rc);
5371247122Snp
5372247122Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
5373247122Snp	if (sb == NULL)
5374247122Snp		return (ENOMEM);
5375247122Snp
5376247122Snp	buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE,
5377247122Snp	    M_ZERO | M_WAITOK);
5378247122Snp
5379247122Snp	rc = -t4_cim_read_la(sc, buf, NULL);
5380247122Snp	if (rc != 0)
5381247122Snp		goto done;
5382247122Snp
5383247122Snp	sbuf_printf(sb, "Status   Data      PC%s",
5384247122Snp	    cfg & F_UPDBGLACAPTPCONLY ? "" :
5385247122Snp	    "     LS0Stat  LS0Addr             LS0Data");
5386247122Snp
5387247122Snp	KASSERT((sc->params.cim_la_size & 7) == 0,
5388247122Snp	    ("%s: p will walk off the end of buf", __func__));
5389247122Snp
5390247122Snp	for (p = buf; p < &buf[sc->params.cim_la_size]; p += 8) {
5391247122Snp		if (cfg & F_UPDBGLACAPTPCONLY) {
5392247122Snp			sbuf_printf(sb, "\n  %02x   %08x %08x", p[5] & 0xff,
5393247122Snp			    p[6], p[7]);
5394247122Snp			sbuf_printf(sb, "\n  %02x   %02x%06x %02x%06x",
5395247122Snp			    (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8,
5396247122Snp			    p[4] & 0xff, p[5] >> 8);
5397247122Snp			sbuf_printf(sb, "\n  %02x   %x%07x %x%07x",
5398247122Snp			    (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4,
5399247122Snp			    p[1] & 0xf, p[2] >> 4);
5400247122Snp		} else {
5401247122Snp			sbuf_printf(sb,
5402247122Snp			    "\n  %02x   %x%07x %x%07x %08x %08x "
5403247122Snp			    "%08x%08x%08x%08x",
5404247122Snp			    (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4,
5405247122Snp			    p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5],
5406247122Snp			    p[6], p[7]);
5407247122Snp		}
5408247122Snp	}
5409247122Snp
5410247122Snp	rc = sbuf_finish(sb);
5411247122Snp	sbuf_delete(sb);
5412247122Snpdone:
5413247122Snp	free(buf, M_CXGBE);
5414247122Snp	return (rc);
5415247122Snp}
5416247122Snp
5417247122Snpstatic int
5418251213Snpsysctl_cim_ma_la(SYSCTL_HANDLER_ARGS)
5419251213Snp{
5420251213Snp	struct adapter *sc = arg1;
5421251213Snp	u_int i;
5422251213Snp	struct sbuf *sb;
5423251213Snp	uint32_t *buf, *p;
5424251213Snp	int rc;
5425251213Snp
5426251213Snp	rc = sysctl_wire_old_buffer(req, 0);
5427251213Snp	if (rc != 0)
5428251213Snp		return (rc);
5429251213Snp
5430251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
5431251213Snp	if (sb == NULL)
5432251213Snp		return (ENOMEM);
5433251213Snp
5434251213Snp	buf = malloc(2 * CIM_MALA_SIZE * 5 * sizeof(uint32_t), M_CXGBE,
5435251213Snp	    M_ZERO | M_WAITOK);
5436251213Snp
5437251213Snp	t4_cim_read_ma_la(sc, buf, buf + 5 * CIM_MALA_SIZE);
5438251213Snp	p = buf;
5439251213Snp
5440251213Snp	for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) {
5441251213Snp		sbuf_printf(sb, "\n%02x%08x%08x%08x%08x", p[4], p[3], p[2],
5442251213Snp		    p[1], p[0]);
5443251213Snp	}
5444251213Snp
5445251213Snp	sbuf_printf(sb, "\n\nCnt ID Tag UE       Data       RDY VLD");
5446251213Snp	for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) {
5447251213Snp		sbuf_printf(sb, "\n%3u %2u  %x   %u %08x%08x  %u   %u",
5448251213Snp		    (p[2] >> 10) & 0xff, (p[2] >> 7) & 7,
5449251213Snp		    (p[2] >> 3) & 0xf, (p[2] >> 2) & 1,
5450251213Snp		    (p[1] >> 2) | ((p[2] & 3) << 30),
5451251213Snp		    (p[0] >> 2) | ((p[1] & 3) << 30), (p[0] >> 1) & 1,
5452251213Snp		    p[0] & 1);
5453251213Snp	}
5454251213Snp
5455251213Snp	rc = sbuf_finish(sb);
5456251213Snp	sbuf_delete(sb);
5457251213Snp	free(buf, M_CXGBE);
5458251213Snp	return (rc);
5459251213Snp}
5460251213Snp
5461251213Snpstatic int
5462251213Snpsysctl_cim_pif_la(SYSCTL_HANDLER_ARGS)
5463251213Snp{
5464251213Snp	struct adapter *sc = arg1;
5465251213Snp	u_int i;
5466251213Snp	struct sbuf *sb;
5467251213Snp	uint32_t *buf, *p;
5468251213Snp	int rc;
5469251213Snp
5470251213Snp	rc = sysctl_wire_old_buffer(req, 0);
5471251213Snp	if (rc != 0)
5472251213Snp		return (rc);
5473251213Snp
5474251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
5475251213Snp	if (sb == NULL)
5476251213Snp		return (ENOMEM);
5477251213Snp
5478251213Snp	buf = malloc(2 * CIM_PIFLA_SIZE * 6 * sizeof(uint32_t), M_CXGBE,
5479251213Snp	    M_ZERO | M_WAITOK);
5480251213Snp
5481251213Snp	t4_cim_read_pif_la(sc, buf, buf + 6 * CIM_PIFLA_SIZE, NULL, NULL);
5482251213Snp	p = buf;
5483251213Snp
5484251213Snp	sbuf_printf(sb, "Cntl ID DataBE   Addr                 Data");
5485251213Snp	for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) {
5486251213Snp		sbuf_printf(sb, "\n %02x  %02x  %04x  %08x %08x%08x%08x%08x",
5487251213Snp		    (p[5] >> 22) & 0xff, (p[5] >> 16) & 0x3f, p[5] & 0xffff,
5488251213Snp		    p[4], p[3], p[2], p[1], p[0]);
5489251213Snp	}
5490251213Snp
5491251213Snp	sbuf_printf(sb, "\n\nCntl ID               Data");
5492251213Snp	for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) {
5493251213Snp		sbuf_printf(sb, "\n %02x  %02x %08x%08x%08x%08x",
5494251213Snp		    (p[4] >> 6) & 0xff, p[4] & 0x3f, p[3], p[2], p[1], p[0]);
5495251213Snp	}
5496251213Snp
5497251213Snp	rc = sbuf_finish(sb);
5498251213Snp	sbuf_delete(sb);
5499251213Snp	free(buf, M_CXGBE);
5500251213Snp	return (rc);
5501251213Snp}
5502251213Snp
5503251213Snpstatic int
5504247122Snpsysctl_cim_qcfg(SYSCTL_HANDLER_ARGS)
5505247122Snp{
5506247122Snp	struct adapter *sc = arg1;
5507247122Snp	struct sbuf *sb;
5508247122Snp	int rc, i;
5509248925Snp	uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5];
5510248925Snp	uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5];
5511247122Snp	uint16_t thres[CIM_NUM_IBQ];
5512248925Snp	uint32_t obq_wr[2 * CIM_NUM_OBQ_T5], *wr = obq_wr;
5513248925Snp	uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)], *p = stat;
5514248925Snp	u_int cim_num_obq, ibq_rdaddr, obq_rdaddr, nq;
5515247122Snp
5516248925Snp	if (is_t4(sc)) {
5517248925Snp		cim_num_obq = CIM_NUM_OBQ;
5518248925Snp		ibq_rdaddr = A_UP_IBQ_0_RDADDR;
5519248925Snp		obq_rdaddr = A_UP_OBQ_0_REALADDR;
5520248925Snp	} else {
5521248925Snp		cim_num_obq = CIM_NUM_OBQ_T5;
5522248925Snp		ibq_rdaddr = A_UP_IBQ_0_SHADOW_RDADDR;
5523248925Snp		obq_rdaddr = A_UP_OBQ_0_SHADOW_REALADDR;
5524248925Snp	}
5525248925Snp	nq = CIM_NUM_IBQ + cim_num_obq;
5526248925Snp
5527248925Snp	rc = -t4_cim_read(sc, ibq_rdaddr, 4 * nq, stat);
5528247122Snp	if (rc == 0)
5529248925Snp		rc = -t4_cim_read(sc, obq_rdaddr, 2 * cim_num_obq, obq_wr);
5530247122Snp	if (rc != 0)
5531247122Snp		return (rc);
5532247122Snp
5533247122Snp	t4_read_cimq_cfg(sc, base, size, thres);
5534247122Snp
5535247122Snp	rc = sysctl_wire_old_buffer(req, 0);
5536247122Snp	if (rc != 0)
5537247122Snp		return (rc);
5538247122Snp
5539248925Snp	sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req);
5540247122Snp	if (sb == NULL)
5541247122Snp		return (ENOMEM);
5542247122Snp
5543247122Snp	sbuf_printf(sb, "Queue  Base  Size Thres RdPtr WrPtr  SOP  EOP Avail");
5544247122Snp
5545247122Snp	for (i = 0; i < CIM_NUM_IBQ; i++, p += 4)
5546248925Snp		sbuf_printf(sb, "\n%7s %5x %5u %5u %6x  %4x %4u %4u %5u",
5547247122Snp		    qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]),
5548247122Snp		    G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]),
5549247122Snp		    G_QUEREMFLITS(p[2]) * 16);
5550248925Snp	for ( ; i < nq; i++, p += 4, wr += 2)
5551248925Snp		sbuf_printf(sb, "\n%7s %5x %5u %12x  %4x %4u %4u %5u", qname[i],
5552247122Snp		    base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff,
5553247122Snp		    wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]),
5554247122Snp		    G_QUEREMFLITS(p[2]) * 16);
5555247122Snp
5556247122Snp	rc = sbuf_finish(sb);
5557247122Snp	sbuf_delete(sb);
5558247122Snp
5559247122Snp	return (rc);
5560247122Snp}
5561247122Snp
5562247122Snpstatic int
5563228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS)
5564228561Snp{
5565228561Snp	struct adapter *sc = arg1;
5566228561Snp	struct sbuf *sb;
5567228561Snp	int rc;
5568228561Snp	struct tp_cpl_stats stats;
5569228561Snp
5570228561Snp	rc = sysctl_wire_old_buffer(req, 0);
5571228561Snp	if (rc != 0)
5572228561Snp		return (rc);
5573228561Snp
5574228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
5575228561Snp	if (sb == NULL)
5576228561Snp		return (ENOMEM);
5577228561Snp
5578228561Snp	t4_tp_get_cpl_stats(sc, &stats);
5579228561Snp
5580228561Snp	sbuf_printf(sb, "                 channel 0  channel 1  channel 2  "
5581228561Snp	    "channel 3\n");
5582228561Snp	sbuf_printf(sb, "CPL requests:   %10u %10u %10u %10u\n",
5583228561Snp		   stats.req[0], stats.req[1], stats.req[2], stats.req[3]);
5584228561Snp	sbuf_printf(sb, "CPL responses:  %10u %10u %10u %10u",
5585228561Snp		   stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]);
5586228561Snp
5587228561Snp	rc = sbuf_finish(sb);
5588228561Snp	sbuf_delete(sb);
5589228561Snp
5590228561Snp	return (rc);
5591228561Snp}
5592228561Snp
5593228561Snpstatic int
5594228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS)
5595228561Snp{
5596228561Snp	struct adapter *sc = arg1;
5597228561Snp	struct sbuf *sb;
5598228561Snp	int rc;
5599228561Snp	struct tp_usm_stats stats;
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, 256, req);
5606228561Snp	if (sb == NULL)
5607228561Snp		return (ENOMEM);
5608228561Snp
5609228561Snp	t4_get_usm_stats(sc, &stats);
5610228561Snp
5611228561Snp	sbuf_printf(sb, "Frames: %u\n", stats.frames);
5612228561Snp	sbuf_printf(sb, "Octets: %ju\n", stats.octets);
5613228561Snp	sbuf_printf(sb, "Drops:  %u", stats.drops);
5614228561Snp
5615228561Snp	rc = sbuf_finish(sb);
5616228561Snp	sbuf_delete(sb);
5617228561Snp
5618228561Snp	return (rc);
5619228561Snp}
5620228561Snp
5621222551Snpconst char *devlog_level_strings[] = {
5622222551Snp	[FW_DEVLOG_LEVEL_EMERG]		= "EMERG",
5623222551Snp	[FW_DEVLOG_LEVEL_CRIT]		= "CRIT",
5624222551Snp	[FW_DEVLOG_LEVEL_ERR]		= "ERR",
5625222551Snp	[FW_DEVLOG_LEVEL_NOTICE]	= "NOTICE",
5626222551Snp	[FW_DEVLOG_LEVEL_INFO]		= "INFO",
5627222551Snp	[FW_DEVLOG_LEVEL_DEBUG]		= "DEBUG"
5628222551Snp};
5629222551Snp
5630222551Snpconst char *devlog_facility_strings[] = {
5631222551Snp	[FW_DEVLOG_FACILITY_CORE]	= "CORE",
5632268823Snp	[FW_DEVLOG_FACILITY_CF]		= "CF",
5633222551Snp	[FW_DEVLOG_FACILITY_SCHED]	= "SCHED",
5634222551Snp	[FW_DEVLOG_FACILITY_TIMER]	= "TIMER",
5635222551Snp	[FW_DEVLOG_FACILITY_RES]	= "RES",
5636222551Snp	[FW_DEVLOG_FACILITY_HW]		= "HW",
5637222551Snp	[FW_DEVLOG_FACILITY_FLR]	= "FLR",
5638222551Snp	[FW_DEVLOG_FACILITY_DMAQ]	= "DMAQ",
5639222551Snp	[FW_DEVLOG_FACILITY_PHY]	= "PHY",
5640222551Snp	[FW_DEVLOG_FACILITY_MAC]	= "MAC",
5641222551Snp	[FW_DEVLOG_FACILITY_PORT]	= "PORT",
5642222551Snp	[FW_DEVLOG_FACILITY_VI]		= "VI",
5643222551Snp	[FW_DEVLOG_FACILITY_FILTER]	= "FILTER",
5644222551Snp	[FW_DEVLOG_FACILITY_ACL]	= "ACL",
5645222551Snp	[FW_DEVLOG_FACILITY_TM]		= "TM",
5646222551Snp	[FW_DEVLOG_FACILITY_QFC]	= "QFC",
5647222551Snp	[FW_DEVLOG_FACILITY_DCB]	= "DCB",
5648222551Snp	[FW_DEVLOG_FACILITY_ETH]	= "ETH",
5649222551Snp	[FW_DEVLOG_FACILITY_OFLD]	= "OFLD",
5650222551Snp	[FW_DEVLOG_FACILITY_RI]		= "RI",
5651222551Snp	[FW_DEVLOG_FACILITY_ISCSI]	= "ISCSI",
5652222551Snp	[FW_DEVLOG_FACILITY_FCOE]	= "FCOE",
5653222551Snp	[FW_DEVLOG_FACILITY_FOISCSI]	= "FOISCSI",
5654222551Snp	[FW_DEVLOG_FACILITY_FOFCOE]	= "FOFCOE"
5655222551Snp};
5656222551Snp
5657222551Snpstatic int
5658222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS)
5659222551Snp{
5660222551Snp	struct adapter *sc = arg1;
5661222551Snp	struct devlog_params *dparams = &sc->params.devlog;
5662222551Snp	struct fw_devlog_e *buf, *e;
5663256791Snp	int i, j, rc, nentries, first = 0, m;
5664222551Snp	struct sbuf *sb;
5665222551Snp	uint64_t ftstamp = UINT64_MAX;
5666222551Snp
5667248925Snp	if (dparams->start == 0) {
5668256791Snp		dparams->memtype = FW_MEMTYPE_EDC0;
5669248925Snp		dparams->start = 0x84000;
5670248925Snp		dparams->size = 32768;
5671248925Snp	}
5672222551Snp
5673222551Snp	nentries = dparams->size / sizeof(struct fw_devlog_e);
5674222551Snp
5675222551Snp	buf = malloc(dparams->size, M_CXGBE, M_NOWAIT);
5676222551Snp	if (buf == NULL)
5677222551Snp		return (ENOMEM);
5678222551Snp
5679256791Snp	m = fwmtype_to_hwmtype(dparams->memtype);
5680256791Snp	rc = -t4_mem_read(sc, m, dparams->start, dparams->size, (void *)buf);
5681222551Snp	if (rc != 0)
5682222551Snp		goto done;
5683222551Snp
5684222551Snp	for (i = 0; i < nentries; i++) {
5685222551Snp		e = &buf[i];
5686222551Snp
5687222551Snp		if (e->timestamp == 0)
5688222551Snp			break;	/* end */
5689222551Snp
5690222551Snp		e->timestamp = be64toh(e->timestamp);
5691222551Snp		e->seqno = be32toh(e->seqno);
5692222551Snp		for (j = 0; j < 8; j++)
5693222551Snp			e->params[j] = be32toh(e->params[j]);
5694222551Snp
5695222551Snp		if (e->timestamp < ftstamp) {
5696222551Snp			ftstamp = e->timestamp;
5697222551Snp			first = i;
5698222551Snp		}
5699222551Snp	}
5700222551Snp
5701222551Snp	if (buf[first].timestamp == 0)
5702222551Snp		goto done;	/* nothing in the log */
5703222551Snp
5704222551Snp	rc = sysctl_wire_old_buffer(req, 0);
5705222551Snp	if (rc != 0)
5706222551Snp		goto done;
5707222551Snp
5708222551Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
5709228561Snp	if (sb == NULL) {
5710228561Snp		rc = ENOMEM;
5711228561Snp		goto done;
5712228561Snp	}
5713228561Snp	sbuf_printf(sb, "%10s  %15s  %8s  %8s  %s\n",
5714222551Snp	    "Seq#", "Tstamp", "Level", "Facility", "Message");
5715222551Snp
5716222551Snp	i = first;
5717222551Snp	do {
5718222551Snp		e = &buf[i];
5719222551Snp		if (e->timestamp == 0)
5720222551Snp			break;	/* end */
5721222551Snp
5722222551Snp		sbuf_printf(sb, "%10d  %15ju  %8s  %8s  ",
5723222551Snp		    e->seqno, e->timestamp,
5724240452Snp		    (e->level < nitems(devlog_level_strings) ?
5725222551Snp			devlog_level_strings[e->level] : "UNKNOWN"),
5726240452Snp		    (e->facility < nitems(devlog_facility_strings) ?
5727222551Snp			devlog_facility_strings[e->facility] : "UNKNOWN"));
5728222551Snp		sbuf_printf(sb, e->fmt, e->params[0], e->params[1],
5729222551Snp		    e->params[2], e->params[3], e->params[4],
5730222551Snp		    e->params[5], e->params[6], e->params[7]);
5731222551Snp
5732222551Snp		if (++i == nentries)
5733222551Snp			i = 0;
5734222551Snp	} while (i != first);
5735222551Snp
5736222551Snp	rc = sbuf_finish(sb);
5737222551Snp	sbuf_delete(sb);
5738222551Snpdone:
5739222551Snp	free(buf, M_CXGBE);
5740222551Snp	return (rc);
5741222551Snp}
5742222551Snp
5743228561Snpstatic int
5744228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS)
5745228561Snp{
5746228561Snp	struct adapter *sc = arg1;
5747228561Snp	struct sbuf *sb;
5748228561Snp	int rc;
5749228561Snp	struct tp_fcoe_stats stats[4];
5750228561Snp
5751228561Snp	rc = sysctl_wire_old_buffer(req, 0);
5752228561Snp	if (rc != 0)
5753228561Snp		return (rc);
5754228561Snp
5755228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
5756228561Snp	if (sb == NULL)
5757228561Snp		return (ENOMEM);
5758228561Snp
5759228561Snp	t4_get_fcoe_stats(sc, 0, &stats[0]);
5760228561Snp	t4_get_fcoe_stats(sc, 1, &stats[1]);
5761228561Snp	t4_get_fcoe_stats(sc, 2, &stats[2]);
5762228561Snp	t4_get_fcoe_stats(sc, 3, &stats[3]);
5763228561Snp
5764228561Snp	sbuf_printf(sb, "                   channel 0        channel 1        "
5765228561Snp	    "channel 2        channel 3\n");
5766228561Snp	sbuf_printf(sb, "octetsDDP:  %16ju %16ju %16ju %16ju\n",
5767228561Snp	    stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP,
5768228561Snp	    stats[3].octetsDDP);
5769228561Snp	sbuf_printf(sb, "framesDDP:  %16u %16u %16u %16u\n", stats[0].framesDDP,
5770228561Snp	    stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP);
5771228561Snp	sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u",
5772228561Snp	    stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop,
5773228561Snp	    stats[3].framesDrop);
5774228561Snp
5775228561Snp	rc = sbuf_finish(sb);
5776228561Snp	sbuf_delete(sb);
5777228561Snp
5778228561Snp	return (rc);
5779228561Snp}
5780228561Snp
5781228561Snpstatic int
5782228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS)
5783228561Snp{
5784228561Snp	struct adapter *sc = arg1;
5785228561Snp	struct sbuf *sb;
5786228561Snp	int rc, i;
5787228561Snp	unsigned int map, kbps, ipg, mode;
5788228561Snp	unsigned int pace_tab[NTX_SCHED];
5789228561Snp
5790228561Snp	rc = sysctl_wire_old_buffer(req, 0);
5791228561Snp	if (rc != 0)
5792228561Snp		return (rc);
5793228561Snp
5794228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
5795228561Snp	if (sb == NULL)
5796228561Snp		return (ENOMEM);
5797228561Snp
5798228561Snp	map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP);
5799228561Snp	mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG));
5800228561Snp	t4_read_pace_tbl(sc, pace_tab);
5801228561Snp
5802228561Snp	sbuf_printf(sb, "Scheduler  Mode   Channel  Rate (Kbps)   "
5803228561Snp	    "Class IPG (0.1 ns)   Flow IPG (us)");
5804228561Snp
5805228561Snp	for (i = 0; i < NTX_SCHED; ++i, map >>= 2) {
5806228561Snp		t4_get_tx_sched(sc, i, &kbps, &ipg);
5807228561Snp		sbuf_printf(sb, "\n    %u      %-5s     %u     ", i,
5808228561Snp		    (mode & (1 << i)) ? "flow" : "class", map & 3);
5809228561Snp		if (kbps)
5810228561Snp			sbuf_printf(sb, "%9u     ", kbps);
5811228561Snp		else
5812228561Snp			sbuf_printf(sb, " disabled     ");
5813228561Snp
5814228561Snp		if (ipg)
5815228561Snp			sbuf_printf(sb, "%13u        ", ipg);
5816228561Snp		else
5817228561Snp			sbuf_printf(sb, "     disabled        ");
5818228561Snp
5819228561Snp		if (pace_tab[i])
5820228561Snp			sbuf_printf(sb, "%10u", pace_tab[i]);
5821228561Snp		else
5822228561Snp			sbuf_printf(sb, "  disabled");
5823228561Snp	}
5824228561Snp
5825228561Snp	rc = sbuf_finish(sb);
5826228561Snp	sbuf_delete(sb);
5827228561Snp
5828228561Snp	return (rc);
5829228561Snp}
5830228561Snp
5831228561Snpstatic int
5832228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS)
5833228561Snp{
5834228561Snp	struct adapter *sc = arg1;
5835228561Snp	struct sbuf *sb;
5836228561Snp	int rc, i, j;
5837228561Snp	uint64_t *p0, *p1;
5838228561Snp	struct lb_port_stats s[2];
5839228561Snp	static const char *stat_name[] = {
5840228561Snp		"OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:",
5841228561Snp		"UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:",
5842228561Snp		"Frames128To255:", "Frames256To511:", "Frames512To1023:",
5843228561Snp		"Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:",
5844228561Snp		"BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:",
5845228561Snp		"BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:",
5846228561Snp		"BG2FramesTrunc:", "BG3FramesTrunc:"
5847228561Snp	};
5848228561Snp
5849228561Snp	rc = sysctl_wire_old_buffer(req, 0);
5850228561Snp	if (rc != 0)
5851228561Snp		return (rc);
5852228561Snp
5853228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
5854228561Snp	if (sb == NULL)
5855228561Snp		return (ENOMEM);
5856228561Snp
5857228561Snp	memset(s, 0, sizeof(s));
5858228561Snp
5859228561Snp	for (i = 0; i < 4; i += 2) {
5860228561Snp		t4_get_lb_stats(sc, i, &s[0]);
5861228561Snp		t4_get_lb_stats(sc, i + 1, &s[1]);
5862228561Snp
5863228561Snp		p0 = &s[0].octets;
5864228561Snp		p1 = &s[1].octets;
5865228561Snp		sbuf_printf(sb, "%s                       Loopback %u"
5866228561Snp		    "           Loopback %u", i == 0 ? "" : "\n", i, i + 1);
5867228561Snp
5868240452Snp		for (j = 0; j < nitems(stat_name); j++)
5869228561Snp			sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j],
5870228561Snp				   *p0++, *p1++);
5871228561Snp	}
5872228561Snp
5873228561Snp	rc = sbuf_finish(sb);
5874228561Snp	sbuf_delete(sb);
5875228561Snp
5876228561Snp	return (rc);
5877228561Snp}
5878228561Snp
5879253701Snpstatic int
5880253701Snpsysctl_linkdnrc(SYSCTL_HANDLER_ARGS)
5881253701Snp{
5882253701Snp	int rc = 0;
5883253701Snp	struct port_info *pi = arg1;
5884253701Snp	struct sbuf *sb;
5885253701Snp	static const char *linkdnreasons[] = {
5886253701Snp		"non-specific", "remote fault", "autoneg failed", "reserved3",
5887253701Snp		"PHY overheated", "unknown", "rx los", "reserved7"
5888253701Snp	};
5889253701Snp
5890253701Snp	rc = sysctl_wire_old_buffer(req, 0);
5891253701Snp	if (rc != 0)
5892253701Snp		return(rc);
5893253701Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 64, req);
5894253701Snp	if (sb == NULL)
5895253701Snp		return (ENOMEM);
5896253701Snp
5897253701Snp	if (pi->linkdnrc < 0)
5898253701Snp		sbuf_printf(sb, "n/a");
5899253701Snp	else if (pi->linkdnrc < nitems(linkdnreasons))
5900253701Snp		sbuf_printf(sb, "%s", linkdnreasons[pi->linkdnrc]);
5901253701Snp	else
5902253701Snp		sbuf_printf(sb, "%d", pi->linkdnrc);
5903253701Snp
5904253701Snp	rc = sbuf_finish(sb);
5905253701Snp	sbuf_delete(sb);
5906253701Snp
5907253701Snp	return (rc);
5908253701Snp}
5909253701Snp
5910228561Snpstruct mem_desc {
5911228561Snp	unsigned int base;
5912228561Snp	unsigned int limit;
5913228561Snp	unsigned int idx;
5914228561Snp};
5915228561Snp
5916228561Snpstatic int
5917228561Snpmem_desc_cmp(const void *a, const void *b)
5918228561Snp{
5919228561Snp	return ((const struct mem_desc *)a)->base -
5920228561Snp	       ((const struct mem_desc *)b)->base;
5921228561Snp}
5922228561Snp
5923228561Snpstatic void
5924228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from,
5925228561Snp    unsigned int to)
5926228561Snp{
5927228561Snp	unsigned int size;
5928228561Snp
5929228561Snp	size = to - from + 1;
5930228561Snp	if (size == 0)
5931228561Snp		return;
5932228561Snp
5933228561Snp	/* XXX: need humanize_number(3) in libkern for a more readable 'size' */
5934228561Snp	sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size);
5935228561Snp}
5936228561Snp
5937228561Snpstatic int
5938228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS)
5939228561Snp{
5940228561Snp	struct adapter *sc = arg1;
5941228561Snp	struct sbuf *sb;
5942228561Snp	int rc, i, n;
5943248925Snp	uint32_t lo, hi, used, alloc;
5944248925Snp	static const char *memory[] = {"EDC0:", "EDC1:", "MC:", "MC0:", "MC1:"};
5945228561Snp	static const char *region[] = {
5946228561Snp		"DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:",
5947228561Snp		"Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:",
5948228561Snp		"Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:",
5949228561Snp		"TDDP region:", "TPT region:", "STAG region:", "RQ region:",
5950248925Snp		"RQUDP region:", "PBL region:", "TXPBL region:",
5951248925Snp		"DBVFIFO region:", "ULPRX state:", "ULPTX state:",
5952248925Snp		"On-chip queues:"
5953228561Snp	};
5954248925Snp	struct mem_desc avail[4];
5955240452Snp	struct mem_desc mem[nitems(region) + 3];	/* up to 3 holes */
5956228561Snp	struct mem_desc *md = mem;
5957228561Snp
5958228561Snp	rc = sysctl_wire_old_buffer(req, 0);
5959228561Snp	if (rc != 0)
5960228561Snp		return (rc);
5961228561Snp
5962228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
5963228561Snp	if (sb == NULL)
5964228561Snp		return (ENOMEM);
5965228561Snp
5966240452Snp	for (i = 0; i < nitems(mem); i++) {
5967228561Snp		mem[i].limit = 0;
5968228561Snp		mem[i].idx = i;
5969228561Snp	}
5970228561Snp
5971228561Snp	/* Find and sort the populated memory ranges */
5972228561Snp	i = 0;
5973228561Snp	lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
5974228561Snp	if (lo & F_EDRAM0_ENABLE) {
5975228561Snp		hi = t4_read_reg(sc, A_MA_EDRAM0_BAR);
5976228561Snp		avail[i].base = G_EDRAM0_BASE(hi) << 20;
5977228561Snp		avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20);
5978228561Snp		avail[i].idx = 0;
5979228561Snp		i++;
5980228561Snp	}
5981228561Snp	if (lo & F_EDRAM1_ENABLE) {
5982228561Snp		hi = t4_read_reg(sc, A_MA_EDRAM1_BAR);
5983228561Snp		avail[i].base = G_EDRAM1_BASE(hi) << 20;
5984228561Snp		avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20);
5985228561Snp		avail[i].idx = 1;
5986228561Snp		i++;
5987228561Snp	}
5988228561Snp	if (lo & F_EXT_MEM_ENABLE) {
5989228561Snp		hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
5990228561Snp		avail[i].base = G_EXT_MEM_BASE(hi) << 20;
5991248925Snp		avail[i].limit = avail[i].base +
5992248925Snp		    (G_EXT_MEM_SIZE(hi) << 20);
5993248925Snp		avail[i].idx = is_t4(sc) ? 2 : 3;	/* Call it MC for T4 */
5994228561Snp		i++;
5995228561Snp	}
5996248925Snp	if (!is_t4(sc) && lo & F_EXT_MEM1_ENABLE) {
5997248925Snp		hi = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR);
5998248925Snp		avail[i].base = G_EXT_MEM1_BASE(hi) << 20;
5999248925Snp		avail[i].limit = avail[i].base +
6000248925Snp		    (G_EXT_MEM1_SIZE(hi) << 20);
6001248925Snp		avail[i].idx = 4;
6002248925Snp		i++;
6003248925Snp	}
6004228561Snp	if (!i)                                    /* no memory available */
6005228561Snp		return 0;
6006228561Snp	qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp);
6007228561Snp
6008228561Snp	(md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR);
6009228561Snp	(md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR);
6010228561Snp	(md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR);
6011228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE);
6012228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE);
6013228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE);
6014228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE);
6015228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE);
6016228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE);
6017228561Snp
6018228561Snp	/* the next few have explicit upper bounds */
6019228561Snp	md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE);
6020228561Snp	md->limit = md->base - 1 +
6021228561Snp		    t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) *
6022228561Snp		    G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE));
6023228561Snp	md++;
6024228561Snp
6025228561Snp	md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE);
6026228561Snp	md->limit = md->base - 1 +
6027228561Snp		    t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) *
6028228561Snp		    G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE));
6029228561Snp	md++;
6030228561Snp
6031228561Snp	if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) {
6032228561Snp		hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4;
6033228561Snp		md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE);
6034228561Snp		md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1;
6035228561Snp	} else {
6036228561Snp		md->base = 0;
6037240452Snp		md->idx = nitems(region);  /* hide it */
6038228561Snp	}
6039228561Snp	md++;
6040228561Snp
6041228561Snp#define ulp_region(reg) \
6042228561Snp	md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\
6043228561Snp	(md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT)
6044228561Snp
6045228561Snp	ulp_region(RX_ISCSI);
6046228561Snp	ulp_region(RX_TDDP);
6047228561Snp	ulp_region(TX_TPT);
6048228561Snp	ulp_region(RX_STAG);
6049228561Snp	ulp_region(RX_RQ);
6050228561Snp	ulp_region(RX_RQUDP);
6051228561Snp	ulp_region(RX_PBL);
6052228561Snp	ulp_region(TX_PBL);
6053228561Snp#undef ulp_region
6054228561Snp
6055248925Snp	md->base = 0;
6056248925Snp	md->idx = nitems(region);
6057248925Snp	if (!is_t4(sc) && t4_read_reg(sc, A_SGE_CONTROL2) & F_VFIFO_ENABLE) {
6058248925Snp		md->base = G_BASEADDR(t4_read_reg(sc, A_SGE_DBVFIFO_BADDR));
6059248925Snp		md->limit = md->base + (G_DBVFIFO_SIZE((t4_read_reg(sc,
6060248925Snp		    A_SGE_DBVFIFO_SIZE))) << 2) - 1;
6061248925Snp	}
6062248925Snp	md++;
6063248925Snp
6064228561Snp	md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE);
6065228561Snp	md->limit = md->base + sc->tids.ntids - 1;
6066228561Snp	md++;
6067228561Snp	md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE);
6068228561Snp	md->limit = md->base + sc->tids.ntids - 1;
6069228561Snp	md++;
6070228561Snp
6071228561Snp	md->base = sc->vres.ocq.start;
6072228561Snp	if (sc->vres.ocq.size)
6073228561Snp		md->limit = md->base + sc->vres.ocq.size - 1;
6074228561Snp	else
6075240452Snp		md->idx = nitems(region);  /* hide it */
6076228561Snp	md++;
6077228561Snp
6078228561Snp	/* add any address-space holes, there can be up to 3 */
6079228561Snp	for (n = 0; n < i - 1; n++)
6080228561Snp		if (avail[n].limit < avail[n + 1].base)
6081228561Snp			(md++)->base = avail[n].limit;
6082228561Snp	if (avail[n].limit)
6083228561Snp		(md++)->base = avail[n].limit;
6084228561Snp
6085228561Snp	n = md - mem;
6086228561Snp	qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp);
6087228561Snp
6088228561Snp	for (lo = 0; lo < i; lo++)
6089228561Snp		mem_region_show(sb, memory[avail[lo].idx], avail[lo].base,
6090228561Snp				avail[lo].limit - 1);
6091228561Snp
6092228561Snp	sbuf_printf(sb, "\n");
6093228561Snp	for (i = 0; i < n; i++) {
6094240452Snp		if (mem[i].idx >= nitems(region))
6095228561Snp			continue;                        /* skip holes */
6096228561Snp		if (!mem[i].limit)
6097228561Snp			mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0;
6098228561Snp		mem_region_show(sb, region[mem[i].idx], mem[i].base,
6099228561Snp				mem[i].limit);
6100228561Snp	}
6101228561Snp
6102228561Snp	sbuf_printf(sb, "\n");
6103228561Snp	lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR);
6104228561Snp	hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1;
6105228561Snp	mem_region_show(sb, "uP RAM:", lo, hi);
6106228561Snp
6107228561Snp	lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR);
6108228561Snp	hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1;
6109228561Snp	mem_region_show(sb, "uP Extmem2:", lo, hi);
6110228561Snp
6111228561Snp	lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE);
6112228561Snp	sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n",
6113228561Snp		   G_PMRXMAXPAGE(lo),
6114228561Snp		   t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10,
6115228561Snp		   (lo & F_PMRXNUMCHN) ? 2 : 1);
6116228561Snp
6117228561Snp	lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE);
6118228561Snp	hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE);
6119228561Snp	sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n",
6120228561Snp		   G_PMTXMAXPAGE(lo),
6121228561Snp		   hi >= (1 << 20) ? (hi >> 20) : (hi >> 10),
6122228561Snp		   hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo));
6123228561Snp	sbuf_printf(sb, "%u p-structs\n",
6124228561Snp		   t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT));
6125228561Snp
6126228561Snp	for (i = 0; i < 4; i++) {
6127228561Snp		lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4);
6128248925Snp		if (is_t4(sc)) {
6129248925Snp			used = G_USED(lo);
6130248925Snp			alloc = G_ALLOC(lo);
6131248925Snp		} else {
6132248925Snp			used = G_T5_USED(lo);
6133248925Snp			alloc = G_T5_ALLOC(lo);
6134248925Snp		}
6135228561Snp		sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated",
6136248925Snp			   i, used, alloc);
6137228561Snp	}
6138228561Snp	for (i = 0; i < 4; i++) {
6139228561Snp		lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4);
6140248925Snp		if (is_t4(sc)) {
6141248925Snp			used = G_USED(lo);
6142248925Snp			alloc = G_ALLOC(lo);
6143248925Snp		} else {
6144248925Snp			used = G_T5_USED(lo);
6145248925Snp			alloc = G_T5_ALLOC(lo);
6146248925Snp		}
6147228561Snp		sbuf_printf(sb,
6148228561Snp			   "\nLoopback %d using %u pages out of %u allocated",
6149248925Snp			   i, used, alloc);
6150228561Snp	}
6151228561Snp
6152228561Snp	rc = sbuf_finish(sb);
6153228561Snp	sbuf_delete(sb);
6154228561Snp
6155228561Snp	return (rc);
6156228561Snp}
6157228561Snp
6158251213Snpstatic inline void
6159251213Snptcamxy2valmask(uint64_t x, uint64_t y, uint8_t *addr, uint64_t *mask)
6160251213Snp{
6161251213Snp	*mask = x | y;
6162251213Snp	y = htobe64(y);
6163251213Snp	memcpy(addr, (char *)&y + 2, ETHER_ADDR_LEN);
6164251213Snp}
6165251213Snp
6166228561Snpstatic int
6167251213Snpsysctl_mps_tcam(SYSCTL_HANDLER_ARGS)
6168251213Snp{
6169251213Snp	struct adapter *sc = arg1;
6170251213Snp	struct sbuf *sb;
6171251213Snp	int rc, i, n;
6172251213Snp
6173251213Snp	rc = sysctl_wire_old_buffer(req, 0);
6174251213Snp	if (rc != 0)
6175251213Snp		return (rc);
6176251213Snp
6177251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6178251213Snp	if (sb == NULL)
6179251213Snp		return (ENOMEM);
6180251213Snp
6181251213Snp	sbuf_printf(sb,
6182251213Snp	    "Idx  Ethernet address     Mask     Vld Ports PF"
6183251213Snp	    "  VF              Replication             P0 P1 P2 P3  ML");
6184251213Snp	n = is_t4(sc) ? NUM_MPS_CLS_SRAM_L_INSTANCES :
6185251213Snp	    NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
6186251213Snp	for (i = 0; i < n; i++) {
6187251213Snp		uint64_t tcamx, tcamy, mask;
6188251213Snp		uint32_t cls_lo, cls_hi;
6189251213Snp		uint8_t addr[ETHER_ADDR_LEN];
6190251213Snp
6191251213Snp		tcamy = t4_read_reg64(sc, MPS_CLS_TCAM_Y_L(i));
6192251213Snp		tcamx = t4_read_reg64(sc, MPS_CLS_TCAM_X_L(i));
6193251213Snp		cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i));
6194251213Snp		cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i));
6195251213Snp
6196251213Snp		if (tcamx & tcamy)
6197251213Snp			continue;
6198251213Snp
6199251213Snp		tcamxy2valmask(tcamx, tcamy, addr, &mask);
6200251213Snp		sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x %012jx"
6201251213Snp			   "  %c   %#x%4u%4d", i, addr[0], addr[1], addr[2],
6202251213Snp			   addr[3], addr[4], addr[5], (uintmax_t)mask,
6203251213Snp			   (cls_lo & F_SRAM_VLD) ? 'Y' : 'N',
6204251213Snp			   G_PORTMAP(cls_hi), G_PF(cls_lo),
6205251213Snp			   (cls_lo & F_VF_VALID) ? G_VF(cls_lo) : -1);
6206251213Snp
6207251213Snp		if (cls_lo & F_REPLICATE) {
6208251213Snp			struct fw_ldst_cmd ldst_cmd;
6209251213Snp
6210251213Snp			memset(&ldst_cmd, 0, sizeof(ldst_cmd));
6211251213Snp			ldst_cmd.op_to_addrspace =
6212251213Snp			    htobe32(V_FW_CMD_OP(FW_LDST_CMD) |
6213251213Snp				F_FW_CMD_REQUEST | F_FW_CMD_READ |
6214251213Snp				V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS));
6215251213Snp			ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd));
6216251213Snp			ldst_cmd.u.mps.fid_ctl =
6217251213Snp			    htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) |
6218251213Snp				V_FW_LDST_CMD_CTL(i));
6219251213Snp
6220251213Snp			rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK,
6221251213Snp			    "t4mps");
6222251213Snp			if (rc)
6223251213Snp				break;
6224251213Snp			rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd,
6225251213Snp			    sizeof(ldst_cmd), &ldst_cmd);
6226251213Snp			end_synchronized_op(sc, 0);
6227251213Snp
6228251213Snp			if (rc != 0) {
6229251213Snp				sbuf_printf(sb,
6230251213Snp				    " ------------ error %3u ------------", rc);
6231251213Snp				rc = 0;
6232251213Snp			} else {
6233251213Snp				sbuf_printf(sb, " %08x %08x %08x %08x",
6234251213Snp				    be32toh(ldst_cmd.u.mps.rplc127_96),
6235251213Snp				    be32toh(ldst_cmd.u.mps.rplc95_64),
6236251213Snp				    be32toh(ldst_cmd.u.mps.rplc63_32),
6237251213Snp				    be32toh(ldst_cmd.u.mps.rplc31_0));
6238251213Snp			}
6239251213Snp		} else
6240251213Snp			sbuf_printf(sb, "%36s", "");
6241251213Snp
6242251213Snp		sbuf_printf(sb, "%4u%3u%3u%3u %#3x", G_SRAM_PRIO0(cls_lo),
6243251213Snp		    G_SRAM_PRIO1(cls_lo), G_SRAM_PRIO2(cls_lo),
6244251213Snp		    G_SRAM_PRIO3(cls_lo), (cls_lo >> S_MULTILISTEN0) & 0xf);
6245251213Snp	}
6246251213Snp
6247251213Snp	if (rc)
6248251213Snp		(void) sbuf_finish(sb);
6249251213Snp	else
6250251213Snp		rc = sbuf_finish(sb);
6251251213Snp	sbuf_delete(sb);
6252251213Snp
6253251213Snp	return (rc);
6254251213Snp}
6255251213Snp
6256251213Snpstatic int
6257228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS)
6258228561Snp{
6259228561Snp	struct adapter *sc = arg1;
6260228561Snp	struct sbuf *sb;
6261228561Snp	int rc;
6262228561Snp	uint16_t mtus[NMTUS];
6263228561Snp
6264228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6265228561Snp	if (rc != 0)
6266228561Snp		return (rc);
6267228561Snp
6268228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6269228561Snp	if (sb == NULL)
6270228561Snp		return (ENOMEM);
6271228561Snp
6272228561Snp	t4_read_mtu_tbl(sc, mtus, NULL);
6273228561Snp
6274228561Snp	sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
6275228561Snp	    mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6],
6276228561Snp	    mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13],
6277228561Snp	    mtus[14], mtus[15]);
6278228561Snp
6279228561Snp	rc = sbuf_finish(sb);
6280228561Snp	sbuf_delete(sb);
6281228561Snp
6282228561Snp	return (rc);
6283228561Snp}
6284228561Snp
6285228561Snpstatic int
6286228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS)
6287228561Snp{
6288228561Snp	struct adapter *sc = arg1;
6289228561Snp	struct sbuf *sb;
6290228561Snp	int rc, i;
6291259142Snp	uint32_t cnt[PM_NSTATS];
6292259142Snp	uint64_t cyc[PM_NSTATS];
6293259142Snp	static const char *rx_stats[] = {
6294259142Snp		"Read:", "Write bypass:", "Write mem:", "Flush:"
6295228561Snp	};
6296259142Snp	static const char *tx_stats[] = {
6297259142Snp		"Read:", "Write bypass:", "Write mem:", "Bypass + mem:"
6298259142Snp	};
6299228561Snp
6300228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6301228561Snp	if (rc != 0)
6302228561Snp		return (rc);
6303228561Snp
6304228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6305228561Snp	if (sb == NULL)
6306228561Snp		return (ENOMEM);
6307228561Snp
6308259142Snp	t4_pmtx_get_stats(sc, cnt, cyc);
6309259142Snp	sbuf_printf(sb, "                Tx pcmds             Tx bytes");
6310259142Snp	for (i = 0; i < ARRAY_SIZE(tx_stats); i++)
6311259142Snp		sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], cnt[i],
6312259142Snp		    cyc[i]);
6313228561Snp
6314259142Snp	t4_pmrx_get_stats(sc, cnt, cyc);
6315259142Snp	sbuf_printf(sb, "\n                Rx pcmds             Rx bytes");
6316259142Snp	for (i = 0; i < ARRAY_SIZE(rx_stats); i++)
6317259142Snp		sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], cnt[i],
6318259142Snp		    cyc[i]);
6319228561Snp
6320228561Snp	rc = sbuf_finish(sb);
6321228561Snp	sbuf_delete(sb);
6322228561Snp
6323228561Snp	return (rc);
6324228561Snp}
6325228561Snp
6326228561Snpstatic int
6327228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS)
6328228561Snp{
6329228561Snp	struct adapter *sc = arg1;
6330228561Snp	struct sbuf *sb;
6331228561Snp	int rc;
6332228561Snp	struct tp_rdma_stats stats;
6333228561Snp
6334228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6335228561Snp	if (rc != 0)
6336228561Snp		return (rc);
6337228561Snp
6338228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6339228561Snp	if (sb == NULL)
6340228561Snp		return (ENOMEM);
6341228561Snp
6342228561Snp	t4_tp_get_rdma_stats(sc, &stats);
6343228561Snp	sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod);
6344228561Snp	sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt);
6345228561Snp
6346228561Snp	rc = sbuf_finish(sb);
6347228561Snp	sbuf_delete(sb);
6348228561Snp
6349228561Snp	return (rc);
6350228561Snp}
6351228561Snp
6352228561Snpstatic int
6353228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS)
6354228561Snp{
6355228561Snp	struct adapter *sc = arg1;
6356228561Snp	struct sbuf *sb;
6357228561Snp	int rc;
6358228561Snp	struct tp_tcp_stats v4, v6;
6359228561Snp
6360228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6361228561Snp	if (rc != 0)
6362228561Snp		return (rc);
6363228561Snp
6364228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6365228561Snp	if (sb == NULL)
6366228561Snp		return (ENOMEM);
6367228561Snp
6368228561Snp	t4_tp_get_tcp_stats(sc, &v4, &v6);
6369228561Snp	sbuf_printf(sb,
6370228561Snp	    "                                IP                 IPv6\n");
6371228561Snp	sbuf_printf(sb, "OutRsts:      %20u %20u\n",
6372228561Snp	    v4.tcpOutRsts, v6.tcpOutRsts);
6373228561Snp	sbuf_printf(sb, "InSegs:       %20ju %20ju\n",
6374228561Snp	    v4.tcpInSegs, v6.tcpInSegs);
6375228561Snp	sbuf_printf(sb, "OutSegs:      %20ju %20ju\n",
6376228561Snp	    v4.tcpOutSegs, v6.tcpOutSegs);
6377228561Snp	sbuf_printf(sb, "RetransSegs:  %20ju %20ju",
6378228561Snp	    v4.tcpRetransSegs, v6.tcpRetransSegs);
6379228561Snp
6380228561Snp	rc = sbuf_finish(sb);
6381228561Snp	sbuf_delete(sb);
6382228561Snp
6383228561Snp	return (rc);
6384228561Snp}
6385228561Snp
6386228561Snpstatic int
6387228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS)
6388228561Snp{
6389228561Snp	struct adapter *sc = arg1;
6390228561Snp	struct sbuf *sb;
6391228561Snp	int rc;
6392228561Snp	struct tid_info *t = &sc->tids;
6393228561Snp
6394228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6395228561Snp	if (rc != 0)
6396228561Snp		return (rc);
6397228561Snp
6398228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6399228561Snp	if (sb == NULL)
6400228561Snp		return (ENOMEM);
6401228561Snp
6402228561Snp	if (t->natids) {
6403228561Snp		sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1,
6404228561Snp		    t->atids_in_use);
6405228561Snp	}
6406228561Snp
6407228561Snp	if (t->ntids) {
6408228561Snp		if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) {
6409228561Snp			uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4;
6410228561Snp
6411228561Snp			if (b) {
6412228561Snp				sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1,
6413228561Snp				    t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4,
6414228561Snp				    t->ntids - 1);
6415228561Snp			} else {
6416228561Snp				sbuf_printf(sb, "TID range: %u-%u",
6417228561Snp				    t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4,
6418228561Snp				    t->ntids - 1);
6419228561Snp			}
6420228561Snp		} else
6421228561Snp			sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1);
6422228561Snp		sbuf_printf(sb, ", in use: %u\n",
6423228561Snp		    atomic_load_acq_int(&t->tids_in_use));
6424228561Snp	}
6425228561Snp
6426228561Snp	if (t->nstids) {
6427228561Snp		sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base,
6428228561Snp		    t->stid_base + t->nstids - 1, t->stids_in_use);
6429228561Snp	}
6430228561Snp
6431228561Snp	if (t->nftids) {
6432228561Snp		sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base,
6433228561Snp		    t->ftid_base + t->nftids - 1);
6434228561Snp	}
6435228561Snp
6436265426Snp	if (t->netids) {
6437265426Snp		sbuf_printf(sb, "ETID range: %u-%u\n", t->etid_base,
6438265426Snp		    t->etid_base + t->netids - 1);
6439265426Snp	}
6440265426Snp
6441228561Snp	sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users",
6442228561Snp	    t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4),
6443228561Snp	    t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6));
6444228561Snp
6445228561Snp	rc = sbuf_finish(sb);
6446228561Snp	sbuf_delete(sb);
6447228561Snp
6448228561Snp	return (rc);
6449228561Snp}
6450228561Snp
6451228561Snpstatic int
6452228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS)
6453228561Snp{
6454228561Snp	struct adapter *sc = arg1;
6455228561Snp	struct sbuf *sb;
6456228561Snp	int rc;
6457228561Snp	struct tp_err_stats stats;
6458228561Snp
6459228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6460228561Snp	if (rc != 0)
6461228561Snp		return (rc);
6462228561Snp
6463228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6464228561Snp	if (sb == NULL)
6465228561Snp		return (ENOMEM);
6466228561Snp
6467228561Snp	t4_tp_get_err_stats(sc, &stats);
6468228561Snp
6469228561Snp	sbuf_printf(sb, "                 channel 0  channel 1  channel 2  "
6470228561Snp		      "channel 3\n");
6471228561Snp	sbuf_printf(sb, "macInErrs:      %10u %10u %10u %10u\n",
6472228561Snp	    stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2],
6473228561Snp	    stats.macInErrs[3]);
6474228561Snp	sbuf_printf(sb, "hdrInErrs:      %10u %10u %10u %10u\n",
6475228561Snp	    stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2],
6476228561Snp	    stats.hdrInErrs[3]);
6477228561Snp	sbuf_printf(sb, "tcpInErrs:      %10u %10u %10u %10u\n",
6478228561Snp	    stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2],
6479228561Snp	    stats.tcpInErrs[3]);
6480228561Snp	sbuf_printf(sb, "tcp6InErrs:     %10u %10u %10u %10u\n",
6481228561Snp	    stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2],
6482228561Snp	    stats.tcp6InErrs[3]);
6483228561Snp	sbuf_printf(sb, "tnlCongDrops:   %10u %10u %10u %10u\n",
6484228561Snp	    stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2],
6485228561Snp	    stats.tnlCongDrops[3]);
6486228561Snp	sbuf_printf(sb, "tnlTxDrops:     %10u %10u %10u %10u\n",
6487228561Snp	    stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2],
6488228561Snp	    stats.tnlTxDrops[3]);
6489228561Snp	sbuf_printf(sb, "ofldVlanDrops:  %10u %10u %10u %10u\n",
6490228561Snp	    stats.ofldVlanDrops[0], stats.ofldVlanDrops[1],
6491228561Snp	    stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]);
6492228561Snp	sbuf_printf(sb, "ofldChanDrops:  %10u %10u %10u %10u\n\n",
6493228561Snp	    stats.ofldChanDrops[0], stats.ofldChanDrops[1],
6494228561Snp	    stats.ofldChanDrops[2], stats.ofldChanDrops[3]);
6495228561Snp	sbuf_printf(sb, "ofldNoNeigh:    %u\nofldCongDefer:  %u",
6496228561Snp	    stats.ofldNoNeigh, stats.ofldCongDefer);
6497228561Snp
6498228561Snp	rc = sbuf_finish(sb);
6499228561Snp	sbuf_delete(sb);
6500228561Snp
6501228561Snp	return (rc);
6502228561Snp}
6503228561Snp
6504251213Snpstruct field_desc {
6505251213Snp	const char *name;
6506251213Snp	u_int start;
6507251213Snp	u_int width;
6508251213Snp};
6509251213Snp
6510251213Snpstatic void
6511251213Snpfield_desc_show(struct sbuf *sb, uint64_t v, const struct field_desc *f)
6512251213Snp{
6513251213Snp	char buf[32];
6514251213Snp	int line_size = 0;
6515251213Snp
6516251213Snp	while (f->name) {
6517251213Snp		uint64_t mask = (1ULL << f->width) - 1;
6518251213Snp		int len = snprintf(buf, sizeof(buf), "%s: %ju", f->name,
6519251213Snp		    ((uintmax_t)v >> f->start) & mask);
6520251213Snp
6521251213Snp		if (line_size + len >= 79) {
6522251213Snp			line_size = 8;
6523251213Snp			sbuf_printf(sb, "\n        ");
6524251213Snp		}
6525251213Snp		sbuf_printf(sb, "%s ", buf);
6526251213Snp		line_size += len + 1;
6527251213Snp		f++;
6528251213Snp	}
6529251213Snp	sbuf_printf(sb, "\n");
6530251213Snp}
6531251213Snp
6532251213Snpstatic struct field_desc tp_la0[] = {
6533251213Snp	{ "RcfOpCodeOut", 60, 4 },
6534251213Snp	{ "State", 56, 4 },
6535251213Snp	{ "WcfState", 52, 4 },
6536251213Snp	{ "RcfOpcSrcOut", 50, 2 },
6537251213Snp	{ "CRxError", 49, 1 },
6538251213Snp	{ "ERxError", 48, 1 },
6539251213Snp	{ "SanityFailed", 47, 1 },
6540251213Snp	{ "SpuriousMsg", 46, 1 },
6541251213Snp	{ "FlushInputMsg", 45, 1 },
6542251213Snp	{ "FlushInputCpl", 44, 1 },
6543251213Snp	{ "RssUpBit", 43, 1 },
6544251213Snp	{ "RssFilterHit", 42, 1 },
6545251213Snp	{ "Tid", 32, 10 },
6546251213Snp	{ "InitTcb", 31, 1 },
6547251213Snp	{ "LineNumber", 24, 7 },
6548251213Snp	{ "Emsg", 23, 1 },
6549251213Snp	{ "EdataOut", 22, 1 },
6550251213Snp	{ "Cmsg", 21, 1 },
6551251213Snp	{ "CdataOut", 20, 1 },
6552251213Snp	{ "EreadPdu", 19, 1 },
6553251213Snp	{ "CreadPdu", 18, 1 },
6554251213Snp	{ "TunnelPkt", 17, 1 },
6555251213Snp	{ "RcfPeerFin", 16, 1 },
6556251213Snp	{ "RcfReasonOut", 12, 4 },
6557251213Snp	{ "TxCchannel", 10, 2 },
6558251213Snp	{ "RcfTxChannel", 8, 2 },
6559251213Snp	{ "RxEchannel", 6, 2 },
6560251213Snp	{ "RcfRxChannel", 5, 1 },
6561251213Snp	{ "RcfDataOutSrdy", 4, 1 },
6562251213Snp	{ "RxDvld", 3, 1 },
6563251213Snp	{ "RxOoDvld", 2, 1 },
6564251213Snp	{ "RxCongestion", 1, 1 },
6565251213Snp	{ "TxCongestion", 0, 1 },
6566251213Snp	{ NULL }
6567251213Snp};
6568251213Snp
6569251213Snpstatic struct field_desc tp_la1[] = {
6570251213Snp	{ "CplCmdIn", 56, 8 },
6571251213Snp	{ "CplCmdOut", 48, 8 },
6572251213Snp	{ "ESynOut", 47, 1 },
6573251213Snp	{ "EAckOut", 46, 1 },
6574251213Snp	{ "EFinOut", 45, 1 },
6575251213Snp	{ "ERstOut", 44, 1 },
6576251213Snp	{ "SynIn", 43, 1 },
6577251213Snp	{ "AckIn", 42, 1 },
6578251213Snp	{ "FinIn", 41, 1 },
6579251213Snp	{ "RstIn", 40, 1 },
6580251213Snp	{ "DataIn", 39, 1 },
6581251213Snp	{ "DataInVld", 38, 1 },
6582251213Snp	{ "PadIn", 37, 1 },
6583251213Snp	{ "RxBufEmpty", 36, 1 },
6584251213Snp	{ "RxDdp", 35, 1 },
6585251213Snp	{ "RxFbCongestion", 34, 1 },
6586251213Snp	{ "TxFbCongestion", 33, 1 },
6587251213Snp	{ "TxPktSumSrdy", 32, 1 },
6588251213Snp	{ "RcfUlpType", 28, 4 },
6589251213Snp	{ "Eread", 27, 1 },
6590251213Snp	{ "Ebypass", 26, 1 },
6591251213Snp	{ "Esave", 25, 1 },
6592251213Snp	{ "Static0", 24, 1 },
6593251213Snp	{ "Cread", 23, 1 },
6594251213Snp	{ "Cbypass", 22, 1 },
6595251213Snp	{ "Csave", 21, 1 },
6596251213Snp	{ "CPktOut", 20, 1 },
6597251213Snp	{ "RxPagePoolFull", 18, 2 },
6598251213Snp	{ "RxLpbkPkt", 17, 1 },
6599251213Snp	{ "TxLpbkPkt", 16, 1 },
6600251213Snp	{ "RxVfValid", 15, 1 },
6601251213Snp	{ "SynLearned", 14, 1 },
6602251213Snp	{ "SetDelEntry", 13, 1 },
6603251213Snp	{ "SetInvEntry", 12, 1 },
6604251213Snp	{ "CpcmdDvld", 11, 1 },
6605251213Snp	{ "CpcmdSave", 10, 1 },
6606251213Snp	{ "RxPstructsFull", 8, 2 },
6607251213Snp	{ "EpcmdDvld", 7, 1 },
6608251213Snp	{ "EpcmdFlush", 6, 1 },
6609251213Snp	{ "EpcmdTrimPrefix", 5, 1 },
6610251213Snp	{ "EpcmdTrimPostfix", 4, 1 },
6611251213Snp	{ "ERssIp4Pkt", 3, 1 },
6612251213Snp	{ "ERssIp6Pkt", 2, 1 },
6613251213Snp	{ "ERssTcpUdpPkt", 1, 1 },
6614251213Snp	{ "ERssFceFipPkt", 0, 1 },
6615251213Snp	{ NULL }
6616251213Snp};
6617251213Snp
6618251213Snpstatic struct field_desc tp_la2[] = {
6619251213Snp	{ "CplCmdIn", 56, 8 },
6620251213Snp	{ "MpsVfVld", 55, 1 },
6621251213Snp	{ "MpsPf", 52, 3 },
6622251213Snp	{ "MpsVf", 44, 8 },
6623251213Snp	{ "SynIn", 43, 1 },
6624251213Snp	{ "AckIn", 42, 1 },
6625251213Snp	{ "FinIn", 41, 1 },
6626251213Snp	{ "RstIn", 40, 1 },
6627251213Snp	{ "DataIn", 39, 1 },
6628251213Snp	{ "DataInVld", 38, 1 },
6629251213Snp	{ "PadIn", 37, 1 },
6630251213Snp	{ "RxBufEmpty", 36, 1 },
6631251213Snp	{ "RxDdp", 35, 1 },
6632251213Snp	{ "RxFbCongestion", 34, 1 },
6633251213Snp	{ "TxFbCongestion", 33, 1 },
6634251213Snp	{ "TxPktSumSrdy", 32, 1 },
6635251213Snp	{ "RcfUlpType", 28, 4 },
6636251213Snp	{ "Eread", 27, 1 },
6637251213Snp	{ "Ebypass", 26, 1 },
6638251213Snp	{ "Esave", 25, 1 },
6639251213Snp	{ "Static0", 24, 1 },
6640251213Snp	{ "Cread", 23, 1 },
6641251213Snp	{ "Cbypass", 22, 1 },
6642251213Snp	{ "Csave", 21, 1 },
6643251213Snp	{ "CPktOut", 20, 1 },
6644251213Snp	{ "RxPagePoolFull", 18, 2 },
6645251213Snp	{ "RxLpbkPkt", 17, 1 },
6646251213Snp	{ "TxLpbkPkt", 16, 1 },
6647251213Snp	{ "RxVfValid", 15, 1 },
6648251213Snp	{ "SynLearned", 14, 1 },
6649251213Snp	{ "SetDelEntry", 13, 1 },
6650251213Snp	{ "SetInvEntry", 12, 1 },
6651251213Snp	{ "CpcmdDvld", 11, 1 },
6652251213Snp	{ "CpcmdSave", 10, 1 },
6653251213Snp	{ "RxPstructsFull", 8, 2 },
6654251213Snp	{ "EpcmdDvld", 7, 1 },
6655251213Snp	{ "EpcmdFlush", 6, 1 },
6656251213Snp	{ "EpcmdTrimPrefix", 5, 1 },
6657251213Snp	{ "EpcmdTrimPostfix", 4, 1 },
6658251213Snp	{ "ERssIp4Pkt", 3, 1 },
6659251213Snp	{ "ERssIp6Pkt", 2, 1 },
6660251213Snp	{ "ERssTcpUdpPkt", 1, 1 },
6661251213Snp	{ "ERssFceFipPkt", 0, 1 },
6662251213Snp	{ NULL }
6663251213Snp};
6664251213Snp
6665251213Snpstatic void
6666251213Snptp_la_show(struct sbuf *sb, uint64_t *p, int idx)
6667251213Snp{
6668251213Snp
6669251213Snp	field_desc_show(sb, *p, tp_la0);
6670251213Snp}
6671251213Snp
6672251213Snpstatic void
6673251213Snptp_la_show2(struct sbuf *sb, uint64_t *p, int idx)
6674251213Snp{
6675251213Snp
6676251213Snp	if (idx)
6677251213Snp		sbuf_printf(sb, "\n");
6678251213Snp	field_desc_show(sb, p[0], tp_la0);
6679251213Snp	if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL)
6680251213Snp		field_desc_show(sb, p[1], tp_la0);
6681251213Snp}
6682251213Snp
6683251213Snpstatic void
6684251213Snptp_la_show3(struct sbuf *sb, uint64_t *p, int idx)
6685251213Snp{
6686251213Snp
6687251213Snp	if (idx)
6688251213Snp		sbuf_printf(sb, "\n");
6689251213Snp	field_desc_show(sb, p[0], tp_la0);
6690251213Snp	if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL)
6691251213Snp		field_desc_show(sb, p[1], (p[0] & (1 << 17)) ? tp_la2 : tp_la1);
6692251213Snp}
6693251213Snp
6694228561Snpstatic int
6695251213Snpsysctl_tp_la(SYSCTL_HANDLER_ARGS)
6696251213Snp{
6697251213Snp	struct adapter *sc = arg1;
6698251213Snp	struct sbuf *sb;
6699251213Snp	uint64_t *buf, *p;
6700251213Snp	int rc;
6701251213Snp	u_int i, inc;
6702251213Snp	void (*show_func)(struct sbuf *, uint64_t *, int);
6703251213Snp
6704251213Snp	rc = sysctl_wire_old_buffer(req, 0);
6705251213Snp	if (rc != 0)
6706251213Snp		return (rc);
6707251213Snp
6708251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6709251213Snp	if (sb == NULL)
6710251213Snp		return (ENOMEM);
6711251213Snp
6712251213Snp	buf = malloc(TPLA_SIZE * sizeof(uint64_t), M_CXGBE, M_ZERO | M_WAITOK);
6713251213Snp
6714251213Snp	t4_tp_read_la(sc, buf, NULL);
6715251213Snp	p = buf;
6716251213Snp
6717251213Snp	switch (G_DBGLAMODE(t4_read_reg(sc, A_TP_DBG_LA_CONFIG))) {
6718251213Snp	case 2:
6719251213Snp		inc = 2;
6720251213Snp		show_func = tp_la_show2;
6721251213Snp		break;
6722251213Snp	case 3:
6723251213Snp		inc = 2;
6724251213Snp		show_func = tp_la_show3;
6725251213Snp		break;
6726251213Snp	default:
6727251213Snp		inc = 1;
6728251213Snp		show_func = tp_la_show;
6729251213Snp	}
6730251213Snp
6731251213Snp	for (i = 0; i < TPLA_SIZE / inc; i++, p += inc)
6732251213Snp		(*show_func)(sb, p, i);
6733251213Snp
6734251213Snp	rc = sbuf_finish(sb);
6735251213Snp	sbuf_delete(sb);
6736251213Snp	free(buf, M_CXGBE);
6737251213Snp	return (rc);
6738251213Snp}
6739251213Snp
6740251213Snpstatic int
6741228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS)
6742228561Snp{
6743228561Snp	struct adapter *sc = arg1;
6744228561Snp	struct sbuf *sb;
6745228561Snp	int rc;
6746228561Snp	u64 nrate[NCHAN], orate[NCHAN];
6747228561Snp
6748228561Snp	rc = sysctl_wire_old_buffer(req, 0);
6749228561Snp	if (rc != 0)
6750228561Snp		return (rc);
6751228561Snp
6752228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
6753228561Snp	if (sb == NULL)
6754228561Snp		return (ENOMEM);
6755228561Snp
6756228561Snp	t4_get_chan_txrate(sc, nrate, orate);
6757228561Snp	sbuf_printf(sb, "              channel 0   channel 1   channel 2   "
6758228561Snp		 "channel 3\n");
6759228561Snp	sbuf_printf(sb, "NIC B/s:     %10ju  %10ju  %10ju  %10ju\n",
6760228561Snp	    nrate[0], nrate[1], nrate[2], nrate[3]);
6761228561Snp	sbuf_printf(sb, "Offload B/s: %10ju  %10ju  %10ju  %10ju",
6762228561Snp	    orate[0], orate[1], orate[2], orate[3]);
6763228561Snp
6764228561Snp	rc = sbuf_finish(sb);
6765228561Snp	sbuf_delete(sb);
6766228561Snp
6767228561Snp	return (rc);
6768228561Snp}
6769248925Snp
6770248925Snpstatic int
6771251213Snpsysctl_ulprx_la(SYSCTL_HANDLER_ARGS)
6772251213Snp{
6773251213Snp	struct adapter *sc = arg1;
6774251213Snp	struct sbuf *sb;
6775251213Snp	uint32_t *buf, *p;
6776251213Snp	int rc, i;
6777251213Snp
6778251213Snp	rc = sysctl_wire_old_buffer(req, 0);
6779251213Snp	if (rc != 0)
6780251213Snp		return (rc);
6781251213Snp
6782251213Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6783251213Snp	if (sb == NULL)
6784251213Snp		return (ENOMEM);
6785251213Snp
6786251213Snp	buf = malloc(ULPRX_LA_SIZE * 8 * sizeof(uint32_t), M_CXGBE,
6787251213Snp	    M_ZERO | M_WAITOK);
6788251213Snp
6789251213Snp	t4_ulprx_read_la(sc, buf);
6790251213Snp	p = buf;
6791251213Snp
6792251213Snp	sbuf_printf(sb, "      Pcmd        Type   Message"
6793251213Snp	    "                Data");
6794251213Snp	for (i = 0; i < ULPRX_LA_SIZE; i++, p += 8) {
6795251213Snp		sbuf_printf(sb, "\n%08x%08x  %4x  %08x  %08x%08x%08x%08x",
6796251213Snp		    p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]);
6797251213Snp	}
6798251213Snp
6799251213Snp	rc = sbuf_finish(sb);
6800251213Snp	sbuf_delete(sb);
6801251213Snp	free(buf, M_CXGBE);
6802251213Snp	return (rc);
6803251213Snp}
6804251213Snp
6805251213Snpstatic int
6806249392Snpsysctl_wcwr_stats(SYSCTL_HANDLER_ARGS)
6807248925Snp{
6808248925Snp	struct adapter *sc = arg1;
6809248925Snp	struct sbuf *sb;
6810248925Snp	int rc, v;
6811248925Snp
6812248925Snp	rc = sysctl_wire_old_buffer(req, 0);
6813248925Snp	if (rc != 0)
6814248925Snp		return (rc);
6815248925Snp
6816248925Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6817248925Snp	if (sb == NULL)
6818248925Snp		return (ENOMEM);
6819248925Snp
6820248925Snp	v = t4_read_reg(sc, A_SGE_STAT_CFG);
6821248925Snp	if (G_STATSOURCE_T5(v) == 7) {
6822248925Snp		if (G_STATMODE(v) == 0) {
6823249383Snp			sbuf_printf(sb, "total %d, incomplete %d",
6824248925Snp			    t4_read_reg(sc, A_SGE_STAT_TOTAL),
6825248925Snp			    t4_read_reg(sc, A_SGE_STAT_MATCH));
6826248925Snp		} else if (G_STATMODE(v) == 1) {
6827249383Snp			sbuf_printf(sb, "total %d, data overflow %d",
6828248925Snp			    t4_read_reg(sc, A_SGE_STAT_TOTAL),
6829248925Snp			    t4_read_reg(sc, A_SGE_STAT_MATCH));
6830248925Snp		}
6831248925Snp	}
6832248925Snp	rc = sbuf_finish(sb);
6833248925Snp	sbuf_delete(sb);
6834248925Snp
6835248925Snp	return (rc);
6836248925Snp}
6837231115Snp#endif
6838228561Snp
6839219286Snpstatic inline void
6840219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq)
6841219286Snp{
6842219286Snp	struct buf_ring *br;
6843219286Snp	struct mbuf *m;
6844219286Snp
6845219286Snp	TXQ_LOCK_ASSERT_OWNED(txq);
6846219286Snp
6847220873Snp	br = txq->br;
6848219286Snp	m = txq->m ? txq->m : drbr_dequeue(ifp, br);
6849219286Snp	if (m)
6850219286Snp		t4_eth_tx(ifp, txq, m);
6851219286Snp}
6852219286Snp
6853219286Snpvoid
6854228561Snpt4_tx_callout(void *arg)
6855219286Snp{
6856228561Snp	struct sge_eq *eq = arg;
6857228561Snp	struct adapter *sc;
6858219286Snp
6859228561Snp	if (EQ_TRYLOCK(eq) == 0)
6860228561Snp		goto reschedule;
6861228561Snp
6862228561Snp	if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) {
6863228561Snp		EQ_UNLOCK(eq);
6864228561Snpreschedule:
6865228561Snp		if (__predict_true(!(eq->flags && EQ_DOOMED)))
6866228561Snp			callout_schedule(&eq->tx_callout, 1);
6867228561Snp		return;
6868228561Snp	}
6869228561Snp
6870228561Snp	EQ_LOCK_ASSERT_OWNED(eq);
6871228561Snp
6872228561Snp	if (__predict_true((eq->flags & EQ_DOOMED) == 0)) {
6873228561Snp
6874228561Snp		if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) {
6875228561Snp			struct sge_txq *txq = arg;
6876228561Snp			struct port_info *pi = txq->ifp->if_softc;
6877228561Snp
6878228561Snp			sc = pi->adapter;
6879228561Snp		} else {
6880228561Snp			struct sge_wrq *wrq = arg;
6881228561Snp
6882228561Snp			sc = wrq->adapter;
6883228561Snp		}
6884228561Snp
6885228561Snp		taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task);
6886228561Snp	}
6887228561Snp
6888228561Snp	EQ_UNLOCK(eq);
6889228561Snp}
6890228561Snp
6891228561Snpvoid
6892228561Snpt4_tx_task(void *arg, int count)
6893228561Snp{
6894228561Snp	struct sge_eq *eq = arg;
6895228561Snp
6896228561Snp	EQ_LOCK(eq);
6897228561Snp	if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) {
6898228561Snp		struct sge_txq *txq = arg;
6899220649Snp		txq_start(txq->ifp, txq);
6900228561Snp	} else {
6901228561Snp		struct sge_wrq *wrq = arg;
6902228561Snp		t4_wrq_tx_locked(wrq->adapter, wrq, NULL);
6903228561Snp	}
6904228561Snp	EQ_UNLOCK(eq);
6905219286Snp}
6906219286Snp
6907221474Snpstatic uint32_t
6908221474Snpfconf_to_mode(uint32_t fconf)
6909221474Snp{
6910221474Snp	uint32_t mode;
6911221474Snp
6912221474Snp	mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR |
6913221474Snp	    T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT;
6914221474Snp
6915221474Snp	if (fconf & F_FRAGMENTATION)
6916221474Snp		mode |= T4_FILTER_IP_FRAGMENT;
6917221474Snp
6918221474Snp	if (fconf & F_MPSHITTYPE)
6919221474Snp		mode |= T4_FILTER_MPS_HIT_TYPE;
6920221474Snp
6921221474Snp	if (fconf & F_MACMATCH)
6922221474Snp		mode |= T4_FILTER_MAC_IDX;
6923221474Snp
6924221474Snp	if (fconf & F_ETHERTYPE)
6925221474Snp		mode |= T4_FILTER_ETH_TYPE;
6926221474Snp
6927221474Snp	if (fconf & F_PROTOCOL)
6928221474Snp		mode |= T4_FILTER_IP_PROTO;
6929221474Snp
6930221474Snp	if (fconf & F_TOS)
6931221474Snp		mode |= T4_FILTER_IP_TOS;
6932221474Snp
6933221474Snp	if (fconf & F_VLAN)
6934228561Snp		mode |= T4_FILTER_VLAN;
6935221474Snp
6936221474Snp	if (fconf & F_VNIC_ID)
6937228561Snp		mode |= T4_FILTER_VNIC;
6938221474Snp
6939221474Snp	if (fconf & F_PORT)
6940221474Snp		mode |= T4_FILTER_PORT;
6941221474Snp
6942221474Snp	if (fconf & F_FCOE)
6943221474Snp		mode |= T4_FILTER_FCoE;
6944221474Snp
6945221474Snp	return (mode);
6946221474Snp}
6947221474Snp
6948221474Snpstatic uint32_t
6949221474Snpmode_to_fconf(uint32_t mode)
6950221474Snp{
6951221474Snp	uint32_t fconf = 0;
6952221474Snp
6953221474Snp	if (mode & T4_FILTER_IP_FRAGMENT)
6954221474Snp		fconf |= F_FRAGMENTATION;
6955221474Snp
6956221474Snp	if (mode & T4_FILTER_MPS_HIT_TYPE)
6957221474Snp		fconf |= F_MPSHITTYPE;
6958221474Snp
6959221474Snp	if (mode & T4_FILTER_MAC_IDX)
6960221474Snp		fconf |= F_MACMATCH;
6961221474Snp
6962221474Snp	if (mode & T4_FILTER_ETH_TYPE)
6963221474Snp		fconf |= F_ETHERTYPE;
6964221474Snp
6965221474Snp	if (mode & T4_FILTER_IP_PROTO)
6966221474Snp		fconf |= F_PROTOCOL;
6967221474Snp
6968221474Snp	if (mode & T4_FILTER_IP_TOS)
6969221474Snp		fconf |= F_TOS;
6970221474Snp
6971228561Snp	if (mode & T4_FILTER_VLAN)
6972221474Snp		fconf |= F_VLAN;
6973221474Snp
6974228561Snp	if (mode & T4_FILTER_VNIC)
6975221474Snp		fconf |= F_VNIC_ID;
6976221474Snp
6977221474Snp	if (mode & T4_FILTER_PORT)
6978221474Snp		fconf |= F_PORT;
6979221474Snp
6980221474Snp	if (mode & T4_FILTER_FCoE)
6981221474Snp		fconf |= F_FCOE;
6982221474Snp
6983221474Snp	return (fconf);
6984221474Snp}
6985221474Snp
6986221474Snpstatic uint32_t
6987221474Snpfspec_to_fconf(struct t4_filter_specification *fs)
6988221474Snp{
6989221474Snp	uint32_t fconf = 0;
6990221474Snp
6991221474Snp	if (fs->val.frag || fs->mask.frag)
6992221474Snp		fconf |= F_FRAGMENTATION;
6993221474Snp
6994221474Snp	if (fs->val.matchtype || fs->mask.matchtype)
6995221474Snp		fconf |= F_MPSHITTYPE;
6996221474Snp
6997221474Snp	if (fs->val.macidx || fs->mask.macidx)
6998221474Snp		fconf |= F_MACMATCH;
6999221474Snp
7000221474Snp	if (fs->val.ethtype || fs->mask.ethtype)
7001221474Snp		fconf |= F_ETHERTYPE;
7002221474Snp
7003221474Snp	if (fs->val.proto || fs->mask.proto)
7004221474Snp		fconf |= F_PROTOCOL;
7005221474Snp
7006221474Snp	if (fs->val.tos || fs->mask.tos)
7007221474Snp		fconf |= F_TOS;
7008221474Snp
7009228561Snp	if (fs->val.vlan_vld || fs->mask.vlan_vld)
7010221474Snp		fconf |= F_VLAN;
7011221474Snp
7012228561Snp	if (fs->val.vnic_vld || fs->mask.vnic_vld)
7013221474Snp		fconf |= F_VNIC_ID;
7014221474Snp
7015221474Snp	if (fs->val.iport || fs->mask.iport)
7016221474Snp		fconf |= F_PORT;
7017221474Snp
7018221474Snp	if (fs->val.fcoe || fs->mask.fcoe)
7019221474Snp		fconf |= F_FCOE;
7020221474Snp
7021221474Snp	return (fconf);
7022221474Snp}
7023221474Snp
7024221474Snpstatic int
7025221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode)
7026221474Snp{
7027245274Snp	int rc;
7028221474Snp	uint32_t fconf;
7029221474Snp
7030245274Snp	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
7031245274Snp	    "t4getfm");
7032245274Snp	if (rc)
7033245274Snp		return (rc);
7034245274Snp
7035221474Snp	t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1,
7036221474Snp	    A_TP_VLAN_PRI_MAP);
7037221474Snp
7038252705Snp	if (sc->params.tp.vlan_pri_map != fconf) {
7039228561Snp		log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n",
7040252705Snp		    device_get_nameunit(sc->dev), sc->params.tp.vlan_pri_map,
7041252705Snp		    fconf);
7042252705Snp		sc->params.tp.vlan_pri_map = fconf;
7043228561Snp	}
7044221474Snp
7045252705Snp	*mode = fconf_to_mode(sc->params.tp.vlan_pri_map);
7046228561Snp
7047245274Snp	end_synchronized_op(sc, LOCK_HELD);
7048221474Snp	return (0);
7049221474Snp}
7050221474Snp
7051221474Snpstatic int
7052221474Snpset_filter_mode(struct adapter *sc, uint32_t mode)
7053221474Snp{
7054221474Snp	uint32_t fconf;
7055221474Snp	int rc;
7056221474Snp
7057221474Snp	fconf = mode_to_fconf(mode);
7058221474Snp
7059245274Snp	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
7060245274Snp	    "t4setfm");
7061245274Snp	if (rc)
7062245274Snp		return (rc);
7063221474Snp
7064221474Snp	if (sc->tids.ftids_in_use > 0) {
7065221474Snp		rc = EBUSY;
7066221474Snp		goto done;
7067221474Snp	}
7068221474Snp
7069237263Snp#ifdef TCP_OFFLOAD
7070228561Snp	if (sc->offload_map) {
7071228561Snp		rc = EBUSY;
7072228561Snp		goto done;
7073228561Snp	}
7074228561Snp#endif
7075228561Snp
7076228561Snp#ifdef notyet
7077221474Snp	rc = -t4_set_filter_mode(sc, fconf);
7078228561Snp	if (rc == 0)
7079228561Snp		sc->filter_mode = fconf;
7080228561Snp#else
7081228561Snp	rc = ENOTSUP;
7082228561Snp#endif
7083228561Snp
7084221474Snpdone:
7085245274Snp	end_synchronized_op(sc, LOCK_HELD);
7086221474Snp	return (rc);
7087221474Snp}
7088221474Snp
7089222552Snpstatic inline uint64_t
7090222552Snpget_filter_hits(struct adapter *sc, uint32_t fid)
7091222552Snp{
7092248925Snp	uint32_t mw_base, off, tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE);
7093222552Snp	uint64_t hits;
7094222552Snp
7095248925Snp	memwin_info(sc, 0, &mw_base, NULL);
7096248925Snp	off = position_memwin(sc, 0,
7097222552Snp	    tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE);
7098251358Snp	if (is_t4(sc)) {
7099251358Snp		hits = t4_read_reg64(sc, mw_base + off + 16);
7100251358Snp		hits = be64toh(hits);
7101251358Snp	} else {
7102251358Snp		hits = t4_read_reg(sc, mw_base + off + 24);
7103251358Snp		hits = be32toh(hits);
7104251358Snp	}
7105222552Snp
7106251358Snp	return (hits);
7107222552Snp}
7108222552Snp
7109221474Snpstatic int
7110221474Snpget_filter(struct adapter *sc, struct t4_filter *t)
7111221474Snp{
7112245274Snp	int i, rc, nfilters = sc->tids.nftids;
7113221474Snp	struct filter_entry *f;
7114221474Snp
7115245274Snp	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
7116245274Snp	    "t4getf");
7117245274Snp	if (rc)
7118245274Snp		return (rc);
7119221474Snp
7120221474Snp	if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL ||
7121221474Snp	    t->idx >= nfilters) {
7122221474Snp		t->idx = 0xffffffff;
7123245274Snp		goto done;
7124221474Snp	}
7125221474Snp
7126221474Snp	f = &sc->tids.ftid_tab[t->idx];
7127221474Snp	for (i = t->idx; i < nfilters; i++, f++) {
7128221474Snp		if (f->valid) {
7129221474Snp			t->idx = i;
7130222509Snp			t->l2tidx = f->l2t ? f->l2t->idx : 0;
7131222509Snp			t->smtidx = f->smtidx;
7132222552Snp			if (f->fs.hitcnts)
7133222552Snp				t->hits = get_filter_hits(sc, t->idx);
7134222552Snp			else
7135222552Snp				t->hits = UINT64_MAX;
7136221474Snp			t->fs = f->fs;
7137221474Snp
7138245274Snp			goto done;
7139221474Snp		}
7140221474Snp	}
7141221474Snp
7142221474Snp	t->idx = 0xffffffff;
7143245274Snpdone:
7144245274Snp	end_synchronized_op(sc, LOCK_HELD);
7145221474Snp	return (0);
7146221474Snp}
7147221474Snp
7148221474Snpstatic int
7149221474Snpset_filter(struct adapter *sc, struct t4_filter *t)
7150221474Snp{
7151221474Snp	unsigned int nfilters, nports;
7152221474Snp	struct filter_entry *f;
7153245274Snp	int i, rc;
7154221474Snp
7155245274Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf");
7156245274Snp	if (rc)
7157245274Snp		return (rc);
7158221474Snp
7159221474Snp	nfilters = sc->tids.nftids;
7160221474Snp	nports = sc->params.nports;
7161221474Snp
7162245274Snp	if (nfilters == 0) {
7163245274Snp		rc = ENOTSUP;
7164245274Snp		goto done;
7165245274Snp	}
7166221474Snp
7167245274Snp	if (!(sc->flags & FULL_INIT_DONE)) {
7168245274Snp		rc = EAGAIN;
7169245274Snp		goto done;
7170245274Snp	}
7171221474Snp
7172245274Snp	if (t->idx >= nfilters) {
7173245274Snp		rc = EINVAL;
7174245274Snp		goto done;
7175245274Snp	}
7176221474Snp
7177221474Snp	/* Validate against the global filter mode */
7178252705Snp	if ((sc->params.tp.vlan_pri_map | fspec_to_fconf(&t->fs)) !=
7179252705Snp	    sc->params.tp.vlan_pri_map) {
7180245274Snp		rc = E2BIG;
7181245274Snp		goto done;
7182245274Snp	}
7183221474Snp
7184245274Snp	if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) {
7185245274Snp		rc = EINVAL;
7186245274Snp		goto done;
7187245274Snp	}
7188221474Snp
7189245274Snp	if (t->fs.val.iport >= nports) {
7190245274Snp		rc = EINVAL;
7191245274Snp		goto done;
7192245274Snp	}
7193221474Snp
7194221474Snp	/* Can't specify an iq if not steering to it */
7195245274Snp	if (!t->fs.dirsteer && t->fs.iq) {
7196245274Snp		rc = EINVAL;
7197245274Snp		goto done;
7198245274Snp	}
7199221474Snp
7200221474Snp	/* IPv6 filter idx must be 4 aligned */
7201221474Snp	if (t->fs.type == 1 &&
7202245274Snp	    ((t->idx & 0x3) || t->idx + 4 >= nfilters)) {
7203245274Snp		rc = EINVAL;
7204245274Snp		goto done;
7205245274Snp	}
7206221474Snp
7207221474Snp	if (sc->tids.ftid_tab == NULL) {
7208221474Snp		KASSERT(sc->tids.ftids_in_use == 0,
7209221474Snp		    ("%s: no memory allocated but filters_in_use > 0",
7210221474Snp		    __func__));
7211221474Snp
7212221474Snp		sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) *
7213221474Snp		    nfilters, M_CXGBE, M_NOWAIT | M_ZERO);
7214245274Snp		if (sc->tids.ftid_tab == NULL) {
7215245274Snp			rc = ENOMEM;
7216245274Snp			goto done;
7217245274Snp		}
7218245274Snp		mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF);
7219221474Snp	}
7220221474Snp
7221221474Snp	for (i = 0; i < 4; i++) {
7222221474Snp		f = &sc->tids.ftid_tab[t->idx + i];
7223221474Snp
7224245274Snp		if (f->pending || f->valid) {
7225245274Snp			rc = EBUSY;
7226245274Snp			goto done;
7227245274Snp		}
7228245274Snp		if (f->locked) {
7229245274Snp			rc = EPERM;
7230245274Snp			goto done;
7231245274Snp		}
7232221474Snp
7233221474Snp		if (t->fs.type == 0)
7234221474Snp			break;
7235221474Snp	}
7236221474Snp
7237221474Snp	f = &sc->tids.ftid_tab[t->idx];
7238221474Snp	f->fs = t->fs;
7239221474Snp
7240245274Snp	rc = set_filter_wr(sc, t->idx);
7241245274Snpdone:
7242245274Snp	end_synchronized_op(sc, 0);
7243245274Snp
7244245274Snp	if (rc == 0) {
7245245274Snp		mtx_lock(&sc->tids.ftid_lock);
7246245274Snp		for (;;) {
7247245274Snp			if (f->pending == 0) {
7248245274Snp				rc = f->valid ? 0 : EIO;
7249245274Snp				break;
7250245274Snp			}
7251245274Snp
7252245274Snp			if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock,
7253245274Snp			    PCATCH, "t4setfw", 0)) {
7254245274Snp				rc = EINPROGRESS;
7255245274Snp				break;
7256245274Snp			}
7257245274Snp		}
7258245274Snp		mtx_unlock(&sc->tids.ftid_lock);
7259245274Snp	}
7260245274Snp	return (rc);
7261221474Snp}
7262221474Snp
7263221474Snpstatic int
7264221474Snpdel_filter(struct adapter *sc, struct t4_filter *t)
7265221474Snp{
7266221474Snp	unsigned int nfilters;
7267221474Snp	struct filter_entry *f;
7268245274Snp	int rc;
7269221474Snp
7270245274Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf");
7271245274Snp	if (rc)
7272245274Snp		return (rc);
7273221474Snp
7274221474Snp	nfilters = sc->tids.nftids;
7275221474Snp
7276245274Snp	if (nfilters == 0) {
7277245274Snp		rc = ENOTSUP;
7278245274Snp		goto done;
7279245274Snp	}
7280221474Snp
7281221474Snp	if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 ||
7282245274Snp	    t->idx >= nfilters) {
7283245274Snp		rc = EINVAL;
7284245274Snp		goto done;
7285245274Snp	}
7286221474Snp
7287245274Snp	if (!(sc->flags & FULL_INIT_DONE)) {
7288245274Snp		rc = EAGAIN;
7289245274Snp		goto done;
7290245274Snp	}
7291221474Snp
7292221474Snp	f = &sc->tids.ftid_tab[t->idx];
7293221474Snp
7294245274Snp	if (f->pending) {
7295245274Snp		rc = EBUSY;
7296245274Snp		goto done;
7297245274Snp	}
7298245274Snp	if (f->locked) {
7299245274Snp		rc = EPERM;
7300245274Snp		goto done;
7301245274Snp	}
7302221474Snp
7303221474Snp	if (f->valid) {
7304221474Snp		t->fs = f->fs;	/* extra info for the caller */
7305245274Snp		rc = del_filter_wr(sc, t->idx);
7306221474Snp	}
7307221474Snp
7308245274Snpdone:
7309245274Snp	end_synchronized_op(sc, 0);
7310245274Snp
7311245274Snp	if (rc == 0) {
7312245274Snp		mtx_lock(&sc->tids.ftid_lock);
7313245274Snp		for (;;) {
7314245274Snp			if (f->pending == 0) {
7315245274Snp				rc = f->valid ? EIO : 0;
7316245274Snp				break;
7317245274Snp			}
7318245274Snp
7319245274Snp			if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock,
7320245274Snp			    PCATCH, "t4delfw", 0)) {
7321245274Snp				rc = EINPROGRESS;
7322245274Snp				break;
7323245274Snp			}
7324245274Snp		}
7325245274Snp		mtx_unlock(&sc->tids.ftid_lock);
7326245274Snp	}
7327245274Snp
7328245274Snp	return (rc);
7329221474Snp}
7330221474Snp
7331221474Snpstatic void
7332222509Snpclear_filter(struct filter_entry *f)
7333221474Snp{
7334222509Snp	if (f->l2t)
7335222509Snp		t4_l2t_release(f->l2t);
7336222509Snp
7337221474Snp	bzero(f, sizeof (*f));
7338221474Snp}
7339221474Snp
7340221474Snpstatic int
7341221474Snpset_filter_wr(struct adapter *sc, int fidx)
7342221474Snp{
7343221474Snp	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
7344237263Snp	struct wrqe *wr;
7345221474Snp	struct fw_filter_wr *fwr;
7346221474Snp	unsigned int ftid;
7347221474Snp
7348245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
7349221474Snp
7350222509Snp	if (f->fs.newdmac || f->fs.newvlan) {
7351222509Snp		/* This filter needs an L2T entry; allocate one. */
7352222509Snp		f->l2t = t4_l2t_alloc_switching(sc->l2t);
7353222509Snp		if (f->l2t == NULL)
7354222509Snp			return (EAGAIN);
7355222509Snp		if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport,
7356222509Snp		    f->fs.dmac)) {
7357222509Snp			t4_l2t_release(f->l2t);
7358222509Snp			f->l2t = NULL;
7359222509Snp			return (ENOMEM);
7360222509Snp		}
7361222509Snp	}
7362221474Snp
7363221474Snp	ftid = sc->tids.ftid_base + fidx;
7364221474Snp
7365237263Snp	wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq);
7366237263Snp	if (wr == NULL)
7367221474Snp		return (ENOMEM);
7368221474Snp
7369237263Snp	fwr = wrtod(wr);
7370221474Snp	bzero(fwr, sizeof (*fwr));
7371221474Snp
7372221474Snp	fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR));
7373221474Snp	fwr->len16_pkd = htobe32(FW_LEN16(*fwr));
7374221474Snp	fwr->tid_to_iq =
7375221474Snp	    htobe32(V_FW_FILTER_WR_TID(ftid) |
7376221474Snp		V_FW_FILTER_WR_RQTYPE(f->fs.type) |
7377221474Snp		V_FW_FILTER_WR_NOREPLY(0) |
7378221474Snp		V_FW_FILTER_WR_IQ(f->fs.iq));
7379221474Snp	fwr->del_filter_to_l2tix =
7380221474Snp	    htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) |
7381221474Snp		V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) |
7382221474Snp		V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) |
7383221474Snp		V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) |
7384221474Snp		V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) |
7385221474Snp		V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) |
7386221474Snp		V_FW_FILTER_WR_DMAC(f->fs.newdmac) |
7387221474Snp		V_FW_FILTER_WR_SMAC(f->fs.newsmac) |
7388221474Snp		V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT ||
7389221474Snp		    f->fs.newvlan == VLAN_REWRITE) |
7390221474Snp		V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE ||
7391221474Snp		    f->fs.newvlan == VLAN_REWRITE) |
7392221474Snp		V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) |
7393221474Snp		V_FW_FILTER_WR_TXCHAN(f->fs.eport) |
7394221474Snp		V_FW_FILTER_WR_PRIO(f->fs.prio) |
7395222509Snp		V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0));
7396221474Snp	fwr->ethtype = htobe16(f->fs.val.ethtype);
7397221474Snp	fwr->ethtypem = htobe16(f->fs.mask.ethtype);
7398221474Snp	fwr->frag_to_ovlan_vldm =
7399221474Snp	    (V_FW_FILTER_WR_FRAG(f->fs.val.frag) |
7400221474Snp		V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) |
7401228561Snp		V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) |
7402228561Snp		V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) |
7403228561Snp		V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) |
7404228561Snp		V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld));
7405221474Snp	fwr->smac_sel = 0;
7406221474Snp	fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) |
7407228561Snp	    V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id));
7408221474Snp	fwr->maci_to_matchtypem =
7409221474Snp	    htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) |
7410221474Snp		V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) |
7411221474Snp		V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) |
7412221474Snp		V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) |
7413221474Snp		V_FW_FILTER_WR_PORT(f->fs.val.iport) |
7414221474Snp		V_FW_FILTER_WR_PORTM(f->fs.mask.iport) |
7415221474Snp		V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) |
7416221474Snp		V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype));
7417221474Snp	fwr->ptcl = f->fs.val.proto;
7418221474Snp	fwr->ptclm = f->fs.mask.proto;
7419221474Snp	fwr->ttyp = f->fs.val.tos;
7420221474Snp	fwr->ttypm = f->fs.mask.tos;
7421228561Snp	fwr->ivlan = htobe16(f->fs.val.vlan);
7422228561Snp	fwr->ivlanm = htobe16(f->fs.mask.vlan);
7423228561Snp	fwr->ovlan = htobe16(f->fs.val.vnic);
7424228561Snp	fwr->ovlanm = htobe16(f->fs.mask.vnic);
7425221474Snp	bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip));
7426221474Snp	bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm));
7427221474Snp	bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip));
7428221474Snp	bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm));
7429221474Snp	fwr->lp = htobe16(f->fs.val.dport);
7430221474Snp	fwr->lpm = htobe16(f->fs.mask.dport);
7431221474Snp	fwr->fp = htobe16(f->fs.val.sport);
7432221474Snp	fwr->fpm = htobe16(f->fs.mask.sport);
7433221474Snp	if (f->fs.newsmac)
7434221474Snp		bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma));
7435221474Snp
7436221474Snp	f->pending = 1;
7437221474Snp	sc->tids.ftids_in_use++;
7438228561Snp
7439237263Snp	t4_wrq_tx(sc, wr);
7440228561Snp	return (0);
7441221474Snp}
7442221474Snp
7443221474Snpstatic int
7444221474Snpdel_filter_wr(struct adapter *sc, int fidx)
7445221474Snp{
7446221474Snp	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
7447237263Snp	struct wrqe *wr;
7448221474Snp	struct fw_filter_wr *fwr;
7449228561Snp	unsigned int ftid;
7450221474Snp
7451221474Snp	ftid = sc->tids.ftid_base + fidx;
7452221474Snp
7453237263Snp	wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq);
7454237263Snp	if (wr == NULL)
7455221474Snp		return (ENOMEM);
7456237263Snp	fwr = wrtod(wr);
7457221474Snp	bzero(fwr, sizeof (*fwr));
7458221474Snp
7459228561Snp	t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id);
7460221474Snp
7461221474Snp	f->pending = 1;
7462237263Snp	t4_wrq_tx(sc, wr);
7463228561Snp	return (0);
7464221474Snp}
7465221474Snp
7466239338Snpint
7467239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
7468221474Snp{
7469228561Snp	struct adapter *sc = iq->adapter;
7470228561Snp	const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1);
7471221474Snp	unsigned int idx = GET_TID(rpl);
7472265426Snp	unsigned int rc;
7473265426Snp	struct filter_entry *f;
7474221474Snp
7475228561Snp	KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__,
7476228561Snp	    rss->opcode));
7477228561Snp
7478265426Snp	if (is_ftid(sc, idx)) {
7479221474Snp
7480265426Snp		idx -= sc->tids.ftid_base;
7481265426Snp		f = &sc->tids.ftid_tab[idx];
7482265426Snp		rc = G_COOKIE(rpl->cookie);
7483265426Snp
7484245274Snp		mtx_lock(&sc->tids.ftid_lock);
7485228561Snp		if (rc == FW_FILTER_WR_FLT_ADDED) {
7486245274Snp			KASSERT(f->pending, ("%s: filter[%u] isn't pending.",
7487245274Snp			    __func__, idx));
7488221474Snp			f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff;
7489221474Snp			f->pending = 0;  /* asynchronous setup completed */
7490221474Snp			f->valid = 1;
7491231120Snp		} else {
7492231120Snp			if (rc != FW_FILTER_WR_FLT_DELETED) {
7493231120Snp				/* Add or delete failed, display an error */
7494231120Snp				log(LOG_ERR,
7495231120Snp				    "filter %u setup failed with error %u\n",
7496231120Snp				    idx, rc);
7497231120Snp			}
7498228561Snp
7499231120Snp			clear_filter(f);
7500231120Snp			sc->tids.ftids_in_use--;
7501221474Snp		}
7502245274Snp		wakeup(&sc->tids.ftid_tab);
7503245274Snp		mtx_unlock(&sc->tids.ftid_lock);
7504221474Snp	}
7505228561Snp
7506228561Snp	return (0);
7507221474Snp}
7508221474Snp
7509222973Snpstatic int
7510222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt)
7511222973Snp{
7512245274Snp	int rc;
7513222973Snp
7514222973Snp	if (cntxt->cid > M_CTXTQID)
7515245274Snp		return (EINVAL);
7516222973Snp
7517222973Snp	if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS &&
7518222973Snp	    cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM)
7519245274Snp		return (EINVAL);
7520222973Snp
7521246575Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ctxt");
7522246575Snp	if (rc)
7523246575Snp		return (rc);
7524246575Snp
7525222973Snp	if (sc->flags & FW_OK) {
7526246575Snp		rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id,
7527246575Snp		    &cntxt->data[0]);
7528246575Snp		if (rc == 0)
7529246575Snp			goto done;
7530222973Snp	}
7531222973Snp
7532245274Snp	/*
7533245274Snp	 * Read via firmware failed or wasn't even attempted.  Read directly via
7534245274Snp	 * the backdoor.
7535245274Snp	 */
7536246575Snp	rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, &cntxt->data[0]);
7537246575Snpdone:
7538246575Snp	end_synchronized_op(sc, 0);
7539245274Snp	return (rc);
7540245274Snp}
7541222973Snp
7542245274Snpstatic int
7543245274Snpload_fw(struct adapter *sc, struct t4_data *fw)
7544245274Snp{
7545245274Snp	int rc;
7546245274Snp	uint8_t *fw_data;
7547245274Snp
7548245274Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw");
7549245274Snp	if (rc)
7550245274Snp		return (rc);
7551245274Snp
7552245274Snp	if (sc->flags & FULL_INIT_DONE) {
7553245274Snp		rc = EBUSY;
7554245274Snp		goto done;
7555222973Snp	}
7556222973Snp
7557245274Snp	fw_data = malloc(fw->len, M_CXGBE, M_WAITOK);
7558245274Snp	if (fw_data == NULL) {
7559245274Snp		rc = ENOMEM;
7560245274Snp		goto done;
7561245274Snp	}
7562245274Snp
7563245274Snp	rc = copyin(fw->data, fw_data, fw->len);
7564245274Snp	if (rc == 0)
7565245274Snp		rc = -t4_load_fw(sc, fw_data, fw->len);
7566245274Snp
7567245274Snp	free(fw_data, M_CXGBE);
7568245274Snpdone:
7569245274Snp	end_synchronized_op(sc, 0);
7570222973Snp	return (rc);
7571222973Snp}
7572222973Snp
7573228561Snpstatic int
7574248925Snpread_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr)
7575228561Snp{
7576248925Snp	uint32_t addr, off, remaining, i, n;
7577228561Snp	uint32_t *buf, *b;
7578248925Snp	uint32_t mw_base, mw_aperture;
7579228561Snp	int rc;
7580248925Snp	uint8_t *dst;
7581228561Snp
7582248925Snp	rc = validate_mem_range(sc, mr->addr, mr->len);
7583248925Snp	if (rc != 0)
7584248925Snp		return (rc);
7585228561Snp
7586248925Snp	memwin_info(sc, win, &mw_base, &mw_aperture);
7587248925Snp	buf = b = malloc(min(mr->len, mw_aperture), M_CXGBE, M_WAITOK);
7588248925Snp	addr = mr->addr;
7589228561Snp	remaining = mr->len;
7590248925Snp	dst = (void *)mr->data;
7591228561Snp
7592228561Snp	while (remaining) {
7593248925Snp		off = position_memwin(sc, win, addr);
7594228561Snp
7595228561Snp		/* number of bytes that we'll copy in the inner loop */
7596248925Snp		n = min(remaining, mw_aperture - off);
7597248925Snp		for (i = 0; i < n; i += 4)
7598248925Snp			*b++ = t4_read_reg(sc, mw_base + off + i);
7599228561Snp
7600248925Snp		rc = copyout(buf, dst, n);
7601248925Snp		if (rc != 0)
7602248925Snp			break;
7603228561Snp
7604248925Snp		b = buf;
7605248925Snp		dst += n;
7606248925Snp		remaining -= n;
7607248925Snp		addr += n;
7608228561Snp	}
7609228561Snp
7610228561Snp	free(buf, M_CXGBE);
7611228561Snp	return (rc);
7612228561Snp}
7613228561Snp
7614241399Snpstatic int
7615241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd)
7616241399Snp{
7617241399Snp	int rc;
7618241399Snp
7619241399Snp	if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports)
7620241399Snp		return (EINVAL);
7621241399Snp
7622269082Snp	if (i2cd->len > sizeof(i2cd->data))
7623269082Snp		return (EFBIG);
7624241399Snp
7625245274Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd");
7626245274Snp	if (rc)
7627245274Snp		return (rc);
7628241399Snp	rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr,
7629269082Snp	    i2cd->offset, i2cd->len, &i2cd->data[0]);
7630245274Snp	end_synchronized_op(sc, 0);
7631241399Snp
7632241399Snp	return (rc);
7633241399Snp}
7634241399Snp
7635259142Snpstatic int
7636259142Snpin_range(int val, int lo, int hi)
7637259142Snp{
7638259142Snp
7639259142Snp	return (val < 0 || (val <= hi && val >= lo));
7640259142Snp}
7641259142Snp
7642259142Snpstatic int
7643259142Snpset_sched_class(struct adapter *sc, struct t4_sched_params *p)
7644259142Snp{
7645259142Snp	int fw_subcmd, fw_type, rc;
7646259142Snp
7647259142Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsc");
7648259142Snp	if (rc)
7649259142Snp		return (rc);
7650259142Snp
7651259142Snp	if (!(sc->flags & FULL_INIT_DONE)) {
7652259142Snp		rc = EAGAIN;
7653259142Snp		goto done;
7654259142Snp	}
7655259142Snp
7656259142Snp	/*
7657259142Snp	 * Translate the cxgbetool parameters into T4 firmware parameters.  (The
7658259142Snp	 * sub-command and type are in common locations.)
7659259142Snp	 */
7660259142Snp	if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG)
7661259142Snp		fw_subcmd = FW_SCHED_SC_CONFIG;
7662259142Snp	else if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS)
7663259142Snp		fw_subcmd = FW_SCHED_SC_PARAMS;
7664259142Snp	else {
7665259142Snp		rc = EINVAL;
7666259142Snp		goto done;
7667259142Snp	}
7668259142Snp	if (p->type == SCHED_CLASS_TYPE_PACKET)
7669259142Snp		fw_type = FW_SCHED_TYPE_PKTSCHED;
7670259142Snp	else {
7671259142Snp		rc = EINVAL;
7672259142Snp		goto done;
7673259142Snp	}
7674259142Snp
7675259142Snp	if (fw_subcmd == FW_SCHED_SC_CONFIG) {
7676259142Snp		/* Vet our parameters ..*/
7677259142Snp		if (p->u.config.minmax < 0) {
7678259142Snp			rc = EINVAL;
7679259142Snp			goto done;
7680259142Snp		}
7681259142Snp
7682259142Snp		/* And pass the request to the firmware ...*/
7683270297Snp		rc = -t4_sched_config(sc, fw_type, p->u.config.minmax, 1);
7684259142Snp		goto done;
7685259142Snp	}
7686259142Snp
7687259142Snp	if (fw_subcmd == FW_SCHED_SC_PARAMS) {
7688259142Snp		int fw_level;
7689259142Snp		int fw_mode;
7690259142Snp		int fw_rateunit;
7691259142Snp		int fw_ratemode;
7692259142Snp
7693259142Snp		if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL)
7694259142Snp			fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL;
7695259142Snp		else if (p->u.params.level == SCHED_CLASS_LEVEL_CL_WRR)
7696259142Snp			fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
7697259142Snp		else if (p->u.params.level == SCHED_CLASS_LEVEL_CH_RL)
7698259142Snp			fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL;
7699259142Snp		else {
7700259142Snp			rc = EINVAL;
7701259142Snp			goto done;
7702259142Snp		}
7703259142Snp
7704259142Snp		if (p->u.params.mode == SCHED_CLASS_MODE_CLASS)
7705259142Snp			fw_mode = FW_SCHED_PARAMS_MODE_CLASS;
7706259142Snp		else if (p->u.params.mode == SCHED_CLASS_MODE_FLOW)
7707259142Snp			fw_mode = FW_SCHED_PARAMS_MODE_FLOW;
7708259142Snp		else {
7709259142Snp			rc = EINVAL;
7710259142Snp			goto done;
7711259142Snp		}
7712259142Snp
7713259142Snp		if (p->u.params.rateunit == SCHED_CLASS_RATEUNIT_BITS)
7714259142Snp			fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
7715259142Snp		else if (p->u.params.rateunit == SCHED_CLASS_RATEUNIT_PKTS)
7716259142Snp			fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE;
7717259142Snp		else {
7718259142Snp			rc = EINVAL;
7719259142Snp			goto done;
7720259142Snp		}
7721259142Snp
7722259142Snp		if (p->u.params.ratemode == SCHED_CLASS_RATEMODE_REL)
7723259142Snp			fw_ratemode = FW_SCHED_PARAMS_RATE_REL;
7724259142Snp		else if (p->u.params.ratemode == SCHED_CLASS_RATEMODE_ABS)
7725259142Snp			fw_ratemode = FW_SCHED_PARAMS_RATE_ABS;
7726259142Snp		else {
7727259142Snp			rc = EINVAL;
7728259142Snp			goto done;
7729259142Snp		}
7730259142Snp
7731259142Snp		/* Vet our parameters ... */
7732259142Snp		if (!in_range(p->u.params.channel, 0, 3) ||
7733259142Snp		    !in_range(p->u.params.cl, 0, is_t4(sc) ? 15 : 16) ||
7734259142Snp		    !in_range(p->u.params.minrate, 0, 10000000) ||
7735259142Snp		    !in_range(p->u.params.maxrate, 0, 10000000) ||
7736259142Snp		    !in_range(p->u.params.weight, 0, 100)) {
7737259142Snp			rc = ERANGE;
7738259142Snp			goto done;
7739259142Snp		}
7740259142Snp
7741259142Snp		/*
7742259142Snp		 * Translate any unset parameters into the firmware's
7743259142Snp		 * nomenclature and/or fail the call if the parameters
7744259142Snp		 * are required ...
7745259142Snp		 */
7746259142Snp		if (p->u.params.rateunit < 0 || p->u.params.ratemode < 0 ||
7747259142Snp		    p->u.params.channel < 0 || p->u.params.cl < 0) {
7748259142Snp			rc = EINVAL;
7749259142Snp			goto done;
7750259142Snp		}
7751259142Snp		if (p->u.params.minrate < 0)
7752259142Snp			p->u.params.minrate = 0;
7753259142Snp		if (p->u.params.maxrate < 0) {
7754259142Snp			if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL ||
7755259142Snp			    p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) {
7756259142Snp				rc = EINVAL;
7757259142Snp				goto done;
7758259142Snp			} else
7759259142Snp				p->u.params.maxrate = 0;
7760259142Snp		}
7761259142Snp		if (p->u.params.weight < 0) {
7762259142Snp			if (p->u.params.level == SCHED_CLASS_LEVEL_CL_WRR) {
7763259142Snp				rc = EINVAL;
7764259142Snp				goto done;
7765259142Snp			} else
7766259142Snp				p->u.params.weight = 0;
7767259142Snp		}
7768259142Snp		if (p->u.params.pktsize < 0) {
7769259142Snp			if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL ||
7770259142Snp			    p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) {
7771259142Snp				rc = EINVAL;
7772259142Snp				goto done;
7773259142Snp			} else
7774259142Snp				p->u.params.pktsize = 0;
7775259142Snp		}
7776259142Snp
7777259142Snp		/* See what the firmware thinks of the request ... */
7778259142Snp		rc = -t4_sched_params(sc, fw_type, fw_level, fw_mode,
7779259142Snp		    fw_rateunit, fw_ratemode, p->u.params.channel,
7780259142Snp		    p->u.params.cl, p->u.params.minrate, p->u.params.maxrate,
7781270297Snp		    p->u.params.weight, p->u.params.pktsize, 1);
7782259142Snp		goto done;
7783259142Snp	}
7784259142Snp
7785259142Snp	rc = EINVAL;
7786259142Snpdone:
7787259142Snp	end_synchronized_op(sc, 0);
7788259142Snp	return (rc);
7789259142Snp}
7790259142Snp
7791259142Snpstatic int
7792259142Snpset_sched_queue(struct adapter *sc, struct t4_sched_queue *p)
7793259142Snp{
7794259142Snp	struct port_info *pi = NULL;
7795259142Snp	struct sge_txq *txq;
7796259142Snp	uint32_t fw_mnem, fw_queue, fw_class;
7797259142Snp	int i, rc;
7798259142Snp
7799259142Snp	rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq");
7800259142Snp	if (rc)
7801259142Snp		return (rc);
7802259142Snp
7803259142Snp	if (!(sc->flags & FULL_INIT_DONE)) {
7804259142Snp		rc = EAGAIN;
7805259142Snp		goto done;
7806259142Snp	}
7807259142Snp
7808259142Snp	if (p->port >= sc->params.nports) {
7809259142Snp		rc = EINVAL;
7810259142Snp		goto done;
7811259142Snp	}
7812259142Snp
7813259142Snp	pi = sc->port[p->port];
7814259142Snp	if (!in_range(p->queue, 0, pi->ntxq - 1) || !in_range(p->cl, 0, 7)) {
7815259142Snp		rc = EINVAL;
7816259142Snp		goto done;
7817259142Snp	}
7818259142Snp
7819259142Snp	/*
7820259142Snp	 * Create a template for the FW_PARAMS_CMD mnemonic and value (TX
7821259142Snp	 * Scheduling Class in this case).
7822259142Snp	 */
7823259142Snp	fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
7824259142Snp	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH));
7825259142Snp	fw_class = p->cl < 0 ? 0xffffffff : p->cl;
7826259142Snp
7827259142Snp	/*
7828259142Snp	 * If op.queue is non-negative, then we're only changing the scheduling
7829259142Snp	 * on a single specified TX queue.
7830259142Snp	 */
7831259142Snp	if (p->queue >= 0) {
7832259142Snp		txq = &sc->sge.txq[pi->first_txq + p->queue];
7833259142Snp		fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id));
7834259142Snp		rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue,
7835259142Snp		    &fw_class);
7836259142Snp		goto done;
7837259142Snp	}
7838259142Snp
7839259142Snp	/*
7840259142Snp	 * Change the scheduling on all the TX queues for the
7841259142Snp	 * interface.
7842259142Snp	 */
7843259142Snp	for_each_txq(pi, i, txq) {
7844259142Snp		fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id));
7845259142Snp		rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue,
7846259142Snp		    &fw_class);
7847259142Snp		if (rc)
7848259142Snp			goto done;
7849259142Snp	}
7850259142Snp
7851259142Snp	rc = 0;
7852259142Snpdone:
7853259142Snp	end_synchronized_op(sc, 0);
7854259142Snp	return (rc);
7855259142Snp}
7856259142Snp
7857218792Snpint
7858218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap)
7859218792Snp{
7860222102Snp	int i;
7861218792Snp
7862222102Snp	return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0);
7863218792Snp}
7864218792Snp
7865218792Snpint
7866218792Snpt4_os_pci_save_state(struct adapter *sc)
7867218792Snp{
7868218792Snp	device_t dev;
7869218792Snp	struct pci_devinfo *dinfo;
7870218792Snp
7871218792Snp	dev = sc->dev;
7872218792Snp	dinfo = device_get_ivars(dev);
7873218792Snp
7874218792Snp	pci_cfg_save(dev, dinfo, 0);
7875218792Snp	return (0);
7876218792Snp}
7877218792Snp
7878218792Snpint
7879218792Snpt4_os_pci_restore_state(struct adapter *sc)
7880218792Snp{
7881218792Snp	device_t dev;
7882218792Snp	struct pci_devinfo *dinfo;
7883218792Snp
7884218792Snp	dev = sc->dev;
7885218792Snp	dinfo = device_get_ivars(dev);
7886218792Snp
7887218792Snp	pci_cfg_restore(dev, dinfo);
7888218792Snp	return (0);
7889218792Snp}
7890219299Snp
7891218792Snpvoid
7892218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx)
7893218792Snp{
7894218792Snp	struct port_info *pi = sc->port[idx];
7895218792Snp	static const char *mod_str[] = {
7896220232Snp		NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
7897218792Snp	};
7898218792Snp
7899218792Snp	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
7900218792Snp		if_printf(pi->ifp, "transceiver unplugged.\n");
7901220232Snp	else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
7902220232Snp		if_printf(pi->ifp, "unknown transceiver inserted.\n");
7903220232Snp	else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
7904220232Snp		if_printf(pi->ifp, "unsupported transceiver inserted.\n");
7905240452Snp	else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) {
7906218792Snp		if_printf(pi->ifp, "%s transceiver inserted.\n",
7907218792Snp		    mod_str[pi->mod_type]);
7908219299Snp	} else {
7909219299Snp		if_printf(pi->ifp, "transceiver (type %d) inserted.\n",
7910219299Snp		    pi->mod_type);
7911219299Snp	}
7912218792Snp}
7913218792Snp
7914218792Snpvoid
7915252747Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat, int reason)
7916218792Snp{
7917218792Snp	struct port_info *pi = sc->port[idx];
7918218792Snp	struct ifnet *ifp = pi->ifp;
7919218792Snp
7920218792Snp	if (link_stat) {
7921252747Snp		pi->linkdnrc = -1;
7922218792Snp		ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed);
7923218792Snp		if_link_state_change(ifp, LINK_STATE_UP);
7924252747Snp	} else {
7925252747Snp		if (reason >= 0)
7926252747Snp			pi->linkdnrc = reason;
7927218792Snp		if_link_state_change(ifp, LINK_STATE_DOWN);
7928252747Snp	}
7929218792Snp}
7930218792Snp
7931228561Snpvoid
7932228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg)
7933228561Snp{
7934228561Snp	struct adapter *sc;
7935228561Snp
7936255006Snp	sx_slock(&t4_list_lock);
7937228561Snp	SLIST_FOREACH(sc, &t4_list, link) {
7938228561Snp		/*
7939228561Snp		 * func should not make any assumptions about what state sc is
7940228561Snp		 * in - the only guarantee is that sc->sc_lock is a valid lock.
7941228561Snp		 */
7942228561Snp		func(sc, arg);
7943228561Snp	}
7944255006Snp	sx_sunlock(&t4_list_lock);
7945228561Snp}
7946228561Snp
7947218792Snpstatic int
7948218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td)
7949218792Snp{
7950218792Snp       return (0);
7951218792Snp}
7952218792Snp
7953218792Snpstatic int
7954218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td)
7955218792Snp{
7956218792Snp       return (0);
7957218792Snp}
7958218792Snp
7959218792Snpstatic int
7960218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag,
7961218792Snp    struct thread *td)
7962218792Snp{
7963218792Snp	int rc;
7964218792Snp	struct adapter *sc = dev->si_drv1;
7965218792Snp
7966218792Snp	rc = priv_check(td, PRIV_DRIVER);
7967218792Snp	if (rc != 0)
7968218792Snp		return (rc);
7969218792Snp
7970218792Snp	switch (cmd) {
7971220410Snp	case CHELSIO_T4_GETREG: {
7972220410Snp		struct t4_reg *edata = (struct t4_reg *)data;
7973220410Snp
7974218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
7975218792Snp			return (EFAULT);
7976220410Snp
7977220410Snp		if (edata->size == 4)
7978220410Snp			edata->val = t4_read_reg(sc, edata->addr);
7979220410Snp		else if (edata->size == 8)
7980220410Snp			edata->val = t4_read_reg64(sc, edata->addr);
7981220410Snp		else
7982220410Snp			return (EINVAL);
7983220410Snp
7984218792Snp		break;
7985218792Snp	}
7986220410Snp	case CHELSIO_T4_SETREG: {
7987220410Snp		struct t4_reg *edata = (struct t4_reg *)data;
7988220410Snp
7989218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
7990218792Snp			return (EFAULT);
7991220410Snp
7992220410Snp		if (edata->size == 4) {
7993220410Snp			if (edata->val & 0xffffffff00000000)
7994220410Snp				return (EINVAL);
7995220410Snp			t4_write_reg(sc, edata->addr, (uint32_t) edata->val);
7996220410Snp		} else if (edata->size == 8)
7997220410Snp			t4_write_reg64(sc, edata->addr, edata->val);
7998220410Snp		else
7999220410Snp			return (EINVAL);
8000218792Snp		break;
8001218792Snp	}
8002218792Snp	case CHELSIO_T4_REGDUMP: {
8003218792Snp		struct t4_regdump *regs = (struct t4_regdump *)data;
8004248925Snp		int reglen = is_t4(sc) ? T4_REGDUMP_SIZE : T5_REGDUMP_SIZE;
8005218792Snp		uint8_t *buf;
8006218792Snp
8007218792Snp		if (regs->len < reglen) {
8008218792Snp			regs->len = reglen; /* hint to the caller */
8009218792Snp			return (ENOBUFS);
8010218792Snp		}
8011218792Snp
8012218792Snp		regs->len = reglen;
8013218792Snp		buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO);
8014218792Snp		t4_get_regs(sc, regs, buf);
8015218792Snp		rc = copyout(buf, regs->data, reglen);
8016218792Snp		free(buf, M_CXGBE);
8017218792Snp		break;
8018218792Snp	}
8019221474Snp	case CHELSIO_T4_GET_FILTER_MODE:
8020221474Snp		rc = get_filter_mode(sc, (uint32_t *)data);
8021221474Snp		break;
8022221474Snp	case CHELSIO_T4_SET_FILTER_MODE:
8023221474Snp		rc = set_filter_mode(sc, *(uint32_t *)data);
8024221474Snp		break;
8025221474Snp	case CHELSIO_T4_GET_FILTER:
8026221474Snp		rc = get_filter(sc, (struct t4_filter *)data);
8027221474Snp		break;
8028221474Snp	case CHELSIO_T4_SET_FILTER:
8029221474Snp		rc = set_filter(sc, (struct t4_filter *)data);
8030221474Snp		break;
8031221474Snp	case CHELSIO_T4_DEL_FILTER:
8032221474Snp		rc = del_filter(sc, (struct t4_filter *)data);
8033221474Snp		break;
8034222973Snp	case CHELSIO_T4_GET_SGE_CONTEXT:
8035222973Snp		rc = get_sge_context(sc, (struct t4_sge_context *)data);
8036222973Snp		break;
8037245274Snp	case CHELSIO_T4_LOAD_FW:
8038245274Snp		rc = load_fw(sc, (struct t4_data *)data);
8039228561Snp		break;
8040228561Snp	case CHELSIO_T4_GET_MEM:
8041248925Snp		rc = read_card_mem(sc, 2, (struct t4_mem_range *)data);
8042228561Snp		break;
8043241399Snp	case CHELSIO_T4_GET_I2C:
8044241399Snp		rc = read_i2c(sc, (struct t4_i2c_data *)data);
8045241399Snp		break;
8046241409Snp	case CHELSIO_T4_CLEAR_STATS: {
8047245518Snp		int i;
8048241409Snp		u_int port_id = *(uint32_t *)data;
8049245518Snp		struct port_info *pi;
8050241409Snp
8051241409Snp		if (port_id >= sc->params.nports)
8052241409Snp			return (EINVAL);
8053265410Snp		pi = sc->port[port_id];
8054241409Snp
8055245518Snp		/* MAC stats */
8056265410Snp		t4_clr_port_stats(sc, pi->tx_chan);
8057245518Snp
8058245518Snp		if (pi->flags & PORT_INIT_DONE) {
8059245518Snp			struct sge_rxq *rxq;
8060245518Snp			struct sge_txq *txq;
8061245518Snp			struct sge_wrq *wrq;
8062245518Snp
8063245518Snp			for_each_rxq(pi, i, rxq) {
8064245518Snp#if defined(INET) || defined(INET6)
8065245518Snp				rxq->lro.lro_queued = 0;
8066245518Snp				rxq->lro.lro_flushed = 0;
8067245518Snp#endif
8068245518Snp				rxq->rxcsum = 0;
8069245518Snp				rxq->vlan_extraction = 0;
8070245518Snp			}
8071245518Snp
8072245518Snp			for_each_txq(pi, i, txq) {
8073245518Snp				txq->txcsum = 0;
8074245518Snp				txq->tso_wrs = 0;
8075245518Snp				txq->vlan_insertion = 0;
8076245518Snp				txq->imm_wrs = 0;
8077245518Snp				txq->sgl_wrs = 0;
8078245518Snp				txq->txpkt_wrs = 0;
8079245518Snp				txq->txpkts_wrs = 0;
8080245518Snp				txq->txpkts_pkts = 0;
8081246093Snp				txq->br->br_drops = 0;
8082245518Snp				txq->no_dmamap = 0;
8083245518Snp				txq->no_desc = 0;
8084245518Snp			}
8085245518Snp
8086245518Snp#ifdef TCP_OFFLOAD
8087245518Snp			/* nothing to clear for each ofld_rxq */
8088245518Snp
8089245518Snp			for_each_ofld_txq(pi, i, wrq) {
8090245518Snp				wrq->tx_wrs = 0;
8091245518Snp				wrq->no_desc = 0;
8092245518Snp			}
8093245518Snp#endif
8094245518Snp			wrq = &sc->sge.ctrlq[pi->port_id];
8095245518Snp			wrq->tx_wrs = 0;
8096245518Snp			wrq->no_desc = 0;
8097245518Snp		}
8098241409Snp		break;
8099241409Snp	}
8100259142Snp	case CHELSIO_T4_SCHED_CLASS:
8101259142Snp		rc = set_sched_class(sc, (struct t4_sched_params *)data);
8102259142Snp		break;
8103259142Snp	case CHELSIO_T4_SCHED_QUEUE:
8104259142Snp		rc = set_sched_queue(sc, (struct t4_sched_queue *)data);
8105259142Snp		break;
8106253691Snp	case CHELSIO_T4_GET_TRACER:
8107253691Snp		rc = t4_get_tracer(sc, (struct t4_tracer *)data);
8108253691Snp		break;
8109253691Snp	case CHELSIO_T4_SET_TRACER:
8110253691Snp		rc = t4_set_tracer(sc, (struct t4_tracer *)data);
8111253691Snp		break;
8112218792Snp	default:
8113218792Snp		rc = EINVAL;
8114218792Snp	}
8115218792Snp
8116218792Snp	return (rc);
8117218792Snp}
8118218792Snp
8119237263Snp#ifdef TCP_OFFLOAD
8120270297Snpvoid
8121270297Snpt4_iscsi_init(struct ifnet *ifp, unsigned int tag_mask,
8122270297Snp    const unsigned int *pgsz_order)
8123270297Snp{
8124270297Snp	struct port_info *pi = ifp->if_softc;
8125270297Snp	struct adapter *sc = pi->adapter;
8126270297Snp
8127270297Snp	t4_write_reg(sc, A_ULP_RX_ISCSI_TAGMASK, tag_mask);
8128270297Snp	t4_write_reg(sc, A_ULP_RX_ISCSI_PSZ, V_HPZ0(pgsz_order[0]) |
8129270297Snp		V_HPZ1(pgsz_order[1]) | V_HPZ2(pgsz_order[2]) |
8130270297Snp		V_HPZ3(pgsz_order[3]));
8131270297Snp}
8132270297Snp
8133219392Snpstatic int
8134228561Snptoe_capability(struct port_info *pi, int enable)
8135228561Snp{
8136228561Snp	int rc;
8137228561Snp	struct adapter *sc = pi->adapter;
8138228561Snp
8139245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
8140228561Snp
8141228561Snp	if (!is_offload(sc))
8142228561Snp		return (ENODEV);
8143228561Snp
8144228561Snp	if (enable) {
8145237263Snp		if (!(sc->flags & FULL_INIT_DONE)) {
8146245274Snp			rc = cxgbe_init_synchronized(pi);
8147245274Snp			if (rc)
8148245274Snp				return (rc);
8149237263Snp		}
8150237263Snp
8151228561Snp		if (isset(&sc->offload_map, pi->port_id))
8152228561Snp			return (0);
8153228561Snp
8154237263Snp		if (!(sc->flags & TOM_INIT_DONE)) {
8155237263Snp			rc = t4_activate_uld(sc, ULD_TOM);
8156237263Snp			if (rc == EAGAIN) {
8157237263Snp				log(LOG_WARNING,
8158237263Snp				    "You must kldload t4_tom.ko before trying "
8159237263Snp				    "to enable TOE on a cxgbe interface.\n");
8160237263Snp			}
8161228561Snp			if (rc != 0)
8162228561Snp				return (rc);
8163237263Snp			KASSERT(sc->tom_softc != NULL,
8164237263Snp			    ("%s: TOM activated but softc NULL", __func__));
8165237263Snp			KASSERT(sc->flags & TOM_INIT_DONE,
8166237263Snp			    ("%s: TOM activated but flag not set", __func__));
8167228561Snp		}
8168228561Snp
8169228561Snp		setbit(&sc->offload_map, pi->port_id);
8170228561Snp	} else {
8171228561Snp		if (!isset(&sc->offload_map, pi->port_id))
8172228561Snp			return (0);
8173228561Snp
8174237263Snp		KASSERT(sc->flags & TOM_INIT_DONE,
8175237263Snp		    ("%s: TOM never initialized?", __func__));
8176228561Snp		clrbit(&sc->offload_map, pi->port_id);
8177228561Snp	}
8178228561Snp
8179228561Snp	return (0);
8180228561Snp}
8181228561Snp
8182228561Snp/*
8183228561Snp * Add an upper layer driver to the global list.
8184228561Snp */
8185228561Snpint
8186228561Snpt4_register_uld(struct uld_info *ui)
8187228561Snp{
8188228561Snp	int rc = 0;
8189228561Snp	struct uld_info *u;
8190228561Snp
8191255006Snp	sx_xlock(&t4_uld_list_lock);
8192228561Snp	SLIST_FOREACH(u, &t4_uld_list, link) {
8193228561Snp	    if (u->uld_id == ui->uld_id) {
8194228561Snp		    rc = EEXIST;
8195228561Snp		    goto done;
8196228561Snp	    }
8197228561Snp	}
8198228561Snp
8199228561Snp	SLIST_INSERT_HEAD(&t4_uld_list, ui, link);
8200228561Snp	ui->refcount = 0;
8201228561Snpdone:
8202255006Snp	sx_xunlock(&t4_uld_list_lock);
8203228561Snp	return (rc);
8204228561Snp}
8205228561Snp
8206228561Snpint
8207228561Snpt4_unregister_uld(struct uld_info *ui)
8208228561Snp{
8209228561Snp	int rc = EINVAL;
8210228561Snp	struct uld_info *u;
8211228561Snp
8212255006Snp	sx_xlock(&t4_uld_list_lock);
8213228561Snp
8214228561Snp	SLIST_FOREACH(u, &t4_uld_list, link) {
8215228561Snp	    if (u == ui) {
8216228561Snp		    if (ui->refcount > 0) {
8217228561Snp			    rc = EBUSY;
8218228561Snp			    goto done;
8219228561Snp		    }
8220228561Snp
8221228561Snp		    SLIST_REMOVE(&t4_uld_list, ui, uld_info, link);
8222228561Snp		    rc = 0;
8223228561Snp		    goto done;
8224228561Snp	    }
8225228561Snp	}
8226228561Snpdone:
8227255006Snp	sx_xunlock(&t4_uld_list_lock);
8228228561Snp	return (rc);
8229228561Snp}
8230228561Snp
8231237263Snpint
8232237263Snpt4_activate_uld(struct adapter *sc, int id)
8233228561Snp{
8234228561Snp	int rc = EAGAIN;
8235228561Snp	struct uld_info *ui;
8236228561Snp
8237245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
8238245274Snp
8239255006Snp	sx_slock(&t4_uld_list_lock);
8240228561Snp
8241228561Snp	SLIST_FOREACH(ui, &t4_uld_list, link) {
8242228561Snp		if (ui->uld_id == id) {
8243237263Snp			rc = ui->activate(sc);
8244237263Snp			if (rc == 0)
8245228561Snp				ui->refcount++;
8246228561Snp			goto done;
8247228561Snp		}
8248228561Snp	}
8249228561Snpdone:
8250255006Snp	sx_sunlock(&t4_uld_list_lock);
8251228561Snp
8252228561Snp	return (rc);
8253228561Snp}
8254228561Snp
8255237263Snpint
8256237263Snpt4_deactivate_uld(struct adapter *sc, int id)
8257228561Snp{
8258237263Snp	int rc = EINVAL;
8259237263Snp	struct uld_info *ui;
8260228561Snp
8261245274Snp	ASSERT_SYNCHRONIZED_OP(sc);
8262245274Snp
8263255006Snp	sx_slock(&t4_uld_list_lock);
8264228561Snp
8265237263Snp	SLIST_FOREACH(ui, &t4_uld_list, link) {
8266237263Snp		if (ui->uld_id == id) {
8267237263Snp			rc = ui->deactivate(sc);
8268237263Snp			if (rc == 0)
8269237263Snp				ui->refcount--;
8270237263Snp			goto done;
8271237263Snp		}
8272228561Snp	}
8273228561Snpdone:
8274255006Snp	sx_sunlock(&t4_uld_list_lock);
8275228561Snp
8276228561Snp	return (rc);
8277228561Snp}
8278228561Snp#endif
8279228561Snp
8280228561Snp/*
8281228561Snp * Come up with reasonable defaults for some of the tunables, provided they're
8282228561Snp * not set by the user (in which case we'll use the values as is).
8283228561Snp */
8284228561Snpstatic void
8285228561Snptweak_tunables(void)
8286228561Snp{
8287228561Snp	int nc = mp_ncpus;	/* our snapshot of the number of CPUs */
8288228561Snp
8289228561Snp	if (t4_ntxq10g < 1)
8290228561Snp		t4_ntxq10g = min(nc, NTXQ_10G);
8291228561Snp
8292228561Snp	if (t4_ntxq1g < 1)
8293228561Snp		t4_ntxq1g = min(nc, NTXQ_1G);
8294228561Snp
8295228561Snp	if (t4_nrxq10g < 1)
8296228561Snp		t4_nrxq10g = min(nc, NRXQ_10G);
8297228561Snp
8298228561Snp	if (t4_nrxq1g < 1)
8299228561Snp		t4_nrxq1g = min(nc, NRXQ_1G);
8300228561Snp
8301237263Snp#ifdef TCP_OFFLOAD
8302228561Snp	if (t4_nofldtxq10g < 1)
8303228561Snp		t4_nofldtxq10g = min(nc, NOFLDTXQ_10G);
8304228561Snp
8305228561Snp	if (t4_nofldtxq1g < 1)
8306228561Snp		t4_nofldtxq1g = min(nc, NOFLDTXQ_1G);
8307228561Snp
8308228561Snp	if (t4_nofldrxq10g < 1)
8309228561Snp		t4_nofldrxq10g = min(nc, NOFLDRXQ_10G);
8310228561Snp
8311228561Snp	if (t4_nofldrxq1g < 1)
8312228561Snp		t4_nofldrxq1g = min(nc, NOFLDRXQ_1G);
8313238028Snp
8314238028Snp	if (t4_toecaps_allowed == -1)
8315238028Snp		t4_toecaps_allowed = FW_CAPS_CONFIG_TOE;
8316238028Snp#else
8317238028Snp	if (t4_toecaps_allowed == -1)
8318238028Snp		t4_toecaps_allowed = 0;
8319228561Snp#endif
8320228561Snp
8321270297Snp#ifdef DEV_NETMAP
8322270297Snp	if (t4_nnmtxq10g < 1)
8323270297Snp		t4_nnmtxq10g = min(nc, NNMTXQ_10G);
8324270297Snp
8325270297Snp	if (t4_nnmtxq1g < 1)
8326270297Snp		t4_nnmtxq1g = min(nc, NNMTXQ_1G);
8327270297Snp
8328270297Snp	if (t4_nnmrxq10g < 1)
8329270297Snp		t4_nnmrxq10g = min(nc, NNMRXQ_10G);
8330270297Snp
8331270297Snp	if (t4_nnmrxq1g < 1)
8332270297Snp		t4_nnmrxq1g = min(nc, NNMRXQ_1G);
8333270297Snp#endif
8334270297Snp
8335228561Snp	if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS)
8336228561Snp		t4_tmr_idx_10g = TMR_IDX_10G;
8337228561Snp
8338228561Snp	if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS)
8339228561Snp		t4_pktc_idx_10g = PKTC_IDX_10G;
8340228561Snp
8341228561Snp	if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS)
8342228561Snp		t4_tmr_idx_1g = TMR_IDX_1G;
8343228561Snp
8344228561Snp	if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS)
8345228561Snp		t4_pktc_idx_1g = PKTC_IDX_1G;
8346228561Snp
8347228561Snp	if (t4_qsize_txq < 128)
8348228561Snp		t4_qsize_txq = 128;
8349228561Snp
8350228561Snp	if (t4_qsize_rxq < 128)
8351228561Snp		t4_qsize_rxq = 128;
8352228561Snp	while (t4_qsize_rxq & 7)
8353228561Snp		t4_qsize_rxq++;
8354228561Snp
8355228561Snp	t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX;
8356228561Snp}
8357228561Snp
8358269356Snpstatic struct sx mlu;	/* mod load unload */
8359269356SnpSX_SYSINIT(cxgbe_mlu, &mlu, "cxgbe mod load/unload");
8360269356Snp
8361228561Snpstatic int
8362249370Snpmod_event(module_t mod, int cmd, void *arg)
8363219392Snp{
8364228561Snp	int rc = 0;
8365249370Snp	static int loaded = 0;
8366219392Snp
8367228561Snp	switch (cmd) {
8368228561Snp	case MOD_LOAD:
8369269356Snp		sx_xlock(&mlu);
8370269356Snp		if (loaded++ == 0) {
8371269356Snp			t4_sge_modload();
8372269356Snp			sx_init(&t4_list_lock, "T4/T5 adapters");
8373269356Snp			SLIST_INIT(&t4_list);
8374237263Snp#ifdef TCP_OFFLOAD
8375269356Snp			sx_init(&t4_uld_list_lock, "T4/T5 ULDs");
8376269356Snp			SLIST_INIT(&t4_uld_list);
8377228561Snp#endif
8378269356Snp			t4_tracer_modload();
8379269356Snp			tweak_tunables();
8380269356Snp		}
8381269356Snp		sx_xunlock(&mlu);
8382228561Snp		break;
8383219392Snp
8384228561Snp	case MOD_UNLOAD:
8385269356Snp		sx_xlock(&mlu);
8386269356Snp		if (--loaded == 0) {
8387269356Snp			int tries;
8388269356Snp
8389269356Snp			sx_slock(&t4_list_lock);
8390269356Snp			if (!SLIST_EMPTY(&t4_list)) {
8391269356Snp				rc = EBUSY;
8392269356Snp				sx_sunlock(&t4_list_lock);
8393269356Snp				goto done_unload;
8394269356Snp			}
8395237263Snp#ifdef TCP_OFFLOAD
8396269356Snp			sx_slock(&t4_uld_list_lock);
8397269356Snp			if (!SLIST_EMPTY(&t4_uld_list)) {
8398269356Snp				rc = EBUSY;
8399269356Snp				sx_sunlock(&t4_uld_list_lock);
8400269356Snp				sx_sunlock(&t4_list_lock);
8401269356Snp				goto done_unload;
8402269356Snp			}
8403269356Snp#endif
8404269356Snp			tries = 0;
8405269356Snp			while (tries++ < 5 && t4_sge_extfree_refs() != 0) {
8406269356Snp				uprintf("%ju clusters with custom free routine "
8407269356Snp				    "still is use.\n", t4_sge_extfree_refs());
8408269356Snp				pause("t4unload", 2 * hz);
8409269356Snp			}
8410269356Snp#ifdef TCP_OFFLOAD
8411255006Snp			sx_sunlock(&t4_uld_list_lock);
8412228561Snp#endif
8413255006Snp			sx_sunlock(&t4_list_lock);
8414269356Snp
8415269356Snp			if (t4_sge_extfree_refs() == 0) {
8416269356Snp				t4_tracer_modunload();
8417269356Snp#ifdef TCP_OFFLOAD
8418269356Snp				sx_destroy(&t4_uld_list_lock);
8419269356Snp#endif
8420269356Snp				sx_destroy(&t4_list_lock);
8421269356Snp				t4_sge_modunload();
8422269356Snp				loaded = 0;
8423269356Snp			} else {
8424269356Snp				rc = EBUSY;
8425269356Snp				loaded++;	/* undo earlier decrement */
8426269356Snp			}
8427228561Snp		}
8428269356Snpdone_unload:
8429269356Snp		sx_xunlock(&mlu);
8430228561Snp		break;
8431228561Snp	}
8432228561Snp
8433228561Snp	return (rc);
8434219392Snp}
8435219392Snp
8436248925Snpstatic devclass_t t4_devclass, t5_devclass;
8437248925Snpstatic devclass_t cxgbe_devclass, cxl_devclass;
8438218792Snp
8439249370SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, mod_event, 0);
8440218792SnpMODULE_VERSION(t4nex, 1);
8441250697SkibMODULE_DEPEND(t4nex, firmware, 1, 1, 1);
8442218792Snp
8443249370SnpDRIVER_MODULE(t5nex, pci, t5_driver, t5_devclass, mod_event, 0);
8444248925SnpMODULE_VERSION(t5nex, 1);
8445250697SkibMODULE_DEPEND(t5nex, firmware, 1, 1, 1);
8446248925Snp
8447218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0);
8448218792SnpMODULE_VERSION(cxgbe, 1);
8449248925Snp
8450248925SnpDRIVER_MODULE(cxl, t5nex, cxl_driver, cxl_devclass, 0, 0);
8451248925SnpMODULE_VERSION(cxl, 1);
8452